From 23818fc5a389c49e2673f79af2c90d9d56b1aaf0 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 1 Sep 2020 14:28:08 +0200 Subject: [PATCH] typing: more fixes --- mesonbuild/ast/introspection.py | 3 +- mesonbuild/backend/backends.py | 18 ++++--- mesonbuild/backend/ninjabackend.py | 2 +- mesonbuild/backend/vs2010backend.py | 4 +- mesonbuild/build.py | 51 ++++++++++-------- mesonbuild/coredata.py | 81 +++++++++++++++-------------- mesonbuild/dependencies/boost.py | 4 +- mesonbuild/environment.py | 25 +++++---- mesonbuild/interpreter.py | 42 ++++++++++----- mesonbuild/mcompile.py | 6 ++- mesonbuild/mconf.py | 8 ++- mesonbuild/mintro.py | 19 ++++--- mesonbuild/modules/__init__.py | 12 +++-- mesonbuild/msetup.py | 18 ++++--- mesonbuild/mtest.py | 67 ++++++++++++------------ mesonbuild/optinterpreter.py | 11 ++-- mesonbuild/scripts/depfixer.py | 2 +- mesonbuild/scripts/meson_exe.py | 2 +- run_mypy.py | 1 + 19 files changed, 215 insertions(+), 161 deletions(-) diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 73cd42201..19fedbf6f 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -25,10 +25,11 @@ from ..build import BuildTarget, Executable, Jar, SharedLibrary, SharedModule, S from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, StringNode import typing as T import os +import argparse build_target_functions = ['executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library', 'both_libraries'] -class IntrospectionHelper: +class IntrospectionHelper(argparse.Namespace): # mimic an argparse namespace def __init__(self, cross_file: str): self.cross_file = cross_file # type: str diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index e0bab7ca5..b12932a57 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -36,7 +36,7 @@ from ..mesonlib import ( ) if T.TYPE_CHECKING: - from ..interpreter import Interpreter + from ..interpreter import Interpreter, Test class TestProtocol(enum.Enum): @@ -104,7 +104,7 @@ class TargetInstallData: class ExecutableSerialisation: def __init__(self, cmd_args, env=None, exe_wrapper=None, - workdir=None, extra_paths=None, capture=None): + workdir=None, extra_paths=None, capture=None) -> None: self.cmd_args = cmd_args self.env = env or {} if exe_wrapper is not None: @@ -182,11 +182,15 @@ class Backend: self.interpreter = interpreter self.environment = build.environment self.processed_targets = {} + self.name = '' self.build_dir = self.environment.get_build_dir() self.source_dir = self.environment.get_source_dir() self.build_to_src = mesonlib.relpath(self.environment.get_source_dir(), self.environment.get_build_dir()) + def generate(self) -> None: + raise RuntimeError('generate is not implemented in {}'.format(type(self).__name__)) + def get_target_filename(self, t, *, warn_multi_output: bool = True): if isinstance(t, build.CustomTarget): if warn_multi_output and len(t.get_outputs()) != 1: @@ -794,7 +798,7 @@ class Backend: def write_test_file(self, datafile): self.write_test_serialisation(self.build.get_tests(), datafile) - def create_test_serialisation(self, tests): + def create_test_serialisation(self, tests: T.List['Test']) -> T.List[TestSerialisation]: arr = [] for t in sorted(tests, key=lambda tst: -1 * tst.priority): exe = t.get_exe() @@ -864,7 +868,7 @@ class Backend: arr.append(ts) return arr - def write_test_serialisation(self, tests, datafile): + def write_test_serialisation(self, tests: T.List['Test'], datafile: str): pickle.dump(self.create_test_serialisation(tests), datafile) def construct_target_rel_path(self, a, workdir): @@ -1128,7 +1132,7 @@ class Backend: cmd = [i.replace('\\', '/') for i in cmd] return inputs, outputs, cmd - def run_postconf_scripts(self): + def run_postconf_scripts(self) -> None: env = {'MESON_SOURCE_ROOT': self.environment.get_source_dir(), 'MESON_BUILD_ROOT': self.environment.get_build_dir(), 'MESONINTROSPECT': ' '.join([shlex.quote(x) for x in self.environment.get_build_command() + ['introspect']]), @@ -1140,7 +1144,7 @@ class Backend: cmd = s['exe'] + s['args'] subprocess.check_call(cmd, env=child_env) - def create_install_data(self): + def create_install_data(self) -> InstallData: strip_bin = self.environment.lookup_binary_entry(MachineChoice.HOST, 'strip') if strip_bin is None: if self.environment.is_cross_build(): @@ -1338,7 +1342,7 @@ class Backend: d.install_subdirs.append([src_dir, dst_dir, sd.install_mode, sd.exclude]) - def get_introspection_data(self, target_id, target): + def get_introspection_data(self, target_id: str, target: build.Target) -> T.List[T.Dict[str, T.Union[bool, str, T.List[T.Union[str, T.Dict[str, T.Union[str, T.List[str], bool]]]]]]]: ''' Returns a list of source dicts with the following format for a given target: [ diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 9004165cd..0cf1d54b5 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2997,7 +2997,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) elem = NinjaBuildElement(self.all_outputs, deps, 'phony', '') self.add_build(elem) - def get_introspection_data(self, target_id, target): + def get_introspection_data(self, target_id: str, target: build.Target) -> T.List[T.Dict[str, T.Union[bool, str, T.List[T.Union[str, T.Dict[str, T.Union[str, T.List[str], bool]]]]]]]: if target_id not in self.introspection_data or len(self.introspection_data[target_id]) == 0: return super().get_introspection_data(target_id, target) diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index f282d02c0..4fc3d5c01 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -192,11 +192,11 @@ class Vs2010Backend(backends.Backend): Vs2010Backend.touch_regen_timestamp(self.environment.get_build_dir()) @staticmethod - def get_regen_stampfile(build_dir): + def get_regen_stampfile(build_dir: str) -> None: return os.path.join(os.path.join(build_dir, Environment.private_dir), 'regen.stamp') @staticmethod - def touch_regen_timestamp(build_dir): + def touch_regen_timestamp(build_dir: str) -> None: with open(Vs2010Backend.get_regen_stampfile(build_dir), 'w'): pass diff --git a/mesonbuild/build.py b/mesonbuild/build.py index edd1506a2..bf325b090 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -37,6 +37,9 @@ from .compilers import ( from .linkers import StaticLinker from .interpreterbase import FeatureNew +if T.TYPE_CHECKING: + from .interpreter import Test + pch_kwargs = set(['c_pch', 'cpp_pch']) lang_arg_kwargs = set([ @@ -128,14 +131,14 @@ class Build: self.project_version = None self.environment = environment self.projects = {} - self.targets = OrderedDict() + self.targets = OrderedDict() # type: T.Dict[str, 'Target'] self.run_target_names = set() # type: T.Set[T.Tuple[str, str]] self.global_args = PerMachine({}, {}) # type: PerMachine[T.Dict[str, T.List[str]]] self.projects_args = PerMachine({}, {}) # type: PerMachine[T.Dict[str, T.List[str]]] self.global_link_args = PerMachine({}, {}) # type: PerMachine[T.Dict[str, T.List[str]]] self.projects_link_args = PerMachine({}, {}) # type: PerMachine[T.Dict[str, T.List[str]]] - self.tests = [] - self.benchmarks = [] + self.tests = [] # type: T.List['Test'] + self.benchmarks = [] # type: T.List['Test'] self.headers = [] self.man = [] self.data = [] @@ -178,13 +181,13 @@ class Build: def get_subproject_dir(self): return self.subproject_dir - def get_targets(self): + def get_targets(self) -> T.Dict[str, 'Target']: return self.targets - def get_tests(self): + def get_tests(self) -> T.List['Test']: return self.tests - def get_benchmarks(self): + def get_benchmarks(self) -> T.List['Test']: return self.benchmarks def get_headers(self): @@ -403,13 +406,13 @@ a hard error in the future.'''.format(name)) outdirs[0] = default_install_dir return outdirs, custom_install_dir - def get_basename(self): + def get_basename(self) -> str: return self.name - def get_subdir(self): + def get_subdir(self) -> str: return self.subdir - def get_typename(self): + def get_typename(self) -> str: return self.typename @staticmethod @@ -423,7 +426,7 @@ a hard error in the future.'''.format(name)) return h.hexdigest()[:7] @staticmethod - def construct_id_from_path(subdir, name, type_suffix): + def construct_id_from_path(subdir: str, name: str, type_suffix: str) -> str: """Construct target ID from subdir, name and type suffix. This helper function is made public mostly for tests.""" @@ -441,7 +444,7 @@ a hard error in the future.'''.format(name)) return subdir_part + '@@' + my_id return my_id - def get_id(self): + def get_id(self) -> str: return self.construct_id_from_path( self.subdir, self.name, self.type_suffix()) @@ -480,6 +483,12 @@ a hard error in the future.'''.format(name)) def is_linkable_target(self) -> bool: return False + def get_outputs(self) -> T.List[str]: + return [] + + def should_install(self) -> bool: + return False + class BuildTarget(Target): known_kwargs = known_build_target_kwargs @@ -1006,7 +1015,7 @@ This will become a hard error in a future Meson release.''') def get_filename(self): return self.filename - def get_outputs(self): + def get_outputs(self) -> T.List[str]: return self.outputs def get_extra_args(self, language): @@ -1036,7 +1045,7 @@ This will become a hard error in a future Meson release.''') def get_generated_sources(self): return self.generated - def should_install(self): + def should_install(self) -> bool: return self.need_install def has_pch(self): @@ -1474,7 +1483,7 @@ class GeneratedList: def get_inputs(self): return self.infilelist - def get_outputs(self): + def get_outputs(self) -> T.List[str]: return self.outfilelist def get_outputs_for(self, filename): @@ -2192,7 +2201,7 @@ class CustomTarget(Target): def get_dependencies(self): return self.dependencies - def should_install(self): + def should_install(self) -> bool: return self.install def get_custom_install_dir(self): @@ -2201,7 +2210,7 @@ class CustomTarget(Target): def get_custom_install_mode(self): return self.install_mode - def get_outputs(self): + def get_outputs(self) -> T.List[str]: return self.outputs def get_filename(self): @@ -2289,13 +2298,13 @@ class RunTarget(Target): def get_sources(self): return [] - def should_install(self): + def should_install(self) -> bool: return False - def get_filename(self): + def get_filename(self) -> str: return self.name - def get_outputs(self): + def get_outputs(self) -> T.List[str]: if isinstance(self.name, str): return [self.name] elif isinstance(self.name, list): @@ -2367,7 +2376,7 @@ class CustomTargetIndex: return ''.format( self.target, self.target.get_outputs().index(self.output)) - def get_outputs(self): + def get_outputs(self) -> T.List[str]: return [self.output] def get_subdir(self): @@ -2509,6 +2518,6 @@ def load(build_dir: str) -> Build: raise MesonException(load_fail_msg) return obj -def save(obj, filename): +def save(obj: Build, filename: str) -> None: with open(filename, 'wb') as f: pickle.dump(obj, f) diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index ce03fbc0e..4fc49990c 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -47,7 +47,7 @@ _T = T.TypeVar('_T') class MesonVersionMismatchException(MesonException): '''Build directory generated with Meson version incompatible with current version''' - def __init__(self, old_version, current_version): + def __init__(self, old_version: str, current_version: str) -> None: super().__init__('Build directory has been generated with Meson version {}, ' 'which is incompatible with current version {}.' .format(old_version, current_version)) @@ -56,7 +56,7 @@ class MesonVersionMismatchException(MesonException): class UserOption(T.Generic[_T]): - def __init__(self, description, choices, yielding): + def __init__(self, description: str, choices: T.Optional[T.Union[str, T.List[_T]]], yielding: T.Optional[bool]): super().__init__() self.choices = choices self.description = description @@ -66,7 +66,8 @@ class UserOption(T.Generic[_T]): raise MesonException('Value of "yielding" must be a boolean.') self.yielding = yielding - def printable_value(self): + def printable_value(self) -> T.Union[str, int, bool, T.List[T.Union[str, int, bool]]]: + assert isinstance(self.value, (str, int, bool, list)) return self.value # Check that the input is a valid value and return the @@ -75,30 +76,32 @@ class UserOption(T.Generic[_T]): def validate_value(self, value: T.Any) -> _T: raise RuntimeError('Derived option class did not override validate_value.') - def set_value(self, newvalue): + def set_value(self, newvalue: T.Any) -> None: self.value = self.validate_value(newvalue) class UserStringOption(UserOption[str]): - def __init__(self, description, value, choices=None, yielding=None): - super().__init__(description, choices, yielding) + def __init__(self, description: str, value: T.Any, yielding: T.Optional[bool] = None): + super().__init__(description, None, yielding) self.set_value(value) - def validate_value(self, value): + def validate_value(self, value: T.Any) -> str: if not isinstance(value, str): raise MesonException('Value "%s" for string option is not a string.' % str(value)) return value class UserBooleanOption(UserOption[bool]): - def __init__(self, description, value, yielding=None): + def __init__(self, description: str, value, yielding: T.Optional[bool] = None) -> None: super().__init__(description, [True, False], yielding) self.set_value(value) def __bool__(self) -> bool: return self.value - def validate_value(self, value) -> bool: + def validate_value(self, value: T.Any) -> bool: if isinstance(value, bool): return value + if not isinstance(value, str): + raise MesonException('Value {} cannot be converted to a boolean'.format(value)) if value.lower() == 'true': return True if value.lower() == 'false': @@ -106,7 +109,7 @@ class UserBooleanOption(UserOption[bool]): raise MesonException('Value %s is not boolean (true or false).' % value) class UserIntegerOption(UserOption[int]): - def __init__(self, description, value, yielding=None): + def __init__(self, description: str, value: T.Any, yielding: T.Optional[bool] = None): min_value, max_value, default_value = value self.min_value = min_value self.max_value = max_value @@ -119,7 +122,7 @@ class UserIntegerOption(UserOption[int]): super().__init__(description, choices, yielding) self.set_value(default_value) - def validate_value(self, value) -> int: + def validate_value(self, value: T.Any) -> int: if isinstance(value, str): value = self.toint(value) if not isinstance(value, int): @@ -130,35 +133,35 @@ class UserIntegerOption(UserOption[int]): raise MesonException('New value %d is more than maximum value %d.' % (value, self.max_value)) return value - def toint(self, valuestring) -> int: + def toint(self, valuestring: str) -> int: try: return int(valuestring) except ValueError: raise MesonException('Value string "%s" is not convertible to an integer.' % valuestring) class UserUmaskOption(UserIntegerOption, UserOption[T.Union[str, int]]): - def __init__(self, description, value, yielding=None): + def __init__(self, description: str, value: T.Any, yielding: T.Optional[bool] = None): super().__init__(description, (0, 0o777, value), yielding) self.choices = ['preserve', '0000-0777'] - def printable_value(self): + def printable_value(self) -> str: if self.value == 'preserve': return self.value return format(self.value, '04o') - def validate_value(self, value): + def validate_value(self, value: T.Any) -> T.Union[str, int]: if value is None or value == 'preserve': return 'preserve' return super().validate_value(value) - def toint(self, valuestring): + def toint(self, valuestring: T.Union[str, int]) -> int: try: return int(valuestring, 8) except ValueError as e: raise MesonException('Invalid mode: {}'.format(e)) class UserComboOption(UserOption[str]): - def __init__(self, description, choices: T.List[str], value, yielding=None): + def __init__(self, description: str, choices: T.List[str], value: T.Any, yielding: T.Optional[bool] = None): super().__init__(description, choices, yielding) if not isinstance(self.choices, list): raise MesonException('Combo choices must be an array.') @@ -167,7 +170,7 @@ class UserComboOption(UserOption[str]): raise MesonException('Combo choice elements must be strings.') self.set_value(value) - def validate_value(self, value): + def validate_value(self, value: T.Any) -> str: if value not in self.choices: if isinstance(value, bool): _type = 'boolean' @@ -182,13 +185,13 @@ class UserComboOption(UserOption[str]): return value class UserArrayOption(UserOption[T.List[str]]): - def __init__(self, description, value, split_args=False, user_input=False, allow_dups=False, **kwargs): + def __init__(self, description: str, value: T.Union[str, T.List[str]], split_args: bool = False, user_input: bool = False, allow_dups: bool = False, **kwargs: T.Any) -> None: super().__init__(description, kwargs.get('choices', []), yielding=kwargs.get('yielding', None)) self.split_args = split_args self.allow_dups = allow_dups self.value = self.validate_value(value, user_input=user_input) - def validate_value(self, value, user_input: bool = True) -> T.List[str]: + def validate_value(self, value: T.Union[str, T.List[str]], user_input: bool = True) -> T.List[str]: # User input is for options defined on the command line (via -D # options). Users can put their input in as a comma separated # string, but for defining options in meson_options.txt the format @@ -232,16 +235,16 @@ class UserArrayOption(UserOption[T.List[str]]): class UserFeatureOption(UserComboOption): static_choices = ['enabled', 'disabled', 'auto'] - def __init__(self, description, value, yielding=None): + def __init__(self, description: str, value: T.Any, yielding: T.Optional[bool] = None): super().__init__(description, self.static_choices, value, yielding) - def is_enabled(self): + def is_enabled(self) -> bool: return self.value == 'enabled' - def is_disabled(self): + def is_disabled(self) -> bool: return self.value == 'disabled' - def is_auto(self): + def is_auto(self) -> bool: return self.value == 'auto' if T.TYPE_CHECKING: @@ -534,7 +537,7 @@ class CoreData: value = None opts_map[optname] = opt.init_option(key, value, default_prefix()) - def init_backend_options(self, backend_name): + def init_backend_options(self, backend_name: str) -> None: if backend_name == 'ninja': self.backend_options['backend_max_links'] = \ UserIntegerOption( @@ -547,7 +550,7 @@ class CoreData: 'Default project to execute in Visual Studio', '') - def get_builtin_option(self, optname, subproject=''): + def get_builtin_option(self, optname: str, subproject: str = '') -> T.Union[str, int, bool]: raw_optname = optname if subproject: optname = subproject + ':' + optname @@ -683,7 +686,7 @@ class CoreData: def get_external_link_args(self, for_machine: MachineChoice, lang): return self.compiler_options[for_machine][lang]['link_args'].value - def merge_user_options(self, options): + def merge_user_options(self, options: T.Dict[str, T.Union[str, bool, int]]) -> None: for (name, value) in options.items(): if name not in self.user_options: self.user_options[name] = value @@ -715,7 +718,7 @@ class CoreData: if k in build_opts: build_opts[k].set_value(o.value) - def set_options(self, options, *, subproject='', warn_unknown=True): + def set_options(self, options: T.Dict[str, T.Any], subproject: str = '', warn_unknown: bool = True) -> None: if not self.is_cross_build(): options = self.strip_build_option_names(options) # Set prefix first because it's needed to sanitize other options @@ -912,10 +915,10 @@ def parse_machine_files(filenames): parser = MachineFileParser(filenames) return parser.sections -def get_cmd_line_file(build_dir): +def get_cmd_line_file(build_dir: str) -> str: return os.path.join(build_dir, 'meson-private', 'cmd_line.txt') -def read_cmd_line_file(build_dir, options): +def read_cmd_line_file(build_dir: str, options: argparse.Namespace) -> None: filename = get_cmd_line_file(build_dir) if not os.path.isfile(filename): return @@ -937,10 +940,10 @@ def read_cmd_line_file(build_dir, options): # literal_eval to get it into the list of strings. options.native_file = ast.literal_eval(properties.get('native_file', '[]')) -def cmd_line_options_to_string(options): +def cmd_line_options_to_string(options: argparse.Namespace) -> T.Dict[str, str]: return {k: str(v) for k, v in options.cmd_line_options.items()} -def write_cmd_line_file(build_dir, options): +def write_cmd_line_file(build_dir: str, options: argparse.Namespace) -> None: filename = get_cmd_line_file(build_dir) config = CmdLineFileParser() @@ -955,7 +958,7 @@ def write_cmd_line_file(build_dir, options): with open(filename, 'w') as f: config.write(f) -def update_cmd_line_file(build_dir, options): +def update_cmd_line_file(build_dir: str, options: argparse.Namespace): filename = get_cmd_line_file(build_dir) config = CmdLineFileParser() config.read(filename) @@ -963,7 +966,7 @@ def update_cmd_line_file(build_dir, options): with open(filename, 'w') as f: config.write(f) -def get_cmd_line_options(build_dir, options): +def get_cmd_line_options(build_dir: str, options: argparse.Namespace) -> str: copy = argparse.Namespace(**vars(options)) read_cmd_line_file(build_dir, copy) cmdline = ['-D{}={}'.format(k, v) for k, v in copy.cmd_line_options.items()] @@ -976,7 +979,7 @@ def get_cmd_line_options(build_dir, options): def major_versions_differ(v1, v2): return v1.split('.')[0:2] != v2.split('.')[0:2] -def load(build_dir): +def load(build_dir: str) -> CoreData: filename = os.path.join(build_dir, 'meson-private', 'coredata.dat') load_fail_msg = 'Coredata file {!r} is corrupted. Try with a fresh build tree.'.format(filename) try: @@ -995,7 +998,7 @@ def load(build_dir): raise MesonVersionMismatchException(obj.version, version) return obj -def save(obj, build_dir): +def save(obj: CoreData, build_dir: str) -> str: filename = os.path.join(build_dir, 'meson-private', 'coredata.dat') prev_filename = filename + '.prev' tempfilename = filename + '~' @@ -1012,7 +1015,7 @@ def save(obj, build_dir): return filename -def register_builtin_arguments(parser): +def register_builtin_arguments(parser: argparse.ArgumentParser) -> None: for n, b in BUILTIN_OPTIONS.items(): b.add_to_argparse(n, parser, '', '') for n, b in BUILTIN_OPTIONS_PER_MACHINE.items(): @@ -1021,7 +1024,7 @@ def register_builtin_arguments(parser): parser.add_argument('-D', action='append', dest='projectoptions', default=[], metavar="option", help='Set the value of an option, can be used several times to set multiple options.') -def create_options_dict(options): +def create_options_dict(options: T.List[str]) -> T.Dict[str, str]: result = OrderedDict() for o in options: try: @@ -1031,7 +1034,7 @@ def create_options_dict(options): result[key] = value return result -def parse_cmd_line_options(args): +def parse_cmd_line_options(args: argparse.Namespace) -> None: args.cmd_line_options = create_options_dict(args.projectoptions) # Merge builtin options set with --option into the dict. diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 8497d2c3d..6e9586029 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -341,7 +341,9 @@ class BoostLibraryFile(): class BoostDependency(ExternalDependency): def __init__(self, environment: Environment, kwargs: T.Dict[str, T.Any]) -> None: super().__init__('boost', environment, kwargs, language='cpp') - self.debug = environment.coredata.get_builtin_option('buildtype').startswith('debug') + buildtype = environment.coredata.get_builtin_option('buildtype') + assert isinstance(buildtype, str) + self.debug = buildtype.startswith('debug') self.multithreading = kwargs.get('threading', 'multi') == 'multi' self.boost_root = None # type: Path diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index f8282c011..5cd60697f 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -132,6 +132,9 @@ build_filename = 'meson.build' CompilersDict = T.Dict[str, Compiler] +if T.TYPE_CHECKING: + import argparse + def detect_gcovr(min_version='3.3', new_rootdir_version='4.2', log=False): gcovr_exe = 'gcovr' try: @@ -153,7 +156,7 @@ def detect_llvm_cov(): return tool return None -def find_coverage_tools(): +def find_coverage_tools() -> T.Tuple[T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str]]: gcovr_exe, gcovr_new_rootdir = detect_gcovr() llvm_cov_exe = detect_llvm_cov() @@ -522,7 +525,7 @@ class Environment: log_dir = 'meson-logs' info_dir = 'meson-info' - def __init__(self, source_dir, build_dir, options): + def __init__(self, source_dir: T.Optional[str], build_dir: T.Optional[str], options: 'argparse.Namespace') -> None: self.source_dir = source_dir self.build_dir = build_dir # Do not try to create build directories when build_dir is none. @@ -535,7 +538,7 @@ class Environment: os.makedirs(self.log_dir, exist_ok=True) os.makedirs(self.info_dir, exist_ok=True) try: - self.coredata = coredata.load(self.get_build_dir()) + self.coredata = coredata.load(self.get_build_dir()) # type: coredata.CoreData self.first_invocation = False except FileNotFoundError: self.create_new_coredata(options) @@ -807,7 +810,7 @@ class Environment: self.default_pkgconfig = ['pkg-config'] self.wrap_resolver = None - def create_new_coredata(self, options): + def create_new_coredata(self, options: 'argparse.Namespace') -> None: # WARNING: Don't use any values from coredata in __init__. It gets # re-initialized with project options by the interpreter during # build file parsing. @@ -819,17 +822,17 @@ class Environment: def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) -> bool: return self.coredata.is_cross_build(when_building_for) - def dump_coredata(self): + def dump_coredata(self) -> str: return coredata.save(self.coredata, self.get_build_dir()) - def get_script_dir(self): + def get_script_dir(self) -> str: import mesonbuild.scripts return os.path.dirname(mesonbuild.scripts.__file__) - def get_log_dir(self): + def get_log_dir(self) -> str: return self.log_dir - def get_coredata(self): + def get_coredata(self) -> coredata.CoreData: return self.coredata def get_build_command(self, unbuffered=False): @@ -1535,7 +1538,7 @@ class Environment: self._handle_exceptions(popen_exceptions, compilers) - def get_scratch_dir(self): + def get_scratch_dir(self) -> str: return self.scratch_dir def detect_objc_compiler(self, for_machine: MachineInfo) -> 'Compiler': @@ -1974,10 +1977,10 @@ class Environment: self._handle_exceptions(popen_exceptions, linkers, 'linker') raise EnvironmentException('Unknown static linker "{}"'.format(' '.join(linkers))) - def get_source_dir(self): + def get_source_dir(self) -> str: return self.source_dir - def get_build_dir(self): + def get_build_dir(self) -> str: return self.build_dir def get_import_lib_dir(self) -> str: diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 322cc26dd..031bed0ba 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -31,9 +31,10 @@ from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabler, disablerIfNotFound from .interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs, FeatureDeprecatedKwargs from .interpreterbase import ObjectHolder, MesonVersionString -from .modules import ModuleReturnValue +from .interpreterbase import TYPE_var, TYPE_nkwargs +from .modules import ModuleReturnValue, ExtensionModule from .cmake import CMakeInterpreter -from .backend.backends import TestProtocol +from .backend.backends import TestProtocol, Backend from pathlib import Path, PurePath import os @@ -673,22 +674,22 @@ class MachineHolder(InterpreterObject, ObjectHolder): @noPosargs @permittedKwargs({}) - def cpu_family_method(self, args, kwargs): + def cpu_family_method(self, args: T.List[TYPE_var], kwargs: TYPE_nkwargs) -> str: return self.held_object.cpu_family @noPosargs @permittedKwargs({}) - def cpu_method(self, args, kwargs): + def cpu_method(self, args: T.List[TYPE_var], kwargs: TYPE_nkwargs) -> str: return self.held_object.cpu @noPosargs @permittedKwargs({}) - def system_method(self, args, kwargs): + def system_method(self, args: T.List[TYPE_var], kwargs: TYPE_nkwargs) -> str: return self.held_object.system @noPosargs @permittedKwargs({}) - def endian_method(self, args, kwargs): + def endian_method(self, args: T.List[TYPE_var], kwargs: TYPE_nkwargs) -> str: return self.held_object.endian class IncludeDirsHolder(InterpreterObject, ObjectHolder): @@ -2333,8 +2334,18 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'}, class Interpreter(InterpreterBase): - def __init__(self, build, backend=None, subproject='', subdir='', subproject_dir='subprojects', - modules = None, default_project_options=None, mock=False, ast=None): + def __init__( + self, + build: build.Build, + backend: T.Optional[Backend] = None, + subproject: str = '', + subdir: str = '', + subproject_dir: str = 'subprojects', + modules: T.Optional[T.Dict[str, ExtensionModule]] = None, + default_project_options: T.Optional[T.Dict[str, str]] = None, + mock: bool = False, + ast: T.Optional[mparser.CodeBlockNode] = None, + ) -> None: super().__init__(build.environment.get_source_dir(), subdir, subproject) self.an_unpicklable_object = mesonlib.an_unpicklable_object self.build = build @@ -2396,7 +2407,8 @@ class Interpreter(InterpreterBase): self.builtin['target_machine'] = \ MachineHolder(self.build.environment.machines.target) - def get_non_matching_default_options(self): + # TODO: Why is this in interpreter.py and not CoreData or Environment? + def get_non_matching_default_options(self) -> T.Iterator[T.Tuple[str, str, coredata.UserOption]]: env = self.environment for def_opt_name, def_opt_value in self.project_default_options.items(): for opts in env.coredata.get_all_options(): @@ -2530,7 +2542,7 @@ class Interpreter(InterpreterBase): self.process_new_values(invalues) return self.holderify(return_object.return_value) - def get_build_def_files(self): + def get_build_def_files(self) -> T.List[str]: return self.build_def_files def add_build_def_file(self, f): @@ -2599,7 +2611,9 @@ class Interpreter(InterpreterBase): module = importlib.import_module('mesonbuild.modules.' + modname) except ImportError: raise InvalidArguments('Module "%s" does not exist' % (modname, )) - self.modules[modname] = module.initialize(self) + ext_module = module.initialize(self) + assert isinstance(ext_module, ExtensionModule) + self.modules[modname] = ext_module @stringArgs @noKwargs @@ -4598,7 +4612,7 @@ different subdirectory. def func_join_paths(self, node, args, kwargs): return self.join_path_strings(args) - def run(self): + def run(self) -> None: super().run() mlog.log('Build targets in project:', mlog.bold(str(len(self.build.targets)))) FeatureNew.report(self.subproject) @@ -4608,14 +4622,14 @@ different subdirectory. if self.subproject == '': self._print_summary() - def print_extra_warnings(self): + def print_extra_warnings(self) -> None: # TODO cross compilation for c in self.coredata.compilers.host.values(): if c.get_id() == 'clang': self.check_clang_asan_lundef() break - def check_clang_asan_lundef(self): + def check_clang_asan_lundef(self) -> None: if 'b_lundef' not in self.coredata.base_options: return if 'b_sanitize' not in self.coredata.base_options: diff --git a/mesonbuild/mcompile.py b/mesonbuild/mcompile.py index 5466ad257..326752950 100644 --- a/mesonbuild/mcompile.py +++ b/mesonbuild/mcompile.py @@ -32,7 +32,7 @@ if T.TYPE_CHECKING: import argparse def array_arg(value: str) -> T.List[str]: - return T.cast(T.List[str], UserArrayOption(None, value, allow_dups=True, user_input=True).value) + return UserArrayOption(None, value, allow_dups=True, user_input=True).value def validate_builddir(builddir: Path) -> None: if not (builddir / 'meson-private' / 'coredata.dat' ).is_file(): @@ -45,7 +45,9 @@ def get_backend_from_coredata(builddir: Path) -> str: """ Gets `backend` option value from coredata """ - return T.cast(str, coredata.load(str(builddir)).get_builtin_option('backend')) + backend = coredata.load(str(builddir)).get_builtin_option('backend') + assert isinstance(backend, str) + return backend def parse_introspect_data(builddir: Path) -> T.Dict[str, T.List[dict]]: """ diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index f0703559b..02451558d 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -15,15 +15,19 @@ import os from . import coredata, environment, mesonlib, build, mintro, mlog from .ast import AstIDGenerator +import typing as T -def add_arguments(parser): +if T.TYPE_CHECKING: + import argparse + +def add_arguments(parser: 'argparse.ArgumentParser') -> None: coredata.register_builtin_arguments(parser) parser.add_argument('builddir', nargs='?', default='.') parser.add_argument('--clearcache', action='store_true', default=False, help='Clear cached state (e.g. found dependencies)') -def make_lower_case(val): +def make_lower_case(val: T.Any) -> T.Union[str, T.List[T.Any]]: # T.Any because of recursion... if isinstance(val, bool): return str(val).lower() elif isinstance(val, list): diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index d60386e3c..1e400b0d8 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -254,11 +254,9 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s 'compiler', machine='host', ) + tmp_dict = dict(coredata.flatten_lang_iterator(coredata.compiler_options.build.items())) # type: T.Dict[str, cdata.UserOption] add_keys( - { - 'build.' + k: o for k, o in - coredata.flatten_lang_iterator(coredata.compiler_options.build.items()) - }, + {'build.' + k: o for k, o in tmp_dict.items()}, 'compiler', machine='build', ) @@ -305,10 +303,10 @@ def list_deps(coredata: cdata.CoreData) -> T.List[T.Dict[str, T.Union[str, T.Lis 'link_args': d.get_link_args()}] return result -def get_test_list(testdata: backends.TestSerialisation) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]: +def get_test_list(testdata: T.List[backends.TestSerialisation]) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]: result = [] # type: T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]] for t in testdata: - to = {} + to = {} # type: T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]] if isinstance(t.fname, str): fname = [t.fname] else: @@ -329,21 +327,21 @@ def get_test_list(testdata: backends.TestSerialisation) -> T.List[T.Dict[str, T. result.append(to) return result -def list_tests(testdata: backends.TestSerialisation) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]: +def list_tests(testdata: T.List[backends.TestSerialisation]) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]: return get_test_list(testdata) -def list_benchmarks(benchdata: backends.TestSerialisation) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]: +def list_benchmarks(benchdata: T.List[backends.TestSerialisation]) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]: return get_test_list(benchdata) def list_projinfo(builddata: build.Build) -> T.Dict[str, T.Union[str, T.List[T.Dict[str, str]]]]: result = {'version': builddata.project_version, 'descriptive_name': builddata.project_name, - 'subproject_dir': builddata.subproject_dir} + 'subproject_dir': builddata.subproject_dir} # type: T.Dict[str, T.Union[str, T.List[T.Dict[str, str]]]] subprojects = [] for k, v in builddata.subprojects.items(): c = {'name': k, 'version': v, - 'descriptive_name': builddata.projects.get(k)} + 'descriptive_name': builddata.projects.get(k)} # type: T.Dict[str, str] subprojects.append(c) result['subprojects'] = subprojects return result @@ -391,6 +389,7 @@ def run(options: argparse.Namespace) -> int: # Make sure that log entries in other parts of meson don't interfere with the JSON output mlog.disable() backend = backends.get_backend_from_name(options.backend) + assert backend is not None intr = IntrospectionInterpreter(sourcedir, '', backend.name, visitors = [AstIDGenerator(), AstIndentationGenerator(), AstConditionLevel()]) intr.analyze() # Re-enable logging just in case diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 47be039dc..ff27a112b 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -19,14 +19,18 @@ import os from .. import build from ..mesonlib import unholder +import typing as T +if T.TYPE_CHECKING: + from ..interpreter import Interpreter + from ..interpreterbase import TYPE_var class ExtensionModule: - def __init__(self, interpreter): + def __init__(self, interpreter: 'Interpreter') -> None: self.interpreter = interpreter - self.snippets = set() # List of methods that operate only on the interpreter. + self.snippets = set() # type: T.Set[str] # List of methods that operate only on the interpreter. - def is_snippet(self, funcname): + def is_snippet(self, funcname: str) -> bool: return funcname in self.snippets @@ -69,7 +73,7 @@ def is_module_library(fname): class ModuleReturnValue: - def __init__(self, return_value, new_objects): + def __init__(self, return_value: 'TYPE_var', new_objects: T.List['TYPE_var']) -> None: self.return_value = return_value assert(isinstance(new_objects, list)) self.new_objects = new_objects diff --git a/mesonbuild/msetup.py b/mesonbuild/msetup.py index f940a5837..5fd88d7a9 100644 --- a/mesonbuild/msetup.py +++ b/mesonbuild/msetup.py @@ -178,12 +178,18 @@ class MesonApp: logger_fun = mlog.log else: logger_fun = mlog.debug - logger_fun('Build machine cpu family:', mlog.bold(intr.builtin['build_machine'].cpu_family_method([], {}))) - logger_fun('Build machine cpu:', mlog.bold(intr.builtin['build_machine'].cpu_method([], {}))) - mlog.log('Host machine cpu family:', mlog.bold(intr.builtin['host_machine'].cpu_family_method([], {}))) - mlog.log('Host machine cpu:', mlog.bold(intr.builtin['host_machine'].cpu_method([], {}))) - logger_fun('Target machine cpu family:', mlog.bold(intr.builtin['target_machine'].cpu_family_method([], {}))) - logger_fun('Target machine cpu:', mlog.bold(intr.builtin['target_machine'].cpu_method([], {}))) + build_machine = intr.builtin['build_machine'] + host_machine = intr.builtin['build_machine'] + target_machine = intr.builtin['target_machine'] + assert isinstance(build_machine, interpreter.MachineHolder) + assert isinstance(host_machine, interpreter.MachineHolder) + assert isinstance(target_machine, interpreter.MachineHolder) + logger_fun('Build machine cpu family:', mlog.bold(build_machine.cpu_family_method([], {}))) + logger_fun('Build machine cpu:', mlog.bold(build_machine.cpu_method([], {}))) + mlog.log('Host machine cpu family:', mlog.bold(host_machine.cpu_family_method([], {}))) + mlog.log('Host machine cpu:', mlog.bold(host_machine.cpu_method([], {}))) + logger_fun('Target machine cpu family:', mlog.bold(target_machine.cpu_family_method([], {}))) + logger_fun('Target machine cpu:', mlog.bold(target_machine.cpu_method([], {}))) try: if self.options.profile: fname = os.path.join(self.build_dir, 'meson-private', 'profile-interpreter.log') diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index cc82bd072..86d738406 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -43,10 +43,7 @@ from . import environment from . import mlog from .dependencies import ExternalProgram from .mesonlib import MesonException, get_wine_shortpath, split_args, join_args -from .backend.backends import TestProtocol - -if T.TYPE_CHECKING: - from .backend.backends import TestSerialisation +from .backend.backends import TestProtocol, TestSerialisation # GNU autotools interprets a return code of 77 from tests it executes to # mean that the test should be skipped. @@ -445,7 +442,7 @@ class JunitBuilder: class TestRun: @classmethod - def make_gtest(cls, test: 'TestSerialisation', test_env: T.Dict[str, str], + def make_gtest(cls, test: TestSerialisation, test_env: T.Dict[str, str], returncode: int, starttime: float, duration: float, stdo: T.Optional[str], stde: T.Optional[str], cmd: T.Optional[T.List[str]]) -> 'TestRun': @@ -459,7 +456,7 @@ class TestRun: junit=tree) @classmethod - def make_exitcode(cls, test: 'TestSerialisation', test_env: T.Dict[str, str], + def make_exitcode(cls, test: TestSerialisation, test_env: T.Dict[str, str], returncode: int, starttime: float, duration: float, stdo: T.Optional[str], stde: T.Optional[str], cmd: T.Optional[T.List[str]], **kwargs: T.Any) -> 'TestRun': @@ -474,7 +471,7 @@ class TestRun: return cls(test, test_env, res, [], returncode, starttime, duration, stdo, stde, cmd, **kwargs) @classmethod - def make_tap(cls, test: 'TestSerialisation', test_env: T.Dict[str, str], + def make_tap(cls, test: TestSerialisation, test_env: T.Dict[str, str], returncode: int, starttime: float, duration: float, stdo: str, stde: str, cmd: T.Optional[T.List[str]]) -> 'TestRun': @@ -511,7 +508,7 @@ class TestRun: return cls(test, test_env, res, results, returncode, starttime, duration, stdo, stde, cmd) - def __init__(self, test: 'TestSerialisation', test_env: T.Dict[str, str], + def __init__(self, test: TestSerialisation, test_env: T.Dict[str, str], res: TestResult, results: T.List[TestResult], returncode: int, starttime: float, duration: float, stdo: T.Optional[str], stde: T.Optional[str], @@ -577,26 +574,32 @@ def write_json_log(jsonlogfile: T.TextIO, test_name: str, result: TestRun) -> No def run_with_mono(fname: str) -> bool: return fname.endswith('.exe') and not (is_windows() or is_cygwin()) -def load_benchmarks(build_dir: str) -> T.List['TestSerialisation']: +def load_benchmarks(build_dir: str) -> T.List[TestSerialisation]: datafile = Path(build_dir) / 'meson-private' / 'meson_benchmark_setup.dat' if not datafile.is_file(): raise TestException('Directory {!r} does not seem to be a Meson build directory.'.format(build_dir)) with datafile.open('rb') as f: - obj = T.cast(T.List['TestSerialisation'], pickle.load(f)) + obj = pickle.load(f) + assert isinstance(obj, list) + for i in obj: + assert isinstance(i, TestSerialisation) return obj -def load_tests(build_dir: str) -> T.List['TestSerialisation']: +def load_tests(build_dir: str) -> T.List[TestSerialisation]: datafile = Path(build_dir) / 'meson-private' / 'meson_test_setup.dat' if not datafile.is_file(): raise TestException('Directory {!r} does not seem to be a Meson build directory.'.format(build_dir)) with datafile.open('rb') as f: - obj = T.cast(T.List['TestSerialisation'], pickle.load(f)) + obj = pickle.load(f) + assert isinstance(obj, list) + for i in obj: + assert isinstance(i, TestSerialisation) return obj class SingleTestRunner: - def __init__(self, test: 'TestSerialisation', test_env: T.Dict[str, str], + def __init__(self, test: TestSerialisation, test_env: T.Dict[str, str], env: T.Dict[str, str], options: argparse.Namespace): self.test = test self.test_env = test_env @@ -605,9 +608,9 @@ class SingleTestRunner: def _get_cmd(self) -> T.Optional[T.List[str]]: if self.test.fname[0].endswith('.jar'): - return ['java', '-jar'] + T.cast(T.List[str], self.test.fname) + return ['java', '-jar'] + self.test.fname elif not self.test.is_cross_built and run_with_mono(self.test.fname[0]): - return ['mono'] + T.cast(T.List[str], self.test.fname) + return ['mono'] + self.test.fname elif self.test.cmd_is_built and self.test.needs_exe_wrapper: if self.test.exe_runner is None: # Can not run test on cross compiled executable @@ -620,8 +623,8 @@ class SingleTestRunner: msg = ('The exe_wrapper defined in the cross file {!r} was not ' 'found. Please check the command and/or add it to PATH.') raise TestException(msg.format(self.test.exe_runner.name)) - return T.cast(T.List[str], self.test.exe_runner.get_command()) + T.cast(T.List[str], self.test.fname) - return T.cast(T.List[str], self.test.fname) + return self.test.exe_runner.get_command() + self.test.fname + return self.test.fname def run(self) -> TestRun: cmd = self._get_cmd() @@ -833,7 +836,7 @@ class TestHarness: lfile.close() setattr(self, f, None) - def merge_suite_options(self, options: argparse.Namespace, test: 'TestSerialisation') -> T.Dict[str, str]: + def merge_suite_options(self, options: argparse.Namespace, test: TestSerialisation) -> T.Dict[str, str]: if ':' in options.setup: if options.setup not in self.build_data.test_setups: sys.exit("Unknown test setup '{}'.".format(options.setup)) @@ -855,9 +858,9 @@ class TestHarness: sys.exit('Conflict: both test setup and command line specify an exe wrapper.') if options.wrapper is None: options.wrapper = current.exe_wrapper - return T.cast(T.Dict[str, str], current.env.get_env(os.environ.copy())) + return current.env.get_env(os.environ.copy()) - def get_test_runner(self, test: 'TestSerialisation') -> SingleTestRunner: + def get_test_runner(self, test: TestSerialisation) -> SingleTestRunner: options = deepcopy(self.options) if not options.setup: options.setup = self.build_data.test_setup_default_name @@ -889,7 +892,7 @@ class TestHarness: sys.exit('Unknown test result encountered: {}'.format(result.res)) def print_stats(self, test_count: int, name_max_len: int, - tests: T.List['TestSerialisation'], + tests: T.List[TestSerialisation], name: str, result: TestRun, i: int) -> None: ok_statuses = (TestResult.OK, TestResult.EXPECTEDFAIL) bad_statuses = (TestResult.FAIL, TestResult.TIMEOUT, @@ -983,14 +986,14 @@ class TestHarness: @staticmethod def split_suite_string(suite: str) -> T.Tuple[str, str]: if ':' in suite: - # mypy can't figure out that str.split(n, 1) will return a list of - # length 2, so we have to help it. - return T.cast(T.Tuple[str, str], tuple(suite.split(':', 1))) + split = suite.split(':', 1) + assert len(split) == 2 + return split[0], split[1] else: return suite, "" @staticmethod - def test_in_suites(test: 'TestSerialisation', suites: T.List[str]) -> bool: + def test_in_suites(test: TestSerialisation, suites: T.List[str]) -> bool: for suite in suites: (prj_match, st_match) = TestHarness.split_suite_string(suite) for prjst in test.suite: @@ -1021,12 +1024,12 @@ class TestHarness: return True return False - def test_suitable(self, test: 'TestSerialisation') -> bool: + def test_suitable(self, test: TestSerialisation) -> bool: return ((not self.options.include_suites or TestHarness.test_in_suites(test, self.options.include_suites)) and not TestHarness.test_in_suites(test, self.options.exclude_suites)) - def get_tests(self) -> T.List['TestSerialisation']: + def get_tests(self) -> T.List[TestSerialisation]: if not self.tests: print('No tests defined.') return [] @@ -1089,17 +1092,17 @@ class TestHarness: wrap += options.wrapper return wrap - def get_pretty_suite(self, test: 'TestSerialisation') -> str: + def get_pretty_suite(self, test: TestSerialisation) -> str: if len(self.suites) > 1 and test.suite: rv = TestHarness.split_suite_string(test.suite[0])[0] s = "+".join(TestHarness.split_suite_string(s)[1] for s in test.suite) if s: rv += ":" - return rv + s + " / " + T.cast(str, test.name) + return rv + s + " / " + test.name else: - return T.cast(str, test.name) + return test.name - def run_tests(self, tests: T.List['TestSerialisation']) -> None: + def run_tests(self, tests: T.List[TestSerialisation]) -> None: executor = None futures = [] # type: T.List[T.Tuple[conc.Future[TestRun], int, int, T.List[TestSerialisation], str, int]] test_count = len(tests) @@ -1141,7 +1144,7 @@ class TestHarness: finally: os.chdir(startdir) - def drain_futures(self, futures: T.List[T.Tuple['conc.Future[TestRun]', int, int, T.List['TestSerialisation'], str, int]]) -> None: + def drain_futures(self, futures: T.List[T.Tuple['conc.Future[TestRun]', int, int, T.List[TestSerialisation], str, int]]) -> None: for x in futures: (result, test_count, name_max_len, tests, name, i) = x if self.options.repeat > 1 and self.fail_count: diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py index a6fd503e0..75011e7d0 100644 --- a/mesonbuild/optinterpreter.py +++ b/mesonbuild/optinterpreter.py @@ -62,7 +62,6 @@ optname_regex = re.compile('[^a-zA-Z0-9_-]') def StringParser(description, kwargs): return coredata.UserStringOption(description, kwargs.get('value', ''), - kwargs.get('choices', []), kwargs.get('yield', coredata.default_yielding)) @permitted_kwargs({'value', 'yield'}) @@ -134,11 +133,11 @@ option_types = {'string': StringParser, } # type: T.Dict[str, T.Callable[[str, T.Dict], coredata.UserOption]] class OptionInterpreter: - def __init__(self, subproject): + def __init__(self, subproject: str) -> None: self.options = {} self.subproject = subproject - def process(self, option_file): + def process(self, option_file: str) -> None: try: with open(option_file, 'r', encoding='utf8') as f: ast = mparser.Parser(f.read(), option_file).parse() @@ -159,7 +158,7 @@ class OptionInterpreter: e.file = option_file raise e - def reduce_single(self, arg): + def reduce_single(self, arg: T.Union[str, mparser.BaseNode]) -> T.Union[str, int, bool]: if isinstance(arg, str): return arg elif isinstance(arg, (mparser.StringNode, mparser.BooleanNode, @@ -189,7 +188,7 @@ class OptionInterpreter: else: raise OptionException('Arguments may only be string, int, bool, or array of those.') - def reduce_arguments(self, args): + def reduce_arguments(self, args: mparser.ArgumentNode) -> T.Tuple[T.List[T.Union[str, int, bool]], T.Dict[str, T.Union[str, int, bool]]]: assert(isinstance(args, mparser.ArgumentNode)) if args.incorrect_order(): raise OptionException('All keyword arguments must be after positional arguments.') @@ -202,7 +201,7 @@ class OptionInterpreter: reduced_kw[key.value] = self.reduce_single(a) return reduced_pos, reduced_kw - def evaluate_statement(self, node): + def evaluate_statement(self, node: mparser.BaseNode) -> None: if not isinstance(node, mparser.FunctionNode): raise OptionException('Option file may only contain option definitions') func_name = node.func_name diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py index a64caca6d..76cf2b50a 100644 --- a/mesonbuild/scripts/depfixer.py +++ b/mesonbuild/scripts/depfixer.py @@ -311,7 +311,7 @@ class Elf(DataSizes): old_rpath = self.read_str() # Some rpath entries may come from multiple sources. # Only add each one once. - new_rpaths = OrderedSet() + new_rpaths = OrderedSet() # type: OrderedSet[bytes] if new_rpath: new_rpaths.add(new_rpath) if old_rpath: diff --git a/mesonbuild/scripts/meson_exe.py b/mesonbuild/scripts/meson_exe.py index 68ba1200f..df54b4786 100644 --- a/mesonbuild/scripts/meson_exe.py +++ b/mesonbuild/scripts/meson_exe.py @@ -57,7 +57,7 @@ def run_exe(exe: ExecutableSerialisation) -> int: if p.returncode == 0xc0000135: # STATUS_DLL_NOT_FOUND on Windows indicating a common problem that is otherwise hard to diagnose - raise FileNotFoundError('Missing DLLs on calling {!r}'.format(exe.name)) + raise FileNotFoundError('Missing DLLs on calling {!r}'.format(cmd_args)) if exe.capture and p.returncode == 0: skip_write = False diff --git a/run_mypy.py b/run_mypy.py index 759d66783..d5ec55d67 100755 --- a/run_mypy.py +++ b/run_mypy.py @@ -15,6 +15,7 @@ modules = [ # specific files 'mesonbuild/arglist.py', # 'mesonbuild/compilers/mixins/intel.py', + # 'mesonbuild/coredata.py', 'mesonbuild/dependencies/boost.py', 'mesonbuild/dependencies/hdf5.py', 'mesonbuild/dependencies/mpi.py',