diff --git a/.github/workflows/lint_mypy.yml b/.github/workflows/lint_mypy.yml index 5f98068c4..8f6d917eb 100644 --- a/.github/workflows/lint_mypy.yml +++ b/.github/workflows/lint_mypy.yml @@ -30,4 +30,4 @@ jobs: with: python-version: '3.x' - run: python -m pip install mypy - - run: mypy --follow-imports=skip mesonbuild/mtest.py mesonbuild/minit.py mesonbuild/mintro.py mesonbuild/mparser.py mesonbuild/msetup.py mesonbuild/wrap tools/ mesonbuild/modules/fs.py mesonbuild/dependencies/boost.py mesonbuild/dependencies/mpi.py mesonbuild/dependencies/hdf5.py mesonbuild/compilers/mixins/intel.py mesonbuild/mlog.py + - run: mypy --follow-imports=skip mesonbuild/interpreterbase.py mesonbuild/mtest.py mesonbuild/minit.py mesonbuild/mintro.py mesonbuild/mparser.py mesonbuild/msetup.py mesonbuild/ast mesonbuild/wrap tools/ mesonbuild/modules/fs.py mesonbuild/dependencies/boost.py mesonbuild/dependencies/mpi.py mesonbuild/dependencies/hdf5.py mesonbuild/compilers/mixins/intel.py mesonbuild/mlog.py diff --git a/mesonbuild/ast/interpreter.py b/mesonbuild/ast/interpreter.py index 0eb76ccb7..fd04efd09 100644 --- a/mesonbuild/ast/interpreter.py +++ b/mesonbuild/ast/interpreter.py @@ -19,7 +19,7 @@ from .visitor import AstVisitor from .. import interpreterbase, mparser, mesonlib from .. import environment -from ..interpreterbase import InvalidArguments, BreakRequest, ContinueRequest, TYPE_nvar, TYPE_nkwargs +from ..interpreterbase import InvalidArguments, BreakRequest, ContinueRequest, TYPE_nvar from ..mparser import ( AndNode, ArgumentNode, @@ -341,7 +341,7 @@ class AstInterpreter(interpreterbase.InterpreterBase): return result - def flatten_args(self, args_raw: T.Sequence[TYPE_nvar], include_unknown_args: bool = False, id_loop_detect: T.Optional[T.List[str]] = None) -> T.List[TYPE_nvar]: + def flatten_args(self, args_raw: T.Union[TYPE_nvar, T.Sequence[TYPE_nvar]], include_unknown_args: bool = False, id_loop_detect: T.Optional[T.List[str]] = None) -> T.List[TYPE_nvar]: # Make sure we are always dealing with lists if isinstance(args_raw, list): args = args_raw @@ -362,17 +362,9 @@ class AstInterpreter(interpreterbase.InterpreterBase): flattend_args += [i] return flattend_args - def flatten_kwargs(self, kwargs: TYPE_nkwargs, include_unknown_args: bool = False) -> T.Dict[str, TYPE_nvar]: + def flatten_kwargs(self, kwargs: T.Dict[str, TYPE_nvar], include_unknown_args: bool = False) -> T.Dict[str, TYPE_nvar]: flattend_kwargs = {} - for key_node, val in kwargs.items(): - key = None # type: str - if isinstance(key_node, str): - key = key_node - elif isinstance(key_node, StringNode): - assert isinstance(key_node.value, str) - key = key_node.value - else: - continue + for key, val in kwargs.items(): if isinstance(val, BaseNode): resolved = self.resolve_node(val, include_unknown_args) if resolved is not None: diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 083725329..c60c24b3b 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -15,28 +15,38 @@ # This class contains the basic functionality needed to run any interpreter # or an interpreter-based tool -from . import AstInterpreter +from .interpreter import AstInterpreter +from .visitor import AstVisitor from .. import compilers, environment, mesonlib, optinterpreter from .. import coredata as cdata from ..mesonlib import MachineChoice -from ..interpreterbase import InvalidArguments +from ..interpreterbase import InvalidArguments, TYPE_nvar from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, StringNode +from typing import Any, Dict, List, Optional import os build_target_functions = ['executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library', 'both_libraries'] class IntrospectionHelper: # mimic an argparse namespace - def __init__(self, cross_file): - self.cross_file = cross_file - self.native_file = None - self.cmd_line_options = {} + def __init__(self, cross_file: str) -> None: + self.cross_file = cross_file # type: str + self.native_file = None # type: str + self.cmd_line_options = {} # type: Dict[str, str] class IntrospectionInterpreter(AstInterpreter): # Interpreter to detect the options without a build directory # Most of the code is stolen from interpreter.Interpreter - def __init__(self, source_root, subdir, backend, visitors=None, cross_file=None, subproject='', subproject_dir='subprojects', env=None): + def __init__(self, + source_root: str, + subdir: str, + backend: str, + visitors: Optional[List[AstVisitor]] = None, + cross_file: Optional[str] = None, + subproject: str = '', + subproject_dir: str = 'subprojects', + env: Optional[environment.Environment] = None) -> None: visitors = visitors if visitors is not None else [] super().__init__(source_root, subdir, subproject, visitors=visitors) @@ -51,10 +61,10 @@ class IntrospectionInterpreter(AstInterpreter): self.option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt') self.backend = backend self.default_options = {'backend': self.backend} - self.project_data = {} - self.targets = [] - self.dependencies = [] - self.project_node = None + self.project_data = {} # type: Dict[str, Any] + self.targets = [] # type: List[Dict[str, Any]] + self.dependencies = [] # type: List[Dict[str, Any]] + self.project_node = None # type: BaseNode self.funcs.update({ 'add_languages': self.func_add_languages, @@ -69,7 +79,7 @@ class IntrospectionInterpreter(AstInterpreter): 'both_libraries': self.func_both_lib, }) - def func_project(self, node, args, kwargs): + def func_project(self, node: BaseNode, args: List[TYPE_nvar], kwargs: Dict[str, TYPE_nvar]) -> None: if self.project_node: raise InvalidArguments('Second call to project()') self.project_node = node @@ -98,7 +108,8 @@ class IntrospectionInterpreter(AstInterpreter): if not self.is_subproject() and 'subproject_dir' in kwargs: spdirname = kwargs['subproject_dir'] - if isinstance(spdirname, ElementaryNode): + if isinstance(spdirname, StringNode): + assert isinstance(spdirname.value, str) self.subproject_dir = spdirname.value if not self.is_subproject(): self.project_data['subprojects'] = [] @@ -114,7 +125,7 @@ class IntrospectionInterpreter(AstInterpreter): self.coredata.set_options(options) self.func_add_languages(None, proj_langs, None) - def do_subproject(self, dirname): + def do_subproject(self, dirname: str) -> None: subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir) subpr = os.path.join(subproject_dir_abs, dirname) try: @@ -125,15 +136,20 @@ class IntrospectionInterpreter(AstInterpreter): except (mesonlib.MesonException, RuntimeError): return - def func_add_languages(self, node, args, kwargs): + def func_add_languages(self, node: BaseNode, args: List[TYPE_nvar], kwargs: Dict[str, TYPE_nvar]) -> None: args = self.flatten_args(args) for for_machine in [MachineChoice.BUILD, MachineChoice.HOST]: for lang in sorted(args, key=compilers.sort_clink): + if isinstance(lang, StringNode): + assert isinstance(lang.value, str) + lang = lang.value + if not isinstance(lang, str): + continue lang = lang.lower() if lang not in self.coredata.compilers[for_machine]: self.environment.detect_compiler_for(lang, for_machine) - def func_dependency(self, node, args, kwargs): + def func_dependency(self, node: BaseNode, args: List[TYPE_nvar], kwargs: Dict[str, TYPE_nvar]) -> None: args = self.flatten_args(args) kwargs = self.flatten_kwargs(kwargs) if not args: @@ -157,20 +173,20 @@ class IntrospectionInterpreter(AstInterpreter): 'node': node }] - def build_target(self, node, args, kwargs, targetclass): + def build_target(self, node: BaseNode, args: List[TYPE_nvar], kwargs_raw: Dict[str, TYPE_nvar], targetclass) -> Optional[Dict[str, Any]]: args = self.flatten_args(args) if not args or not isinstance(args[0], str): - return + return None name = args[0] srcqueue = [node] # Process the sources BEFORE flattening the kwargs, to preserve the original nodes - if 'sources' in kwargs: - srcqueue += mesonlib.listify(kwargs['sources']) + if 'sources' in kwargs_raw: + srcqueue += mesonlib.listify(kwargs_raw['sources']) - kwargs = self.flatten_kwargs(kwargs, True) + kwargs = self.flatten_kwargs(kwargs_raw, True) - source_nodes = [] + source_nodes = [] # type: List[BaseNode] while srcqueue: curr = srcqueue.pop(0) arg_node = None @@ -181,6 +197,7 @@ class IntrospectionInterpreter(AstInterpreter): arg_node = curr.args elif isinstance(curr, IdNode): # Try to resolve the ID and append the node to the queue + assert isinstance(curr.value, str) var_name = curr.value if var_name in self.assignments: tmp_node = self.assignments[var_name] @@ -204,8 +221,9 @@ class IntrospectionInterpreter(AstInterpreter): kwargs_reduced = {k: v.value if isinstance(v, ElementaryNode) else v for k, v in kwargs_reduced.items()} kwargs_reduced = {k: v for k, v in kwargs_reduced.items() if not isinstance(v, BaseNode)} for_machine = MachineChoice.HOST - objects = [] - empty_sources = [] # Passing the unresolved sources list causes errors + objects = [] # type: List[Any] + empty_sources = [] # type: List[Any] + # Passing the unresolved sources list causes errors target = targetclass(name, self.subdir, self.subproject, for_machine, empty_sources, objects, self.environment, kwargs_reduced) new_target = { @@ -225,7 +243,7 @@ class IntrospectionInterpreter(AstInterpreter): self.targets += [new_target] return new_target - def build_library(self, node, args, kwargs): + def build_library(self, node: BaseNode, args: List[TYPE_nvar], kwargs: Dict[str, TYPE_nvar]) -> Optional[Dict[str, Any]]: default_library = self.coredata.get_builtin_option('default_library') if default_library == 'shared': return self.build_target(node, args, kwargs, SharedLibrary) @@ -233,31 +251,32 @@ class IntrospectionInterpreter(AstInterpreter): return self.build_target(node, args, kwargs, StaticLibrary) elif default_library == 'both': return self.build_target(node, args, kwargs, SharedLibrary) + return None - def func_executable(self, node, args, kwargs): + def func_executable(self, node: BaseNode, args: List[TYPE_nvar], kwargs: Dict[str, TYPE_nvar]) -> Optional[Dict[str, Any]]: return self.build_target(node, args, kwargs, Executable) - def func_static_lib(self, node, args, kwargs): + def func_static_lib(self, node: BaseNode, args: List[TYPE_nvar], kwargs: Dict[str, TYPE_nvar]) -> Optional[Dict[str, Any]]: return self.build_target(node, args, kwargs, StaticLibrary) - def func_shared_lib(self, node, args, kwargs): + def func_shared_lib(self, node: BaseNode, args: List[TYPE_nvar], kwargs: Dict[str, TYPE_nvar]) -> Optional[Dict[str, Any]]: return self.build_target(node, args, kwargs, SharedLibrary) - def func_both_lib(self, node, args, kwargs): + def func_both_lib(self, node: BaseNode, args: List[TYPE_nvar], kwargs: Dict[str, TYPE_nvar]) -> Optional[Dict[str, Any]]: return self.build_target(node, args, kwargs, SharedLibrary) - def func_shared_module(self, node, args, kwargs): + def func_shared_module(self, node: BaseNode, args: List[TYPE_nvar], kwargs: Dict[str, TYPE_nvar]) -> Optional[Dict[str, Any]]: return self.build_target(node, args, kwargs, SharedModule) - def func_library(self, node, args, kwargs): + def func_library(self, node: BaseNode, args: List[TYPE_nvar], kwargs: Dict[str, TYPE_nvar]) -> Optional[Dict[str, Any]]: return self.build_library(node, args, kwargs) - def func_jar(self, node, args, kwargs): + def func_jar(self, node: BaseNode, args: List[TYPE_nvar], kwargs: Dict[str, TYPE_nvar]) -> Optional[Dict[str, Any]]: return self.build_target(node, args, kwargs, Jar) - def func_build_target(self, node, args, kwargs): + def func_build_target(self, node: BaseNode, args: List[TYPE_nvar], kwargs: Dict[str, TYPE_nvar]) -> Optional[Dict[str, Any]]: if 'target_type' not in kwargs: - return + return None target_type = kwargs.pop('target_type') if isinstance(target_type, ElementaryNode): target_type = target_type.value @@ -273,11 +292,12 @@ class IntrospectionInterpreter(AstInterpreter): return self.build_library(node, args, kwargs) elif target_type == 'jar': return self.build_target(node, args, kwargs, Jar) + return None - def is_subproject(self): + def is_subproject(self) -> bool: return self.subproject != '' - def analyze(self): + def analyze(self) -> None: self.load_root_meson_file() self.sanity_check_ast() self.parse_project()