programs: add type annotations

pull/8563/head
Dylan Baker 4 years ago committed by Xavier Claessens
parent 40e3577a65
commit 97c1283baa
  1. 36
      mesonbuild/programs.py
  2. 1
      run_mypy.py

@ -31,14 +31,17 @@ if T.TYPE_CHECKING:
class ExternalProgram: class ExternalProgram:
"""A program that is found on the system."""
windows_exts = ('exe', 'msc', 'com', 'bat', 'cmd') windows_exts = ('exe', 'msc', 'com', 'bat', 'cmd')
# An 'ExternalProgram' always runs on the build machine
for_machine = MachineChoice.BUILD for_machine = MachineChoice.BUILD
def __init__(self, name: str, command: T.Optional[T.List[str]] = None, def __init__(self, name: str, command: T.Optional[T.List[str]] = None,
silent: bool = False, search_dir: T.Optional[str] = None, silent: bool = False, search_dir: T.Optional[str] = None,
extra_search_dirs: T.Optional[T.List[str]] = None): extra_search_dirs: T.Optional[T.List[str]] = None):
self.name = name self.name = name
self.path = None # type: T.Optional[str]
if command is not None: if command is not None:
self.command = mesonlib.listify(command) self.command = mesonlib.listify(command)
if mesonlib.is_windows(): if mesonlib.is_windows():
@ -61,15 +64,16 @@ class ExternalProgram:
if self.found(): if self.found():
break break
if self.found():
# Set path to be the last item that is actually a file (in order to # Set path to be the last item that is actually a file (in order to
# skip options in something like ['python', '-u', 'file.py']. If we # skip options in something like ['python', '-u', 'file.py']. If we
# can't find any components, default to the last component of the path. # can't find any components, default to the last component of the path.
self.path = self.command[-1] for arg in reversed(self.command):
for i in range(len(self.command) - 1, -1, -1):
arg = self.command[i]
if arg is not None and os.path.isfile(arg): if arg is not None and os.path.isfile(arg):
self.path = arg self.path = arg
break break
else:
self.path = self.command[-1]
if not silent: if not silent:
# ignore the warning because derived classes never call this __init__ # ignore the warning because derived classes never call this __init__
@ -94,7 +98,7 @@ class ExternalProgram:
return ' '.join(self.command) return ' '.join(self.command)
@classmethod @classmethod
def from_bin_list(cls, env: 'Environment', for_machine: MachineChoice, name): def from_bin_list(cls, env: 'Environment', for_machine: MachineChoice, name: str) -> 'ExternalProgram':
# There is a static `for_machine` for this class because the binary # There is a static `for_machine` for this class because the binary
# aways runs on the build platform. (It's host platform is our build # aways runs on the build platform. (It's host platform is our build
# platform.) But some external programs have a target platform, so this # platform.) But some external programs have a target platform, so this
@ -129,20 +133,22 @@ class ExternalProgram:
return os.pathsep.join(paths) return os.pathsep.join(paths)
@staticmethod @staticmethod
def from_entry(name, command): def from_entry(name: str, command: T.Union[str, T.List[str]]) -> 'ExternalProgram':
if isinstance(command, list): if isinstance(command, list):
if len(command) == 1: if len(command) == 1:
command = command[0] command = command[0]
# We cannot do any searching if the command is a list, and we don't # We cannot do any searching if the command is a list, and we don't
# need to search if the path is an absolute path. # need to search if the path is an absolute path.
if isinstance(command, list) or os.path.isabs(command): if isinstance(command, list) or os.path.isabs(command):
if isinstance(command, str):
command = [command]
return ExternalProgram(name, command=command, silent=True) return ExternalProgram(name, command=command, silent=True)
assert isinstance(command, str) assert isinstance(command, str)
# Search for the command using the specified string! # Search for the command using the specified string!
return ExternalProgram(command, silent=True) return ExternalProgram(command, silent=True)
@staticmethod @staticmethod
def _shebang_to_cmd(script: str) -> T.Optional[list]: def _shebang_to_cmd(script: str) -> T.Optional[T.List[str]]:
""" """
Check if the file has a shebang and manually parse it to figure out Check if the file has a shebang and manually parse it to figure out
the interpreter to use. This is useful if the script is not executable the interpreter to use. This is useful if the script is not executable
@ -184,11 +190,11 @@ class ExternalProgram:
commands = mesonlib.python_command + commands[1:] commands = mesonlib.python_command + commands[1:]
return commands + [script] return commands + [script]
except Exception as e: except Exception as e:
mlog.debug(e) mlog.debug(str(e))
mlog.debug(f'Unusable script {script!r}') mlog.debug(f'Unusable script {script!r}')
return None return None
def _is_executable(self, path): def _is_executable(self, path: str) -> bool:
suffix = os.path.splitext(path)[-1].lower()[1:] suffix = os.path.splitext(path)[-1].lower()[1:]
execmask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH execmask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
if mesonlib.is_windows(): if mesonlib.is_windows():
@ -217,7 +223,7 @@ class ExternalProgram:
return [trial_ext] return [trial_ext]
return None return None
def _search_windows_special_cases(self, name: str, command: str) -> list: def _search_windows_special_cases(self, name: str, command: str) -> T.List[T.Optional[str]]:
''' '''
Lots of weird Windows quirks: Lots of weird Windows quirks:
1. PATH search for @name returns files with extensions from PATHEXT, 1. PATH search for @name returns files with extensions from PATHEXT,
@ -260,7 +266,7 @@ class ExternalProgram:
return commands return commands
return [None] return [None]
def _search(self, name: str, search_dir: T.Optional[str]) -> list: def _search(self, name: str, search_dir: T.Optional[str]) -> T.List[T.Optional[str]]:
''' '''
Search in the specified dir for the specified executable by name Search in the specified dir for the specified executable by name
and if not found search in PATH and if not found search in PATH
@ -285,7 +291,7 @@ class ExternalProgram:
def get_command(self) -> T.List[str]: def get_command(self) -> T.List[str]:
return self.command[:] return self.command[:]
def get_path(self) -> str: def get_path(self) -> T.Optional[str]:
return self.path return self.path
def get_name(self) -> str: def get_name(self) -> str:
@ -314,16 +320,16 @@ class EmptyExternalProgram(ExternalProgram): # lgtm [py/missing-call-to-init]
such as a cross file exe_wrapper to represent that it's not required. such as a cross file exe_wrapper to represent that it's not required.
''' '''
def __init__(self): def __init__(self) -> None:
self.name = None self.name = None
self.command = [] self.command = []
self.path = None self.path = None
def __repr__(self): def __repr__(self) -> str:
r = '<{} {!r} -> {!r}>' r = '<{} {!r} -> {!r}>'
return r.format(self.__class__.__name__, self.name, self.command) return r.format(self.__class__.__name__, self.name, self.command)
def found(self): def found(self) -> bool:
return True return True

@ -38,6 +38,7 @@ modules = [
'mesonbuild/msetup.py', 'mesonbuild/msetup.py',
'mesonbuild/mtest.py', 'mesonbuild/mtest.py',
'mesonbuild/optinterpreter.py', 'mesonbuild/optinterpreter.py',
'mesonbuild/programs.py',
'run_mypy.py', 'run_mypy.py',
'run_single_test.py', 'run_single_test.py',

Loading…
Cancel
Save