From a8293dd59c0a22817f2336df8ae97dce1232f72a Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 2 Mar 2020 11:11:17 -0800 Subject: mesonlib: Replace unholder argument to listify listify shouldn't be unholdering, it's a function to turn scalar values into lists, or flatten lists. Having a separate function is clearer, easier to understand, and can be run recursively if necessary. --- mesonbuild/build.py | 24 ++++++++++++------------ mesonbuild/compilers/compilers.py | 2 ++ mesonbuild/interpreter.py | 24 ++++++++++++------------ mesonbuild/mesonlib.py | 19 +++++-------------- mesonbuild/modules/gnome.py | 6 +++--- mesonbuild/modules/pkgconfig.py | 4 ++-- run_unittests.py | 24 +++++++++++++++--------- 7 files changed, 51 insertions(+), 52 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 17b5f11..770e851 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -26,7 +26,7 @@ from . import mlog from .mesonlib import ( File, MesonException, MachineChoice, PerMachine, OrderedSet, listify, extract_as_list, typeslistify, stringlistify, classify_unity_sources, - get_filenames_templates_dict, substitute_values, has_path_sep, + get_filenames_templates_dict, substitute_values, has_path_sep, unholder ) from .compilers import Compiler, is_object, clink_langs, sort_clink, lang_suffixes from .linkers import StaticLinker @@ -856,7 +856,7 @@ just like those detected with the dependency() function.''') if dfeature_debug: dfeatures['debug'] = dfeature_debug if 'd_import_dirs' in kwargs: - dfeature_import_dirs = extract_as_list(kwargs, 'd_import_dirs', unholder=True) + dfeature_import_dirs = unholder(extract_as_list(kwargs, 'd_import_dirs')) for d in dfeature_import_dirs: if not isinstance(d, IncludeDirs): raise InvalidArguments('Arguments to d_import_dirs must be include_directories.') @@ -1083,7 +1083,7 @@ You probably should put it in link_with instead.''') return isinstance(self, StaticLibrary) and not self.need_install def link(self, target): - for t in listify(target, unholder=True): + for t in unholder(listify(target)): if isinstance(self, StaticLibrary) and self.need_install and t.is_internal(): # When we're a static library and we link_with to an # internal/convenience library, promote to link_whole. @@ -1105,7 +1105,7 @@ You probably should put it in link_with instead.''') self.link_targets.append(t) def link_whole(self, target): - for t in listify(target, unholder=True): + for t in unholder(listify(target)): if isinstance(t, (CustomTarget, CustomTargetIndex)): if not t.is_linkable_target(): raise InvalidArguments('Custom target {!r} is not linkable.'.format(t)) @@ -1261,7 +1261,7 @@ You probably should put it in link_with instead.''') if dl != linker.language: stdlib_args += all_compilers[dl].language_stdlib_only_link_flags() added_languages.add(dl) - # Type of var 'linker' is Compiler. + # Type of var 'linker' is Compiler. # Pretty hard to fix because the return value is passed everywhere return linker, stdlib_args @@ -1372,7 +1372,7 @@ class Generator: raise InvalidArguments('Capture must be boolean.') self.capture = capture if 'depends' in kwargs: - depends = listify(kwargs['depends'], unholder=True) + depends = unholder(listify(kwargs['depends'])) for d in depends: if not isinstance(d, BuildTarget): raise InvalidArguments('Depends entries must be build targets.') @@ -2054,7 +2054,7 @@ class CustomTarget(Target): return bdeps def flatten_command(self, cmd): - cmd = listify(cmd, unholder=True) + cmd = unholder(listify(cmd)) final_cmd = [] for c in cmd: if isinstance(c, str): @@ -2082,7 +2082,7 @@ class CustomTarget(Target): def process_kwargs(self, kwargs, backend): self.process_kwargs_base(kwargs) - self.sources = extract_as_list(kwargs, 'input', unholder=True) + self.sources = unholder(extract_as_list(kwargs, 'input')) if 'output' not in kwargs: raise InvalidArguments('Missing keyword argument "output".') self.outputs = listify(kwargs['output']) @@ -2411,18 +2411,18 @@ class ConfigureFile: class ConfigurationData: def __init__(self) -> None: super().__init__() - self.values = {} + self.values = {} # T.Dict[str, T.Union[str, int, bool]] def __repr__(self): return repr(self.values) - def __contains__(self, value): + def __contains__(self, value: str) -> bool: return value in self.values - def get(self, name): + def get(self, name: str) -> T.Tuple[T.Union[str, int, bool], T.Optional[str]]: return self.values[name] # (val, desc) - def keys(self): + def keys(self) -> T.Iterator[str]: return self.values.keys() # A bit poorly named, but this represents plain data files to copy diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 1c0adff..caa8600 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -35,6 +35,8 @@ if T.TYPE_CHECKING: from ..environment import Environment from ..linkers import DynamicLinker # noqa: F401 + CompilerType = T.TypeVar('CompilerType', bound=Compiler) + """This file contains the data files of all compilers Meson knows about. To support a new compiler, add its information below. Also add corresponding autodetection code in environment.py.""" diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 9e88975..4c0807c 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -21,7 +21,7 @@ from . import optinterpreter from . import compilers from .wrap import wrap, WrapMode from . import mesonlib -from .mesonlib import FileMode, MachineChoice, Popen_safe, listify, extract_as_list, has_path_sep +from .mesonlib import FileMode, MachineChoice, Popen_safe, listify, extract_as_list, has_path_sep, unholder from .dependencies import ExternalProgram from .dependencies import InternalDependency, Dependency, NotFoundDependency, DependencyException from .depfile import DepFile @@ -2460,11 +2460,11 @@ class Interpreter(InterpreterBase): if not isinstance(version, str): raise InterpreterException('Version must be a string.') incs = self.extract_incdirs(kwargs) - libs = extract_as_list(kwargs, 'link_with', unholder=True) - libs_whole = extract_as_list(kwargs, 'link_whole', unholder=True) + libs = unholder(extract_as_list(kwargs, 'link_with')) + libs_whole = unholder(extract_as_list(kwargs, 'link_whole')) sources = extract_as_list(kwargs, 'sources') - sources = listify(self.source_strings_to_files(sources), unholder=True) - deps = extract_as_list(kwargs, 'dependencies', unholder=True) + sources = unholder(listify(self.source_strings_to_files(sources))) + deps = unholder(extract_as_list(kwargs, 'dependencies')) compile_args = mesonlib.stringlistify(kwargs.get('compile_args', [])) link_args = mesonlib.stringlistify(kwargs.get('link_args', [])) variables = kwargs.get('variables', {}) @@ -3581,12 +3581,12 @@ This will become a hard error in the future.''' % kwargs['input'], location=self if 'command' not in kwargs: raise InterpreterException('Missing "command" keyword argument') all_args = extract_as_list(kwargs, 'command') - deps = extract_as_list(kwargs, 'depends', unholder=True) + deps = unholder(extract_as_list(kwargs, 'depends')) else: raise InterpreterException('Run_target needs at least one positional argument.') cleaned_args = [] - for i in listify(all_args, unholder=True): + for i in unholder(listify(all_args)): if not isinstance(i, (str, build.BuildTarget, build.CustomTarget, dependencies.ExternalProgram, mesonlib.File)): mlog.debug('Wrong type:', str(i)) raise InterpreterException('Invalid argument to run_target.') @@ -3617,7 +3617,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self name = args[0] if not isinstance(name, str): raise InterpreterException('First argument must be a string.') - deps = listify(args[1:], unholder=True) + deps = unholder(listify(args[1:])) for d in deps: if not isinstance(d, (build.BuildTarget, build.CustomTarget)): raise InterpreterException('Depends items must be build targets.') @@ -3675,7 +3675,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self par = kwargs.get('is_parallel', True) if not isinstance(par, bool): raise InterpreterException('Keyword argument is_parallel must be a boolean.') - cmd_args = extract_as_list(kwargs, 'args', unholder=True) + cmd_args = unholder(extract_as_list(kwargs, 'args')) for i in cmd_args: if not isinstance(i, (str, mesonlib.File, build.Target)): raise InterpreterException('Command line arguments must be strings, files or targets.') @@ -3703,7 +3703,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self if len(s) > 0: s = ':' + s suite.append(prj.replace(' ', '_').replace(':', '_') + s) - depends = extract_as_list(kwargs, 'depends', unholder=True) + depends = unholder(extract_as_list(kwargs, 'depends')) for dep in depends: if not isinstance(dep, (build.CustomTarget, build.BuildTarget)): raise InterpreterException('Depends items must be build targets.') @@ -4066,7 +4066,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self return mesonlib.File.from_built_file(self.subdir, output) def extract_incdirs(self, kwargs): - prospectives = listify(kwargs.get('include_directories', []), unholder=True) + prospectives = unholder(extract_as_list(kwargs, 'include_directories')) result = [] for p in prospectives: if isinstance(p, build.IncludeDirs): @@ -4127,7 +4127,7 @@ different subdirectory. if ":" not in setup_name: setup_name = (self.subproject if self.subproject else self.build.project_name) + ":" + setup_name try: - inp = extract_as_list(kwargs, 'exe_wrapper', unholder=True) + inp = unholder(extract_as_list(kwargs, 'exe_wrapper')) exe_wrapper = [] for i in inp: if isinstance(i, str): diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 49ddc94..07e30e2 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -1058,34 +1058,25 @@ def unholder(item): return item -def listify(item: T.Any, - flatten: bool = True, - unholder: bool = False) -> T.List[T.Any]: +def listify(item: T.Any, flatten: bool = True) -> T.List[T.Any]: ''' Returns a list with all args embedded in a list if they are not a list. This function preserves order. @flatten: Convert lists of lists to a flat list - @unholder: Replace each item with the object it holds, if required - - Note: unholding only works recursively when flattening ''' if not isinstance(item, list): - if unholder and hasattr(item, 'held_object'): - item = item.held_object return [item] result = [] # type: T.List[T.Any] for i in item: - if unholder and hasattr(i, 'held_object'): - i = i.held_object if flatten and isinstance(i, list): - result += listify(i, flatten=True, unholder=unholder) + result += listify(i, flatten=True) else: result.append(i) return result def extract_as_list(dict_object: T.Dict[_T, _U], *keys: _T, pop: bool = False, - **kwargs: T.Any) -> T.List[T.Union[_U, T.List[_U]]]: + flatten: bool = True) -> T.List[T.Union[_U, T.List[_U]]]: ''' Extracts all values from given dict_object and listifies them. ''' @@ -1095,10 +1086,10 @@ def extract_as_list(dict_object: T.Dict[_T, _U], *keys: _T, pop: bool = False, fetch = dict_object.pop # If there's only one key, we don't return a list with one element if len(keys) == 1: - return listify(fetch(keys[0], []), **kwargs) + return listify(fetch(keys[0], []), flatten=True) # Return a list of values corresponding to *keys for key in keys: - result.append(listify(fetch(key, []), **kwargs)) + result.append(listify(fetch(key, []), flatten=True)) return result diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 1743b59..4ff40ad 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -316,7 +316,7 @@ class GnomeModule(ExtensionModule): # require two args in order, such as -framework AVFoundation external_ldflags_nodedup = [] gi_includes = OrderedSet() - deps = mesonlib.listify(deps, unholder=True) + deps = mesonlib.unholder(mesonlib.listify(deps)) for dep in deps: if isinstance(dep, InternalDependency): @@ -776,7 +776,7 @@ class GnomeModule(ExtensionModule): langs_compilers = self._get_girtargets_langs_compilers(girtargets) cflags, internal_ldflags, external_ldflags = self._get_langs_compilers_flags(state, langs_compilers) deps = self._get_gir_targets_deps(girtargets) - deps += extract_as_list(kwargs, 'dependencies', pop=True, unholder=True) + deps += mesonlib.unholder(extract_as_list(kwargs, 'dependencies', pop=True)) typelib_includes = self._gather_typelib_includes_and_update_depends(state, deps, depends) # ldflags will be misinterpreted by gir scanner (showing # spurious dependencies) but building GStreamer fails if they @@ -1057,7 +1057,7 @@ This will become a hard error in the future.''') def _get_build_args(self, kwargs, state, depends): args = [] - deps = extract_as_list(kwargs, 'dependencies', unholder=True) + deps = mesonlib.unholder(extract_as_list(kwargs, 'dependencies')) cflags = [] cflags.extend(mesonlib.stringlistify(kwargs.pop('c_args', []))) deps_cflags, internal_ldflags, external_ldflags, gi_includes = \ diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 8de88c9..1d8e8a9 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -74,7 +74,7 @@ class DependenciesHelper: def _process_reqs(self, reqs): '''Returns string names of requirements''' processed_reqs = [] - for obj in mesonlib.listify(reqs, unholder=True): + for obj in mesonlib.unholder(mesonlib.listify(reqs)): if not isinstance(obj, str): FeatureNew('pkgconfig.generate requirement from non-string object', '0.46.0').use(self.state.subproject) if hasattr(obj, 'generated_pc'): @@ -108,7 +108,7 @@ class DependenciesHelper: self.cflags += mesonlib.stringlistify(cflags) def _process_libs(self, libs, public): - libs = mesonlib.listify(libs, unholder=True) + libs = mesonlib.unholder(mesonlib.listify(libs)) processed_libs = [] processed_reqs = [] processed_cflags = [] diff --git a/run_unittests.py b/run_unittests.py index 658da37..b39ba28 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -686,12 +686,17 @@ class InternalTests(unittest.TestCase): self.assertEqual([holder1], listify([holder1])) self.assertEqual([holder1, 2], listify([holder1, 2])) self.assertEqual([holder1, 2, 3], listify([holder1, 2, [3]])) - self.assertEqual([1], listify(holder1, unholder=True)) - self.assertEqual([1], listify([holder1], unholder=True)) - self.assertEqual([1, 2], listify([holder1, 2], unholder=True)) - self.assertEqual([1, 2, 3], listify([holder1, 2, [holder3]], unholder=True)) - # Unholding doesn't work recursively when not flattening - self.assertEqual([1, [2], [holder3]], listify([holder1, [2], [holder3]], unholder=True, flatten=False)) + + def test_unholder(self): + unholder = mesonbuild.mesonlib.unholder + + holder1 = ObjectHolder(1) + holder3 = ObjectHolder(3) + holders = [holder1, holder3] + + self.assertEqual(1, unholder(holder1)) + self.assertEqual([1], unholder([holder1])) + self.assertEqual([1, 3], unholder(holders)) def test_extract_as_list(self): extract = mesonbuild.mesonlib.extract_as_list @@ -704,14 +709,15 @@ class InternalTests(unittest.TestCase): # Test unholding holder3 = ObjectHolder(3) kwargs = {'sources': [1, 2, holder3]} - self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True)) self.assertEqual(kwargs, {'sources': [1, 2, holder3]}) - self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True, pop=True)) - self.assertEqual(kwargs, {}) # Test listification kwargs = {'sources': [1, 2, 3], 'pch_sources': [4, 5, 6]} self.assertEqual([[1, 2, 3], [4, 5, 6]], extract(kwargs, 'sources', 'pch_sources')) + # flatten nested lists + kwargs = {'sources': [1, [2, [3]]]} + self.assertEqual([1, 2, 3], extract(kwargs, 'sources', flatten=True)) + def test_pkgconfig_module(self): class Mock: -- cgit v1.1