FeatureNew: add mypy type annotations for subproject arg

Use a derived type when passing `subproject` around, so that mypy knows
it's actually a SubProject, not a str. This means that passing anything
other than a handle to the interpreter state's subproject attribute
becomes a type violation, specifically when the order of the *four*
different str arguments is typoed.
pull/9990/head
Eli Schwartz 3 years ago
parent bab651a7a0
commit c0b8e02d9f
No known key found for this signature in database
GPG Key ID: CEB167EFB5722BD6
  1. 5
      mesonbuild/build.py
  2. 3
      mesonbuild/interpreter/interpreterobjects.py
  3. 5
      mesonbuild/interpreter/primitives/range.py
  4. 4
      mesonbuild/interpreterbase/__init__.py
  5. 6
      mesonbuild/interpreterbase/baseobjects.py
  6. 7
      mesonbuild/interpreterbase/decorators.py
  7. 4
      mesonbuild/interpreterbase/interpreterbase.py
  8. 3
      mesonbuild/optinterpreter.py
  9. 3
      mesonbuild/wrap/wrap.py

@ -49,6 +49,7 @@ if T.TYPE_CHECKING:
from ._typing import ImmutableListProtocol, ImmutableSetProtocol
from .backend.backends import Backend, ExecutableSerialisation
from .interpreter.interpreter import Test, SourceOutputs, Interpreter
from .interpreterbase import SubProject
from .mesonlib import FileMode, FileOrString
from .modules import ModuleState
from .mparser import BaseNode
@ -514,7 +515,7 @@ class Target(HoldableObject):
name: str
subdir: str
subproject: str
subproject: 'SubProject'
build_by_default: bool
for_machine: MachineChoice
@ -675,7 +676,7 @@ class BuildTarget(Target):
install_dir: T.List[T.Union[str, bool]]
def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice,
def __init__(self, name: str, subdir: str, subproject: 'SubProject', for_machine: MachineChoice,
sources: T.List['SourceOutputs'], objects, environment: environment.Environment, kwargs):
super().__init__(name, subdir, subproject, True, for_machine)
unity_opt = environment.coredata.get_option(OptionKey('unity'))

@ -31,6 +31,7 @@ if T.TYPE_CHECKING:
from . import kwargs
from .interpreter import Interpreter
from ..envconfig import MachineInfo
from ..interpreterbase import SubProject
from typing_extensions import TypedDict
@ -40,7 +41,7 @@ if T.TYPE_CHECKING:
def extract_required_kwarg(kwargs: 'kwargs.ExtractRequired',
subproject: str,
subproject: 'SubProject',
feature_check: T.Optional[FeatureCheckBase] = None,
default: bool = True) -> T.Tuple[bool, bool, T.Optional[str]]:
val = kwargs.get('required', default)

