aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2021-06-01 15:42:07 -0400
committerXavier Claessens <xclaesse@gmail.com>2021-06-01 20:01:20 -0400
commit16c3f033943206b4b90532a9656f64678e87a7ec (patch)
treedf2087377105deb1dcbe0a337befa913395da892
parent6aef800ba83a4dd469c354900b6e537777d3080c (diff)
downloadmeson-16c3f033943206b4b90532a9656f64678e87a7ec.zip
meson-16c3f033943206b4b90532a9656f64678e87a7ec.tar.gz
meson-16c3f033943206b4b90532a9656f64678e87a7ec.tar.bz2
typed_kwargs: Add since and deprecated annotations
-rw-r--r--mesonbuild/interpreterbase.py19
-rwxr-xr-xrun_unittests.py32
2 files changed, 47 insertions, 4 deletions
diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py
index ed0f9fa..4318023 100644
--- a/mesonbuild/interpreterbase.py
+++ b/mesonbuild/interpreterbase.py
@@ -420,15 +420,20 @@ class KwargInfo(T.Generic[_T]):
checked. This is useful for cases where the Meson DSL allows a scalar or
a container, but internally we only want to work with containers
:param default: A default value to use if this isn't set. defaults to None
+ :param since: Meson version in which this argument has been added. defaults to None
+ :param deprecated: Meson version in which this argument has been deprecated. defaults to None
"""
def __init__(self, name: str, types: T.Union[T.Type[_T], T.Tuple[T.Type[_T], ...], ContainerTypeInfo],
- required: bool = False, listify: bool = False, default: T.Optional[_T] = None):
+ required: bool = False, listify: bool = False, default: T.Optional[_T] = None,
+ since: T.Optional[str] = None, deprecated: T.Optional[str] = None):
self.name = name
self.types = types
self.required = required
self.listify = listify
self.default = default
+ self.since = since
+ self.deprecated = deprecated
def typed_kwargs(name: str, *types: KwargInfo) -> T.Callable[..., T.Any]:
@@ -447,7 +452,7 @@ def typed_kwargs(name: str, *types: KwargInfo) -> T.Callable[..., T.Any]:
@wraps(f)
def wrapper(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
- kwargs = _get_callee_args(wrapped_args)[3]
+ kwargs, subproject = _get_callee_args(wrapped_args, want_subproject=True)[3:5]
all_names = {t.name for t in types}
unknowns = set(kwargs).difference(all_names)
@@ -460,8 +465,14 @@ def typed_kwargs(name: str, *types: KwargInfo) -> T.Callable[..., T.Any]:
del kwargs[u]
for info in types:
- if info.name in kwargs:
- value = kwargs[info.name]
+ value = kwargs.get(info.name)
+ if value is not None:
+ if info.since:
+ feature_name = info.name + ' arg in ' + name
+ FeatureNew.single_use(feature_name, info.since, subproject)
+ if info.deprecated:
+ feature_name = info.name + ' arg in ' + name
+ FeatureDeprecated.single_use(feature_name, info.deprecated, subproject)
if info.listify:
kwargs[info.name] = value = mesonlib.listify(value)
if isinstance(info.types, ContainerTypeInfo):
diff --git a/run_unittests.py b/run_unittests.py
index 1c6d491..3a98368 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -1586,6 +1586,38 @@ class InternalTests(unittest.TestCase):
_(None, mock.Mock(), [], {'input': ['a']})
self.assertEqual(str(cm.exception), "testfunc keyword argument \"input\" container should be of even length, but is not")
+ def test_typed_kwarg_since(self) -> None:
+ @typed_kwargs(
+ 'testfunc',
+ KwargInfo('input', str, since='1.0', deprecated='2.0')
+ )
+ def _(obj, node, args: T.Tuple, kwargs: T.Dict[str, str]) -> None:
+ self.assertIsInstance(kwargs['input'], str)
+ self.assertEqual(kwargs['input'], 'foo')
+
+ # With Meson 0.1 it should trigger the "introduced" warning but not the "deprecated" warning
+ mesonbuild.mesonlib.project_meson_versions[''] = '0.1'
+ sys.stdout = io.StringIO()
+ _(None, mock.Mock(subproject=''), [], {'input': 'foo'})
+ self.assertRegex(sys.stdout.getvalue(), r'WARNING:.*introduced.*input arg in testfunc')
+ self.assertNotRegex(sys.stdout.getvalue(), r'WARNING:.*deprecated.*input arg in testfunc')
+
+ # With Meson 1.5 it shouldn't trigger any warning
+ mesonbuild.mesonlib.project_meson_versions[''] = '1.5'
+ sys.stdout = io.StringIO()
+ _(None, mock.Mock(subproject=''), [], {'input': 'foo'})
+ self.assertNotRegex(sys.stdout.getvalue(), r'WARNING:.*')
+ self.assertNotRegex(sys.stdout.getvalue(), r'WARNING:.*')
+
+ # With Meson 2.0 it should trigger the "deprecated" warning but not the "introduced" warning
+ mesonbuild.mesonlib.project_meson_versions[''] = '2.0'
+ sys.stdout = io.StringIO()
+ _(None, mock.Mock(subproject=''), [], {'input': 'foo'})
+ self.assertRegex(sys.stdout.getvalue(), r'WARNING:.*deprecated.*input arg in testfunc')
+ self.assertNotRegex(sys.stdout.getvalue(), r'WARNING:.*introduced.*input arg in testfunc')
+
+ sys.stdout = sys.__stdout__
+
@unittest.skipIf(is_tarball(), 'Skipping because this is a tarball release')
class DataTests(unittest.TestCase):