From 205cf95f99b654d4b133fde571dcba13400d1a7a Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 12 Apr 2019 10:48:14 -0700 Subject: [PATCH] envconfig: Add type annotations --- mesonbuild/envconfig.py | 108 ++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/mesonbuild/envconfig.py b/mesonbuild/envconfig.py index d3b1989d6..f4c371f69 100644 --- a/mesonbuild/envconfig.py +++ b/mesonbuild/envconfig.py @@ -19,6 +19,8 @@ from . import mesonlib from .mesonlib import EnvironmentException, MachineChoice, PerMachine from . import mlog +_T = typing.TypeVar('_T') + # These classes contains all the data pulled from configuration files (native # and cross file currently), and also assists with the reading environment @@ -69,7 +71,7 @@ CPU_FAMILES_64_BIT = [ class MesonConfigFile: @classmethod - def from_config_parser(cls, parser: configparser.ConfigParser): + def from_config_parser(cls, parser: configparser.ConfigParser) -> typing.Dict[str, typing.Dict[str, typing.Dict[str, str]]]: out = {} # This is a bit hackish at the moment. for s in parser.sections(): @@ -106,55 +108,58 @@ class HasEnvVarFallback: that we deal with environment variables will become more structured, and this can be starting point. """ - def __init__(self, fallback = True): + def __init__(self, fallback: bool = True): self.fallback = fallback class Properties(HasEnvVarFallback): def __init__( self, properties: typing.Optional[typing.Dict[str, typing.Union[str, typing.List[str]]]] = None, - fallback = True): + fallback: bool = True): super().__init__(fallback) - self.properties = properties or {} + self.properties = properties or {} # type: typing.Dict[str, typing.Union[str, typing.List[str]]] - def has_stdlib(self, language): + def has_stdlib(self, language: str) -> bool: return language + '_stdlib' in self.properties - def get_stdlib(self, language): + # Some of get_stdlib, get_root, get_sys_root are wider than is actually + # true, but without heterogenious dict annotations it's not practical to + # narrow them + def get_stdlib(self, language: str) -> typing.Union[str, typing.List[str]]: return self.properties[language + '_stdlib'] - def get_root(self): + def get_root(self) -> typing.Optional[typing.Union[str, typing.List[str]]]: return self.properties.get('root', None) - def get_sys_root(self): + def get_sys_root(self) -> typing.Optional[typing.Union[str, typing.List[str]]]: return self.properties.get('sys_root', None) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> typing.Union[bool, 'NotImplemented']: if isinstance(other, type(self)): return self.properties == other.properties return NotImplemented # TODO consider removing so Properties is less freeform - def __getitem__(self, key): + def __getitem__(self, key: str) -> typing.Any: return self.properties[key] # TODO consider removing so Properties is less freeform - def __contains__(self, item): + def __contains__(self, item: typing.Any) -> bool: return item in self.properties # TODO consider removing, for same reasons as above - def get(self, key, default=None): + def get(self, key: str, default: typing.Any = None) -> typing.Any: return self.properties.get(key, default) class MachineInfo: - def __init__(self, system, cpu_family, cpu, endian): + def __init__(self, system: str, cpu_family: str, cpu: str, endian: str): self.system = system self.cpu_family = cpu_family self.cpu = cpu self.endian = endian - self.is_64_bit = cpu_family in CPU_FAMILES_64_BIT + self.is_64_bit = cpu_family in CPU_FAMILES_64_BIT # type: bool - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> typing.Union[bool, 'NotImplemented']: if self.__class__ is not other.__class__: return NotImplemented return \ @@ -163,16 +168,16 @@ class MachineInfo: self.cpu == other.cpu and \ self.endian == other.endian - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> typing.Union[bool, 'NotImplemented']: if self.__class__ is not other.__class__: return NotImplemented return not self.__eq__(other) - def __repr__(self): + def __repr__(self) -> str: return ''.format(self.system, self.cpu_family, self.cpu) - @staticmethod - def from_literal(literal): + @classmethod + def from_literal(cls, literal: typing.Dict[str, str]) -> 'MachineInfo': minimum_literal = {'cpu', 'cpu_family', 'endian', 'system'} if set(literal) < minimum_literal: raise EnvironmentException( @@ -187,49 +192,45 @@ class MachineInfo: if endian not in ('little', 'big'): mlog.warning('Unknown endian %s' % endian) - return MachineInfo( - literal['system'], - cpu_family, - literal['cpu'], - endian) + return cls(literal['system'], cpu_family, literal['cpu'], endian) - def is_windows(self): + def is_windows(self) -> bool: """ Machine is windows? """ return self.system == 'windows' - def is_cygwin(self): + def is_cygwin(self) -> bool: """ Machine is cygwin? """ return self.system == 'cygwin' - def is_linux(self): + def is_linux(self) -> bool: """ Machine is linux? """ return self.system == 'linux' - def is_darwin(self): + def is_darwin(self) -> bool: """ Machine is Darwin (iOS/OS X)? """ return self.system in ('darwin', 'ios') - def is_android(self): + def is_android(self) -> bool: """ Machine is Android? """ return self.system == 'android' - def is_haiku(self): + def is_haiku(self) -> bool: """ Machine is Haiku? """ return self.system == 'haiku' - def is_openbsd(self): + def is_openbsd(self) -> bool: """ Machine is OpenBSD? """ @@ -239,29 +240,28 @@ class MachineInfo: # static libraries, and executables. # Versioning is added to these names in the backends as-needed. - def get_exe_suffix(self): + def get_exe_suffix(self) -> str: if self.is_windows() or self.is_cygwin(): return 'exe' else: return '' - def get_object_suffix(self): + def get_object_suffix(self) -> str: if self.is_windows(): return 'obj' else: return 'o' - def libdir_layout_is_win(self): - return self.is_windows() \ - or self.is_cygwin() + def libdir_layout_is_win(self) -> bool: + return self.is_windows() or self.is_cygwin() -class PerMachineDefaultable(PerMachine): +class PerMachineDefaultable(PerMachine[_T]): """Extends `PerMachine` with the ability to default from `None`s. """ - def __init__(self): + def __init__(self) -> None: super().__init__(None, None, None) - def default_missing(self): + def default_missing(self) -> None: """Default host to buid and target to host. This allows just specifying nothing in the native case, just host in the @@ -273,7 +273,7 @@ class PerMachineDefaultable(PerMachine): if self.target is None: self.target = self.host - def miss_defaulting(self): + def miss_defaulting(self) -> None: """Unset definition duplicated from their previous to None This is the inverse of ''default_missing''. By removing defaulted @@ -285,18 +285,17 @@ class PerMachineDefaultable(PerMachine): if self.host == self.build: self.host = None -class MachineInfos(PerMachineDefaultable): - def matches_build_machine(self, machine: MachineChoice): +class MachineInfos(PerMachineDefaultable[typing.Optional[MachineInfo]]): + def matches_build_machine(self, machine: MachineChoice) -> bool: return self.build == self[machine] class BinaryTable(HasEnvVarFallback): def __init__( self, binaries: typing.Optional[typing.Dict[str, typing.Union[str, typing.List[str]]]] = None, - - fallback = True): + fallback: bool = True): super().__init__(fallback) - self.binaries = binaries or {} + self.binaries = binaries or {} # type: typing.Dict[str, typing.Union[str, typing.List[str]]] for name, command in self.binaries.items(): if not isinstance(command, (list, str)): # TODO generalize message @@ -325,10 +324,10 @@ class BinaryTable(HasEnvVarFallback): 'cmake': 'CMAKE', 'qmake': 'QMAKE', 'pkgconfig': 'PKG_CONFIG', - } + } # type: typing.Dict[str, str] @staticmethod - def detect_ccache(): + def detect_ccache() -> typing.List[str]: try: subprocess.check_call(['ccache', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) except (OSError, subprocess.CalledProcessError): @@ -336,14 +335,14 @@ class BinaryTable(HasEnvVarFallback): return ['ccache'] @classmethod - def _warn_about_lang_pointing_to_cross(cls, compiler_exe, evar): + def _warn_about_lang_pointing_to_cross(cls, compiler_exe: str, evar: str) -> None: evar_str = os.environ.get(evar, 'WHO_WOULD_CALL_THEIR_COMPILER_WITH_THIS_NAME') if evar_str == compiler_exe: mlog.warning('''Env var %s seems to point to the cross compiler. This is probably wrong, it should always point to the native compiler.''' % evar) @classmethod - def parse_entry(cls, entry): + def parse_entry(cls, entry: typing.Union[str, typing.List[str]]) -> typing.Tuple[typing.List[str], typing.List[str]]: compiler = mesonlib.stringlistify(entry) # Ensure ccache exists and remove it if it doesn't if compiler[0] == 'ccache': @@ -354,8 +353,8 @@ This is probably wrong, it should always point to the native compiler.''' % evar # Return value has to be a list of compiler 'choices' return compiler, ccache - def lookup_entry(self, name): - """Lookup binary + def lookup_entry(self, name: str) -> typing.Optional[typing.List[str]]: + """Lookup binaryk Returns command with args as list if found, Returns `None` if nothing is found. @@ -404,11 +403,12 @@ class Directories: self.sharedstatedir = sharedstatedir self.sysconfdir = sysconfdir - def __contains__(self, key: str) -> str: + def __contains__(self, key: str) -> bool: return hasattr(self, key) - def __getitem__(self, key: str) -> str: - return getattr(self, key) + def __getitem__(self, key: str) -> typing.Optional[str]: + # Mypy can't figure out what to do with getattr here, so we'll case for it + return typing.cast(typing.Optional[str], getattr(self, key)) def __setitem__(self, key: str, value: typing.Optional[str]) -> None: setattr(self, key, value)