first pass at migrating to dataclasses

In some cases, init variables that accept None as a sentinel and
immediately overwrite with [], are migrated to dataclass field
factories. \o/

Note: dataclasses by default cannot provide eq methods, as they then
become unhashable. In the future we may wish to opt into declaring them
frozen, instead/additionally.
pull/9510/head
Eli Schwartz 3 years ago
parent 98a41ec24e
commit 4b351aef26
No known key found for this signature in database
GPG Key ID: CEB167EFB5722BD6
  1. 207
      mesonbuild/backend/backends.py
  2. 229
      mesonbuild/build.py
  3. 27
      mesonbuild/envconfig.py
  4. 8
      mesonbuild/interpreterbase/decorators.py
  5. 35
      mesonbuild/mparser.py
  6. 19
      mesonbuild/msubprojects.py
  7. 15
      mesonbuild/wrap/wrap.py

@ -13,6 +13,7 @@
# limitations under the License.
from collections import OrderedDict
from dataclasses import dataclass, InitVar
from functools import lru_cache
from itertools import chain
from pathlib import Path
@ -61,11 +62,11 @@ if T.TYPE_CHECKING:
# Assembly files cannot be unitified and neither can LLVM IR files
LANGS_CANT_UNITY = ('d', 'fortran', 'vala')
@dataclass(eq=False)
class RegenInfo:
def __init__(self, source_dir: str, build_dir: str, depfiles: T.List[str]):
self.source_dir = source_dir
self.build_dir = build_dir
self.depfiles = depfiles
source_dir: str
build_dir: str
depfiles: T.List[str]
class TestProtocol(enum.Enum):
@ -97,28 +98,30 @@ class TestProtocol(enum.Enum):
return 'tap'
@dataclass(eq=False)
class CleanTrees:
'''
Directories outputted by custom targets that have to be manually cleaned
because on Linux `ninja clean` only deletes empty directories.
'''
def __init__(self, build_dir: str, trees: T.List[str]):
self.build_dir = build_dir
self.trees = trees
build_dir: str
trees: T.List[str]
@dataclass(eq=False)
class InstallData:
def __init__(self, source_dir: str, build_dir: str, prefix: str, libdir: str,
strip_bin: T.List[str], install_umask: T.Union[str, int],
mesonintrospect: T.List[str], version: str,
is_cross_build: bool):
# TODO: in python 3.8 or with typing_Extensions install_umask could be:
# `T.Union[T.Literal['preserve'], int]`, which would be more accurate.
self.source_dir = source_dir
self.build_dir = build_dir
self.prefix = prefix
self.libdir = libdir
self.strip_bin = strip_bin
self.install_umask = install_umask
source_dir: str
build_dir: str
prefix: str
libdir: str
strip_bin: T.List[str]
# TODO: in python 3.8 or with typing_Extensions this could be:
# `T.Union[T.Literal['preserve'], int]`, which would be more accurate.
install_umask: T.Union[str, int]
mesonintrospect: T.List[str]
version: str
is_cross_build: bool
def __post_init__(self) -> None:
self.targets: T.List[TargetInstallData] = []
self.headers: T.List[InstallDataBase] = []
self.man: T.List[InstallDataBase] = []
@ -127,59 +130,52 @@ class InstallData:
self.symlinks: T.List[InstallSymlinkData] = []
self.install_scripts: T.List[ExecutableSerialisation] = []
self.install_subdirs: T.List[SubdirInstallData] = []
self.mesonintrospect = mesonintrospect
self.version = version
self.is_cross_build = is_cross_build
@dataclass(eq=False)
class TargetInstallData:
fname: str
outdir: str
outdir_name: InitVar[str]
aliases: T.Dict[str, str]
strip: bool
install_name_mappings: T.Mapping[str, str]
rpath_dirs_to_remove: T.Set[bytes]
install_rpath: str
# TODO: install_mode should just always be a FileMode object
install_mode: T.Optional['FileMode']
subproject: str
optional: bool = False
tag: T.Optional[str] = None
def __init__(self, fname: str, outdir: str, outdir_name: str, aliases: T.Dict[str, str],
strip: bool, install_name_mappings: T.Mapping[str, str], rpath_dirs_to_remove: T.Set[bytes],
install_rpath: str, install_mode: T.Optional['FileMode'],
subproject: str, optional: bool = False, tag: T.Optional[str] = None):
self.fname = fname
self.outdir = outdir
self.out_name = os.path.join(outdir_name, os.path.basename(fname))
self.aliases = aliases
self.strip = strip
self.install_name_mappings = install_name_mappings
self.rpath_dirs_to_remove = rpath_dirs_to_remove
self.install_rpath = install_rpath
self.install_mode = install_mode
self.subproject = subproject
self.optional = optional
self.tag = tag
def __post_init__(self, outdir_name: str) -> None:
self.out_name = os.path.join(outdir_name, os.path.basename(self.fname))
@dataclass(eq=False)
class InstallEmptyDir:
def __init__(self, path: str, install_mode: 'FileMode', subproject: str, tag: T.Optional[str] = None):
self.path = path
self.install_mode = install_mode
self.subproject = subproject
self.tag = tag
path: str
install_mode: 'FileMode'
subproject: str
tag: T.Optional[str] = None
@dataclass(eq=False)
class InstallDataBase:
def __init__(self, path: str, install_path: str, install_path_name: str,
install_mode: 'FileMode', subproject: str, tag: T.Optional[str] = None,
data_type: T.Optional[str] = None):
self.path = path
self.install_path = install_path
self.install_path_name = install_path_name
self.install_mode = install_mode
self.subproject = subproject
self.tag = tag
self.data_type = data_type
path: str
install_path: str
install_path_name: str
install_mode: 'FileMode'
subproject: str
tag: T.Optional[str] = None
data_type: T.Optional[str] = None
@dataclass(eq=False)
class InstallSymlinkData:
def __init__(self, target: str, name: str, install_path: str,
subproject: str, tag: T.Optional[str] = None):
self.target = target
self.name = name
self.install_path = install_path
self.subproject = subproject
self.tag = tag
target: str
name: str
install_path: str
subproject: str
tag: T.Optional[str] = None
# cannot use dataclass here because "exclude" is out of order
class SubdirInstallData(InstallDataBase):
def __init__(self, path: str, install_path: str, install_path_name: str,
install_mode: 'FileMode', exclude: T.Tuple[T.Set[str], T.Set[str]],
@ -187,64 +183,53 @@ class SubdirInstallData(InstallDataBase):
super().__init__(path, install_path, install_path_name, install_mode, subproject, tag, data_type)
self.exclude = exclude
@dataclass(eq=False)
class ExecutableSerialisation:
# XXX: should capture and feed default to False, instead of None?
def __init__(self, cmd_args: T.List[str],
env: T.Optional[build.EnvironmentVariables] = None,
exe_wrapper: T.Optional['programs.ExternalProgram'] = None,
workdir: T.Optional[str] = None,
extra_paths: T.Optional[T.List] = None,
capture: T.Optional[bool] = None,
feed: T.Optional[bool] = None,
tag: T.Optional[str] = None,
verbose: bool = False,
) -> None:
self.cmd_args = cmd_args
self.env = env
if exe_wrapper is not None:
assert isinstance(exe_wrapper, programs.ExternalProgram)
self.exe_wrapper = exe_wrapper
self.workdir = workdir
self.extra_paths = extra_paths
self.capture = capture
self.feed = feed
cmd_args: T.List[str]
env: T.Optional[build.EnvironmentVariables] = None
exe_wrapper: T.Optional['programs.ExternalProgram'] = None
workdir: T.Optional[str] = None
extra_paths: T.Optional[T.List] = None
capture: T.Optional[bool] = None
feed: T.Optional[bool] = None
tag: T.Optional[str] = None
verbose: bool = False
def __post_init__(self) -> None:
if self.exe_wrapper is not None:
assert isinstance(self.exe_wrapper, programs.ExternalProgram)
self.pickled = False
self.skip_if_destdir = False
self.verbose = verbose
self.subproject = ''
self.tag = tag
@dataclass(eq=False)
class TestSerialisation:
def __init__(self, name: str, project_name: str, suite: T.List[str], fname: T.List[str],
is_cross_built: bool, exe_wrapper: T.Optional[programs.ExternalProgram],
needs_exe_wrapper: bool, is_parallel: bool, cmd_args: T.List[str],
env: build.EnvironmentVariables, should_fail: bool,
timeout: T.Optional[int], workdir: T.Optional[str],
extra_paths: T.List[str], protocol: TestProtocol, priority: int,
cmd_is_built: bool, depends: T.List[str], version: str):
self.name = name
self.project_name = project_name
self.suite = suite
self.fname = fname
self.is_cross_built = is_cross_built
if exe_wrapper is not None:
assert isinstance(exe_wrapper, programs.ExternalProgram)
self.exe_wrapper = exe_wrapper
self.is_parallel = is_parallel
self.cmd_args = cmd_args
self.env = env
self.should_fail = should_fail
self.timeout = timeout
self.workdir = workdir
self.extra_paths = extra_paths
self.protocol = protocol
self.priority = priority
self.needs_exe_wrapper = needs_exe_wrapper
self.cmd_is_built = cmd_is_built
self.depends = depends
self.version = version
name: str
project_name: str
suite: T.List[str]
fname: T.List[str]
is_cross_built: bool
exe_wrapper: T.Optional[programs.ExternalProgram]
needs_exe_wrapper: bool
is_parallel: bool
cmd_args: T.List[str]
env: build.EnvironmentVariables
should_fail: bool
timeout: T.Optional[int]
workdir: T.Optional[str]
extra_paths: T.List[str]
protocol: TestProtocol
priority: int
cmd_is_built: bool
depends: T.List[str]
version: str
def __post_init__(self) -> None:
if self.exe_wrapper is not None:
assert isinstance(self.exe_wrapper, programs.ExternalProgram)
def get_backend_from_name(backend: str, build: T.Optional[build.Build] = None, interpreter: T.Optional['Interpreter'] = None) -> T.Optional['Backend']:

@ -13,6 +13,7 @@
# limitations under the License.
from collections import OrderedDict
from dataclasses import dataclass, field
from functools import lru_cache
import copy
import hashlib
@ -130,22 +131,19 @@ def get_target_macos_dylib_install_name(ld) -> str:
class InvalidArguments(MesonException):
pass
@dataclass(eq=False)
class DependencyOverride(HoldableObject):
def __init__(self, dep: dependencies.Dependency, node: 'BaseNode', explicit: bool = True):
self.dep = dep
self.node = node
self.explicit = explicit
dep: dependencies.Dependency
node: 'BaseNode'
explicit: bool = True
@dataclass(eq=False)
class Headers(HoldableObject):
def __init__(self, sources: T.List[File], install_subdir: T.Optional[str],
custom_install_dir: T.Optional[str], custom_install_mode: 'FileMode',
subproject: str):
self.sources = sources
self.install_subdir = install_subdir
self.custom_install_dir = custom_install_dir
self.custom_install_mode = custom_install_mode
self.subproject = subproject
sources: T.List[File]
install_subdir: T.Optional[str]
custom_install_dir: T.Optional[str]
custom_install_mode: 'FileMode'
subproject: str
# TODO: we really don't need any of these methods, but they're preserved to
# keep APIs relying on them working.
@ -166,16 +164,13 @@ class Headers(HoldableObject):
return self.custom_install_mode
@dataclass(eq=False)
class Man(HoldableObject):
def __init__(self, sources: T.List[File], custom_install_dir: T.Optional[str],
custom_install_mode: 'FileMode', subproject: str,
locale: T.Optional[str]):
self.sources = sources
self.custom_install_dir = custom_install_dir
self.custom_install_mode = custom_install_mode
self.subproject = subproject
self.locale = locale
sources: T.List[File]
custom_install_dir: T.Optional[str]
custom_install_mode: 'FileMode'
subproject: str
locale: T.Optional[str]
def get_custom_install_dir(self) -> T.Optional[str]:
return self.custom_install_dir
@ -187,40 +182,30 @@ class Man(HoldableObject):
return self.sources
@dataclass(eq=False)
class EmptyDir(HoldableObject):
def __init__(self, path: str, install_mode: 'FileMode', subproject: str,
install_tag: T.Optional[str] = None):
self.path = path
self.install_mode = install_mode
self.subproject = subproject
self.install_tag = install_tag
path: str
install_mode: 'FileMode'
subproject: str
install_tag: T.Optional[str] = None
@dataclass(eq=False)
class InstallDir(HoldableObject):
source_subdir: str
installable_subdir: str
install_dir: str
install_mode: 'FileMode'
exclude: T.Tuple[T.Set[str], T.Set[str]]
strip_directory: bool
subproject: str
from_source_dir: bool = True
install_tag: T.Optional[str] = None
def __init__(self, source_subdir: str, installable_subdir: str, install_dir: str,
install_mode: 'FileMode',
exclude: T.Tuple[T.Set[str], T.Set[str]],
strip_directory: bool, subproject: str,
from_source_dir: bool = True,
install_tag: T.Optional[str] = None):
self.source_subdir = source_subdir
self.installable_subdir = installable_subdir
self.install_dir = install_dir
self.install_mode = install_mode
self.exclude = exclude
self.strip_directory = strip_directory
self.from_source_dir = from_source_dir
self.subproject = subproject
self.install_tag = install_tag
@dataclass(eq=False)
class DepManifest:
def __init__(self, version: str, license: T.List[str]):
self.version = version
self.license = license
version: str
license: T.List[str]
def to_json(self) -> T.Dict[str, T.Union[str, T.List[str]]]:
return {
@ -229,6 +214,7 @@ class DepManifest:
}
# literally everything isn't dataclass stuff
class Build:
"""A class that holds the status of one build including
all dependencies and so on.
@ -363,18 +349,17 @@ class Build:
return link_args.get(compiler.get_language(), [])
@dataclass(eq=False)
class IncludeDirs(HoldableObject):
"""Internal representation of an include_directories call."""
def __init__(self, curdir: str, incdirs: T.List[str], is_system: bool, extra_build_dirs: T.Optional[T.List[str]] = None):
self.curdir = curdir
self.incdirs = incdirs
self.is_system = is_system
# Interpreter has validated that all given directories
# actually exist.
self.extra_build_dirs: T.List[str] = extra_build_dirs or []
curdir: str
incdirs: T.List[str]
is_system: bool
# Interpreter has validated that all given directories
# actually exist.
extra_build_dirs: T.List[str] = field(default_factory=list)
def __repr__(self) -> str:
r = '<{} {}/{}>'
@ -404,21 +389,18 @@ class IncludeDirs(HoldableObject):
strlist.append(os.path.join(builddir, self.curdir, idir))
return strlist
@dataclass(eq=False)
class ExtractedObjects(HoldableObject):
'''
Holds a list of sources for which the objects must be extracted
'''
def __init__(self, target: 'BuildTarget',
srclist: T.Optional[T.List[File]] = None,
genlist: T.Optional[T.List['GeneratedTypes']] = None,
objlist: T.Optional[T.List[T.Union[str, 'File', 'ExtractedObjects']]] = None,
recursive: bool = True):
self.target = target
self.recursive = recursive
self.srclist: T.List[File] = srclist if srclist is not None else []
self.genlist: T.List['GeneratedTypes'] = genlist if genlist is not None else []
self.objlist: T.Optional[T.List[T.Union[str, 'File', 'ExtractedObjects']]] = \
objlist if objlist is not None else []
target: 'BuildTarget'
srclist: T.List[File] = field(default_factory=list)
genlist: T.List['GeneratedTypes'] = field(default_factory=list)
objlist: T.List[T.Union[str, 'File', 'ExtractedObjects']] = field(default_factory=list)
recursive: bool = True
def __post_init__(self) -> None:
if self.target.is_unity:
self.check_unity_compatible()
@ -523,23 +505,25 @@ class EnvironmentVariables(HoldableObject):
env[name] = method(env, name, values, separator)
return env
@dataclass(eq=False)
class Target(HoldableObject):
# TODO: should Target be an abc.ABCMeta?
def __init__(self, name: str, subdir: str, subproject: str, build_by_default: bool, for_machine: MachineChoice):
if has_path_sep(name):
name: str
subdir: str
subproject: str
build_by_default: bool
for_machine: MachineChoice
def __post_init__(self) -> None:
if has_path_sep(self.name):
# Fix failing test 53 when this becomes an error.
mlog.warning(textwrap.dedent(f'''\
Target "{name}" has a path separator in its name.
Target "{self.name}" has a path separator in its name.
This is not supported, it can cause unexpected failures and will become
a hard error in the future.\
'''))
self.name = name
self.subdir = subdir
self.subproject = subproject
self.build_by_default = build_by_default
self.for_machine = for_machine
self.install = False
self.build_always_stale = False
self.option_overrides_base: T.Dict[OptionKey, str] = {}
@ -548,6 +532,7 @@ class Target(HoldableObject):
if not hasattr(self, 'typename'):
raise RuntimeError(f'Target type is not set for target class "{type(self).__name__}". This is a bug')
# dataclass comparators?
def __lt__(self, other: object) -> bool:
if not isinstance(other, Target):
return NotImplemented
@ -1619,6 +1604,7 @@ class Generator(HoldableObject):
def __init__(self, exe: T.Union['Executable', programs.ExternalProgram],
arguments: T.List[str],
output: T.List[str],
# how2dataclass
*,
depfile: T.Optional[str] = None,
capture: bool = False,
@ -1691,24 +1677,27 @@ class Generator(HoldableObject):
return output
@dataclass(eq=False)
class GeneratedList(HoldableObject):
"""The output of generator.process."""
def __init__(self, generator: Generator, subdir: str,
preserve_path_from: T.Optional[str],
extra_args: T.List[str]):
self.generator = generator
self.name = generator.exe
generator: Generator
subdir: str
preserve_path_from: T.Optional[str]
extra_args: T.List[str]
def __post_init__(self) -> None:
self.name = self.generator.exe
self.depends: T.Set['CustomTarget'] = set() # Things this target depends on (because e.g. a custom target was used as input)
self.subdir = subdir
self.infilelist: T.List['File'] = []
self.outfilelist: T.List[str] = []
self.outmap: T.Dict[File, T.List[str]] = {}
self.extra_depends = [] # XXX: Doesn't seem to be used?
self.depend_files: T.List[File] = []
self.preserve_path_from = preserve_path_from
self.extra_args: T.List[str] = extra_args if extra_args is not None else []
if self.extra_args is None:
self.extra_args: T.List[str] = []
if isinstance(self.generator.exe, programs.ExternalProgram):
if not self.generator.exe.found():
@ -2712,6 +2701,7 @@ class Jar(BuildTarget):
return ['-cp', os.pathsep.join(cp_paths)]
return []
@dataclass(eq=False)
class CustomTargetIndex(HoldableObject):
"""A special opaque object returned by indexing a CustomTarget. This object
@ -2720,11 +2710,12 @@ class CustomTargetIndex(HoldableObject):
the sources.
"""
def __init__(self, target: CustomTarget, output: str):
target: CustomTarget
output: str
def __post_init__(self) -> None:
self.typename = 'custom'
self.target = target
self.output = output
self.for_machine = target.for_machine
self.for_machine = self.target.for_machine
@property
def name(self) -> str:
@ -2800,45 +2791,41 @@ class ConfigurationData(HoldableObject):
# A bit poorly named, but this represents plain data files to copy
# during install.
@dataclass(eq=False)
class Data(HoldableObject):
def __init__(self, sources: T.List[File], install_dir: str, install_dir_name: str,
install_mode: 'FileMode', subproject: str,
rename: T.List[str] = None,
install_tag: T.Optional[str] = None,
data_type: str = None):
self.sources = sources
self.install_dir = install_dir
self.install_dir_name = install_dir_name
self.install_mode = install_mode
self.install_tag = install_tag
if rename is None:
sources: T.List[File]
install_dir: str
install_dir_name: str
install_mode: 'FileMode'
subproject: str
rename: T.List[str] = None
install_tag: T.Optional[str] = None
data_type: str = None
def __post_init__(self) -> None:
if self.rename is None:
self.rename = [os.path.basename(f.fname) for f in self.sources]
else:
self.rename = rename
self.subproject = subproject
self.data_type = data_type
@dataclass(eq=False)
class SymlinkData(HoldableObject):
def __init__(self, target: str, name: str, install_dir: str,
subproject: str, install_tag: T.Optional[str] = None):
self.target = target
if name != os.path.basename(name):
raise InvalidArguments(f'Link name is "{name}", but link names cannot contain path separators. '
target: str
name: str
install_dir: str
subproject: str
install_tag: T.Optional[str] = None
def __post_init__(self) -> None:
if self.name != os.path.basename(self.name):
raise InvalidArguments(f'Link name is "{self.name}", but link names cannot contain path separators. '
'The dir part should be in install_dir.')
self.name = name
self.install_dir = install_dir
self.subproject = subproject
self.install_tag = install_tag
@dataclass(eq=False)
class TestSetup:
def __init__(self, exe_wrapper: T.List[str], gdb: bool,
timeout_multiplier: int, env: EnvironmentVariables,
exclude_suites: T.List[str]):
self.exe_wrapper = exe_wrapper
self.gdb = gdb
self.timeout_multiplier = timeout_multiplier
self.env = env
self.exclude_suites = exclude_suites
exe_wrapper: T.List[str]
gdb: bool
timeout_multiplier: int
env: EnvironmentVariables
exclude_suites: T.List[str]
def get_sources_string_names(sources, backend):
'''

@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from dataclasses import dataclass
import subprocess
import typing as T
from enum import Enum
@ -234,27 +235,15 @@ class Properties:
def get(self, key: str, default: T.Optional[T.Union[str, bool, int, T.List[str]]] = None) -> T.Optional[T.Union[str, bool, int, T.List[str]]]:
return self.properties.get(key, default)
@dataclass(unsafe_hash=True)
class MachineInfo(HoldableObject):
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_FAMILIES_64_BIT # type: bool
system: str
cpu_family: str
cpu: str
endian: str
def __eq__(self, other: object) -> bool:
if not isinstance(other, MachineInfo):
return NotImplemented
return \
self.system == other.system and \
self.cpu_family == other.cpu_family and \
self.cpu == other.cpu and \
self.endian == other.endian
def __ne__(self, other: object) -> bool:
if not isinstance(other, MachineInfo):
return NotImplemented
return not self.__eq__(other)
def __post_init__(self) -> None:
self.is_64_bit: bool = self.cpu_family in CPU_FAMILIES_64_BIT
def __repr__(self) -> str:
return f'<MachineInfo: {self.system} {self.cpu_family} ({self.cpu})>'

@ -19,6 +19,7 @@ from .exceptions import InterpreterException, InvalidArguments
from .operator import MesonOperator
from ._unholder import _unholder
from dataclasses import dataclass
from functools import wraps
import abc
import itertools
@ -99,10 +100,9 @@ def disablerIfNotFound(f: TV_func) -> TV_func:
return ret
return T.cast(TV_func, wrapped)
@dataclass(repr=False, eq=False)
class permittedKwargs:
def __init__(self, permitted: T.Set[str]):
self.permitted = permitted # type: T.Set[str]
permitted: T.Set[str]
def __call__(self, f: TV_func) -> TV_func:
@wraps(f)
@ -575,6 +575,7 @@ def typed_kwargs(name: str, *types: KwargInfo) -> T.Callable[..., T.Any]:
return inner
# This cannot be a dataclass due to https://github.com/python/mypy/issues/5374
class FeatureCheckBase(metaclass=abc.ABCMeta):
"Base class for feature version checks"
@ -738,6 +739,7 @@ class FeatureDeprecated(FeatureCheckBase):
mlog.warning(*args, location=self.location)
# This cannot be a dataclass due to https://github.com/python/mypy/issues/5374
class FeatureCheckKwargsBase(metaclass=abc.ABCMeta):
@property

@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from dataclasses import dataclass
import re
import codecs
import textwrap
@ -87,15 +88,15 @@ class BlockParseException(MesonException):
TV_TokenTypes = T.TypeVar('TV_TokenTypes', int, str, bool)
@dataclass(eq=False)
class Token(T.Generic[TV_TokenTypes]):
def __init__(self, tid: str, filename: str, line_start: int, lineno: int, colno: int, bytespan: T.Tuple[int, int], value: TV_TokenTypes):
self.tid = tid # type: str
self.filename = filename # type: str
self.line_start = line_start # type: int
self.lineno = lineno # type: int
self.colno = colno # type: int
self.bytespan = bytespan # type: T.Tuple[int, int]
self.value = value # type: TV_TokenTypes
tid: str
filename: str
line_start: int
lineno: int
colno: int
bytespan: T.Tuple[int, int]
value: TV_TokenTypes
def __eq__(self, other: object) -> bool:
if isinstance(other, str):
@ -237,13 +238,19 @@ class Lexer:
if not matched:
raise ParseException('lexer', self.getline(line_start), lineno, col)
@dataclass(eq=False)
class BaseNode:
def __init__(self, lineno: int, colno: int, filename: str, end_lineno: T.Optional[int] = None, end_colno: T.Optional[int] = None):
self.lineno = lineno # type: int
self.colno = colno # type: int
self.filename = filename # type: str
self.end_lineno = end_lineno if end_lineno is not None else self.lineno
self.end_colno = end_colno if end_colno is not None else self.colno
lineno: int
colno: int
filename: str
end_lineno: T.Optional[int] = None
end_colno: T.Optional[int] = None
def __post_init__(self) -> None:
if self.end_lineno is None:
self.end_lineno = self.lineno
if self.end_colno is None:
self.end_colno = self.colno
# Attributes for the visitors
self.level = 0 # type: int

@ -1,3 +1,4 @@
from dataclasses import dataclass, InitVar
import os, subprocess
import argparse
import asyncio
@ -94,18 +95,22 @@ class Logger:
self.print_progress()
@dataclass(eq=False)
class Runner:
def __init__(self, logger: Logger, r: Resolver, wrap: PackageDefinition, repo_dir: str, options: 'Arguments') -> None:
logger: Logger
r: InitVar[Resolver]
wrap: PackageDefinition
repo_dir: str
options: 'Arguments'
def __post_init__(self, r: Resolver) -> None:
# FIXME: Do a copy because Resolver.resolve() is stateful method that
# cannot be called from multiple threads.
self.wrap_resolver = copy.copy(r)
self.wrap_resolver.dirname = os.path.join(r.subdir_root, wrap.directory)
self.wrap = self.wrap_resolver.wrap = wrap
self.repo_dir = repo_dir
self.options = options
self.run_method: T.Callable[[], bool] = options.subprojects_func.__get__(self) # type: ignore
self.wrap_resolver.dirname = os.path.join(r.subdir_root, self.wrap.directory)
self.wrap_resolver.wrap = self.wrap
self.run_method: T.Callable[[], bool] = self.options.subprojects_func.__get__(self) # type: ignore
self.log_queue: T.List[T.Tuple[mlog.TV_LoggableList, T.Any]] = []
self.logger = logger
def log(self, *args: mlog.TV_Loggable, **kwargs: T.Any) -> None:
self.log_queue.append((list(args), kwargs))

@ -14,6 +14,7 @@
from .. import mlog
import contextlib
from dataclasses import dataclass
import urllib.request
import urllib.error
import urllib.parse
@ -203,13 +204,15 @@ def verbose_git(cmd: T.List[str], workingdir: str, check: bool = False) -> bool:
except mesonlib.GitException as e:
raise WrapException(str(e))
@dataclass(eq=False)
class Resolver:
def __init__(self, source_dir: str, subdir: str, subproject: str = '', wrap_mode: WrapMode = WrapMode.default) -> None:
self.source_dir = source_dir
self.subdir = subdir
self.subproject = subproject
self.wrap_mode = wrap_mode
self.subdir_root = os.path.join(source_dir, subdir)
source_dir: str
subdir: str
subproject: str = ''
wrap_mode: WrapMode = WrapMode.default
def __post_init__(self) -> None:
self.subdir_root = os.path.join(self.source_dir, self.subdir)
self.cachedir = os.path.join(self.subdir_root, 'packagecache')
self.wraps = {} # type: T.Dict[str, PackageDefinition]
self.provided_deps = {} # type: T.Dict[str, PackageDefinition]

Loading…
Cancel
Save