diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 99fc2d3ea47cc913159434c75e913e3061f84cdf..108e7717481133b3a6dd7ed4b61f60f9dc69c6e8 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -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):
diff --git a/lib/spack/spack/test/spec_syntax.py b/lib/spack/spack/test/spec_syntax.py
index 3079288c77c3a3d12b6c19542fda83c1e756f0c0..d4eb9e057f6fba76a57406af8d0b0df66b299b84 100644
--- a/lib/spack/spack/test/spec_syntax.py
+++ b/lib/spack/spack/test/spec_syntax.py
@@ -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.