summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2021-12-23 00:29:06 -0800
committerGreg Becker <becker33@llnl.gov>2022-01-12 06:14:18 -0800
commit93a6c51d8819a2f0003ed4f788f621717cbece81 (patch)
tree739b2537fe5bb919794845f909f27ec4aee2d6cb /lib
parent8880a00862026700a82de1004e24ff06e54a165a (diff)
downloadspack-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.py18
-rw-r--r--lib/spack/spack/test/util/package_hash.py27
-rw-r--r--lib/spack/spack/util/package_hash.py2
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