From 930cbdb86d5db3e5222d385fb785359000288d94 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 1 Dec 2021 22:31:24 -0800 Subject: [PATCH] Add deprecated_message and since_message to KwargInfo For passing an extra message to Feature* This allows providing a more detailed message. --- mesonbuild/interpreterbase/decorators.py | 23 +++++++++++++++++------ unittests/internaltests.py | 12 ++++++------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/mesonbuild/interpreterbase/decorators.py b/mesonbuild/interpreterbase/decorators.py index 9434ab709..1a203f832 100644 --- a/mesonbuild/interpreterbase/decorators.py +++ b/mesonbuild/interpreterbase/decorators.py @@ -362,7 +362,10 @@ class KwargInfo(T.Generic[_T]): this may be safely set to a mutable type, as long as that type does not itself contain mutable types, typed_kwargs will copy the default :param since: Meson version in which this argument has been added. defaults to None + :param since_message: An extra message to pass to FeatureNew when since is triggered :param deprecated: Meson version in which this argument has been deprecated. defaults to None + :param deprecated_message: An extra message to pass to FeatureDeprecated + when since is triggered :param validator: A callable that does additional validation. This is mainly intended for cases where a string is expected, but only a few specific values are accepted. Must return None if the input is valid, or a @@ -384,8 +387,10 @@ class KwargInfo(T.Generic[_T]): *, required: bool = False, listify: bool = False, default: T.Optional[_T] = None, since: T.Optional[str] = None, - since_values: T.Optional[T.Dict[str, str]] = None, + since_message: T.Optional[str] = None, + since_values: T.Optional[T.Dict[_T, str]] = None, deprecated: T.Optional[str] = None, + deprecated_message: T.Optional[str] = None, deprecated_values: T.Optional[T.Dict[_T, str]] = None, validator: T.Optional[T.Callable[[T.Any], T.Optional[str]]] = None, convertor: T.Optional[T.Callable[[_T], object]] = None, @@ -395,9 +400,11 @@ class KwargInfo(T.Generic[_T]): self.required = required self.listify = listify self.default = default - self.since_values = since_values self.since = since + self.since_message = since_message + self.since_values = since_values self.deprecated = deprecated + self.deprecated_message = deprecated_message self.deprecated_values = deprecated_values self.validator = validator self.convertor = convertor @@ -409,9 +416,11 @@ class KwargInfo(T.Generic[_T]): listify: T.Union[bool, _NULL_T] = _NULL, default: T.Union[_T, None, _NULL_T] = _NULL, since: T.Union[str, None, _NULL_T] = _NULL, - since_values: T.Union[T.Dict[str, str], None, _NULL_T] = _NULL, + since_message: T.Union[str, None, _NULL_T] = _NULL, + since_values: T.Union[T.Dict[_T, str], None, _NULL_T] = _NULL, deprecated: T.Union[str, None, _NULL_T] = _NULL, - deprecated_values: T.Union[T.Dict[str, str], None, _NULL_T] = _NULL, + deprecated_message: T.Union[str, None, _NULL_T] = _NULL, + deprecated_values: T.Union[T.Dict[_T, str], None, _NULL_T] = _NULL, validator: T.Union[T.Callable[[_T], T.Optional[str]], None, _NULL_T] = _NULL, convertor: T.Union[T.Callable[[_T], TYPE_var], None, _NULL_T] = _NULL) -> 'KwargInfo': """Create a shallow copy of this KwargInfo, with modifications. @@ -432,8 +441,10 @@ class KwargInfo(T.Generic[_T]): required=required if not isinstance(required, _NULL_T) else self.required, default=default if not isinstance(default, _NULL_T) else self.default, since=since if not isinstance(since, _NULL_T) else self.since, + since_message=since_message if not isinstance(since_message, _NULL_T) else self.since_message, since_values=since_values if not isinstance(since_values, _NULL_T) else self.since_values, deprecated=deprecated if not isinstance(deprecated, _NULL_T) else self.deprecated, + deprecated_message=deprecated_message if not isinstance(deprecated_message, _NULL_T) else self.deprecated_message, deprecated_values=deprecated_values if not isinstance(deprecated_values, _NULL_T) else self.deprecated_values, validator=validator if not isinstance(validator, _NULL_T) else self.validator, convertor=convertor if not isinstance(convertor, _NULL_T) else self.convertor, @@ -508,10 +519,10 @@ def typed_kwargs(name: str, *types: KwargInfo) -> T.Callable[..., T.Any]: if value is not None: if info.since: feature_name = info.name + ' arg in ' + name - FeatureNew.single_use(feature_name, info.since, subproject, location=node) + FeatureNew.single_use(feature_name, info.since, subproject, info.since_message, location=node) if info.deprecated: feature_name = info.name + ' arg in ' + name - FeatureDeprecated.single_use(feature_name, info.deprecated, subproject, location=node) + FeatureDeprecated.single_use(feature_name, info.deprecated, subproject, info.deprecated_message, location=node) if info.listify: kwargs[info.name] = value = mesonlib.listify(value) if not check_value_type(types_tuple, value): diff --git a/unittests/internaltests.py b/unittests/internaltests.py index eca9cff96..a332d81e1 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -1319,7 +1319,8 @@ class InternalTests(unittest.TestCase): def test_typed_kwarg_since(self) -> None: @typed_kwargs( 'testfunc', - KwargInfo('input', str, since='1.0', deprecated='2.0') + KwargInfo('input', str, since='1.0', since_message='Its awesome, use it', + deprecated='2.0', deprecated_message='Its terrible, dont use it') ) def _(obj, node, args: T.Tuple, kwargs: T.Dict[str, str]) -> None: self.assertIsInstance(kwargs['input'], str) @@ -1330,8 +1331,8 @@ class InternalTests(unittest.TestCase): mock.patch('mesonbuild.mesonlib.project_meson_versions', {'': '0.1'}): # With Meson 0.1 it should trigger the "introduced" warning but not the "deprecated" warning _(None, mock.Mock(subproject=''), [], {'input': 'foo'}) - self.assertRegex(out.getvalue(), r'WARNING:.*introduced.*input arg in testfunc') - self.assertNotRegex(out.getvalue(), r'WARNING:.*deprecated.*input arg in testfunc') + self.assertRegex(out.getvalue(), r'WARNING:.*introduced.*input arg in testfunc. Its awesome, use it') + self.assertNotRegex(out.getvalue(), r'WARNING:.*deprecated.*input arg in testfunc. Its terrible, dont use it') with self.subTest('no warnings should be triggered'), \ mock.patch('sys.stdout', io.StringIO()) as out, \ @@ -1339,15 +1340,14 @@ class InternalTests(unittest.TestCase): # With Meson 1.5 it shouldn't trigger any warning _(None, mock.Mock(subproject=''), [], {'input': 'foo'}) self.assertNotRegex(out.getvalue(), r'WARNING:.*') - self.assertNotRegex(out.getvalue(), r'WARNING:.*') with self.subTest('use after deprecated'), \ mock.patch('sys.stdout', io.StringIO()) as out, \ mock.patch('mesonbuild.mesonlib.project_meson_versions', {'': '2.0'}): # With Meson 2.0 it should trigger the "deprecated" warning but not the "introduced" warning _(None, mock.Mock(subproject=''), [], {'input': 'foo'}) - self.assertRegex(out.getvalue(), r'WARNING:.*deprecated.*input arg in testfunc') - self.assertNotRegex(out.getvalue(), r'WARNING:.*introduced.*input arg in testfunc') + self.assertRegex(out.getvalue(), r'WARNING:.*deprecated.*input arg in testfunc. Its terrible, dont use it') + self.assertNotRegex(out.getvalue(), r'WARNING:.*introduced.*input arg in testfunc. Its awesome, use it') def test_typed_kwarg_validator(self) -> None: @typed_kwargs(