Skip to content

Commit e005e9a

Browse files
committed
interpreter: Rework extract_required_kwarg to have better typing
This allows us to avoid making `feature` a union, therefore if we write code like: ```python disabled, required, feature = extract_required_kwarg(...) if disabled: ... ``` and now mypy knows that feature is a `str` inside the `if disabled` block
1 parent 87dac85 commit e005e9a

File tree

2 files changed

+24
-9
lines changed

2 files changed

+24
-9
lines changed

mesonbuild/interpreter/interpreter.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,6 @@ def do_subproject(self, subp_name: str, kwargs: kwtypes.DoSubproject, force_meth
868868
pass
869869
disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
870870
if disabled:
871-
assert feature, 'for mypy'
872871
mlog.log('Subproject', mlog.bold(subp_name), ':', 'skipped: feature', mlog.bold(feature), 'disabled')
873872
return self.disabled_subproject(subp_name, disabled_feature=feature)
874873

@@ -1299,7 +1298,6 @@ def func_add_languages(self, node: mparser.FunctionNode, args: T.Tuple[T.List[st
12991298
native = kwargs['native']
13001299

13011300
if disabled:
1302-
assert feature, 'for mypy'
13031301
for lang in sorted(langs, key=compilers.sort_clink):
13041302
mlog.log('Compiler for language', mlog.bold(lang), 'skipped: feature', mlog.bold(feature), 'disabled')
13051303
return False
@@ -1754,7 +1752,6 @@ def func_find_program(self, node: mparser.BaseNode, args: T.Tuple[T.List[mesonli
17541752
) -> T.Union['build.Executable', ExternalProgram, 'OverrideProgram']:
17551753
disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
17561754
if disabled:
1757-
assert feature, 'for mypy'
17581755
mlog.log('Program', mlog.bold(' '.join(args[0])), 'skipped: feature', mlog.bold(feature), 'disabled')
17591756
return self.notfound_program(args[0])
17601757

mesonbuild/interpreter/interpreterobjects.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
from ..interpreterbase import FeatureCheckBase, SubProject, TYPE_var, TYPE_kwargs, TYPE_nvar, TYPE_nkwargs
3737
from .interpreter import Interpreter
3838

39-
from typing_extensions import TypedDict
39+
from typing_extensions import Literal, TypedDict
4040

4141
class EnvironmentSeparatorKW(TypedDict):
4242

@@ -52,18 +52,36 @@ class InternalDependencyAsKW(TypedDict):
5252
def extract_required_kwarg(kwargs: 'kwargs.ExtractRequired',
5353
subproject: 'SubProject',
5454
feature_check: T.Optional[FeatureCheckBase] = None,
55-
default: bool = True) -> T.Tuple[bool, bool, T.Optional[str]]:
55+
default: bool = True
56+
) -> T.Union[T.Tuple[Literal[True], bool, str],
57+
T.Tuple[Literal[False], bool, None]]:
58+
"""Check common keyword arguments for required status.
59+
60+
This handles booleans vs feature option.
61+
62+
:param kwargs:
63+
keyword arguments from the Interpreter, containing a `required` argument
64+
:param subproject: The subproject this is
65+
:param feature_check:
66+
A custom feature check for this use of `required` with a
67+
`UserFeatureOption`, defaults to None.
68+
:param default:
69+
The default value is `required` is not set in `kwargs`, defaults to
70+
True
71+
:raises InterpreterException: If the type of `kwargs['required']` is invalid
72+
:return:
73+
a tuple of `disabled, required, feature_name`. If `disabled` is `True`
74+
`feature_name` will be a string, otherwise it is `None`
75+
"""
5676
val = kwargs.get('required', default)
57-
disabled = False
5877
required = False
59-
feature: T.Optional[str] = None
6078
if isinstance(val, options.UserFeatureOption):
6179
if not feature_check:
6280
feature_check = FeatureNew('User option "feature"', '0.47.0')
6381
feature_check.use(subproject)
6482
feature = val.name
6583
if val.is_disabled():
66-
disabled = True
84+
return True, required, feature
6785
elif val.is_enabled():
6886
required = True
6987
elif isinstance(val, bool):
@@ -76,7 +94,7 @@ def extract_required_kwarg(kwargs: 'kwargs.ExtractRequired',
7694
# TODO: this should be removed, and those callers should learn about FeatureOptions
7795
kwargs['required'] = required
7896

79-
return disabled, required, feature
97+
return False, required, None
8098

8199
def extract_search_dirs(kwargs: 'kwargs.ExtractSearchDirs') -> T.List[str]:
82100
search_dirs_str = mesonlib.stringlistify(kwargs.get('dirs', []))

0 commit comments

Comments
 (0)