Factor out canonical_deptype function, cleanup spec.py

This commit is contained in:
Todd Gamblin 2016-09-27 09:28:22 -04:00
parent cd960caf8d
commit 43ca805248
2 changed files with 100 additions and 41 deletions

View File

@ -123,6 +123,39 @@
from spack.version import *
from spack.provider_index import ProviderIndex
__all__ = [
'Spec',
'alldeps',
'nolink',
'nobuild',
'canonical_deptype',
'validate_deptype',
'parse',
'parse_anonymous_spec',
'SpecError',
'SpecParseError',
'DuplicateDependencyError',
'DuplicateVariantError',
'DuplicateCompilerSpecError',
'UnsupportedCompilerError',
'UnknownVariantError',
'DuplicateArchitectureError',
'InconsistentSpecError',
'InvalidDependencyError',
'InvalidDependencyTypeError',
'NoProviderError',
'MultipleProviderError',
'UnsatisfiableSpecError',
'UnsatisfiableSpecNameError',
'UnsatisfiableVersionSpecError',
'UnsatisfiableCompilerSpecError',
'UnsatisfiableVariantSpecError',
'UnsatisfiableCompilerFlagSpecError',
'UnsatisfiableArchitectureSpecError',
'UnsatisfiableProviderSpecError',
'UnsatisfiableDependencySpecError',
'SpackYAMLError',
'AmbiguousHashError']
# Valid pattern for an identifier in Spack
identifier_re = r'\w[\w-]*'
@ -156,12 +189,45 @@
# Special types of dependencies.
alldeps = ('build', 'link', 'run')
nolink = ('build', 'run')
nolink = ('build', 'run')
nobuild = ('link', 'run')
norun = ('link', 'build')
special_types = {
'alldeps': alldeps,
'nolink': nolink,
'nobuild': nobuild,
'norun': norun,
}
legal_deps = tuple(special_types) + alldeps
def validate_deptype(deptype):
if isinstance(deptype, str):
if deptype not in legal_deps:
raise InvalidDependencyTypeError(
"Invalid dependency type: %s" % deptype)
elif isinstance(deptype, (list, tuple)):
for t in deptype:
validate_deptype(t)
elif deptype is None:
raise InvalidDependencyTypeError("deptype cannot be None!")
def canonical_deptype(deptype):
if deptype is None:
return alldeps
elif isinstance(deptype, str):
return special_types.get(deptype, (deptype,))
elif isinstance(deptype, (tuple, list)):
return (sum((canonical_deptype(d) for d in deptype), ()))
return deptype
def colorize_spec(spec):
"""Returns a spec colorized according to the colors specified in
@ -542,17 +608,8 @@ def get_dependency(self, name):
raise InvalidDependencyException(
self.name + " does not depend on " + comma_or(name))
def _deptype_norm(self, deptype):
if deptype is None:
return alldeps
# Force deptype to be a set object so that we can do set intersections.
if isinstance(deptype, str):
# Support special deptypes.
return special_types.get(deptype, (deptype,))
return deptype
def _find_deps(self, where, deptype):
deptype = self._deptype_norm(deptype)
deptype = canonical_deptype(deptype)
return [dep.spec
for dep in where.values()
@ -565,7 +622,7 @@ def dependents(self, deptype=None):
return self._find_deps(self._dependents, deptype)
def _find_deps_dict(self, where, deptype):
deptype = self._deptype_norm(deptype)
deptype = canonical_deptype(deptype)
return dict((dep.spec.name, dep)
for dep in where.values()
@ -2718,6 +2775,10 @@ class InvalidDependencyError(SpecError):
of the package."""
class InvalidDependencyTypeError(SpecError):
"""Raised when a dependency type is not a legal Spack dep type."""
class NoProviderError(SpecError):
"""Raised when there is no package that provides a particular
virtual dependency.
@ -2804,8 +2865,6 @@ def __init__(self, provided, required):
# TODO: get rid of this and be more specific about particular incompatible
# dep constraints
class UnsatisfiableDependencySpecError(UnsatisfiableSpecError):
"""Raised when some dependency of constrained specs are incompatible"""
def __init__(self, provided, required):

View File

@ -24,34 +24,34 @@
##############################################################################
import unittest
import spack.spec
import spack.spec as sp
from spack.parse import Token
from spack.spec import *
# Sample output for a complex lexing.
complex_lex = [Token(ID, 'mvapich_foo'),
Token(DEP),
Token(ID, '_openmpi'),
Token(AT),
Token(ID, '1.2'),
Token(COLON),
Token(ID, '1.4'),
Token(COMMA),
Token(ID, '1.6'),
Token(PCT),
Token(ID, 'intel'),
Token(AT),
Token(ID, '12.1'),
Token(COLON),
Token(ID, '12.6'),
Token(ON),
Token(ID, 'debug'),
Token(OFF),
Token(ID, 'qt_4'),
Token(DEP),
Token(ID, 'stackwalker'),
Token(AT),
Token(ID, '8.1_1e')]
complex_lex = [Token(sp.ID, 'mvapich_foo'),
Token(sp.DEP),
Token(sp.ID, '_openmpi'),
Token(sp.AT),
Token(sp.ID, '1.2'),
Token(sp.COLON),
Token(sp.ID, '1.4'),
Token(sp.COMMA),
Token(sp.ID, '1.6'),
Token(sp.PCT),
Token(sp.ID, 'intel'),
Token(sp.AT),
Token(sp.ID, '12.1'),
Token(sp.COLON),
Token(sp.ID, '12.6'),
Token(sp.ON),
Token(sp.ID, 'debug'),
Token(sp.OFF),
Token(sp.ID, 'qt_4'),
Token(sp.DEP),
Token(sp.ID, 'stackwalker'),
Token(sp.AT),
Token(sp.ID, '8.1_1e')]
class SpecSyntaxTest(unittest.TestCase):
@ -74,16 +74,16 @@ def check_parse(self, expected, spec=None, remove_arch=True):
"""
if spec is None:
spec = expected
output = spack.spec.parse(spec)
output = sp.parse(spec)
parsed = (" ".join(str(spec) for spec in output))
self.assertEqual(expected, parsed)
def check_lex(self, tokens, spec):
"""Check that the provided spec parses to the provided token list."""
lex_output = SpecLexer().lex(spec)
lex_output = sp.SpecLexer().lex(spec)
for tok, spec_tok in zip(tokens, lex_output):
if tok.type == ID:
if tok.type == sp.ID:
self.assertEqual(tok, spec_tok)
else:
# Only check the type for non-identifiers.