diff options
author | Todd Gamblin <tgamblin@llnl.gov> | 2021-12-23 00:29:06 -0800 |
---|---|---|
committer | Greg Becker <becker33@llnl.gov> | 2022-01-12 06:14:18 -0800 |
commit | 93a6c51d8819a2f0003ed4f788f621717cbece81 (patch) | |
tree | 739b2537fe5bb919794845f909f27ec4aee2d6cb /lib | |
parent | 8880a00862026700a82de1004e24ff06e54a165a (diff) | |
download | spack-93a6c51d8819a2f0003ed4f788f621717cbece81.tar.gz spack-93a6c51d8819a2f0003ed4f788f621717cbece81.tar.bz2 spack-93a6c51d8819a2f0003ed4f788f621717cbece81.tar.xz spack-93a6c51d8819a2f0003ed4f788f621717cbece81.zip |
package_hash: rework `RemoveDirectives` and add a test
Previously we used `directives.__all__` to get directive names, but it wasn't
quite right -- it included `DirectiveMeta`, etc. It's not wrong, but it's also
not the clearest way to do this.
- [x] Refactor `@directive` to track names in `directive_names` global
- [x] Rename `_directive_names` to `_directive_dict_names` in `DirectiveMeta`
- [x] Add a test for `RemoveDirectives`
Co-authored-by: Danny McClanahan <1305167+cosmicexplorer@users.noreply.github.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/spack/directives.py | 18 | ||||
-rw-r--r-- | lib/spack/spack/test/util/package_hash.py | 27 | ||||
-rw-r--r-- | lib/spack/spack/util/package_hash.py | 2 |
3 files changed, 41 insertions, 6 deletions
diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py index c23146125a..060465184d 100644 --- a/lib/spack/spack/directives.py +++ b/lib/spack/spack/directives.py @@ -59,6 +59,10 @@ __all__ = ['DirectiveError', 'DirectiveMeta'] #: These are variant names used by Spack internally; packages can't use them reserved_names = ['patches', 'dev_path'] +#: Names of possible directives. This list is populated elsewhere in the file and then +#: added to `__all__` at the bottom. +directive_names = [] + _patch_order_index = 0 @@ -113,7 +117,7 @@ class DirectiveMeta(type): """ # Set of all known directives - _directive_names = set() # type: Set[str] + _directive_dict_names = set() # type: Set[str] _directives_to_be_executed = [] # type: List[str] _when_constraints_from_context = [] # type: List[str] @@ -156,7 +160,7 @@ class DirectiveMeta(type): if 'spack.pkg' in cls.__module__: # Ensure the presence of the dictionaries associated # with the directives - for d in DirectiveMeta._directive_names: + for d in DirectiveMeta._directive_dict_names: setattr(cls, d, {}) # Lazily execute directives @@ -222,7 +226,7 @@ class DirectiveMeta(type): Package class, and it's how Spack gets information from the packages to the core. """ - global __all__ + global directive_names if isinstance(dicts, six.string_types): dicts = (dicts, ) @@ -232,11 +236,11 @@ class DirectiveMeta(type): raise TypeError(message.format(type(dicts))) # Add the dictionary names if not already there - DirectiveMeta._directive_names |= set(dicts) + DirectiveMeta._directive_dict_names |= set(dicts) # This decorator just returns the directive functions def _decorator(decorated_function): - __all__.append(decorated_function.__name__) + directive_names.append(decorated_function.__name__) @functools.wraps(decorated_function) def _wrapper(*args, **kwargs): @@ -730,3 +734,7 @@ class DependencyPatchError(DirectiveError): class UnsupportedPackageDirective(DirectiveError): """Raised when an invalid or unsupported package directive is specified.""" + + +#: add all directive names to __all__ +__all__.extend(directive_names) diff --git a/lib/spack/spack/test/util/package_hash.py b/lib/spack/spack/test/util/package_hash.py index 16829586e4..aedb42e20d 100644 --- a/lib/spack/spack/test/util/package_hash.py +++ b/lib/spack/spack/test/util/package_hash.py @@ -5,6 +5,7 @@ import ast +import spack.directives import spack.paths import spack.util.package_hash as ph from spack.spec import Spec @@ -123,3 +124,29 @@ def test_remove_docstrings(): assert "SEVEN" in unparsed assert "NINE" in unparsed assert "TWELVE" in unparsed + + +many_directives = """\ + +class HasManyDirectives: +{directives} + + def foo(): + # just a method to get in the way + pass + +{directives} +""".format(directives="\n".join( + " %s()" % name for name in spack.directives.directive_names +)) + + +def test_remove_directives(): + """Ensure all directives are removed from packages before hashing.""" + tree = ast.parse(many_directives) + spec = Spec("has-many-directives") + tree = ph.RemoveDirectives(spec).visit(tree) + unparsed = unparse(tree) + + for name in spack.directives.directive_names: + assert name not in unparsed diff --git a/lib/spack/spack/util/package_hash.py b/lib/spack/spack/util/package_hash.py index d1412e16fd..3421d90d23 100644 --- a/lib/spack/spack/util/package_hash.py +++ b/lib/spack/spack/util/package_hash.py @@ -66,7 +66,7 @@ class RemoveDirectives(ast.NodeTransformer): return (isinstance(node, ast.Expr) and node.value and isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Name) and - node.value.func.id in spack.directives.__all__) + node.value.func.id in spack.directives.directive_names) def is_spack_attr(self, node): return (isinstance(node, ast.Assign) and |