types: Annotate ast/introspection.py

pull/6316/head
Daniel Mensinger 5 years ago
parent 5a89a6f804
commit ad5df1b9c3
No known key found for this signature in database
GPG Key ID: 54DD94C131E277D4
  1. 2
      .github/workflows/lint_mypy.yml
  2. 16
      mesonbuild/ast/interpreter.py
  3. 92
      mesonbuild/ast/introspection.py

@ -30,4 +30,4 @@ jobs:
with: with:
python-version: '3.x' python-version: '3.x'
- run: python -m pip install mypy - 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

@ -19,7 +19,7 @@ from .visitor import AstVisitor
from .. import interpreterbase, mparser, mesonlib from .. import interpreterbase, mparser, mesonlib
from .. import environment from .. import environment
from ..interpreterbase import InvalidArguments, BreakRequest, ContinueRequest, TYPE_nvar, TYPE_nkwargs from ..interpreterbase import InvalidArguments, BreakRequest, ContinueRequest, TYPE_nvar
from ..mparser import ( from ..mparser import (
AndNode, AndNode,
ArgumentNode, ArgumentNode,
@ -341,7 +341,7 @@ class AstInterpreter(interpreterbase.InterpreterBase):
return result 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 # Make sure we are always dealing with lists
if isinstance(args_raw, list): if isinstance(args_raw, list):
args = args_raw args = args_raw
@ -362,17 +362,9 @@ class AstInterpreter(interpreterbase.InterpreterBase):
flattend_args += [i] flattend_args += [i]
return flattend_args 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 = {} flattend_kwargs = {}
for key_node, val in kwargs.items(): for key, 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
if isinstance(val, BaseNode): if isinstance(val, BaseNode):
resolved = self.resolve_node(val, include_unknown_args) resolved = self.resolve_node(val, include_unknown_args)
if resolved is not None: if resolved is not None:

@ -15,28 +15,38 @@
# This class contains the basic functionality needed to run any interpreter # This class contains the basic functionality needed to run any interpreter
# or an interpreter-based tool # or an interpreter-based tool
from . import AstInterpreter from .interpreter import AstInterpreter
from .visitor import AstVisitor
from .. import compilers, environment, mesonlib, optinterpreter from .. import compilers, environment, mesonlib, optinterpreter
from .. import coredata as cdata from .. import coredata as cdata
from ..mesonlib import MachineChoice from ..mesonlib import MachineChoice
from ..interpreterbase import InvalidArguments from ..interpreterbase import InvalidArguments, TYPE_nvar
from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary
from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, StringNode from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, StringNode
from typing import Any, Dict, List, Optional
import os import os
build_target_functions = ['executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library', 'both_libraries'] build_target_functions = ['executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library', 'both_libraries']
class IntrospectionHelper: class IntrospectionHelper:
# mimic an argparse namespace # mimic an argparse namespace
def __init__(self, cross_file): def __init__(self, cross_file: str) -> None:
self.cross_file = cross_file self.cross_file = cross_file # type: str
self.native_file = None self.native_file = None # type: str
self.cmd_line_options = {} self.cmd_line_options = {} # type: Dict[str, str]
class IntrospectionInterpreter(AstInterpreter): class IntrospectionInterpreter(AstInterpreter):
# Interpreter to detect the options without a build directory # Interpreter to detect the options without a build directory
# Most of the code is stolen from interpreter.Interpreter # 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 [] visitors = visitors if visitors is not None else []
super().__init__(source_root, subdir, subproject, visitors=visitors) 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.option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt')
self.backend = backend self.backend = backend
self.default_options = {'backend': self.backend} self.default_options = {'backend': self.backend}
self.project_data = {} self.project_data = {} # type: Dict[str, Any]
self.targets = [] self.targets = [] # type: List[Dict[str, Any]]
self.dependencies = [] self.dependencies = [] # type: List[Dict[str, Any]]
self.project_node = None self.project_node = None # type: BaseNode
self.funcs.update({ self.funcs.update({
'add_languages': self.func_add_languages, 'add_languages': self.func_add_languages,
@ -69,7 +79,7 @@ class IntrospectionInterpreter(AstInterpreter):
'both_libraries': self.func_both_lib, '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: if self.project_node:
raise InvalidArguments('Second call to project()') raise InvalidArguments('Second call to project()')
self.project_node = node self.project_node = node
@ -98,7 +108,8 @@ class IntrospectionInterpreter(AstInterpreter):
if not self.is_subproject() and 'subproject_dir' in kwargs: if not self.is_subproject() and 'subproject_dir' in kwargs:
spdirname = kwargs['subproject_dir'] spdirname = kwargs['subproject_dir']
if isinstance(spdirname, ElementaryNode): if isinstance(spdirname, StringNode):
assert isinstance(spdirname.value, str)
self.subproject_dir = spdirname.value self.subproject_dir = spdirname.value
if not self.is_subproject(): if not self.is_subproject():
self.project_data['subprojects'] = [] self.project_data['subprojects'] = []
@ -114,7 +125,7 @@ class IntrospectionInterpreter(AstInterpreter):
self.coredata.set_options(options) self.coredata.set_options(options)
self.func_add_languages(None, proj_langs, None) 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) subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir)
subpr = os.path.join(subproject_dir_abs, dirname) subpr = os.path.join(subproject_dir_abs, dirname)
try: try:
@ -125,15 +136,20 @@ class IntrospectionInterpreter(AstInterpreter):
except (mesonlib.MesonException, RuntimeError): except (mesonlib.MesonException, RuntimeError):
return 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) args = self.flatten_args(args)
for for_machine in [MachineChoice.BUILD, MachineChoice.HOST]: for for_machine in [MachineChoice.BUILD, MachineChoice.HOST]:
for lang in sorted(args, key=compilers.sort_clink): 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() lang = lang.lower()
if lang not in self.coredata.compilers[for_machine]: if lang not in self.coredata.compilers[for_machine]:
self.environment.detect_compiler_for(lang, 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) args = self.flatten_args(args)
kwargs = self.flatten_kwargs(kwargs) kwargs = self.flatten_kwargs(kwargs)
if not args: if not args:
@ -157,20 +173,20 @@ class IntrospectionInterpreter(AstInterpreter):
'node': node '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) args = self.flatten_args(args)
if not args or not isinstance(args[0], str): if not args or not isinstance(args[0], str):
return return None
name = args[0] name = args[0]
srcqueue = [node] srcqueue = [node]
# Process the sources BEFORE flattening the kwargs, to preserve the original nodes # Process the sources BEFORE flattening the kwargs, to preserve the original nodes
if 'sources' in kwargs: if 'sources' in kwargs_raw:
srcqueue += mesonlib.listify(kwargs['sources']) 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: while srcqueue:
curr = srcqueue.pop(0) curr = srcqueue.pop(0)
arg_node = None arg_node = None
@ -181,6 +197,7 @@ class IntrospectionInterpreter(AstInterpreter):
arg_node = curr.args arg_node = curr.args
elif isinstance(curr, IdNode): elif isinstance(curr, IdNode):
# Try to resolve the ID and append the node to the queue # Try to resolve the ID and append the node to the queue
assert isinstance(curr.value, str)
var_name = curr.value var_name = curr.value
if var_name in self.assignments: if var_name in self.assignments:
tmp_node = self.assignments[var_name] 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.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)} kwargs_reduced = {k: v for k, v in kwargs_reduced.items() if not isinstance(v, BaseNode)}
for_machine = MachineChoice.HOST for_machine = MachineChoice.HOST
objects = [] objects = [] # type: List[Any]
empty_sources = [] # Passing the unresolved sources list causes errors 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) target = targetclass(name, self.subdir, self.subproject, for_machine, empty_sources, objects, self.environment, kwargs_reduced)
new_target = { new_target = {
@ -225,7 +243,7 @@ class IntrospectionInterpreter(AstInterpreter):
self.targets += [new_target] self.targets += [new_target]
return 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') default_library = self.coredata.get_builtin_option('default_library')
if default_library == 'shared': if default_library == 'shared':
return self.build_target(node, args, kwargs, SharedLibrary) return self.build_target(node, args, kwargs, SharedLibrary)
@ -233,31 +251,32 @@ class IntrospectionInterpreter(AstInterpreter):
return self.build_target(node, args, kwargs, StaticLibrary) return self.build_target(node, args, kwargs, StaticLibrary)
elif default_library == 'both': elif default_library == 'both':
return self.build_target(node, args, kwargs, SharedLibrary) 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) 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) 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) 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) 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) 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) 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) 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: if 'target_type' not in kwargs:
return return None
target_type = kwargs.pop('target_type') target_type = kwargs.pop('target_type')
if isinstance(target_type, ElementaryNode): if isinstance(target_type, ElementaryNode):
target_type = target_type.value target_type = target_type.value
@ -273,11 +292,12 @@ class IntrospectionInterpreter(AstInterpreter):
return self.build_library(node, args, kwargs) return self.build_library(node, args, kwargs)
elif target_type == 'jar': elif target_type == 'jar':
return self.build_target(node, args, kwargs, Jar) return self.build_target(node, args, kwargs, Jar)
return None
def is_subproject(self): def is_subproject(self) -> bool:
return self.subproject != '' return self.subproject != ''
def analyze(self): def analyze(self) -> None:
self.load_root_meson_file() self.load_root_meson_file()
self.sanity_check_ast() self.sanity_check_ast()
self.parse_project() self.parse_project()

Loading…
Cancel
Save