From a4f4379c44c7f13bc9e44bc01504077af1f3a338 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Sat, 29 Aug 2020 21:23:43 +0200 Subject: typing: fully annotate scripts --- mesonbuild/scripts/__init__.py | 3 +- mesonbuild/scripts/clangformat.py | 5 ++- mesonbuild/scripts/clangtidy.py | 8 ++-- mesonbuild/scripts/cleantrees.py | 5 ++- mesonbuild/scripts/cmake_run_ctgt.py | 44 ++++++++++---------- mesonbuild/scripts/commandrunner.py | 15 +++---- mesonbuild/scripts/coverage.py | 5 ++- mesonbuild/scripts/delwithsuffix.py | 3 +- mesonbuild/scripts/depfixer.py | 78 +++++++++++++++++++---------------- mesonbuild/scripts/dirchanger.py | 3 +- mesonbuild/scripts/gettext.py | 14 ++++--- mesonbuild/scripts/gtkdochelper.py | 19 +++++---- mesonbuild/scripts/hotdochelper.py | 6 ++- mesonbuild/scripts/meson_exe.py | 7 ++-- mesonbuild/scripts/msgfmthelper.py | 3 +- mesonbuild/scripts/regen_checker.py | 20 +++++---- mesonbuild/scripts/scanbuild.py | 23 ++++++----- mesonbuild/scripts/symbolextractor.py | 34 +++++++-------- mesonbuild/scripts/tags.py | 14 +++---- mesonbuild/scripts/uninstall.py | 5 ++- mesonbuild/scripts/vcstagger.py | 6 +-- mesonbuild/scripts/yelphelper.py | 14 ++++--- 22 files changed, 182 insertions(+), 152 deletions(-) (limited to 'mesonbuild/scripts') diff --git a/mesonbuild/scripts/__init__.py b/mesonbuild/scripts/__init__.py index af6bedc17..2edbe8899 100644 --- a/mesonbuild/scripts/__init__.py +++ b/mesonbuild/scripts/__init__.py @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -def destdir_join(d1, d2): +# TODO: consider switching to pathlib for this +def destdir_join(d1: str, d2: str) -> str: # c:\destdir + c:\prefix must produce c:\destdir\prefix if len(d1) > 1 and d1[1] == ':' \ and len(d2) > 1 and d2[1] == ':': diff --git a/mesonbuild/scripts/clangformat.py b/mesonbuild/scripts/clangformat.py index 4b441de13..19ea5ec2f 100644 --- a/mesonbuild/scripts/clangformat.py +++ b/mesonbuild/scripts/clangformat.py @@ -18,8 +18,9 @@ from concurrent.futures import ThreadPoolExecutor from ..environment import detect_clangformat from ..compilers import lang_suffixes +import typing as T -def clangformat(exelist, srcdir_name, builddir_name): +def clangformat(exelist: T.List[str], srcdir_name: str, builddir_name: str) -> int: srcdir = pathlib.Path(srcdir_name) suffixes = set(lang_suffixes['c']).union(set(lang_suffixes['cpp'])) suffixes.add('h') @@ -33,7 +34,7 @@ def clangformat(exelist, srcdir_name, builddir_name): [x.result() for x in futures] return 0 -def run(args): +def run(args: T.List[str]) -> int: srcdir_name = args[0] builddir_name = args[1] diff --git a/mesonbuild/scripts/clangtidy.py b/mesonbuild/scripts/clangtidy.py index 0452086ee..11174ea25 100644 --- a/mesonbuild/scripts/clangtidy.py +++ b/mesonbuild/scripts/clangtidy.py @@ -16,10 +16,11 @@ import pathlib import subprocess import shutil from concurrent.futures import ThreadPoolExecutor +import typing as T from ..compilers import lang_suffixes -def manual_clangformat(srcdir_name, builddir_name): +def manual_clangformat(srcdir_name: str, builddir_name: str) -> int: srcdir = pathlib.Path(srcdir_name) suffixes = set(lang_suffixes['c']).union(set(lang_suffixes['cpp'])) suffixes.add('h') @@ -34,7 +35,7 @@ def manual_clangformat(srcdir_name, builddir_name): [max(returncode, x.result().returncode) for x in futures] return returncode -def clangformat(srcdir_name, builddir_name): +def clangformat(srcdir_name: str, builddir_name: str) -> int: run_clang_tidy = None for rct in ('run-clang-tidy', 'run-clang-tidy.py'): if shutil.which(rct): @@ -45,8 +46,9 @@ def clangformat(srcdir_name, builddir_name): else: print('Could not find run-clang-tidy, running checks manually.') manual_clangformat(srcdir_name, builddir_name) + return 0 -def run(args): +def run(args: T.List[str]) -> int: srcdir_name = args[0] builddir_name = args[1] return clangformat(srcdir_name, builddir_name) diff --git a/mesonbuild/scripts/cleantrees.py b/mesonbuild/scripts/cleantrees.py index 0af8dd001..6feb9a782 100644 --- a/mesonbuild/scripts/cleantrees.py +++ b/mesonbuild/scripts/cleantrees.py @@ -16,8 +16,9 @@ import os import sys import shutil import pickle +import typing as T -def rmtrees(build_dir, trees): +def rmtrees(build_dir: str, trees: T.List[str]) -> None: for t in trees: # Never delete trees outside of the builddir if os.path.isabs(t): @@ -28,7 +29,7 @@ def rmtrees(build_dir, trees): if os.path.isdir(bt): shutil.rmtree(bt, ignore_errors=True) -def run(args): +def run(args: T.List[str]) -> int: if len(args) != 1: print('Cleaner script for Meson. Do not run on your own please.') print('cleantrees.py ') diff --git a/mesonbuild/scripts/cmake_run_ctgt.py b/mesonbuild/scripts/cmake_run_ctgt.py index 5c0b31f6f..2d9aeca9e 100755 --- a/mesonbuild/scripts/cmake_run_ctgt.py +++ b/mesonbuild/scripts/cmake_run_ctgt.py @@ -3,12 +3,12 @@ import argparse import subprocess import shutil -import os import sys from pathlib import Path +import typing as T -def run(argsv): - commands = [[]] +def run(argsv: T.List[str]) -> int: + commands = [[]] # type: T.List[T.List[str]] SEPARATOR = ';;;' # Generate CMD parameters @@ -20,13 +20,14 @@ def run(argsv): # Parse args = parser.parse_args(argsv) + directory = Path(args.directory) dummy_target = None if len(args.outputs) == 1 and len(args.original_outputs) == 0: - dummy_target = args.outputs[0] + dummy_target = Path(args.outputs[0]) elif len(args.outputs) != len(args.original_outputs): print('Length of output list and original output list differ') - sys.exit(1) + return 1 for i in args.commands: if i == SEPARATOR: @@ -62,39 +63,40 @@ def run(argsv): cmd += [j] try: - os.makedirs(args.directory, exist_ok=True) + directory.mkdir(parents=True, exist_ok=True) - res = subprocess.run(cmd, stdout=stdout, stderr=stderr, cwd=args.directory, check=True) + res = subprocess.run(cmd, stdout=stdout, stderr=stderr, cwd=str(directory), check=True) if capture_file: - out_file = Path(args.directory) / capture_file + out_file = directory / capture_file out_file.write_bytes(res.stdout) except subprocess.CalledProcessError: - sys.exit(1) + return 1 if dummy_target: - with open(dummy_target, 'a'): - os.utime(dummy_target, None) - sys.exit(0) + dummy_target.touch() + return 0 # Copy outputs - zipped_outputs = zip(args.outputs, args.original_outputs) + zipped_outputs = zip([Path(x) for x in args.outputs], [Path(x) for x in args.original_outputs]) for expected, generated in zipped_outputs: do_copy = False - if not os.path.exists(expected): - if not os.path.exists(generated): + if not expected.exists(): + if not generated.exists(): print('Unable to find generated file. This can cause the build to fail:') print(generated) do_copy = False else: do_copy = True - elif os.path.exists(generated): - if os.path.getmtime(generated) > os.path.getmtime(expected): + elif generated.exists(): + if generated.stat().st_mtime > expected.stat().st_mtime: do_copy = True if do_copy: - if os.path.exists(expected): - os.remove(expected) - shutil.copyfile(generated, expected) + if expected.exists(): + expected.unlink() + shutil.copyfile(str(generated), str(expected)) + + return 0 if __name__ == '__main__': - sys.run(sys.argv[1:]) + sys.exit(run(sys.argv[1:])) diff --git a/mesonbuild/scripts/commandrunner.py b/mesonbuild/scripts/commandrunner.py index 22da4178d..aeeaa3bcf 100644 --- a/mesonbuild/scripts/commandrunner.py +++ b/mesonbuild/scripts/commandrunner.py @@ -17,8 +17,9 @@ what to run, sets up the environment and executes the command.""" import sys, os, subprocess, shutil, shlex import re +import typing as T -def run_command(source_dir, build_dir, subdir, meson_command, command, arguments): +def run_command(source_dir: str, build_dir: str, subdir: str, meson_command: T.List[str], command: str, arguments: T.List[str]) -> subprocess.Popen: env = {'MESON_SOURCE_ROOT': source_dir, 'MESON_BUILD_ROOT': build_dir, 'MESON_SUBDIR': subdir, @@ -50,24 +51,24 @@ def run_command(source_dir, build_dir, subdir, meson_command, command, arguments print('Could not execute command "{}": {}'.format(command, err)) sys.exit(1) -def is_python_command(cmdname): +def is_python_command(cmdname: str) -> bool: end_py_regex = r'python(3|3\.\d+)?(\.exe)?$' return re.search(end_py_regex, cmdname) is not None -def run(args): +def run(args: T.List[str]) -> int: if len(args) < 4: print('commandrunner.py [arguments]') return 1 src_dir = args[0] build_dir = args[1] subdir = args[2] - meson_command = args[3] - if is_python_command(meson_command): - meson_command = [meson_command, args[4]] + meson_bin = args[3] + if is_python_command(meson_bin): + meson_command = [meson_bin, args[4]] command = args[5] arguments = args[6:] else: - meson_command = [meson_command] + meson_command = [meson_bin] command = args[4] arguments = args[5:] pc = run_command(src_dir, build_dir, subdir, meson_command, command, arguments) diff --git a/mesonbuild/scripts/coverage.py b/mesonbuild/scripts/coverage.py index 72319724d..80e9052ff 100644 --- a/mesonbuild/scripts/coverage.py +++ b/mesonbuild/scripts/coverage.py @@ -15,8 +15,9 @@ from mesonbuild import environment, mesonlib import argparse, sys, os, subprocess, pathlib, stat +import typing as T -def coverage(outputs, source_root, subproject_root, build_root, log_dir, use_llvm_cov): +def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build_root: str, log_dir: str, use_llvm_cov: bool) -> int: outfiles = [] exitcode = 0 @@ -146,7 +147,7 @@ def coverage(outputs, source_root, subproject_root, build_root, log_dir, use_llv return exitcode -def run(args): +def run(args: T.List[str]) -> int: if not os.path.isfile('build.ninja'): print('Coverage currently only works with the Ninja backend.') return 1 diff --git a/mesonbuild/scripts/delwithsuffix.py b/mesonbuild/scripts/delwithsuffix.py index 0d410ae16..873db0d40 100644 --- a/mesonbuild/scripts/delwithsuffix.py +++ b/mesonbuild/scripts/delwithsuffix.py @@ -13,8 +13,9 @@ # limitations under the License. import os, sys +import typing as T -def run(args): +def run(args: T.List[str]) -> int: if len(args) != 2: print('delwithsuffix.py ') sys.exit(1) diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py index f92769303..a64caca6d 100644 --- a/mesonbuild/scripts/depfixer.py +++ b/mesonbuild/scripts/depfixer.py @@ -15,6 +15,7 @@ import sys, struct import shutil, subprocess +import typing as T from ..mesonlib import OrderedSet @@ -30,7 +31,7 @@ DT_MIPS_RLD_MAP_REL = 1879048245 INSTALL_NAME_TOOL = False class DataSizes: - def __init__(self, ptrsize, is_le): + def __init__(self, ptrsize: int, is_le: bool) -> None: if is_le: p = '<' else: @@ -57,7 +58,7 @@ class DataSizes: self.OffSize = 4 class DynamicEntry(DataSizes): - def __init__(self, ifile, ptrsize, is_le): + def __init__(self, ifile: T.BinaryIO, ptrsize: int, is_le: bool) -> None: super().__init__(ptrsize, is_le) self.ptrsize = ptrsize if ptrsize == 64: @@ -67,7 +68,7 @@ class DynamicEntry(DataSizes): self.d_tag = struct.unpack(self.Sword, ifile.read(self.SwordSize))[0] self.val = struct.unpack(self.Word, ifile.read(self.WordSize))[0] - def write(self, ofile): + def write(self, ofile: T.BinaryIO) -> None: if self.ptrsize == 64: ofile.write(struct.pack(self.Sxword, self.d_tag)) ofile.write(struct.pack(self.XWord, self.val)) @@ -76,7 +77,7 @@ class DynamicEntry(DataSizes): ofile.write(struct.pack(self.Word, self.val)) class SectionHeader(DataSizes): - def __init__(self, ifile, ptrsize, is_le): + def __init__(self, ifile: T.BinaryIO, ptrsize: int, is_le: bool) -> None: super().__init__(ptrsize, is_le) if ptrsize == 64: is_64 = True @@ -116,10 +117,12 @@ class SectionHeader(DataSizes): self.sh_entsize = struct.unpack(self.Word, ifile.read(self.WordSize))[0] class Elf(DataSizes): - def __init__(self, bfile, verbose=True): + def __init__(self, bfile: str, verbose: bool = True) -> None: self.bfile = bfile self.verbose = verbose self.bf = open(bfile, 'r+b') + self.sections = [] # type: T.List[SectionHeader] + self.dynamic = [] # type: T.List[DynamicEntry] try: (self.ptrsize, self.is_le) = self.detect_elf_type() super().__init__(self.ptrsize, self.is_le) @@ -130,18 +133,18 @@ class Elf(DataSizes): self.bf.close() raise - def __enter__(self): + def __enter__(self) -> 'Elf': return self - def __del__(self): + def __del__(self) -> None: if self.bf: self.bf.close() - def __exit__(self, exc_type, exc_value, traceback): + def __exit__(self, exc_type: T.Any, exc_value: T.Any, traceback: T.Any) -> None: self.bf.close() self.bf = None - def detect_elf_type(self): + def detect_elf_type(self) -> T.Tuple[int, bool]: data = self.bf.read(6) if data[1:4] != b'ELF': # This script gets called to non-elf targets too @@ -163,7 +166,7 @@ class Elf(DataSizes): sys.exit('File "%s" has unknown ELF endianness.' % self.bfile) return ptrsize, is_le - def parse_header(self): + def parse_header(self) -> None: self.bf.seek(0) self.e_ident = struct.unpack('16s', self.bf.read(16))[0] self.e_type = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] @@ -180,13 +183,12 @@ class Elf(DataSizes): self.e_shnum = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] self.e_shstrndx = struct.unpack(self.Half, self.bf.read(self.HalfSize))[0] - def parse_sections(self): + def parse_sections(self) -> None: self.bf.seek(self.e_shoff) - self.sections = [] for _ in range(self.e_shnum): self.sections.append(SectionHeader(self.bf, self.ptrsize, self.is_le)) - def read_str(self): + def read_str(self) -> bytes: arr = [] x = self.bf.read(1) while x != b'\0': @@ -196,17 +198,17 @@ class Elf(DataSizes): raise RuntimeError('Tried to read past the end of the file') return b''.join(arr) - def find_section(self, target_name): + def find_section(self, target_name: bytes) -> T.Optional[SectionHeader]: section_names = self.sections[self.e_shstrndx] for i in self.sections: self.bf.seek(section_names.sh_offset + i.sh_name) name = self.read_str() if name == target_name: return i + return None - def parse_dynamic(self): + def parse_dynamic(self) -> None: sec = self.find_section(b'.dynamic') - self.dynamic = [] if sec is None: return self.bf.seek(sec.sh_offset) @@ -216,14 +218,14 @@ class Elf(DataSizes): if e.d_tag == 0: break - def print_section_names(self): + def print_section_names(self) -> None: section_names = self.sections[self.e_shstrndx] for i in self.sections: self.bf.seek(section_names.sh_offset + i.sh_name) name = self.read_str() print(name.decode()) - def print_soname(self): + def print_soname(self) -> None: soname = None strtab = None for i in self.dynamic: @@ -237,14 +239,16 @@ class Elf(DataSizes): self.bf.seek(strtab.val + soname.val) print(self.read_str()) - def get_entry_offset(self, entrynum): + def get_entry_offset(self, entrynum: int) -> T.Optional[int]: sec = self.find_section(b'.dynstr') for i in self.dynamic: if i.d_tag == entrynum: - return sec.sh_offset + i.val + res = sec.sh_offset + i.val + assert isinstance(res, int) + return res return None - def print_rpath(self): + def print_rpath(self) -> None: offset = self.get_entry_offset(DT_RPATH) if offset is None: print("This file does not have an rpath.") @@ -252,7 +256,7 @@ class Elf(DataSizes): self.bf.seek(offset) print(self.read_str()) - def print_runpath(self): + def print_runpath(self) -> None: offset = self.get_entry_offset(DT_RUNPATH) if offset is None: print("This file does not have a runpath.") @@ -260,7 +264,7 @@ class Elf(DataSizes): self.bf.seek(offset) print(self.read_str()) - def print_deps(self): + def print_deps(self) -> None: sec = self.find_section(b'.dynstr') deps = [] for i in self.dynamic: @@ -272,7 +276,7 @@ class Elf(DataSizes): name = self.read_str() print(name) - def fix_deps(self, prefix): + def fix_deps(self, prefix: bytes) -> None: sec = self.find_section(b'.dynstr') deps = [] for i in self.dynamic: @@ -290,15 +294,13 @@ class Elf(DataSizes): self.bf.seek(offset) self.bf.write(newname) - def fix_rpath(self, rpath_dirs_to_remove, new_rpath): + def fix_rpath(self, rpath_dirs_to_remove: T.List[bytes], new_rpath: bytes) -> None: # The path to search for can be either rpath or runpath. # Fix both of them to be sure. self.fix_rpathtype_entry(rpath_dirs_to_remove, new_rpath, DT_RPATH) self.fix_rpathtype_entry(rpath_dirs_to_remove, new_rpath, DT_RUNPATH) - def fix_rpathtype_entry(self, rpath_dirs_to_remove, new_rpath, entrynum): - if isinstance(new_rpath, str): - new_rpath = new_rpath.encode('utf8') + def fix_rpathtype_entry(self, rpath_dirs_to_remove: T.List[bytes], new_rpath: bytes, entrynum: int) -> None: rp_off = self.get_entry_offset(entrynum) if rp_off is None: if self.verbose: @@ -326,7 +328,7 @@ class Elf(DataSizes): new_rpath = b':'.join(new_rpaths) if len(old_rpath) < len(new_rpath): - msg = "New rpath must not be longer than the old one.\n Old: {}\n New: {}".format(old_rpath, new_rpath) + msg = "New rpath must not be longer than the old one.\n Old: {!r}\n New: {!r}".format(old_rpath, new_rpath) sys.exit(msg) # The linker does read-only string deduplication. If there is a # string that shares a suffix with the rpath, they might get @@ -343,7 +345,7 @@ class Elf(DataSizes): self.bf.write(new_rpath) self.bf.write(b'\0') - def remove_rpath_entry(self, entrynum): + def remove_rpath_entry(self, entrynum: int) -> None: sec = self.find_section(b'.dynamic') if sec is None: return None @@ -363,7 +365,7 @@ class Elf(DataSizes): entry.write(self.bf) return None -def fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose=True): +def fix_elf(fname: str, rpath_dirs_to_remove: T.List[bytes], new_rpath: T.Optional[bytes], verbose: bool = True) -> None: with Elf(fname, verbose) as e: if new_rpath is None: e.print_rpath() @@ -371,7 +373,7 @@ def fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose=True): else: e.fix_rpath(rpath_dirs_to_remove, new_rpath) -def get_darwin_rpaths_to_remove(fname): +def get_darwin_rpaths_to_remove(fname: str) -> T.List[str]: out = subprocess.check_output(['otool', '-l', fname], universal_newlines=True, stderr=subprocess.DEVNULL) @@ -389,7 +391,7 @@ def get_darwin_rpaths_to_remove(fname): result.append(rp) return result -def fix_darwin(fname, new_rpath, final_path, install_name_mappings): +def fix_darwin(fname: str, new_rpath: str, final_path: str, install_name_mappings: T.Dict[str, str]) -> None: try: rpaths = get_darwin_rpaths_to_remove(fname) except subprocess.CalledProcessError: @@ -439,7 +441,7 @@ def fix_darwin(fname, new_rpath, final_path, install_name_mappings): except Exception as err: raise SystemExit(err) -def fix_jar(fname): +def fix_jar(fname: str) -> None: subprocess.check_call(['jar', 'xfv', fname, 'META-INF/MANIFEST.MF']) with open('META-INF/MANIFEST.MF', 'r+') as f: lines = f.readlines() @@ -450,7 +452,7 @@ def fix_jar(fname): f.truncate() subprocess.check_call(['jar', 'ufm', fname, 'META-INF/MANIFEST.MF']) -def fix_rpath(fname, rpath_dirs_to_remove, new_rpath, final_path, install_name_mappings, verbose=True): +def fix_rpath(fname: str, rpath_dirs_to_remove: T.List[bytes], new_rpath: T.Union[str, bytes], final_path: str, install_name_mappings: T.Dict[str, str], verbose: bool = True) -> None: global INSTALL_NAME_TOOL # Static libraries, import libraries, debug information, headers, etc # never have rpaths @@ -461,6 +463,8 @@ def fix_rpath(fname, rpath_dirs_to_remove, new_rpath, final_path, install_name_m if fname.endswith('.jar'): fix_jar(fname) return + if isinstance(new_rpath, str): + new_rpath = new_rpath.encode('utf8') fix_elf(fname, rpath_dirs_to_remove, new_rpath, verbose) return except SystemExit as e: @@ -473,6 +477,8 @@ def fix_rpath(fname, rpath_dirs_to_remove, new_rpath, final_path, install_name_m # (upto 30ms), which is significant with --only-changed. For details, see: # https://github.com/mesonbuild/meson/pull/6612#discussion_r378581401 if INSTALL_NAME_TOOL is False: - INSTALL_NAME_TOOL = shutil.which('install_name_tool') + INSTALL_NAME_TOOL = bool(shutil.which('install_name_tool')) if INSTALL_NAME_TOOL: + if isinstance(new_rpath, bytes): + new_rpath = new_rpath.decode('utf8') fix_darwin(fname, new_rpath, final_path, install_name_mappings) diff --git a/mesonbuild/scripts/dirchanger.py b/mesonbuild/scripts/dirchanger.py index 3d7f4e24e..21632cd89 100644 --- a/mesonbuild/scripts/dirchanger.py +++ b/mesonbuild/scripts/dirchanger.py @@ -16,8 +16,9 @@ the command given in the rest of the arguments.''' import os, subprocess, sys +import typing as T -def run(args): +def run(args: T.List[str]) -> int: dirname = args[0] command = args[1:] diff --git a/mesonbuild/scripts/gettext.py b/mesonbuild/scripts/gettext.py index 704286318..547d14f0d 100644 --- a/mesonbuild/scripts/gettext.py +++ b/mesonbuild/scripts/gettext.py @@ -17,6 +17,7 @@ import shutil import argparse import subprocess from . import destdir_join +import typing as T parser = argparse.ArgumentParser() parser.add_argument('command') @@ -27,7 +28,7 @@ parser.add_argument('--localedir', default='') parser.add_argument('--subdir', default='') parser.add_argument('--extra-args', default='') -def read_linguas(src_sub): +def read_linguas(src_sub: str) -> T.List[str]: # Syntax of this file is documented here: # https://www.gnu.org/software/gettext/manual/html_node/po_002fLINGUAS.html linguas = os.path.join(src_sub, 'LINGUAS') @@ -43,7 +44,7 @@ def read_linguas(src_sub): print('Could not find file LINGUAS in {}'.format(src_sub)) return [] -def run_potgen(src_sub, pkgname, datadirs, args): +def run_potgen(src_sub: str, pkgname: str, datadirs: str, args: T.List[str]) -> int: listfile = os.path.join(src_sub, 'POTFILES.in') if not os.path.exists(listfile): listfile = os.path.join(src_sub, 'POTFILES') @@ -60,13 +61,13 @@ def run_potgen(src_sub, pkgname, datadirs, args): '-D', os.environ['MESON_SOURCE_ROOT'], '-k_', '-o', ofile] + args, env=child_env) -def gen_gmo(src_sub, bld_sub, langs): +def gen_gmo(src_sub: str, bld_sub: str, langs: T.List[str]) -> int: for l in langs: subprocess.check_call(['msgfmt', os.path.join(src_sub, l + '.po'), '-o', os.path.join(bld_sub, l + '.gmo')]) return 0 -def update_po(src_sub, pkgname, langs): +def update_po(src_sub: str, pkgname: str, langs: T.List[str]) -> int: potfile = os.path.join(src_sub, pkgname + '.pot') for l in langs: pofile = os.path.join(src_sub, l + '.po') @@ -76,7 +77,7 @@ def update_po(src_sub, pkgname, langs): subprocess.check_call(['msginit', '--input', potfile, '--output-file', pofile, '--locale', l, '--no-translator']) return 0 -def do_install(src_sub, bld_sub, dest, pkgname, langs): +def do_install(src_sub: str, bld_sub: str, dest: str, pkgname: str, langs: T.List[str]) -> int: for l in langs: srcfile = os.path.join(bld_sub, l + '.gmo') outfile = os.path.join(dest, l, 'LC_MESSAGES', @@ -88,7 +89,7 @@ def do_install(src_sub, bld_sub, dest, pkgname, langs): print('Installing %s to %s' % (srcfile, outfile)) return 0 -def run(args): +def run(args: T.List[str]) -> int: options = parser.parse_args(args) subcmd = options.command langs = options.langs.split('@@') if options.langs else None @@ -120,3 +121,4 @@ def run(args): else: print('Unknown subcommand.') return 1 + return 0 diff --git a/mesonbuild/scripts/gtkdochelper.py b/mesonbuild/scripts/gtkdochelper.py index 812604af5..86949e5e7 100644 --- a/mesonbuild/scripts/gtkdochelper.py +++ b/mesonbuild/scripts/gtkdochelper.py @@ -18,6 +18,7 @@ import shutil import argparse from ..mesonlib import MesonException, Popen_safe, is_windows, is_cygwin, split_args from . import destdir_join +import typing as T parser = argparse.ArgumentParser() @@ -50,7 +51,7 @@ for tool in ['scan', 'scangobj', 'mkdb', 'mkhtml', 'fixxref']: program_name = 'gtkdoc-' + tool parser.add_argument('--' + program_name, dest=program_name.replace('-', '_')) -def gtkdoc_run_check(cmd, cwd, library_paths=None): +def gtkdoc_run_check(cmd: T.List[str], cwd: str, library_paths: T.Optional[T.List[str]] = None) -> None: if library_paths is None: library_paths = [] @@ -85,12 +86,12 @@ def gtkdoc_run_check(cmd, cwd, library_paths=None): except UnicodeEncodeError: pass -def build_gtkdoc(source_root, build_root, doc_subdir, src_subdirs, - main_file, module, module_version, - html_args, scan_args, fixxref_args, mkdb_args, - gobject_typesfile, scanobjs_args, run, ld, cc, ldflags, cflags, - html_assets, content_files, ignore_headers, namespace, - expand_content_files, mode, options): +def build_gtkdoc(source_root: str, build_root: str, doc_subdir: str, src_subdirs: T.List[str], + main_file: str, module: str, module_version: str, + html_args: T.List[str], scan_args: T.List[str], fixxref_args: T.List[str], mkdb_args: T.List[str], + gobject_typesfile: str, scanobjs_args: T.List[str], run: str, ld: str, cc: str, ldflags: str, cflags: str, + html_assets: T.List[str], content_files: T.List[str], ignore_headers: T.List[str], namespace: str, + expand_content_files: T.List[str], mode: str, options: argparse.Namespace) -> None: print("Building documentation for %s" % module) src_dir_args = [] @@ -217,13 +218,13 @@ def build_gtkdoc(source_root, build_root, doc_subdir, src_subdirs, shutil.move(os.path.join(htmldir, '{}.devhelp2'.format(module)), os.path.join(htmldir, '{}-{}.devhelp2'.format(module, module_version))) -def install_gtkdoc(build_root, doc_subdir, install_prefix, datadir, module): +def install_gtkdoc(build_root: str, doc_subdir: str, install_prefix: str, datadir: str, module: str) -> None: source = os.path.join(build_root, doc_subdir, 'html') final_destination = os.path.join(install_prefix, datadir, module) shutil.rmtree(final_destination, ignore_errors=True) shutil.copytree(source, final_destination) -def run(args): +def run(args: T.List[str]) -> int: options = parser.parse_args(args) if options.htmlargs: htmlargs = options.htmlargs.split('@@') diff --git a/mesonbuild/scripts/hotdochelper.py b/mesonbuild/scripts/hotdochelper.py index 826745d09..a96a34afa 100644 --- a/mesonbuild/scripts/hotdochelper.py +++ b/mesonbuild/scripts/hotdochelper.py @@ -5,6 +5,7 @@ import subprocess from . import destdir_join import argparse +import typing as T parser = argparse.ArgumentParser() parser.add_argument('--install') @@ -14,7 +15,7 @@ parser.add_argument('--builddir') parser.add_argument('--project-version') -def run(argv): +def run(argv: T.List[str]) -> int: options, args = parser.parse_known_args(argv) subenv = os.environ.copy() @@ -23,7 +24,7 @@ def run(argv): res = subprocess.call(args, cwd=options.builddir, env=subenv) if res != 0: - exit(res) + return res if options.install: source_dir = os.path.join(options.builddir, options.install) @@ -34,3 +35,4 @@ def run(argv): shutil.rmtree(installdir, ignore_errors=True) shutil.copytree(source_dir, installdir) + return 0 diff --git a/mesonbuild/scripts/meson_exe.py b/mesonbuild/scripts/meson_exe.py index f1b029949..68ba1200f 100644 --- a/mesonbuild/scripts/meson_exe.py +++ b/mesonbuild/scripts/meson_exe.py @@ -17,19 +17,20 @@ import sys import argparse import pickle import subprocess +import typing as T from .. import mesonlib from ..backend.backends import ExecutableSerialisation options = None -def buildparser(): +def buildparser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description='Custom executable wrapper for Meson. Do not run on your own, mmm\'kay?') parser.add_argument('--unpickle') parser.add_argument('--capture') return parser -def run_exe(exe): +def run_exe(exe: ExecutableSerialisation) -> int: if exe.exe_runner: if not exe.exe_runner.found(): raise AssertionError('BUG: Can\'t run cross-compiled exe {!r} with not-found ' @@ -74,7 +75,7 @@ def run_exe(exe): sys.stderr.buffer.write(stderr) return p.returncode -def run(args): +def run(args: T.List[str]) -> int: global options parser = buildparser() options, cmd_args = parser.parse_known_args(args) diff --git a/mesonbuild/scripts/msgfmthelper.py b/mesonbuild/scripts/msgfmthelper.py index 737f1bca6..3ddc9e6a9 100644 --- a/mesonbuild/scripts/msgfmthelper.py +++ b/mesonbuild/scripts/msgfmthelper.py @@ -15,6 +15,7 @@ import argparse import subprocess import os +import typing as T parser = argparse.ArgumentParser() parser.add_argument('input') @@ -25,7 +26,7 @@ parser.add_argument('--datadirs', default='') parser.add_argument('args', default=[], metavar='extra msgfmt argument', nargs='*') -def run(args): +def run(args: T.List[str]) -> int: options = parser.parse_args(args) env = None if options.datadirs: diff --git a/mesonbuild/scripts/regen_checker.py b/mesonbuild/scripts/regen_checker.py index 80d9242b4..84f7d77f6 100644 --- a/mesonbuild/scripts/regen_checker.py +++ b/mesonbuild/scripts/regen_checker.py @@ -14,10 +14,14 @@ import sys, os import pickle, subprocess +import typing as T + +if T.TYPE_CHECKING: + from ..backend.vs2010backend import RegenInfo # This could also be used for XCode. -def need_regen(regeninfo, regen_timestamp): +def need_regen(regeninfo: 'RegenInfo', regen_timestamp: float) -> bool: for i in regeninfo.depfiles: curfile = os.path.join(regeninfo.build_dir, i) curtime = os.stat(curfile).st_mtime @@ -31,7 +35,7 @@ def need_regen(regeninfo, regen_timestamp): Vs2010Backend.touch_regen_timestamp(regeninfo.build_dir) return False -def regen(regeninfo, meson_command, backend): +def regen(regeninfo: 'RegenInfo', meson_command: T.List[str], backend: str) -> None: cmd = meson_command + ['--internal', 'regenerate', regeninfo.build_dir, @@ -39,19 +43,19 @@ def regen(regeninfo, meson_command, backend): '--backend=' + backend] subprocess.check_call(cmd) -def run(args): +def run(args: T.List[str]) -> int: private_dir = args[0] dumpfile = os.path.join(private_dir, 'regeninfo.dump') - coredata = os.path.join(private_dir, 'coredata.dat') + coredata_file = os.path.join(private_dir, 'coredata.dat') with open(dumpfile, 'rb') as f: - regeninfo = pickle.load(f) - with open(coredata, 'rb') as f: + regeninfo = T.cast('RegenInfo', pickle.load(f)) + with open(coredata_file, 'rb') as f: coredata = pickle.load(f) backend = coredata.get_builtin_option('backend') regen_timestamp = os.stat(dumpfile).st_mtime if need_regen(regeninfo, regen_timestamp): regen(regeninfo, coredata.meson_command, backend) - sys.exit(0) + return 0 if __name__ == '__main__': - run(sys.argv[1:]) + sys.exit(run(sys.argv[1:])) diff --git a/mesonbuild/scripts/scanbuild.py b/mesonbuild/scripts/scanbuild.py index 0190067e2..3e5b30fd4 100644 --- a/mesonbuild/scripts/scanbuild.py +++ b/mesonbuild/scripts/scanbuild.py @@ -12,30 +12,31 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os import subprocess import shutil import tempfile from ..environment import detect_ninja, detect_scanbuild +from pathlib import Path +import typing as T -def scanbuild(exelist, srcdir, blddir, privdir, logdir, args): - with tempfile.TemporaryDirectory(dir=privdir) as scandir: +def scanbuild(exelist: T.List[str], srcdir: Path, blddir: Path, privdir: Path, logdir: Path, args: T.List[str]) -> int: + with tempfile.TemporaryDirectory(dir=str(privdir)) as scandir: meson_cmd = exelist + args - build_cmd = exelist + ['-o', logdir] + detect_ninja() + ['-C', scandir] - rc = subprocess.call(meson_cmd + [srcdir, scandir]) + build_cmd = exelist + ['-o', str(logdir)] + detect_ninja() + ['-C', scandir] + rc = subprocess.call(meson_cmd + [str(srcdir), scandir]) if rc != 0: return rc return subprocess.call(build_cmd) -def run(args): - srcdir = args[0] - blddir = args[1] +def run(args: T.List[str]) -> int: + srcdir = Path(args[0]) + blddir = Path(args[1]) meson_cmd = args[2:] - privdir = os.path.join(blddir, 'meson-private') - logdir = os.path.join(blddir, 'meson-logs/scanbuild') - shutil.rmtree(logdir, ignore_errors=True) + privdir = blddir / 'meson-private' + logdir = blddir / 'meson-logs' / 'scanbuild' + shutil.rmtree(str(logdir), ignore_errors=True) exelist = detect_scanbuild() if not exelist: diff --git a/mesonbuild/scripts/symbolextractor.py b/mesonbuild/scripts/symbolextractor.py index cf486afb2..e60731510 100644 --- a/mesonbuild/scripts/symbolextractor.py +++ b/mesonbuild/scripts/symbolextractor.py @@ -36,12 +36,12 @@ parser.add_argument('args', nargs='+') TOOL_WARNING_FILE = None RELINKING_WARNING = 'Relinking will always happen on source changes.' -def dummy_syms(outfilename: str): +def dummy_syms(outfilename: str) -> None: """Just touch it so relinking happens always.""" with open(outfilename, 'w'): pass -def write_if_changed(text: str, outfilename: str): +def write_if_changed(text: str, outfilename: str) -> None: try: with open(outfilename, 'r') as f: oldtext = f.read() @@ -52,13 +52,11 @@ def write_if_changed(text: str, outfilename: str): with open(outfilename, 'w') as f: f.write(text) -def print_tool_warning(tool: list, msg: str, stderr: str = None): +def print_tool_warning(tools: T.List[str], msg: str, stderr: T.Optional[str] = None) -> None: global TOOL_WARNING_FILE if os.path.exists(TOOL_WARNING_FILE): return - if len(tool) == 1: - tool = tool[0] - m = '{!r} {}. {}'.format(tool, msg, RELINKING_WARNING) + m = '{!r} {}. {}'.format(tools, msg, RELINKING_WARNING) if stderr: m += '\n' + stderr mlog.warning(m) @@ -73,7 +71,7 @@ def get_tool(name: str) -> T.List[str]: return shlex.split(os.environ[evar]) return [name] -def call_tool(name: str, args: T.List[str], **kwargs) -> str: +def call_tool(name: str, args: T.List[str], **kwargs: T.Any) -> str: tool = get_tool(name) try: p, output, e = Popen_safe(tool + args, **kwargs) @@ -88,7 +86,7 @@ def call_tool(name: str, args: T.List[str], **kwargs) -> str: return None return output -def call_tool_nowarn(tool: T.List[str], **kwargs) -> T.Tuple[str, str]: +def call_tool_nowarn(tool: T.List[str], **kwargs: T.Any) -> T.Tuple[str, str]: try: p, output, e = Popen_safe(tool, **kwargs) except FileNotFoundError: @@ -99,7 +97,7 @@ def call_tool_nowarn(tool: T.List[str], **kwargs) -> T.Tuple[str, str]: return None, e return output, None -def gnu_syms(libfilename: str, outfilename: str): +def gnu_syms(libfilename: str, outfilename: str) -> None: # Get the name of the library output = call_tool('readelf', ['-d', libfilename]) if not output: @@ -126,7 +124,7 @@ def gnu_syms(libfilename: str, outfilename: str): result += [' '.join(entry)] write_if_changed('\n'.join(result) + '\n', outfilename) -def solaris_syms(libfilename: str, outfilename: str): +def solaris_syms(libfilename: str, outfilename: str) -> None: # gnu_syms() works with GNU nm & readelf, not Solaris nm & elfdump origpath = os.environ['PATH'] try: @@ -135,7 +133,7 @@ def solaris_syms(libfilename: str, outfilename: str): finally: os.environ['PATH'] = origpath -def osx_syms(libfilename: str, outfilename: str): +def osx_syms(libfilename: str, outfilename: str) -> None: # Get the name of the library output = call_tool('otool', ['-l', libfilename]) if not output: @@ -156,7 +154,7 @@ def osx_syms(libfilename: str, outfilename: str): result += [' '.join(x.split()[0:2]) for x in output.split('\n')] write_if_changed('\n'.join(result) + '\n', outfilename) -def openbsd_syms(libfilename: str, outfilename: str): +def openbsd_syms(libfilename: str, outfilename: str) -> None: # Get the name of the library output = call_tool('readelf', ['-d', libfilename]) if not output: @@ -173,7 +171,7 @@ def openbsd_syms(libfilename: str, outfilename: str): result += [' '.join(x.split()[0:2]) for x in output.split('\n') if x and not x.endswith('U ')] write_if_changed('\n'.join(result) + '\n', outfilename) -def cygwin_syms(impfilename: str, outfilename: str): +def cygwin_syms(impfilename: str, outfilename: str) -> None: # Get the name of the library output = call_tool('dlltool', ['-I', impfilename]) if not output: @@ -242,23 +240,23 @@ def _get_implib_exports(impfilename: str) -> T.Tuple[T.List[str], str]: all_stderr += e return ([], all_stderr) -def windows_syms(impfilename: str, outfilename: str): +def windows_syms(impfilename: str, outfilename: str) -> None: # Get the name of the library result, e = _get_implib_dllname(impfilename) if not result: - print_tool_warning('lib, llvm-lib, dlltool', 'do not work or were not found', e) + print_tool_warning(['lib', 'llvm-lib', 'dlltool'], 'do not work or were not found', e) dummy_syms(outfilename) return # Get a list of all symbols exported symbols, e = _get_implib_exports(impfilename) if not symbols: - print_tool_warning('dumpbin, llvm-nm, nm', 'do not work or were not found', e) + print_tool_warning(['dumpbin', 'llvm-nm', 'nm'], 'do not work or were not found', e) dummy_syms(outfilename) return result += symbols write_if_changed('\n'.join(result) + '\n', outfilename) -def gen_symbols(libfilename: str, impfilename: str, outfilename: str, cross_host: str): +def gen_symbols(libfilename: str, impfilename: str, outfilename: str, cross_host: str) -> None: if cross_host is not None: # In case of cross builds just always relink. In theory we could # determine the correct toolset, but we would need to use the correct @@ -295,7 +293,7 @@ def gen_symbols(libfilename: str, impfilename: str, outfilename: str, cross_host pass dummy_syms(outfilename) -def run(args): +def run(args: T.List[str]) -> int: global TOOL_WARNING_FILE options = parser.parse_args(args) if len(options.args) != 4: diff --git a/mesonbuild/scripts/tags.py b/mesonbuild/scripts/tags.py index 431bb5fd3..bb858310d 100644 --- a/mesonbuild/scripts/tags.py +++ b/mesonbuild/scripts/tags.py @@ -15,9 +15,9 @@ import os import subprocess from pathlib import Path +import typing as T - -def ls_as_bytestream(): +def ls_as_bytestream() -> bytes: if os.path.exists('.git'): return subprocess.run(['git', 'ls-tree', '-r', '--name-only', 'HEAD'], stdout=subprocess.PIPE).stdout @@ -28,24 +28,24 @@ def ls_as_bytestream(): return '\n'.join(files).encode() -def cscope(): +def cscope() -> int: ls = b'\n'.join([b'"%s"' % f for f in ls_as_bytestream().split()]) return subprocess.run(['cscope', '-v', '-b', '-i-'], input=ls).returncode -def ctags(): +def ctags() -> int: ls = ls_as_bytestream() return subprocess.run(['ctags', '-L-'], input=ls).returncode -def etags(): +def etags() -> int: ls = ls_as_bytestream() return subprocess.run(['etags', '-'], input=ls).returncode -def run(args): +def run(args: T.List[str]) -> int: tool_name = args[0] srcdir_name = args[1] os.chdir(srcdir_name) assert tool_name in ['cscope', 'ctags', 'etags'] - return globals()[tool_name]() + return T.cast(int, globals()[tool_name]()) diff --git a/mesonbuild/scripts/uninstall.py b/mesonbuild/scripts/uninstall.py index bdc036b85..b648de4cc 100644 --- a/mesonbuild/scripts/uninstall.py +++ b/mesonbuild/scripts/uninstall.py @@ -13,10 +13,11 @@ # limitations under the License. import os +import typing as T logfile = 'meson-logs/install-log.txt' -def do_uninstall(log): +def do_uninstall(log: str) -> None: failures = 0 successes = 0 for line in open(log): @@ -38,7 +39,7 @@ def do_uninstall(log): print('Failed:', failures) print('\nRemember that files created by custom scripts have not been removed.') -def run(args): +def run(args: T.List[str]) -> int: if args: print('Weird error.') return 1 diff --git a/mesonbuild/scripts/vcstagger.py b/mesonbuild/scripts/vcstagger.py index 16dd4d1e5..64985f6d3 100644 --- a/mesonbuild/scripts/vcstagger.py +++ b/mesonbuild/scripts/vcstagger.py @@ -13,9 +13,9 @@ # limitations under the License. import sys, os, subprocess, re +import typing as T - -def config_vcs_tag(infile, outfile, fallback, source_dir, replace_string, regex_selector, cmd): +def config_vcs_tag(infile: str, outfile: str, fallback: str, source_dir: str, replace_string: str, regex_selector: str, cmd: T.List[str]) -> None: try: output = subprocess.check_output(cmd, cwd=source_dir) new_string = re.search(regex_selector, output.decode()).group(1).strip() @@ -34,7 +34,7 @@ def config_vcs_tag(infile, outfile, fallback, source_dir, replace_string, regex_ f.write(new_data) -def run(args): +def run(args: T.List[str]) -> int: infile, outfile, fallback, source_dir, replace_string, regex_selector = args[0:6] command = args[6:] config_vcs_tag(infile, outfile, fallback, source_dir, replace_string, regex_selector, command) diff --git a/mesonbuild/scripts/yelphelper.py b/mesonbuild/scripts/yelphelper.py index 6bf067350..0355d9fd6 100644 --- a/mesonbuild/scripts/yelphelper.py +++ b/mesonbuild/scripts/yelphelper.py @@ -20,6 +20,7 @@ from .. import mlog from ..mesonlib import has_path_sep from . import destdir_join from .gettext import read_linguas +import typing as T parser = argparse.ArgumentParser() parser.add_argument('command') @@ -31,19 +32,19 @@ parser.add_argument('--media', dest='media', default='') parser.add_argument('--langs', dest='langs', default='') parser.add_argument('--symlinks', type=bool, dest='symlinks', default=False) -def build_pot(srcdir, project_id, sources): +def build_pot(srcdir: str, project_id: str, sources: T.List[str]) -> None: # Must be relative paths sources = [os.path.join('C', source) for source in sources] outfile = os.path.join(srcdir, project_id + '.pot') subprocess.call(['itstool', '-o', outfile] + sources) -def update_po(srcdir, project_id, langs): +def update_po(srcdir: str, project_id: str, langs: T.List[str]) -> None: potfile = os.path.join(srcdir, project_id + '.pot') for lang in langs: pofile = os.path.join(srcdir, lang, lang + '.po') subprocess.call(['msgmerge', '-q', '-o', pofile, pofile, potfile]) -def build_translations(srcdir, blddir, langs): +def build_translations(srcdir: str, blddir: str, langs: T.List[str]) -> None: for lang in langs: outdir = os.path.join(blddir, lang) os.makedirs(outdir, exist_ok=True) @@ -52,14 +53,14 @@ def build_translations(srcdir, blddir, langs): '-o', os.path.join(outdir, lang + '.gmo') ]) -def merge_translations(blddir, sources, langs): +def merge_translations(blddir: str, sources: T.List[str], langs: T.List[str]) -> None: for lang in langs: subprocess.call([ 'itstool', '-m', os.path.join(blddir, lang, lang + '.gmo'), '-o', os.path.join(blddir, lang) ] + sources) -def install_help(srcdir, blddir, sources, media, langs, install_dir, destdir, project_id, symlinks): +def install_help(srcdir: str, blddir: str, sources: T.List[str], media: T.List[str], langs: T.List[str], install_dir: str, destdir: str, project_id: str, symlinks: bool) -> None: c_install_dir = os.path.join(install_dir, 'C', project_id) for lang in langs + ['C']: indir = destdir_join(destdir, os.path.join(install_dir, lang, project_id)) @@ -101,7 +102,7 @@ def install_help(srcdir, blddir, sources, media, langs, install_dir, destdir, pr shutil.copyfile(infile, outfile) shutil.copystat(infile, outfile) -def run(args): +def run(args: T.List[str]) -> int: options = parser.parse_args(args) langs = options.langs.split('@@') if options.langs else [] media = options.media.split('@@') if options.media else [] @@ -129,3 +130,4 @@ def run(args): merge_translations(build_subdir, abs_sources, langs) install_help(src_subdir, build_subdir, sources, media, langs, install_dir, destdir, options.project_id, options.symlinks) + return 0 -- cgit v1.2.3 From 23818fc5a389c49e2673f79af2c90d9d56b1aaf0 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 1 Sep 2020 14:28:08 +0200 Subject: 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(-) (limited to 'mesonbuild/scripts') 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', -- cgit v1.2.3 From 47373a2438c0fdeedd229b921c9d7e8dc1fc956a Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 1 Sep 2020 19:36:21 +0200 Subject: typing: get rid of most T.cast --- mesonbuild/arglist.py | 2 +- mesonbuild/compilers/compilers.py | 2 +- mesonbuild/coredata.py | 3 ++- mesonbuild/environment.py | 7 +++---- mesonbuild/interpreterbase.py | 5 +++-- mesonbuild/scripts/regen_checker.py | 14 ++++++++------ mesonbuild/scripts/tags.py | 4 +++- 7 files changed, 21 insertions(+), 16 deletions(-) (limited to 'mesonbuild/scripts') diff --git a/mesonbuild/arglist.py b/mesonbuild/arglist.py index b7fa749ee..d88438957 100644 --- a/mesonbuild/arglist.py +++ b/mesonbuild/arglist.py @@ -242,7 +242,7 @@ class CompilerArgs(collections.abc.MutableSequence): new = self.copy() else: new = self - return T.cast(T.List[str], self.compiler.unix_args_to_native(new._container)) + return self.compiler.unix_args_to_native(new._container) def append_direct(self, arg: str) -> None: ''' diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 0de59a4da..c97bcc6ff 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -578,7 +578,7 @@ class Compiler(metaclass=abc.ABCMeta): raise EnvironmentException('Language %s does not support function checks.' % self.get_display_language()) @classmethod - def unix_args_to_native(cls, args): + def unix_args_to_native(cls, args: T.List[str]) -> T.List[str]: "Always returns a copy that can be independently mutated" return args[:] diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 4fc49990c..7e966a56c 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -365,7 +365,7 @@ _V = T.TypeVar('_V') class CoreData: - def __init__(self, options: argparse.Namespace, scratch_dir: str): + def __init__(self, options: argparse.Namespace, scratch_dir: str, meson_command: T.List[str]): self.lang_guids = { 'default': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942', 'c': '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942', @@ -376,6 +376,7 @@ class CoreData: self.test_guid = str(uuid.uuid4()).upper() self.regen_guid = str(uuid.uuid4()).upper() self.install_guid = str(uuid.uuid4()).upper() + self.meson_command = meson_command self.target_guids = {} self.version = version self.builtins = {} # type: OptionDictType diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 5cd60697f..31d0e81b9 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -814,9 +814,8 @@ class Environment: # WARNING: Don't use any values from coredata in __init__. It gets # re-initialized with project options by the interpreter during # build file parsing. - self.coredata = coredata.CoreData(options, self.scratch_dir) - # Used by the regenchecker script, which runs meson - self.coredata.meson_command = mesonlib.meson_command + # meson_command is used by the regenchecker script, which runs meson + self.coredata = coredata.CoreData(options, self.scratch_dir, mesonlib.meson_command) self.first_invocation = True def is_cross_build(self, when_building_for: MachineChoice = MachineChoice.HOST) -> bool: @@ -1038,7 +1037,7 @@ class Environment: :extra_args: Any additional arguments required (such as a source file) """ self.coredata.add_lang_args(comp_class.language, comp_class, for_machine, self) - extra_args = T.cast(T.List[str], extra_args or []) + extra_args = extra_args or [] extra_args += self.coredata.compiler_options[for_machine][comp_class.language]['args'].value if isinstance(comp_class.LINKER_PREFIX, str): diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index f6c955948..1524409de 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -879,6 +879,7 @@ The result of this is undefined and will become a hard error in a future Meson r if not isinstance(index, str): raise InterpreterException('Key is not a string') try: + # The cast is required because we don't have recursive types... return T.cast(TYPE_var, iobject[index]) except KeyError: raise InterpreterException('Key %s is not in dict' % index) @@ -1091,7 +1092,7 @@ The result of this is undefined and will become a hard error in a future Meson r raise InvalidCode('Unknown function "%s".' % func_name) @builtinMethodNoKwargs - def array_method_call(self, obj: list, method_name: str, posargs: T.List[TYPE_nvar], kwargs: T.Dict[str, T.Any]) -> TYPE_var: + def array_method_call(self, obj: T.List[TYPE_var], method_name: str, posargs: T.List[TYPE_nvar], kwargs: T.Dict[str, T.Any]) -> TYPE_var: if method_name == 'contains': def check_contains(el: list) -> bool: if len(posargs) != 1: @@ -1127,7 +1128,7 @@ The result of this is undefined and will become a hard error in a future Meson r if isinstance(fallback, mparser.BaseNode): return self.evaluate_statement(fallback) return fallback - return T.cast(TYPE_var, obj[index]) + return obj[index] m = 'Arrays do not have a method called {!r}.' raise InterpreterException(m.format(method_name)) diff --git a/mesonbuild/scripts/regen_checker.py b/mesonbuild/scripts/regen_checker.py index 84f7d77f6..fa98f5989 100644 --- a/mesonbuild/scripts/regen_checker.py +++ b/mesonbuild/scripts/regen_checker.py @@ -15,13 +15,12 @@ import sys, os import pickle, subprocess import typing as T - -if T.TYPE_CHECKING: - from ..backend.vs2010backend import RegenInfo +from ..coredata import CoreData +from ..backend.vs2010backend import RegenInfo # This could also be used for XCode. -def need_regen(regeninfo: 'RegenInfo', regen_timestamp: float) -> bool: +def need_regen(regeninfo: RegenInfo, regen_timestamp: float) -> bool: for i in regeninfo.depfiles: curfile = os.path.join(regeninfo.build_dir, i) curtime = os.stat(curfile).st_mtime @@ -35,7 +34,7 @@ def need_regen(regeninfo: 'RegenInfo', regen_timestamp: float) -> bool: Vs2010Backend.touch_regen_timestamp(regeninfo.build_dir) return False -def regen(regeninfo: 'RegenInfo', meson_command: T.List[str], backend: str) -> None: +def regen(regeninfo: RegenInfo, meson_command: T.List[str], backend: str) -> None: cmd = meson_command + ['--internal', 'regenerate', regeninfo.build_dir, @@ -48,10 +47,13 @@ def run(args: T.List[str]) -> int: dumpfile = os.path.join(private_dir, 'regeninfo.dump') coredata_file = os.path.join(private_dir, 'coredata.dat') with open(dumpfile, 'rb') as f: - regeninfo = T.cast('RegenInfo', pickle.load(f)) + regeninfo = pickle.load(f) + assert isinstance(regeninfo, RegenInfo) with open(coredata_file, 'rb') as f: coredata = pickle.load(f) + assert isinstance(coredata, CoreData) backend = coredata.get_builtin_option('backend') + assert isinstance(backend, str) regen_timestamp = os.stat(dumpfile).st_mtime if need_regen(regeninfo, regen_timestamp): regen(regeninfo, coredata.meson_command, backend) diff --git a/mesonbuild/scripts/tags.py b/mesonbuild/scripts/tags.py index bb858310d..9098efb39 100644 --- a/mesonbuild/scripts/tags.py +++ b/mesonbuild/scripts/tags.py @@ -48,4 +48,6 @@ def run(args: T.List[str]) -> int: srcdir_name = args[1] os.chdir(srcdir_name) assert tool_name in ['cscope', 'ctags', 'etags'] - return T.cast(int, globals()[tool_name]()) + res = globals()[tool_name]() + assert isinstance(res, int) + return res -- cgit v1.2.3 From e681235e5fe3ee0a40dd6a3f5922c2c4b0cf98b4 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 1 Sep 2020 19:58:10 +0200 Subject: typing: fix code review --- mesonbuild/arglist.py | 8 ++++---- mesonbuild/ast/introspection.py | 2 +- mesonbuild/build.py | 8 ++++---- mesonbuild/dependencies/boost.py | 8 ++++---- mesonbuild/envconfig.py | 10 +++++----- mesonbuild/mesonlib.py | 32 ++++++++++++++++---------------- mesonbuild/mintro.py | 3 ++- mesonbuild/mparser.py | 2 +- mesonbuild/scripts/depfixer.py | 2 +- mesonbuild/wrap/wrap.py | 2 +- run_project_tests.py | 2 +- tools/boost_names.py | 6 +++--- 12 files changed, 43 insertions(+), 42 deletions(-) (limited to 'mesonbuild/scripts') diff --git a/mesonbuild/arglist.py b/mesonbuild/arglist.py index d88438957..d1d489bfd 100644 --- a/mesonbuild/arglist.py +++ b/mesonbuild/arglist.py @@ -164,7 +164,7 @@ class CompilerArgs(collections.abc.MutableSequence): def __getitem__(self, index: slice) -> T.MutableSequence[str]: # noqa: F811 pass - def __getitem__(self, index): # type: ignore # noqa: F811 + def __getitem__(self, index: T.Union[int, slice]) -> T.Union[str, T.MutableSequence[str]]: # noqa: F811 self.flush_pre_post() return self._container[index] @@ -176,9 +176,9 @@ class CompilerArgs(collections.abc.MutableSequence): def __setitem__(self, index: slice, value: T.Iterable[str]) -> None: # noqa: F811 pass - def __setitem__(self, index, value) -> None: # type: ignore # noqa: F811 + def __setitem__(self, index: T.Union[int, slice], value: T.Union[str, T.Iterable[str]]) -> None: # noqa: F811 self.flush_pre_post() - self._container[index] = value + self._container[index] = value # type: ignore # TODO: fix 'Invalid index type' and 'Incompatible types in assignment' erros def __delitem__(self, index: T.Union[int, slice]) -> None: self.flush_pre_post() @@ -314,7 +314,7 @@ class CompilerArgs(collections.abc.MutableSequence): new += self return new - def __eq__(self, other: T.Any) -> T.Union[bool]: + def __eq__(self, other: object) -> T.Union[bool]: self.flush_pre_post() # Only allow equality checks against other CompilerArgs and lists instances if isinstance(other, CompilerArgs): diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 19fedbf6f..d7d982e44 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -296,7 +296,7 @@ class IntrospectionInterpreter(AstInterpreter): return None def is_subproject(self) -> bool: - return str(self.subproject) != '' + return self.subproject != '' def analyze(self) -> None: self.load_root_meson_file() diff --git a/mesonbuild/build.py b/mesonbuild/build.py index bf325b090..369ac7bf6 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -372,22 +372,22 @@ a hard error in the future.'''.format(name)) if not hasattr(self, 'typename'): raise RuntimeError('Target type is not set for target class "{}". This is a bug'.format(type(self).__name__)) - def __lt__(self, other: T.Any) -> T.Union[bool, type(NotImplemented)]: + def __lt__(self, other: object) -> T.Union[bool, type(NotImplemented)]: if not hasattr(other, 'get_id') and not callable(other.get_id): return NotImplemented return self.get_id() < other.get_id() - def __le__(self, other: T.Any) -> T.Union[bool, type(NotImplemented)]: + def __le__(self, other: object) -> T.Union[bool, type(NotImplemented)]: if not hasattr(other, 'get_id') and not callable(other.get_id): return NotImplemented return self.get_id() <= other.get_id() - def __gt__(self, other: T.Any) -> T.Union[bool, type(NotImplemented)]: + def __gt__(self, other: object) -> T.Union[bool, type(NotImplemented)]: if not hasattr(other, 'get_id') and not callable(other.get_id): return NotImplemented return self.get_id() > other.get_id() - def __ge__(self, other: T.Any) -> T.Union[bool, type(NotImplemented)]: + def __ge__(self, other: object) -> T.Union[bool, type(NotImplemented)]: if not hasattr(other, 'get_id') and not callable(other.get_id): return NotImplemented return self.get_id() >= other.get_id() diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 6e9586029..370fa72d1 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -95,7 +95,7 @@ class BoostIncludeDir(): def __repr__(self) -> str: return ''.format(self.version, self.path) - def __lt__(self, other: T.Any) -> bool: + def __lt__(self, other: object) -> bool: if isinstance(other, BoostIncludeDir): return (self.version_int, self.path) < (other.version_int, other.path) return NotImplemented @@ -187,7 +187,7 @@ class BoostLibraryFile(): def __repr__(self) -> str: return ''.format(self.abitag, self.mod_name, self.path) - def __lt__(self, other: T.Any) -> bool: + def __lt__(self, other: object) -> bool: if isinstance(other, BoostLibraryFile): return ( self.mod_name, self.static, self.version_lib, self.arch, @@ -204,7 +204,7 @@ class BoostLibraryFile(): ) return NotImplemented - def __eq__(self, other: T.Any) -> bool: + def __eq__(self, other: object) -> bool: if isinstance(other, BoostLibraryFile): return self.name == other.name return NotImplemented @@ -346,7 +346,7 @@ class BoostDependency(ExternalDependency): self.debug = buildtype.startswith('debug') self.multithreading = kwargs.get('threading', 'multi') == 'multi' - self.boost_root = None # type: Path + self.boost_root = None # type: T.Optional[Path] self.explicit_static = 'static' in kwargs # Extract and validate modules diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py index 127066652..836ec069b 100644 --- a/mesonbuild/envconfig.py +++ b/mesonbuild/envconfig.py @@ -147,7 +147,7 @@ class Properties: return p return mesonlib.listify(p) - def __eq__(self, other: T.Any) -> 'T.Union[bool, NotImplemented]': + def __eq__(self, other: object) -> 'T.Union[bool, NotImplemented]': if isinstance(other, type(self)): return self.properties == other.properties return NotImplemented @@ -172,8 +172,8 @@ class MachineInfo: self.endian = endian self.is_64_bit = cpu_family in CPU_FAMILES_64_BIT # type: bool - def __eq__(self, other: T.Any) -> 'T.Union[bool, NotImplemented]': - if self.__class__ is not other.__class__: + def __eq__(self, other: object) -> 'T.Union[bool, NotImplemented]': + if self.__class__ is not other.__class__ or not isinstance(other, MachineInfo): return NotImplemented return \ self.system == other.system and \ @@ -181,8 +181,8 @@ class MachineInfo: self.cpu == other.cpu and \ self.endian == other.endian - def __ne__(self, other: T.Any) -> 'T.Union[bool, NotImplemented]': - if self.__class__ is not other.__class__: + def __ne__(self, other: object) -> 'T.Union[bool, NotImplemented]': + if self.__class__ is not other.__class__ or not isinstance(other, MachineInfo): return NotImplemented return not self.__eq__(other) diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 769a904cd..6cc3c081a 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -289,7 +289,7 @@ class File: def split(self, s: str) -> T.List[str]: return self.fname.split(s) - def __eq__(self, other: T.Any) -> bool: + def __eq__(self, other: object) -> bool: if not isinstance(other, File): return NotImplemented if self.hash != other.hash: @@ -327,23 +327,23 @@ class OrderedEnum(Enum): """ An Enum which additionally offers homogeneous ordered comparison. """ - def __ge__(self, other: T.Any) -> bool: - if self.__class__ is other.__class__ and isinstance(self.value, int) and isinstance(other.value, int): + def __ge__(self, other: object) -> bool: + if self.__class__ is other.__class__ and isinstance(other, OrderedEnum)and isinstance(self.value, int) and isinstance(other.value, int): return self.value >= other.value return NotImplemented - def __gt__(self, other: T.Any) -> bool: - if self.__class__ is other.__class__ and isinstance(self.value, int) and isinstance(other.value, int): + def __gt__(self, other: object) -> bool: + if self.__class__ is other.__class__ and isinstance(other, OrderedEnum)and isinstance(self.value, int) and isinstance(other.value, int): return self.value > other.value return NotImplemented - def __le__(self, other: T.Any) -> bool: - if self.__class__ is other.__class__ and isinstance(self.value, int) and isinstance(other.value, int): + def __le__(self, other: object) -> bool: + if self.__class__ is other.__class__ and isinstance(other, OrderedEnum)and isinstance(self.value, int) and isinstance(other.value, int): return self.value <= other.value return NotImplemented - def __lt__(self, other: T.Any) -> bool: - if self.__class__ is other.__class__ and isinstance(self.value, int) and isinstance(other.value, int): + def __lt__(self, other: object) -> bool: + if self.__class__ is other.__class__ and isinstance(other, OrderedEnum) and isinstance(self.value, int) and isinstance(other.value, int): return self.value < other.value return NotImplemented @@ -609,32 +609,32 @@ class Version: def __repr__(self) -> str: return ''.format(self._s) - def __lt__(self, other: T.Any) -> bool: + def __lt__(self, other: object) -> bool: if isinstance(other, Version): return self.__cmp(other, operator.lt) return NotImplemented - def __gt__(self, other: T.Any) -> bool: + def __gt__(self, other: object) -> bool: if isinstance(other, Version): return self.__cmp(other, operator.gt) return NotImplemented - def __le__(self, other: T.Any) -> bool: + def __le__(self, other: object) -> bool: if isinstance(other, Version): return self.__cmp(other, operator.le) return NotImplemented - def __ge__(self, other: T.Any) -> bool: + def __ge__(self, other: object) -> bool: if isinstance(other, Version): return self.__cmp(other, operator.ge) return NotImplemented - def __eq__(self, other: T.Any) -> bool: + def __eq__(self, other: object) -> bool: if isinstance(other, Version): return self._v == other._v return NotImplemented - def __ne__(self, other: T.Any) -> bool: + def __ne__(self, other: object) -> bool: if isinstance(other, Version): return self._v != other._v return NotImplemented @@ -1115,7 +1115,7 @@ def unholder(item: T.List[_T]) -> T.List[_T]: ... @T.overload def unholder(item: T.List[T.Union[_T, 'ObjectHolder[_T]']]) -> T.List[_T]: ... -def unholder(item): # type: ignore # TODO for some reason mypy throws the "Function is missing a type annotation" error +def unholder(item): # type: ignore # TODO fix overload (somehow) """Get the held item of an object holder or list of object holders.""" if isinstance(item, list): return [i.held_object if hasattr(i, 'held_object') else i for i in item] diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index 1e400b0d8..66bbe2ab8 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -30,7 +30,8 @@ from .mparser import BaseNode, FunctionNode, ArrayNode, ArgumentNode, StringNode from .interpreter import Interpreter from pathlib import PurePath import typing as T -import os, argparse +import os +import argparse def get_meson_info_file(info_dir: str) -> str: return os.path.join(info_dir, 'meson-info.json') diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index e3868583f..a60109d01 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -97,7 +97,7 @@ class Token(T.Generic[TV_TokenTypes]): self.bytespan = bytespan # type: T.Tuple[int, int] self.value = value # type: TV_TokenTypes - def __eq__(self, other: T.Any) -> bool: + def __eq__(self, other: object) -> bool: if isinstance(other, str): return self.tid == other elif isinstance(other, Token): diff --git a/mesonbuild/scripts/depfixer.py b/mesonbuild/scripts/depfixer.py index 76cf2b50a..18d70cca9 100644 --- a/mesonbuild/scripts/depfixer.py +++ b/mesonbuild/scripts/depfixer.py @@ -328,7 +328,7 @@ class Elf(DataSizes): new_rpath = b':'.join(new_rpaths) if len(old_rpath) < len(new_rpath): - msg = "New rpath must not be longer than the old one.\n Old: {!r}\n New: {!r}".format(old_rpath, new_rpath) + msg = "New rpath must not be longer than the old one.\n Old: {}\n New: {}".format(old_rpath.decode('utf-8'), new_rpath.decode('utf-8')) sys.exit(msg) # The linker does read-only string deduplication. If there is a # string that shares a suffix with the rpath, they might get diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py index eacc1ddd5..68f83c129 100644 --- a/mesonbuild/wrap/wrap.py +++ b/mesonbuild/wrap/wrap.py @@ -107,7 +107,7 @@ class WrapNotFoundException(WrapException): class PackageDefinition: def __init__(self, fname: str): self.filename = fname - self.type = None # type: str + self.type = None # type: T.Optional[str] self.values = {} # type: T.Dict[str, str] self.provided_deps = {} # type: T.Dict[str, T.Optional[str]] self.provided_programs = [] # type: T.List[str] diff --git a/run_project_tests.py b/run_project_tests.py index c84388892..4566de12f 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -216,7 +216,7 @@ class TestDef: return '{} ({})'.format(self.path.as_posix(), self.name) return self.path.as_posix() - def __lt__(self, other: T.Any) -> bool: + def __lt__(self, other: object) -> bool: if isinstance(other, TestDef): # None is not sortable, so replace it with an empty string s_id = int(self.path.name.split(' ')[0]) diff --git a/tools/boost_names.py b/tools/boost_names.py index b66c6cc1e..897b4fd6d 100755 --- a/tools/boost_names.py +++ b/tools/boost_names.py @@ -48,12 +48,12 @@ class BoostLibrary(): self.single = sorted(set(single)) self.multi = sorted(set(multi)) - def __lt__(self, other: T.Any) -> T.Union[bool, 'NotImplemented']: + def __lt__(self, other: object) -> T.Union[bool, 'NotImplemented']: if isinstance(other, BoostLibrary): return self.name < other.name return NotImplemented - def __eq__(self, other: T.Any) -> T.Union[bool, 'NotImplemented']: + def __eq__(self, other: object) -> T.Union[bool, 'NotImplemented']: if isinstance(other, BoostLibrary): return self.name == other.name elif isinstance(other, str): @@ -71,7 +71,7 @@ class BoostModule(): self.desc = desc self.libs = libs - def __lt__(self, other: T.Any) -> T.Union[bool, 'NotImplemented']: + def __lt__(self, other: object) -> T.Union[bool, 'NotImplemented']: if isinstance(other, BoostModule): return self.key < other.key return NotImplemented -- cgit v1.2.3