@ -10,8 +10,11 @@ from ...interpreterbase import (
InvalidArguments,
)
if T.TYPE_CHECKING:
from ...interpreterbase import SubProject
class RangeHolder(MesonInterpreterObject, IterableObject):
def __init__(self, start: int, stop: int, step: int, *, subproject: str) -> None:
def __init__(self, start: int, stop: int, step: int, *, subproject: 'SubProject') -> None:
super().__init__(subproject=subproject)
self.range = range(start, stop, step)
self.operators.update({

@ -57,6 +57,8 @@ __all__ = [
'InterpreterBase',
'SubProject',
'TV_fw_var',
'TV_fw_args',
'TV_fw_kwargs',
@ -91,6 +93,8 @@ from .baseobjects import (
TYPE_key_resolver,
TYPE_HoldableTypes,
SubProject,
HoldableTypes,
)

@ -39,6 +39,8 @@ TYPE_kwargs = T.Dict[str, TYPE_var]
TYPE_nkwargs = T.Dict[str, TYPE_nvar]
TYPE_key_resolver = T.Callable[[mparser.BaseNode], str]
SubProject = T.NewType('SubProject', str)
if T.TYPE_CHECKING:
from typing_extensions import Protocol
__T = T.TypeVar('__T', bound=TYPE_var, contravariant=True)
@ -47,7 +49,7 @@ if T.TYPE_CHECKING:
def __call__(self, other: __T) -> TYPE_var: ...
class InterpreterObject:
def __init__(self, *, subproject: T.Optional[str] = None) -> None:
def __init__(self, *, subproject: T.Optional['SubProject'] = None) -> None:
self.methods: T.Dict[
str,
T.Callable[[T.List[TYPE_var], TYPE_kwargs], TYPE_var]
@ -63,7 +65,7 @@ class InterpreterObject:
# Current node set during a method call. This can be used as location
# when printing a warning message during a method call.
self.current_node: mparser.BaseNode = None
self.subproject: str = subproject or ''
self.subproject = subproject or SubProject('')
# Some default operators supported by all objects
self.operators.update({

@ -27,8 +27,9 @@ import copy
import typing as T
if T.TYPE_CHECKING:
from .. import mparser
from .interpreterbase import SubProject
def get_callee_args(wrapped_args: T.Sequence[T.Any]) -> T.Tuple['mparser.BaseNode', T.List['TYPE_var'], 'TYPE_kwargs', str]:
def get_callee_args(wrapped_args: T.Sequence[T.Any]) -> T.Tuple['mparser.BaseNode', T.List['TYPE_var'], 'TYPE_kwargs', 'SubProject']:
# First argument could be InterpreterBase, InterpreterObject or ModuleObject.
# In the case of a ModuleObject it is the 2nd argument (ModuleState) that
# contains the needed information.
@ -600,7 +601,7 @@ class FeatureCheckBase(metaclass=abc.ABCMeta):
def check_version(target_version: str, feature_version: str) -> bool:
pass
def use(self, subproject: str) -> None:
def use(self, subproject: 'SubProject') -> None:
tv = self.get_target_version(subproject)
# No target version
if tv == '':
@ -668,7 +669,7 @@ class FeatureCheckBase(metaclass=abc.ABCMeta):
return T.cast(TV_func, wrapped)
@classmethod
def single_use(cls, feature_name: str, version: str, subproject: str,
def single_use(cls, feature_name: str, version: str, subproject: 'SubProject',
extra_message: str = '', location: T.Optional['mparser.BaseNode'] = None) -> None:
"""Oneline version that instantiates and calls use()."""
cls(feature_name, version, extra_message, location).use(subproject)

@ -26,6 +26,8 @@ from .baseobjects import (
ObjectHolder,
IterableObject,
SubProject,
TYPE_var,
TYPE_kwargs,
@ -73,7 +75,7 @@ FunctionType = T.Dict[
]
class InterpreterBase:
def __init__(self, source_root: str, subdir: str, subproject: str):
def __init__(self, source_root: str, subdir: str, subproject: 'SubProject'):
self.source_root = source_root
self.funcs: FunctionType = {}
self.builtin: T.Dict[str, InterpreterObject] = {}

@ -22,6 +22,7 @@ from . import mlog
from .interpreterbase import FeatureNew, typed_pos_args, typed_kwargs, ContainerTypeInfo, KwargInfo, permittedKwargs
if T.TYPE_CHECKING:
from .interpreterbase import TYPE_var, TYPE_kwargs
from .interpreterbase import SubProject
from typing_extensions import TypedDict
FuncOptionArgs = TypedDict('FuncOptionArgs', {
'type': str,
@ -50,7 +51,7 @@ optname_regex = re.compile('[^a-zA-Z0-9_-]')
class OptionInterpreter:
def __init__(self, subproject: str) -> None:
def __init__(self, subproject: 'SubProject') -> None:
self.options: 'coredata.KeyedOptionDictType' = {}
self.subproject = subproject
self.option_types = {'string': self.string_parser,

@ -35,6 +35,7 @@ from . import WrapMode
from .. import coredata
from ..mesonlib import quiet_git, GIT, ProgressBar, MesonException, windows_proof_rmtree
from ..interpreterbase import FeatureNew
from ..interpreterbase import SubProject
from .. import mesonlib
if T.TYPE_CHECKING:
@ -95,7 +96,7 @@ class WrapNotFoundException(WrapException):
class PackageDefinition:
def __init__(self, fname: str, subproject: str = ''):
self.filename = fname
self.subproject = subproject
self.subproject = SubProject(subproject)
self.type = None # type: T.Optional[str]
self.values = {} # type: T.Dict[str, str]
self.provided_deps = {} # type: T.Dict[str, T.Optional[str]]

Loading…
Cancel
Save