summaryrefslogtreecommitdiff
path: root/lib/spack/spack/test/spec_dag.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/spack/test/spec_dag.py')
-rw-r--r--lib/spack/spack/test/spec_dag.py824
1 files changed, 396 insertions, 428 deletions
diff --git a/lib/spack/spack/test/spec_dag.py b/lib/spack/spack/test/spec_dag.py
index b7c0f95332..d7f9a750ee 100644
--- a/lib/spack/spack/test/spec_dag.py
+++ b/lib/spack/spack/test/spec_dag.py
@@ -35,6 +35,7 @@ def set_dependency(saved_deps, monkeypatch):
"""Returns a function that alters the dependency information
for a package in the ``saved_deps`` fixture.
"""
+
def _mock(pkg_name, spec, deptypes=all_deptypes):
"""Alters dependence information for a package.
@@ -49,41 +50,41 @@ def set_dependency(saved_deps, monkeypatch):
cond = Spec(pkg_cls.name)
dependency = Dependency(pkg_cls, spec, type=deptypes)
monkeypatch.setitem(pkg_cls.dependencies, spec.name, {cond: dependency})
+
return _mock
-@pytest.mark.usefixtures('config')
+@pytest.mark.usefixtures("config")
def test_test_deptype():
"""Ensure that test-only dependencies are only included for specified
-packages in the following spec DAG::
+ packages in the following spec DAG::
- w
- /|
- x y
- |
- z
+ w
+ /|
+ x y
+ |
+ z
-w->y deptypes are (link, build), w->x and y->z deptypes are (test)
-
-"""
- default = ('build', 'link')
- test_only = ('test',)
+ w->y deptypes are (link, build), w->x and y->z deptypes are (test)
+ """
+ default = ("build", "link")
+ test_only = ("test",)
mock_repo = MockPackageMultiRepo()
- x = mock_repo.add_package('x', [], [])
- z = mock_repo.add_package('z', [], [])
- y = mock_repo.add_package('y', [z], [test_only])
- w = mock_repo.add_package('w', [x, y], [test_only, default])
+ x = mock_repo.add_package("x", [], [])
+ z = mock_repo.add_package("z", [], [])
+ y = mock_repo.add_package("y", [z], [test_only])
+ w = mock_repo.add_package("w", [x, y], [test_only, default])
with spack.repo.use_repositories(mock_repo):
- spec = Spec('w')
+ spec = Spec("w")
spec.concretize(tests=(w.name,))
- assert ('x' in spec)
- assert ('z' not in spec)
+ assert "x" in spec
+ assert "z" not in spec
-@pytest.mark.usefixtures('config')
+@pytest.mark.usefixtures("config")
def test_installed_deps(monkeypatch, mock_packages):
"""Ensure that concrete specs and their build deps don't constrain solves.
@@ -96,8 +97,8 @@ def test_installed_deps(monkeypatch, mock_packages):
constrain ``a``'s dependency on ``d``.
"""
- if spack.config.get('config:concretizer') == 'original':
- pytest.xfail('fails with the original concretizer and full hashes')
+ if spack.config.get("config:concretizer") == "original":
+ pytest.xfail("fails with the original concretizer and full hashes")
# see installed-deps-[abcde] test packages.
# a
@@ -115,14 +116,14 @@ def test_installed_deps(monkeypatch, mock_packages):
# (concrete) installation.
c_spec = Spec(c)
c_spec.concretize()
- assert c_spec[d].version == spack.version.Version('2')
+ assert c_spec[d].version == spack.version.Version("2")
installed_names = [s.name for s in c_spec.traverse()]
def _mock_installed(self):
return self.name in installed_names
- monkeypatch.setattr(Spec, 'installed', _mock_installed)
+ monkeypatch.setattr(Spec, "installed", _mock_installed)
# install A, which depends on B, C, D, and E, and force A to
# use the installed C. It should *not* force A to use the installed D
@@ -130,43 +131,42 @@ def test_installed_deps(monkeypatch, mock_packages):
a_spec = Spec(a)
a_spec._add_dependency(c_spec, ("build", "link"))
a_spec.concretize()
- assert spack.version.Version('2') == a_spec[c][d].version
- assert spack.version.Version('2') == a_spec[e].version
- assert spack.version.Version('3') == a_spec[b][d].version
- assert spack.version.Version('3') == a_spec[d].version
+ assert spack.version.Version("2") == a_spec[c][d].version
+ assert spack.version.Version("2") == a_spec[e].version
+ assert spack.version.Version("3") == a_spec[b][d].version
+ assert spack.version.Version("3") == a_spec[d].version
-@pytest.mark.usefixtures('config')
+@pytest.mark.usefixtures("config")
def test_specify_preinstalled_dep():
"""Specify the use of a preinstalled package during concretization with a
transitive dependency that is only supplied by the preinstalled package.
"""
- default = ('build', 'link')
+ default = ("build", "link")
mock_repo = MockPackageMultiRepo()
- c = mock_repo.add_package('c', [], [])
- b = mock_repo.add_package('b', [c], [default])
- mock_repo.add_package('a', [b], [default])
+ c = mock_repo.add_package("c", [], [])
+ b = mock_repo.add_package("b", [c], [default])
+ mock_repo.add_package("a", [b], [default])
with spack.repo.use_repositories(mock_repo):
- b_spec = Spec('b')
+ b_spec = Spec("b")
b_spec.concretize()
for spec in b_spec.traverse():
- setattr(spec.package, 'installed', True)
+ setattr(spec.package, "installed", True)
- a_spec = Spec('a')
+ a_spec = Spec("a")
a_spec._add_dependency(b_spec, default)
a_spec.concretize()
- assert set(x.name for x in a_spec.traverse()) == set(['a', 'b', 'c'])
+ assert set(x.name for x in a_spec.traverse()) == set(["a", "b", "c"])
-@pytest.mark.usefixtures('config')
-@pytest.mark.parametrize('spec_str,expr_str,expected', [
- ('x ^y@2', 'y@2', True),
- ('x@1', 'y', False),
- ('x', 'y@3', True)
-])
+@pytest.mark.usefixtures("config")
+@pytest.mark.parametrize(
+ "spec_str,expr_str,expected",
+ [("x ^y@2", "y@2", True), ("x@1", "y", False), ("x", "y@3", True)],
+)
def test_conditional_dep_with_user_constraints(spec_str, expr_str, expected):
"""This sets up packages X->Y such that X depends on Y conditionally. It
then constructs a Spec with X but with no constraints on X, so that the
@@ -177,35 +177,31 @@ def test_conditional_dep_with_user_constraints(spec_str, expr_str, expected):
# FIXME: We need to tweak optimization rules to make this test
# FIXME: not prefer a DAG with fewer nodes wrt more recent
# FIXME: versions of the package
- if spack.config.get('config:concretizer') == 'clingo':
- pytest.xfail('Clingo optimization rules prefer to trim a node')
+ if spack.config.get("config:concretizer") == "clingo":
+ pytest.xfail("Clingo optimization rules prefer to trim a node")
- default = ('build', 'link')
+ default = ("build", "link")
mock_repo = MockPackageMultiRepo()
- y = mock_repo.add_package('y', [], [])
- x_on_y_conditions = {
- y.name: {
- 'x@2:': 'y'
- }
- }
- mock_repo.add_package('x', [y], [default], conditions=x_on_y_conditions)
+ y = mock_repo.add_package("y", [], [])
+ x_on_y_conditions = {y.name: {"x@2:": "y"}}
+ mock_repo.add_package("x", [y], [default], conditions=x_on_y_conditions)
with spack.repo.use_repositories(mock_repo):
spec = Spec(spec_str)
spec.concretize()
result = expr_str in spec
- assert result is expected, '{0} in {1}'.format(expr_str, spec)
+ assert result is expected, "{0} in {1}".format(expr_str, spec)
-@pytest.mark.usefixtures('mutable_mock_repo', 'config')
+@pytest.mark.usefixtures("mutable_mock_repo", "config")
class TestSpecDag(object):
def test_conflicting_package_constraints(self, set_dependency):
- set_dependency('mpileaks', 'mpich@1.0')
- set_dependency('callpath', 'mpich@2.0')
+ set_dependency("mpileaks", "mpich@1.0")
+ set_dependency("callpath", "mpich@2.0")
- spec = Spec('mpileaks ^mpich ^callpath ^dyninst ^libelf ^libdwarf')
+ spec = Spec("mpileaks ^mpich ^callpath ^dyninst ^libelf ^libdwarf")
# TODO: try to do something to show that the issue was with
# TODO: the user's input or with package inconsistencies.
@@ -213,11 +209,10 @@ class TestSpecDag(object):
spec.normalize()
def test_preorder_node_traversal(self):
- dag = Spec('mpileaks ^zmpi')
+ dag = Spec("mpileaks ^zmpi")
dag.normalize()
- names = ['mpileaks', 'callpath', 'dyninst', 'libdwarf', 'libelf',
- 'zmpi', 'fake']
+ names = ["mpileaks", "callpath", "dyninst", "libdwarf", "libelf", "zmpi", "fake"]
pairs = list(zip([0, 1, 2, 3, 4, 2, 3], names))
traversal = dag.traverse()
@@ -227,99 +222,132 @@ class TestSpecDag(object):
assert [(x, y.name) for x, y in traversal] == pairs
def test_preorder_edge_traversal(self):
- dag = Spec('mpileaks ^zmpi')
+ dag = Spec("mpileaks ^zmpi")
dag.normalize()
- names = ['mpileaks', 'callpath', 'dyninst', 'libdwarf', 'libelf',
- 'libelf', 'zmpi', 'fake', 'zmpi']
+ names = [
+ "mpileaks",
+ "callpath",
+ "dyninst",
+ "libdwarf",
+ "libelf",
+ "libelf",
+ "zmpi",
+ "fake",
+ "zmpi",
+ ]
pairs = list(zip([0, 1, 2, 3, 4, 3, 2, 3, 1], names))
- traversal = dag.traverse(cover='edges')
+ traversal = dag.traverse(cover="edges")
assert [x.name for x in traversal] == names
- traversal = dag.traverse(cover='edges', depth=True)
+ traversal = dag.traverse(cover="edges", depth=True)
assert [(x, y.name) for x, y in traversal] == pairs
def test_preorder_path_traversal(self):
- dag = Spec('mpileaks ^zmpi')
+ dag = Spec("mpileaks ^zmpi")
dag.normalize()
- names = ['mpileaks', 'callpath', 'dyninst', 'libdwarf', 'libelf',
- 'libelf', 'zmpi', 'fake', 'zmpi', 'fake']
+ names = [
+ "mpileaks",
+ "callpath",
+ "dyninst",
+ "libdwarf",
+ "libelf",
+ "libelf",
+ "zmpi",
+ "fake",
+ "zmpi",
+ "fake",
+ ]
pairs = list(zip([0, 1, 2, 3, 4, 3, 2, 3, 1, 2], names))
- traversal = dag.traverse(cover='paths')
+ traversal = dag.traverse(cover="paths")
assert [x.name for x in traversal] == names
- traversal = dag.traverse(cover='paths', depth=True)
+ traversal = dag.traverse(cover="paths", depth=True)
assert [(x, y.name) for x, y in traversal] == pairs
def test_postorder_node_traversal(self):
- dag = Spec('mpileaks ^zmpi')
+ dag = Spec("mpileaks ^zmpi")
dag.normalize()
- names = ['libelf', 'libdwarf', 'dyninst', 'fake', 'zmpi',
- 'callpath', 'mpileaks']
+ names = ["libelf", "libdwarf", "dyninst", "fake", "zmpi", "callpath", "mpileaks"]
pairs = list(zip([4, 3, 2, 3, 2, 1, 0], names))
- traversal = dag.traverse(order='post')
+ traversal = dag.traverse(order="post")
assert [x.name for x in traversal] == names
- traversal = dag.traverse(depth=True, order='post')
+ traversal = dag.traverse(depth=True, order="post")
assert [(x, y.name) for x, y in traversal] == pairs
def test_postorder_edge_traversal(self):
- dag = Spec('mpileaks ^zmpi')
+ dag = Spec("mpileaks ^zmpi")
dag.normalize()
- names = ['libelf', 'libdwarf', 'libelf', 'dyninst', 'fake', 'zmpi',
- 'callpath', 'zmpi', 'mpileaks']
+ names = [
+ "libelf",
+ "libdwarf",
+ "libelf",
+ "dyninst",
+ "fake",
+ "zmpi",
+ "callpath",
+ "zmpi",
+ "mpileaks",
+ ]
pairs = list(zip([4, 3, 3, 2, 3, 2, 1, 1, 0], names))
- traversal = dag.traverse(cover='edges', order='post')
+ traversal = dag.traverse(cover="edges", order="post")
assert [x.name for x in traversal] == names
- traversal = dag.traverse(cover='edges', depth=True, order='post')
+ traversal = dag.traverse(cover="edges", depth=True, order="post")
assert [(x, y.name) for x, y in traversal] == pairs
def test_postorder_path_traversal(self):
- dag = Spec('mpileaks ^zmpi')
+ dag = Spec("mpileaks ^zmpi")
dag.normalize()
- names = ['libelf', 'libdwarf', 'libelf', 'dyninst', 'fake', 'zmpi',
- 'callpath', 'fake', 'zmpi', 'mpileaks']
+ names = [
+ "libelf",
+ "libdwarf",
+ "libelf",
+ "dyninst",
+ "fake",
+ "zmpi",
+ "callpath",
+ "fake",
+ "zmpi",
+ "mpileaks",
+ ]
pairs = list(zip([4, 3, 3, 2, 3, 2, 1, 2, 1, 0], names))
- traversal = dag.traverse(cover='paths', order='post')
+ traversal = dag.traverse(cover="paths", order="post")
assert [x.name for x in traversal] == names
- traversal = dag.traverse(cover='paths', depth=True, order='post')
+ traversal = dag.traverse(cover="paths", depth=True, order="post")
assert [(x, y.name) for x, y in traversal] == pairs
def test_conflicting_spec_constraints(self):
- mpileaks = Spec('mpileaks ^mpich ^callpath ^dyninst ^libelf ^libdwarf')
+ mpileaks = Spec("mpileaks ^mpich ^callpath ^dyninst ^libelf ^libdwarf")
# Normalize then add conflicting constraints to the DAG (this is an
# extremely unlikely scenario, but we test for it anyway)
mpileaks.normalize()
- mpileaks.edges_to_dependencies(
- name='mpich'
- )[0].spec = Spec('mpich@1.0')
+ mpileaks.edges_to_dependencies(name="mpich")[0].spec = Spec("mpich@1.0")
- mpileaks.edges_to_dependencies(
- name='callpath'
- )[0].spec.edges_to_dependencies(
- name='mpich'
- )[0].spec = Spec('mpich@2.0')
+ mpileaks.edges_to_dependencies(name="callpath")[0].spec.edges_to_dependencies(
+ name="mpich"
+ )[0].spec = Spec("mpich@2.0")
with pytest.raises(spack.spec.InconsistentSpecError):
mpileaks.flat_dependencies(copy=False)
def test_normalize_twice(self):
"""Make sure normalize can be run twice on the same spec,
- and that it is idempotent."""
- spec = Spec('mpileaks')
+ and that it is idempotent."""
+ spec = Spec("mpileaks")
spec.normalize()
n1 = spec.copy()
@@ -327,25 +355,26 @@ class TestSpecDag(object):
assert n1 == spec
def test_normalize_a_lot(self):
- spec = Spec('mpileaks')
+ spec = Spec("mpileaks")
spec.normalize()
spec.normalize()
spec.normalize()
spec.normalize()
- def test_normalize_with_virtual_spec(self, ):
- dag = Spec.from_literal({
- 'mpileaks': {
- 'callpath': {
- 'dyninst': {
- 'libdwarf': {'libelf': None},
- 'libelf': None
+ def test_normalize_with_virtual_spec(
+ self,
+ ):
+ dag = Spec.from_literal(
+ {
+ "mpileaks": {
+ "callpath": {
+ "dyninst": {"libdwarf": {"libelf": None}, "libelf": None},
+ "mpi": None,
},
- 'mpi': None
- },
- 'mpi': None
+ "mpi": None,
+ }
}
- })
+ )
dag.normalize()
# make sure nothing with the same name occurs twice
@@ -359,53 +388,51 @@ class TestSpecDag(object):
assert counts[name] == 1
def test_dependents_and_dependencies_are_correct(self):
- spec = Spec.from_literal({
- 'mpileaks': {
- 'callpath': {
- 'dyninst': {
- 'libdwarf': {'libelf': None},
- 'libelf': None
+ spec = Spec.from_literal(
+ {
+ "mpileaks": {
+ "callpath": {
+ "dyninst": {"libdwarf": {"libelf": None}, "libelf": None},
+ "mpi": None,
},
- 'mpi': None
- },
- 'mpi': None
+ "mpi": None,
+ }
}
- })
+ )
check_links(spec)
spec.normalize()
check_links(spec)
def test_unsatisfiable_version(self, set_dependency):
- set_dependency('mpileaks', 'mpich@1.0')
- spec = Spec('mpileaks ^mpich@2.0 ^callpath ^dyninst ^libelf ^libdwarf')
+ set_dependency("mpileaks", "mpich@1.0")
+ spec = Spec("mpileaks ^mpich@2.0 ^callpath ^dyninst ^libelf ^libdwarf")
with pytest.raises(spack.spec.UnsatisfiableVersionSpecError):
spec.normalize()
def test_unsatisfiable_compiler(self, set_dependency):
- set_dependency('mpileaks', 'mpich%gcc')
- spec = Spec('mpileaks ^mpich%intel ^callpath ^dyninst ^libelf'
- ' ^libdwarf')
+ set_dependency("mpileaks", "mpich%gcc")
+ spec = Spec("mpileaks ^mpich%intel ^callpath ^dyninst ^libelf" " ^libdwarf")
with pytest.raises(spack.spec.UnsatisfiableCompilerSpecError):
spec.normalize()
def test_unsatisfiable_compiler_version(self, set_dependency):
- set_dependency('mpileaks', 'mpich%gcc@4.6')
- spec = Spec('mpileaks ^mpich%gcc@4.5 ^callpath ^dyninst ^libelf'
- ' ^libdwarf')
+ set_dependency("mpileaks", "mpich%gcc@4.6")
+ spec = Spec("mpileaks ^mpich%gcc@4.5 ^callpath ^dyninst ^libelf" " ^libdwarf")
with pytest.raises(spack.spec.UnsatisfiableCompilerSpecError):
spec.normalize()
def test_unsatisfiable_architecture(self, set_dependency):
- set_dependency('mpileaks', 'mpich platform=test target=be')
- spec = Spec('mpileaks ^mpich platform=test target=fe ^callpath'
- ' ^dyninst ^libelf ^libdwarf')
+ set_dependency("mpileaks", "mpich platform=test target=be")
+ spec = Spec(
+ "mpileaks ^mpich platform=test target=fe ^callpath" " ^dyninst ^libelf ^libdwarf"
+ )
with pytest.raises(spack.spec.UnsatisfiableArchitectureSpecError):
spec.normalize()
- @pytest.mark.parametrize('spec_str', [
- 'libelf ^mpich', 'libelf ^libdwarf', 'mpich ^dyninst ^libelf'
- ])
+ @pytest.mark.parametrize(
+ "spec_str", ["libelf ^mpich", "libelf ^libdwarf", "mpich ^dyninst ^libelf"]
+ )
def test_invalid_dep(self, spec_str):
spec = Spec(spec_str)
with pytest.raises(spack.error.SpecError):
@@ -413,45 +440,19 @@ class TestSpecDag(object):
def test_equal(self):
# Different spec structures to test for equality
- flat = Spec.from_literal(
- {'mpileaks ^callpath ^libelf ^libdwarf': None}
+ flat = Spec.from_literal({"mpileaks ^callpath ^libelf ^libdwarf": None})
+
+ flat_init = Spec.from_literal(
+ {"mpileaks": {"callpath": None, "libdwarf": None, "libelf": None}}
)
- flat_init = Spec.from_literal({
- 'mpileaks': {
- 'callpath': None,
- 'libdwarf': None,
- 'libelf': None
- }
- })
+ flip_flat = Spec.from_literal(
+ {"mpileaks": {"libelf": None, "libdwarf": None, "callpath": None}}
+ )
- flip_flat = Spec.from_literal({
- 'mpileaks': {
- 'libelf': None,
- 'libdwarf': None,
- 'callpath': None
- }
- })
-
- dag = Spec.from_literal({
- 'mpileaks': {
- 'callpath': {
- 'libdwarf': {
- 'libelf': None
- }
- }
- }
- })
-
- flip_dag = Spec.from_literal({
- 'mpileaks': {
- 'callpath': {
- 'libelf': {
- 'libdwarf': None
- }
- }
- }
- })
+ dag = Spec.from_literal({"mpileaks": {"callpath": {"libdwarf": {"libelf": None}}}})
+
+ flip_dag = Spec.from_literal({"mpileaks": {"callpath": {"libelf": {"libdwarf": None}}}})
# All these are equal to each other with regular ==
specs = (flat, flat_init, flip_flat, dag, flip_dag)
@@ -474,52 +475,53 @@ class TestSpecDag(object):
def test_normalize_mpileaks(self):
# Spec parsed in from a string
- spec = Spec.from_literal({
- 'mpileaks ^mpich ^callpath ^dyninst ^libelf@1.8.11 ^libdwarf': None
- })
+ spec = Spec.from_literal(
+ {"mpileaks ^mpich ^callpath ^dyninst ^libelf@1.8.11 ^libdwarf": None}
+ )
# What that spec should look like after parsing
- expected_flat = Spec.from_literal({
- 'mpileaks': {
- 'mpich': None,
- 'callpath': None,
- 'dyninst': None,
- 'libelf@1.8.11': None,
- 'libdwarf': None
+ expected_flat = Spec.from_literal(
+ {
+ "mpileaks": {
+ "mpich": None,
+ "callpath": None,
+ "dyninst": None,
+ "libelf@1.8.11": None,
+ "libdwarf": None,
+ }
}
- })
+ )
# What it should look like after normalization
- mpich = Spec('mpich')
- libelf = Spec('libelf@1.8.11')
- expected_normalized = Spec.from_literal({
- 'mpileaks': {
- 'callpath': {
- 'dyninst': {
- 'libdwarf': {libelf: None},
- libelf: None
+ mpich = Spec("mpich")
+ libelf = Spec("libelf@1.8.11")
+ expected_normalized = Spec.from_literal(
+ {
+ "mpileaks": {
+ "callpath": {
+ "dyninst": {"libdwarf": {libelf: None}, libelf: None},
+ mpich: None,
},
- mpich: None
+ mpich: None,
},
- mpich: None
- },
- })
+ }
+ )
# Similar to normalized spec, but now with copies of the same
# libelf node. Normalization should result in a single unique
# node for each package, so this is the wrong DAG.
- non_unique_nodes = Spec.from_literal({
- 'mpileaks': {
- 'callpath': {
- 'dyninst': {
- 'libdwarf': {'libelf@1.8.11': None},
- 'libelf@1.8.11': None
+ non_unique_nodes = Spec.from_literal(
+ {
+ "mpileaks": {
+ "callpath": {
+ "dyninst": {"libdwarf": {"libelf@1.8.11": None}, "libelf@1.8.11": None},
+ mpich: None,
},
- mpich: None
- },
- mpich: None
- }
- }, normal=False)
+ mpich: None,
+ }
+ },
+ normal=False,
+ )
# All specs here should be equal under regular equality
specs = (spec, expected_flat, expected_normalized, non_unique_nodes)
@@ -553,36 +555,35 @@ class TestSpecDag(object):
assert not spec.eq_dag(non_unique_nodes, deptypes=True)
def test_normalize_with_virtual_package(self):
- spec = Spec('mpileaks ^mpi ^libelf@1.8.11 ^libdwarf')
+ spec = Spec("mpileaks ^mpi ^libelf@1.8.11 ^libdwarf")
spec.normalize()
- expected_normalized = Spec.from_literal({
- 'mpileaks': {
- 'callpath': {
- 'dyninst': {
- 'libdwarf': {'libelf@1.8.11': None},
- 'libelf@1.8.11': None
+ expected_normalized = Spec.from_literal(
+ {
+ "mpileaks": {
+ "callpath": {
+ "dyninst": {"libdwarf": {"libelf@1.8.11": None}, "libelf@1.8.11": None},
+ "mpi": None,
},
- 'mpi': None
- },
- 'mpi': None
+ "mpi": None,
+ }
}
- })
+ )
assert str(spec) == str(expected_normalized)
def test_contains(self):
- spec = Spec('mpileaks ^mpi ^libelf@1.8.11 ^libdwarf')
- assert Spec('mpi') in spec
- assert Spec('libelf') in spec
- assert Spec('libelf@1.8.11') in spec
- assert Spec('libelf@1.8.12') not in spec
- assert Spec('libdwarf') in spec
- assert Spec('libgoblin') not in spec
- assert Spec('mpileaks') in spec
+ spec = Spec("mpileaks ^mpi ^libelf@1.8.11 ^libdwarf")
+ assert Spec("mpi") in spec
+ assert Spec("libelf") in spec
+ assert Spec("libelf@1.8.11") in spec
+ assert Spec("libelf@1.8.12") not in spec
+ assert Spec("libdwarf") in spec
+ assert Spec("libgoblin") not in spec
+ assert Spec("mpileaks") in spec
def test_copy_simple(self):
- orig = Spec('mpileaks')
+ orig = Spec("mpileaks")
copy = orig.copy()
check_links(copy)
@@ -597,7 +598,7 @@ class TestSpecDag(object):
assert not orig_ids.intersection(copy_ids)
def test_copy_normalized(self):
- orig = Spec('mpileaks')
+ orig = Spec("mpileaks")
orig.normalize()
copy = orig.copy()
check_links(copy)
@@ -611,7 +612,7 @@ class TestSpecDag(object):
assert not orig_ids.intersection(copy_ids)
def test_copy_concretized(self):
- orig = Spec('mpileaks')
+ orig = Spec("mpileaks")
orig.concretize()
copy = orig.copy()
@@ -631,17 +632,17 @@ class TestSpecDag(object):
"""Check that copying dependencies using id(node) as a fast identifier of the
node works when the spec is wrapped in a SpecBuildInterface object.
"""
- s = Spec('mpileaks').concretized()
+ s = Spec("mpileaks").concretized()
c0 = s.copy()
assert c0 == s
# Single indirection
- c1 = s['mpileaks'].copy()
+ c1 = s["mpileaks"].copy()
assert c0 == c1 == s
# Double indirection
- c2 = s['mpileaks']['mpileaks'].copy()
+ c2 = s["mpileaks"]["mpileaks"].copy()
assert c0 == c1 == c2 == s
"""
@@ -671,70 +672,88 @@ class TestSpecDag(object):
"""
def test_deptype_traversal(self):
- dag = Spec('dtuse')
+ dag = Spec("dtuse")
dag.normalize()
- names = ['dtuse', 'dttop', 'dtbuild1', 'dtbuild2', 'dtlink2',
- 'dtlink1', 'dtlink3', 'dtlink4']
-
- traversal = dag.traverse(deptype=('build', 'link'))
+ names = [
+ "dtuse",
+ "dttop",
+ "dtbuild1",
+ "dtbuild2",
+ "dtlink2",
+ "dtlink1",
+ "dtlink3",
+ "dtlink4",
+ ]
+
+ traversal = dag.traverse(deptype=("build", "link"))
assert [x.name for x in traversal] == names
def test_deptype_traversal_with_builddeps(self):
- dag = Spec('dttop')
+ dag = Spec("dttop")
dag.normalize()
- names = ['dttop', 'dtbuild1', 'dtbuild2', 'dtlink2',
- 'dtlink1', 'dtlink3', 'dtlink4']
+ names = ["dttop", "dtbuild1", "dtbuild2", "dtlink2", "dtlink1", "dtlink3", "dtlink4"]
- traversal = dag.traverse(deptype=('build', 'link'))
+ traversal = dag.traverse(deptype=("build", "link"))
assert [x.name for x in traversal] == names
def test_deptype_traversal_full(self):
- dag = Spec('dttop')
+ dag = Spec("dttop")
dag.normalize()
- names = ['dttop', 'dtbuild1', 'dtbuild2', 'dtlink2', 'dtrun2',
- 'dtlink1', 'dtlink3', 'dtlink4', 'dtrun1', 'dtlink5',
- 'dtrun3', 'dtbuild3']
+ names = [
+ "dttop",
+ "dtbuild1",
+ "dtbuild2",
+ "dtlink2",
+ "dtrun2",
+ "dtlink1",
+ "dtlink3",
+ "dtlink4",
+ "dtrun1",
+ "dtlink5",
+ "dtrun3",
+ "dtbuild3",
+ ]
traversal = dag.traverse(deptype=all)
assert [x.name for x in traversal] == names
def test_deptype_traversal_run(self):
- dag = Spec('dttop')
+ dag = Spec("dttop")
dag.normalize()
- names = ['dttop', 'dtrun1', 'dtrun3']
+ names = ["dttop", "dtrun1", "dtrun3"]
- traversal = dag.traverse(deptype='run')
+ traversal = dag.traverse(deptype="run")
assert [x.name for x in traversal] == names
def test_hash_bits(self):
"""Ensure getting first n bits of a base32-encoded DAG hash works."""
# RFC 4648 base32 decode table
- b32 = dict((j, i) for i, j in enumerate('abcdefghijklmnopqrstuvwxyz'))
- b32.update(dict((j, i) for i, j in enumerate('234567', 26)))
+ b32 = dict((j, i) for i, j in enumerate("abcdefghijklmnopqrstuvwxyz"))
+ b32.update(dict((j, i) for i, j in enumerate("234567", 26)))
# some package hashes
tests = [
- '35orsd4cenv743hg4i5vxha2lzayycby',
- '6kfqtj7dap3773rxog6kkmoweix5gpwo',
- 'e6h6ff3uvmjbq3azik2ckr6ckwm3depv',
- 'snz2juf4ij7sv77cq3vs467q6acftmur',
- '4eg47oedi5bbkhpoxw26v3oe6vamkfd7',
- 'vrwabwj6umeb5vjw6flx2rnft3j457rw']
+ "35orsd4cenv743hg4i5vxha2lzayycby",
+ "6kfqtj7dap3773rxog6kkmoweix5gpwo",
+ "e6h6ff3uvmjbq3azik2ckr6ckwm3depv",
+ "snz2juf4ij7sv77cq3vs467q6acftmur",
+ "4eg47oedi5bbkhpoxw26v3oe6vamkfd7",
+ "vrwabwj6umeb5vjw6flx2rnft3j457rw",
+ ]
for test_hash in tests:
# string containing raw bits of hash ('1' and '0')
- expected = ''.join([format(b32[c], '#07b').replace('0b', '')
- for c in test_hash])
+ expected = "".join([format(b32[c], "#07b").replace("0b", "") for c in test_hash])
for bits in (1, 2, 3, 4, 7, 8, 9, 16, 64, 117, 128, 160):
actual_int = hashutil.base32_prefix_bits(test_hash, bits)
fmt = "#0%sb" % (bits + 2)
- actual = format(actual_int, fmt).replace('0b', '')
+ actual = format(actual_int, fmt).replace("0b", "")
assert expected[:bits] == actual
@@ -747,95 +766,58 @@ class TestSpecDag(object):
def test_traversal_directions(self):
"""Make sure child and parent traversals of specs work."""
# Mock spec - d is used for a diamond dependency
- spec = Spec.from_literal({
- 'a': {
- 'b': {
- 'c': {'d': None},
- 'e': None
- },
- 'f': {
- 'g': {'d': None}
- }
- }
- })
+ spec = Spec.from_literal(
+ {"a": {"b": {"c": {"d": None}, "e": None}, "f": {"g": {"d": None}}}}
+ )
- assert (
- ['a', 'b', 'c', 'd', 'e', 'f', 'g'] ==
- [s.name for s in spec.traverse(direction='children')])
+ assert ["a", "b", "c", "d", "e", "f", "g"] == [
+ s.name for s in spec.traverse(direction="children")
+ ]
- assert (
- ['g', 'f', 'a'] ==
- [s.name for s in spec['g'].traverse(direction='parents')])
+ assert ["g", "f", "a"] == [s.name for s in spec["g"].traverse(direction="parents")]
- assert (
- ['d', 'c', 'b', 'a', 'g', 'f'] ==
- [s.name for s in spec['d'].traverse(direction='parents')])
+ assert ["d", "c", "b", "a", "g", "f"] == [
+ s.name for s in spec["d"].traverse(direction="parents")
+ ]
def test_edge_traversals(self):
"""Make sure child and parent traversals of specs work."""
# Mock spec - d is used for a diamond dependency
- spec = Spec.from_literal({
- 'a': {
- 'b': {
- 'c': {'d': None},
- 'e': None
- },
- 'f': {
- 'g': {'d': None}
- }
- }
- })
+ spec = Spec.from_literal(
+ {"a": {"b": {"c": {"d": None}, "e": None}, "f": {"g": {"d": None}}}}
+ )
- assert (
- ['a', 'b', 'c', 'd', 'e', 'f', 'g'] ==
- [s.name for s in spec.traverse(direction='children')])
+ assert ["a", "b", "c", "d", "e", "f", "g"] == [
+ s.name for s in spec.traverse(direction="children")
+ ]
- assert (
- ['g', 'f', 'a'] ==
- [s.name for s in spec['g'].traverse(direction='parents')])
+ assert ["g", "f", "a"] == [s.name for s in spec["g"].traverse(direction="parents")]
- assert (
- ['d', 'c', 'b', 'a', 'g', 'f'] ==
- [s.name for s in spec['d'].traverse(direction='parents')])
+ assert ["d", "c", "b", "a", "g", "f"] == [
+ s.name for s in spec["d"].traverse(direction="parents")
+ ]
def test_copy_dependencies(self):
- s1 = Spec('mpileaks ^mpich2@1.1')
+ s1 = Spec("mpileaks ^mpich2@1.1")
s2 = s1.copy()
- assert '^mpich2@1.1' in s2
- assert '^mpich2' in s2
+ assert "^mpich2@1.1" in s2
+ assert "^mpich2" in s2
def test_construct_spec_with_deptypes(self):
"""Ensure that it is possible to construct a spec with explicit
- dependency types."""
- s = Spec.from_literal({
- 'a': {
- 'b': {'c:build': None},
- 'd': {
- 'e:build,link': {'f:run': None}
- }
- }
- })
-
- assert s['b'].edges_to_dependencies(
- name='c'
- )[0].deptypes == ('build',)
- assert s['d'].edges_to_dependencies(
- name='e'
- )[0].deptypes == ('build', 'link')
- assert s['e'].edges_to_dependencies(
- name='f'
- )[0].deptypes == ('run',)
-
- assert s['c'].edges_from_dependents(
- name='b'
- )[0].deptypes == ('build',)
- assert s['e'].edges_from_dependents(
- name='d'
- )[0].deptypes == ('build', 'link')
- assert s['f'].edges_from_dependents(
- name='e'
- )[0].deptypes == ('run',)
+ dependency types."""
+ s = Spec.from_literal(
+ {"a": {"b": {"c:build": None}, "d": {"e:build,link": {"f:run": None}}}}
+ )
+
+ assert s["b"].edges_to_dependencies(name="c")[0].deptypes == ("build",)
+ assert s["d"].edges_to_dependencies(name="e")[0].deptypes == ("build", "link")
+ assert s["e"].edges_to_dependencies(name="f")[0].deptypes == ("run",)
+
+ assert s["c"].edges_from_dependents(name="b")[0].deptypes == ("build",)
+ assert s["e"].edges_from_dependents(name="d")[0].deptypes == ("build", "link")
+ assert s["f"].edges_from_dependents(name="e")[0].deptypes == ("run",)
def check_diamond_deptypes(self, spec):
"""Validate deptypes in dt-diamond spec.
@@ -844,42 +826,41 @@ class TestSpecDag(object):
depend on the same dependency in different ways.
"""
- assert spec['dt-diamond'].edges_to_dependencies(
- name='dt-diamond-left'
- )[0].deptypes == ('build', 'link')
+ assert spec["dt-diamond"].edges_to_dependencies(name="dt-diamond-left")[0].deptypes == (
+ "build",
+ "link",
+ )
- assert spec['dt-diamond'].edges_to_dependencies(
- name='dt-diamond-right'
- )[0].deptypes == ('build', 'link')
+ assert spec["dt-diamond"].edges_to_dependencies(name="dt-diamond-right")[0].deptypes == (
+ "build",
+ "link",
+ )
- assert spec['dt-diamond-left'].edges_to_dependencies(
- name='dt-diamond-bottom'
- )[0].deptypes == ('build',)
+ assert spec["dt-diamond-left"].edges_to_dependencies(name="dt-diamond-bottom")[
+ 0
+ ].deptypes == ("build",)
- assert spec['dt-diamond-right'].edges_to_dependencies(
- name='dt-diamond-bottom'
- )[0].deptypes == ('build', 'link', 'run')
+ assert spec["dt-diamond-right"].edges_to_dependencies(name="dt-diamond-bottom")[
+ 0
+ ].deptypes == ("build", "link", "run")
def check_diamond_normalized_dag(self, spec):
- dag = Spec.from_literal({
- 'dt-diamond': {
- 'dt-diamond-left:build,link': {
- 'dt-diamond-bottom:build': None
- },
- 'dt-diamond-right:build,link': {
- 'dt-diamond-bottom:build,link,run': None
- },
-
+ dag = Spec.from_literal(
+ {
+ "dt-diamond": {
+ "dt-diamond-left:build,link": {"dt-diamond-bottom:build": None},
+ "dt-diamond-right:build,link": {"dt-diamond-bottom:build,link,run": None},
+ }
}
- })
+ )
assert spec.eq_dag(dag)
def test_normalize_diamond_deptypes(self):
"""Ensure that dependency types are preserved even if the same thing is
- depended on in two different ways."""
- s = Spec('dt-diamond')
+ depended on in two different ways."""
+ s = Spec("dt-diamond")
s.normalize()
self.check_diamond_deptypes(s)
@@ -887,13 +868,13 @@ class TestSpecDag(object):
def test_concretize_deptypes(self):
"""Ensure that dependency types are preserved after concretization."""
- s = Spec('dt-diamond')
+ s = Spec("dt-diamond")
s.concretize()
self.check_diamond_deptypes(s)
def test_copy_deptypes(self):
"""Ensure that dependency types are preserved by spec copy."""
- s1 = Spec('dt-diamond')
+ s1 = Spec("dt-diamond")
s1.normalize()
self.check_diamond_deptypes(s1)
self.check_diamond_normalized_dag(s1)
@@ -902,7 +883,7 @@ class TestSpecDag(object):
self.check_diamond_normalized_dag(s2)
self.check_diamond_deptypes(s2)
- s3 = Spec('dt-diamond')
+ s3 = Spec("dt-diamond")
s3.concretize()
self.check_diamond_deptypes(s3)
@@ -910,45 +891,45 @@ class TestSpecDag(object):
self.check_diamond_deptypes(s4)
def test_getitem_query(self):
- s = Spec('mpileaks')
+ s = Spec("mpileaks")
s.concretize()
# Check a query to a non-virtual package
- a = s['callpath']
+ a = s["callpath"]
query = a.last_query
- assert query.name == 'callpath'
+ assert query.name == "callpath"
assert len(query.extra_parameters) == 0
assert not query.isvirtual
# Check a query to a virtual package
- a = s['mpi']
+ a = s["mpi"]
query = a.last_query
- assert query.name == 'mpi'
+ assert query.name == "mpi"
assert len(query.extra_parameters) == 0
assert query.isvirtual
# Check a query to a virtual package with
# extra parameters after query
- a = s['mpi:cxx,fortran']
+ a = s["mpi:cxx,fortran"]
query = a.last_query
- assert query.name == 'mpi'
+ assert query.name == "mpi"
assert len(query.extra_parameters) == 2
- assert 'cxx' in query.extra_parameters
- assert 'fortran' in query.extra_parameters
+ assert "cxx" in query.extra_parameters
+ assert "fortran" in query.extra_parameters
assert query.isvirtual
def test_getitem_exceptional_paths(self):
- s = Spec('mpileaks')
+ s = Spec("mpileaks")
s.concretize()
# Needed to get a proxy object
- q = s['mpileaks']
+ q = s["mpileaks"]
# Test that the attribute is read-only
with pytest.raises(AttributeError):
- q.libs = 'foo'
+ q.libs = "foo"
with pytest.raises(AttributeError):
q.libs
@@ -956,7 +937,7 @@ class TestSpecDag(object):
def test_canonical_deptype(self):
# special values
assert canonical_deptype(all) == all_deptypes
- assert canonical_deptype('all') == all_deptypes
+ assert canonical_deptype("all") == all_deptypes
with pytest.raises(ValueError):
canonical_deptype(None)
@@ -968,67 +949,55 @@ class TestSpecDag(object):
assert canonical_deptype(v) == (v,)
# tuples
- assert canonical_deptype(('build',)) == ('build',)
- assert canonical_deptype(
- ('build', 'link', 'run')) == ('build', 'link', 'run')
- assert canonical_deptype(
- ('build', 'link')) == ('build', 'link')
- assert canonical_deptype(
- ('build', 'run')) == ('build', 'run')
+ assert canonical_deptype(("build",)) == ("build",)
+ assert canonical_deptype(("build", "link", "run")) == ("build", "link", "run")
+ assert canonical_deptype(("build", "link")) == ("build", "link")
+ assert canonical_deptype(("build", "run")) == ("build", "run")
# lists
- assert canonical_deptype(
- ['build', 'link', 'run']) == ('build', 'link', 'run')
- assert canonical_deptype(
- ['build', 'link']) == ('build', 'link')
- assert canonical_deptype(
- ['build', 'run']) == ('build', 'run')
+ assert canonical_deptype(["build", "link", "run"]) == ("build", "link", "run")
+ assert canonical_deptype(["build", "link"]) == ("build", "link")
+ assert canonical_deptype(["build", "run"]) == ("build", "run")
# sorting
- assert canonical_deptype(
- ('run', 'build', 'link')) == ('build', 'link', 'run')
- assert canonical_deptype(
- ('run', 'link', 'build')) == ('build', 'link', 'run')
- assert canonical_deptype(
- ('run', 'link')) == ('link', 'run')
- assert canonical_deptype(
- ('link', 'build')) == ('build', 'link')
+ assert canonical_deptype(("run", "build", "link")) == ("build", "link", "run")
+ assert canonical_deptype(("run", "link", "build")) == ("build", "link", "run")
+ assert canonical_deptype(("run", "link")) == ("link", "run")
+ assert canonical_deptype(("link", "build")) == ("build", "link")
# can't put 'all' in tuple or list
with pytest.raises(ValueError):
- canonical_deptype(['all'])
+ canonical_deptype(["all"])
with pytest.raises(ValueError):
- canonical_deptype(('all',))
+ canonical_deptype(("all",))
# invalid values
with pytest.raises(ValueError):
- canonical_deptype('foo')
+ canonical_deptype("foo")
with pytest.raises(ValueError):
- canonical_deptype(('foo', 'bar'))
+ canonical_deptype(("foo", "bar"))
with pytest.raises(ValueError):
- canonical_deptype(('foo',))
+ canonical_deptype(("foo",))
def test_invalid_literal_spec(self):
# Can't give type 'build' to a top-level spec
with pytest.raises(spack.spec.SpecParseError):
- Spec.from_literal({'foo:build': None})
+ Spec.from_literal({"foo:build": None})
# Can't use more than one ':' separator
with pytest.raises(KeyError):
- Spec.from_literal({'foo': {'bar:build:link': None}})
+ Spec.from_literal({"foo": {"bar:build:link": None}})
def test_spec_tree_respect_deptypes(self):
# Version-test-root uses version-test-pkg as a build dependency
- s = Spec('version-test-root').concretized()
- out = s.tree(deptypes='all')
- assert 'version-test-pkg' in out
- out = s.tree(deptypes=('link', 'run'))
- assert 'version-test-pkg' not in out
+ s = Spec("version-test-root").concretized()
+ out = s.tree(deptypes="all")
+ assert "version-test-pkg" in out
+ out = s.tree(deptypes=("link", "run"))
+ assert "version-test-pkg" not in out
-def test_synthetic_construction_of_split_dependencies_from_same_package(
- mock_packages, config
-):
+def test_synthetic_construction_of_split_dependencies_from_same_package(mock_packages, config):
# Construct in a synthetic way (i.e. without using the solver)
# the following spec:
#
@@ -1038,20 +1007,20 @@ def test_synthetic_construction_of_split_dependencies_from_same_package(
#
# To demonstrate that a spec can now hold two direct
# dependencies from the same package
- root = Spec('b').concretized()
- link_run_spec = Spec('c@1.0').concretized()
- build_spec = Spec('c@2.0').concretized()
+ root = Spec("b").concretized()
+ link_run_spec = Spec("c@1.0").concretized()
+ build_spec = Spec("c@2.0").concretized()
- root.add_dependency_edge(link_run_spec, deptype='link')
- root.add_dependency_edge(link_run_spec, deptype='run')
- root.add_dependency_edge(build_spec, deptype='build')
+ root.add_dependency_edge(link_run_spec, deptype="link")
+ root.add_dependency_edge(link_run_spec, deptype="run")
+ root.add_dependency_edge(build_spec, deptype="build")
# Check dependencies from the perspective of root
assert len(root.dependencies()) == 2
- assert all(x.name == 'c' for x in root.dependencies())
+ assert all(x.name == "c" for x in root.dependencies())
- assert '@2.0' in root.dependencies(name='c', deptype='build')[0]
- assert '@1.0' in root.dependencies(name='c', deptype=('link', 'run'))[0]
+ assert "@2.0" in root.dependencies(name="c", deptype="build")[0]
+ assert "@1.0" in root.dependencies(name="c", deptype=("link", "run"))[0]
# Check parent from the perspective of the dependencies
assert len(build_spec.dependents()) == 1
@@ -1067,14 +1036,14 @@ def test_synthetic_construction_bootstrapping(mock_packages, config):
# | build
# b@1.0
#
- root = Spec('b@2.0').concretized()
- bootstrap = Spec('b@1.0').concretized()
+ root = Spec("b@2.0").concretized()
+ bootstrap = Spec("b@1.0").concretized()
- root.add_dependency_edge(bootstrap, deptype='build')
+ root.add_dependency_edge(bootstrap, deptype="build")
assert len(root.dependencies()) == 1
- assert root.dependencies()[0].name == 'b'
- assert root.name == 'b'
+ assert root.dependencies()[0].name == "b"
+ assert root.name == "b"
def test_addition_of_different_deptypes_in_multiple_calls(mock_packages, config):
@@ -1085,10 +1054,10 @@ def test_addition_of_different_deptypes_in_multiple_calls(mock_packages, config)
# b@1.0
#
# with three calls and check we always have a single edge
- root = Spec('b@2.0').concretized()
- bootstrap = Spec('b@1.0').concretized()
+ root = Spec("b@2.0").concretized()
+ bootstrap = Spec("b@1.0").concretized()
- for current_deptype in ('build', 'link', 'run'):
+ for current_deptype in ("build", "link", "run"):
root.add_dependency_edge(bootstrap, deptype=current_deptype)
# Check edges in dependencies
@@ -1106,16 +1075,15 @@ def test_addition_of_different_deptypes_in_multiple_calls(mock_packages, config)
assert id(backward_edge.spec) == id(bootstrap)
-@pytest.mark.parametrize('c1_deptypes,c2_deptypes', [
- ('link', ('build', 'link')),
- (('link', 'run'), ('build', 'link'))
-])
+@pytest.mark.parametrize(
+ "c1_deptypes,c2_deptypes", [("link", ("build", "link")), (("link", "run"), ("build", "link"))]
+)
def test_adding_same_deptype_with_the_same_name_raises(
- mock_packages, config, c1_deptypes, c2_deptypes
+ mock_packages, config, c1_deptypes, c2_deptypes
):
- p = Spec('b@2.0').concretized()
- c1 = Spec('b@1.0').concretized()
- c2 = Spec('b@2.0').concretized()
+ p = Spec("b@2.0").concretized()
+ c1 = Spec("b@1.0").concretized()
+ c2 = Spec("b@2.0").concretized()
p.add_dependency_edge(c1, deptype=c1_deptypes)
with pytest.raises(spack.error.SpackError):