Local specs now called "anonymous specs"
- anonymous specs have no name - "local spec" came from these first being used in multimethods, i.e. "name of the local Package" - not the most intuitive name.
This commit is contained in:
parent
93e288859a
commit
4c9c7ab65f
@ -26,7 +26,7 @@
|
|||||||
import spack.architecture
|
import spack.architecture
|
||||||
import spack.error
|
import spack.error
|
||||||
from spack.util.lang import *
|
from spack.util.lang import *
|
||||||
from spack.spec import parse_local_spec, Spec
|
from spack.spec import parse_anonymous_spec, Spec
|
||||||
|
|
||||||
|
|
||||||
class SpecMultiMethod(object):
|
class SpecMultiMethod(object):
|
||||||
@ -179,7 +179,7 @@ def install(self, prefix):
|
|||||||
class when(object):
|
class when(object):
|
||||||
def __init__(self, spec):
|
def __init__(self, spec):
|
||||||
pkg = get_calling_package_name()
|
pkg = get_calling_package_name()
|
||||||
self.spec = parse_local_spec(spec, pkg)
|
self.spec = parse_anonymous_spec(spec, pkg)
|
||||||
|
|
||||||
def __call__(self, method):
|
def __call__(self, method):
|
||||||
# Get the first definition of the method in the calling scope
|
# Get the first definition of the method in the calling scope
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
instances = {}
|
instances = {}
|
||||||
|
|
||||||
|
|
||||||
def autospec(function):
|
def _autospec(function):
|
||||||
"""Decorator that automatically converts the argument of a single-arg
|
"""Decorator that automatically converts the argument of a single-arg
|
||||||
function to a Spec."""
|
function to a Spec."""
|
||||||
def converter(arg):
|
def converter(arg):
|
||||||
@ -147,7 +147,7 @@ def satisfies(self, other):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@autospec
|
@_autospec
|
||||||
def get(spec):
|
def get(spec):
|
||||||
if spec.virtual:
|
if spec.virtual:
|
||||||
raise UnknownPackageError(spec.name)
|
raise UnknownPackageError(spec.name)
|
||||||
@ -159,12 +159,12 @@ def get(spec):
|
|||||||
return instances[spec.name]
|
return instances[spec.name]
|
||||||
|
|
||||||
|
|
||||||
@autospec
|
@_autospec
|
||||||
def get_installed(spec):
|
def get_installed(spec):
|
||||||
return [s for s in installed_package_specs() if s.satisfies(spec)]
|
return [s for s in installed_package_specs() if s.satisfies(spec)]
|
||||||
|
|
||||||
|
|
||||||
@autospec
|
@_autospec
|
||||||
def providers_for(vpkg_spec):
|
def providers_for(vpkg_spec):
|
||||||
if not hasattr(providers_for, 'index'):
|
if not hasattr(providers_for, 'index'):
|
||||||
providers_for.index = ProviderIndex(all_package_names())
|
providers_for.index = ProviderIndex(all_package_names())
|
||||||
|
@ -51,7 +51,7 @@ class Mpileaks(Package):
|
|||||||
import spack
|
import spack
|
||||||
import spack.spec
|
import spack.spec
|
||||||
import spack.error
|
import spack.error
|
||||||
from spack.spec import Spec, parse_local_spec
|
from spack.spec import Spec, parse_anonymous_spec
|
||||||
from spack.packages import packages_module
|
from spack.packages import packages_module
|
||||||
from spack.util.lang import *
|
from spack.util.lang import *
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ def provides(*specs, **kwargs):
|
|||||||
"""
|
"""
|
||||||
pkg = get_calling_package_name()
|
pkg = get_calling_package_name()
|
||||||
spec_string = kwargs.get('when', pkg)
|
spec_string = kwargs.get('when', pkg)
|
||||||
provider_spec = parse_local_spec(spec_string, pkg)
|
provider_spec = parse_anonymous_spec(spec_string, pkg)
|
||||||
|
|
||||||
provided = caller_locals().setdefault("provided", {})
|
provided = caller_locals().setdefault("provided", {})
|
||||||
for string in specs:
|
for string in specs:
|
||||||
|
@ -739,6 +739,8 @@ def validate_names(self):
|
|||||||
|
|
||||||
|
|
||||||
def constrain(self, other, **kwargs):
|
def constrain(self, other, **kwargs):
|
||||||
|
other = self._autospec(other)
|
||||||
|
|
||||||
if not self.name == other.name:
|
if not self.name == other.name:
|
||||||
raise UnsatisfiableSpecNameError(self.name, other.name)
|
raise UnsatisfiableSpecNameError(self.name, other.name)
|
||||||
|
|
||||||
@ -766,10 +768,10 @@ def constrain(self, other, **kwargs):
|
|||||||
self.architecture = self.architecture or other.architecture
|
self.architecture = self.architecture or other.architecture
|
||||||
|
|
||||||
if kwargs.get('deps', True):
|
if kwargs.get('deps', True):
|
||||||
self.constrain_dependencies(other)
|
self._constrain_dependencies(other)
|
||||||
|
|
||||||
|
|
||||||
def constrain_dependencies(self, other):
|
def _constrain_dependencies(self, other):
|
||||||
"""Apply constraints of other spec's dependencies to this spec."""
|
"""Apply constraints of other spec's dependencies to this spec."""
|
||||||
if not self.dependencies or not other.dependencies:
|
if not self.dependencies or not other.dependencies:
|
||||||
return
|
return
|
||||||
@ -806,9 +808,22 @@ def dep_difference(self, other):
|
|||||||
return mine
|
return mine
|
||||||
|
|
||||||
|
|
||||||
|
def _autospec(self, spec_like):
|
||||||
|
"""Used to convert arguments to specs. If spec_like is a spec, returns it.
|
||||||
|
If it's a string, tries to parse a string. If that fails, tries to parse
|
||||||
|
a local spec from it (i.e. name is assumed to be self's name).
|
||||||
|
"""
|
||||||
|
if isinstance(spec_like, spack.spec.Spec):
|
||||||
|
return spec_like
|
||||||
|
|
||||||
|
try:
|
||||||
|
return spack.spec.Spec(spec_like)
|
||||||
|
except SpecError:
|
||||||
|
return parse_anonymous_spec(spec_like, self.name)
|
||||||
|
|
||||||
|
|
||||||
def satisfies(self, other, **kwargs):
|
def satisfies(self, other, **kwargs):
|
||||||
if not isinstance(other, Spec):
|
other = self._autospec(other)
|
||||||
other = Spec(other)
|
|
||||||
|
|
||||||
# First thing we care about is whether the name matches
|
# First thing we care about is whether the name matches
|
||||||
if self.name != other.name:
|
if self.name != other.name:
|
||||||
@ -934,9 +949,7 @@ def __getitem__(self, name):
|
|||||||
def __contains__(self, spec):
|
def __contains__(self, spec):
|
||||||
"""True if this spec has any dependency that satisfies the supplied
|
"""True if this spec has any dependency that satisfies the supplied
|
||||||
spec."""
|
spec."""
|
||||||
if not isinstance(spec, Spec):
|
spec = self._autospec(spec)
|
||||||
spec = Spec(spec)
|
|
||||||
|
|
||||||
for s in self.preorder_traversal():
|
for s in self.preorder_traversal():
|
||||||
if s.satisfies(spec):
|
if s.satisfies(spec):
|
||||||
return True
|
return True
|
||||||
@ -1104,18 +1117,22 @@ def __init__(self):
|
|||||||
|
|
||||||
def do_parse(self):
|
def do_parse(self):
|
||||||
specs = []
|
specs = []
|
||||||
while self.next:
|
|
||||||
if self.accept(ID):
|
|
||||||
specs.append(self.spec())
|
|
||||||
|
|
||||||
elif self.accept(DEP):
|
try:
|
||||||
if not specs:
|
while self.next:
|
||||||
self.last_token_error("Dependency has no package")
|
if self.accept(ID):
|
||||||
self.expect(ID)
|
specs.append(self.spec())
|
||||||
specs[-1]._add_dependency(self.spec())
|
|
||||||
|
|
||||||
else:
|
elif self.accept(DEP):
|
||||||
self.unexpected_token()
|
if not specs:
|
||||||
|
self.last_token_error("Dependency has no package")
|
||||||
|
self.expect(ID)
|
||||||
|
specs[-1]._add_dependency(self.spec())
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.unexpected_token()
|
||||||
|
except spack.parse.ParseError, e:
|
||||||
|
raise SpecParseError(e)
|
||||||
|
|
||||||
return specs
|
return specs
|
||||||
|
|
||||||
@ -1238,7 +1255,7 @@ def parse(string):
|
|||||||
return SpecParser().parse(string)
|
return SpecParser().parse(string)
|
||||||
|
|
||||||
|
|
||||||
def parse_local_spec(spec_like, pkg_name):
|
def parse_anonymous_spec(spec_like, pkg_name):
|
||||||
"""Allow the user to omit the package name part of a spec if they
|
"""Allow the user to omit the package name part of a spec if they
|
||||||
know what it has to be already.
|
know what it has to be already.
|
||||||
|
|
||||||
@ -1251,19 +1268,19 @@ def parse_local_spec(spec_like, pkg_name):
|
|||||||
|
|
||||||
if isinstance(spec_like, str):
|
if isinstance(spec_like, str):
|
||||||
try:
|
try:
|
||||||
local_spec = Spec(spec_like)
|
anon_spec = Spec(spec_like)
|
||||||
except spack.parse.ParseError:
|
except SpecParseError:
|
||||||
local_spec = Spec(pkg_name + spec_like)
|
anon_spec = Spec(pkg_name + spec_like)
|
||||||
if local_spec.name != pkg_name: raise ValueError(
|
if anon_spec.name != pkg_name: raise ValueError(
|
||||||
"Invalid spec for package %s: %s" % (pkg_name, spec_like))
|
"Invalid spec for package %s: %s" % (pkg_name, spec_like))
|
||||||
else:
|
else:
|
||||||
local_spec = spec_like
|
anon_spec = spec_like.copy()
|
||||||
|
|
||||||
if local_spec.name != pkg_name:
|
if anon_spec.name != pkg_name:
|
||||||
raise ValueError("Spec name '%s' must match package name '%s'"
|
raise ValueError("Spec name '%s' must match package name '%s'"
|
||||||
% (local_spec.name, pkg_name))
|
% (anon_spec.name, pkg_name))
|
||||||
|
|
||||||
return local_spec
|
return anon_spec
|
||||||
|
|
||||||
|
|
||||||
class SpecError(spack.error.SpackError):
|
class SpecError(spack.error.SpackError):
|
||||||
@ -1272,6 +1289,14 @@ def __init__(self, message):
|
|||||||
super(SpecError, self).__init__(message)
|
super(SpecError, self).__init__(message)
|
||||||
|
|
||||||
|
|
||||||
|
class SpecParseError(SpecError):
|
||||||
|
"""Wrapper for ParseError for when we're parsing specs."""
|
||||||
|
def __init__(self, parse_error):
|
||||||
|
super(SpecParseError, self).__init__(parse_error.message)
|
||||||
|
self.string = parse_error.string
|
||||||
|
self.pos = parse_error.pos
|
||||||
|
|
||||||
|
|
||||||
class DuplicateDependencyError(SpecError):
|
class DuplicateDependencyError(SpecError):
|
||||||
"""Raised when the same dependency occurs in a spec twice."""
|
"""Raised when the same dependency occurs in a spec twice."""
|
||||||
def __init__(self, message):
|
def __init__(self, message):
|
||||||
|
@ -9,25 +9,34 @@ class SpecSematicsTest(MockPackagesTest):
|
|||||||
# ================================================================================
|
# ================================================================================
|
||||||
# Utility functions to set everything up.
|
# Utility functions to set everything up.
|
||||||
# ================================================================================
|
# ================================================================================
|
||||||
def check_satisfies(self, lspec, rspec):
|
def check_satisfies(self, spec, anon_spec):
|
||||||
l, r = Spec(lspec), Spec(rspec)
|
left = Spec(spec)
|
||||||
self.assertTrue(l.satisfies(r))
|
right = parse_anonymous_spec(anon_spec, left.name)
|
||||||
self.assertTrue(r.satisfies(l))
|
|
||||||
|
self.assertTrue(left.satisfies(right))
|
||||||
|
self.assertTrue(left.satisfies(anon_spec))
|
||||||
|
self.assertTrue(right.satisfies(left))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
l.constrain(r)
|
left.copy().constrain(right)
|
||||||
r.constrain(l)
|
left.copy().constrain(anon_spec)
|
||||||
|
right.copy().constrain(left)
|
||||||
except SpecError, e:
|
except SpecError, e:
|
||||||
self.fail("Got a SpecError in constrain! " + e.message)
|
self.fail("Got a SpecError in constrain! " + e.message)
|
||||||
|
|
||||||
|
|
||||||
def check_unsatisfiable(self, lspec, rspec):
|
def check_unsatisfiable(self, spec, anon_spec):
|
||||||
l, r = Spec(lspec), Spec(rspec)
|
left = Spec(spec)
|
||||||
self.assertFalse(l.satisfies(r))
|
right = parse_anonymous_spec(anon_spec, left.name)
|
||||||
self.assertFalse(r.satisfies(l))
|
|
||||||
|
|
||||||
self.assertRaises(UnsatisfiableSpecError, l.constrain, r)
|
self.assertFalse(left.satisfies(right))
|
||||||
self.assertRaises(UnsatisfiableSpecError, r.constrain, l)
|
self.assertFalse(left.satisfies(anon_spec))
|
||||||
|
|
||||||
|
self.assertFalse(right.satisfies(left))
|
||||||
|
|
||||||
|
self.assertRaises(UnsatisfiableSpecError, left.constrain, right)
|
||||||
|
self.assertRaises(UnsatisfiableSpecError, left.constrain, anon_spec)
|
||||||
|
self.assertRaises(UnsatisfiableSpecError, right.constrain, left)
|
||||||
|
|
||||||
|
|
||||||
def check_constrain(self, expected, constrained, constraint):
|
def check_constrain(self, expected, constrained, constraint):
|
||||||
@ -48,77 +57,77 @@ def check_invalid_constraint(self, constrained, constraint):
|
|||||||
# Satisfiability and constraints
|
# Satisfiability and constraints
|
||||||
# ================================================================================
|
# ================================================================================
|
||||||
def test_satisfies(self):
|
def test_satisfies(self):
|
||||||
self.check_satisfies('libelf@0.8.13', 'libelf@0:1')
|
self.check_satisfies('libelf@0.8.13', '@0:1')
|
||||||
self.check_satisfies('libdwarf^libelf@0.8.13', 'libdwarf^libelf@0:1')
|
self.check_satisfies('libdwarf^libelf@0.8.13', '^libelf@0:1')
|
||||||
|
|
||||||
|
|
||||||
def test_satisfies_compiler(self):
|
def test_satisfies_compiler(self):
|
||||||
self.check_satisfies('foo%gcc', 'foo%gcc')
|
self.check_satisfies('foo%gcc', '%gcc')
|
||||||
self.check_satisfies('foo%intel', 'foo%intel')
|
self.check_satisfies('foo%intel', '%intel')
|
||||||
self.check_unsatisfiable('foo%intel', 'foo%gcc')
|
self.check_unsatisfiable('foo%intel', '%gcc')
|
||||||
self.check_unsatisfiable('foo%intel', 'foo%pgi')
|
self.check_unsatisfiable('foo%intel', '%pgi')
|
||||||
|
|
||||||
|
|
||||||
def test_satisfies_compiler_version(self):
|
def test_satisfies_compiler_version(self):
|
||||||
self.check_satisfies('foo%gcc', 'foo%gcc@4.7.2')
|
self.check_satisfies('foo%gcc', '%gcc@4.7.2')
|
||||||
self.check_satisfies('foo%intel', 'foo%intel@4.7.2')
|
self.check_satisfies('foo%intel', '%intel@4.7.2')
|
||||||
|
|
||||||
self.check_satisfies('foo%pgi@4.5', 'foo%pgi@4.4:4.6')
|
self.check_satisfies('foo%pgi@4.5', '%pgi@4.4:4.6')
|
||||||
self.check_satisfies('foo@2.0%pgi@4.5', 'foo@1:3%pgi@4.4:4.6')
|
self.check_satisfies('foo@2.0%pgi@4.5', '@1:3%pgi@4.4:4.6')
|
||||||
|
|
||||||
self.check_unsatisfiable('foo%pgi@4.3', 'foo%pgi@4.4:4.6')
|
self.check_unsatisfiable('foo%pgi@4.3', '%pgi@4.4:4.6')
|
||||||
self.check_unsatisfiable('foo@4.0%pgi', 'foo@1:3%pgi')
|
self.check_unsatisfiable('foo@4.0%pgi', '@1:3%pgi')
|
||||||
self.check_unsatisfiable('foo@4.0%pgi@4.5', 'foo@1:3%pgi@4.4:4.6')
|
self.check_unsatisfiable('foo@4.0%pgi@4.5', '@1:3%pgi@4.4:4.6')
|
||||||
|
|
||||||
|
|
||||||
def test_satisfies_architecture(self):
|
def test_satisfies_architecture(self):
|
||||||
self.check_satisfies('foo=chaos_5_x86_64_ib', 'foo=chaos_5_x86_64_ib')
|
self.check_satisfies('foo=chaos_5_x86_64_ib', '=chaos_5_x86_64_ib')
|
||||||
self.check_satisfies('foo=bgqos_0', 'foo=bgqos_0')
|
self.check_satisfies('foo=bgqos_0', '=bgqos_0')
|
||||||
|
|
||||||
self.check_unsatisfiable('foo=bgqos_0', 'foo=chaos_5_x86_64_ib')
|
self.check_unsatisfiable('foo=bgqos_0', '=chaos_5_x86_64_ib')
|
||||||
self.check_unsatisfiable('foo=chaos_5_x86_64_ib', 'foo=bgqos_0')
|
self.check_unsatisfiable('foo=chaos_5_x86_64_ib', '=bgqos_0')
|
||||||
|
|
||||||
|
|
||||||
def test_satisfies_dependencies(self):
|
def test_satisfies_dependencies(self):
|
||||||
self.check_satisfies('mpileaks^mpich', 'mpileaks^mpich')
|
self.check_satisfies('mpileaks^mpich', '^mpich')
|
||||||
self.check_satisfies('mpileaks^zmpi', 'mpileaks^zmpi')
|
self.check_satisfies('mpileaks^zmpi', '^zmpi')
|
||||||
|
|
||||||
self.check_unsatisfiable('mpileaks^mpich', 'mpileaks^zmpi')
|
self.check_unsatisfiable('mpileaks^mpich', '^zmpi')
|
||||||
self.check_unsatisfiable('mpileaks^zmpi', 'mpileaks^mpich')
|
self.check_unsatisfiable('mpileaks^zmpi', '^mpich')
|
||||||
|
|
||||||
|
|
||||||
def test_satisfies_dependency_versions(self):
|
def test_satisfies_dependency_versions(self):
|
||||||
self.check_satisfies('mpileaks^mpich@2.0', 'mpileaks^mpich@1:3')
|
self.check_satisfies('mpileaks^mpich@2.0', '^mpich@1:3')
|
||||||
self.check_unsatisfiable('mpileaks^mpich@1.2', 'mpileaks^mpich@2.0')
|
self.check_unsatisfiable('mpileaks^mpich@1.2', '^mpich@2.0')
|
||||||
|
|
||||||
self.check_satisfies('mpileaks^mpich@2.0^callpath@1.5', 'mpileaks^mpich@1:3^callpath@1.4:1.6')
|
self.check_satisfies('mpileaks^mpich@2.0^callpath@1.5', '^mpich@1:3^callpath@1.4:1.6')
|
||||||
self.check_unsatisfiable('mpileaks^mpich@4.0^callpath@1.5', 'mpileaks^mpich@1:3^callpath@1.4:1.6')
|
self.check_unsatisfiable('mpileaks^mpich@4.0^callpath@1.5', '^mpich@1:3^callpath@1.4:1.6')
|
||||||
self.check_unsatisfiable('mpileaks^mpich@2.0^callpath@1.7', 'mpileaks^mpich@1:3^callpath@1.4:1.6')
|
self.check_unsatisfiable('mpileaks^mpich@2.0^callpath@1.7', '^mpich@1:3^callpath@1.4:1.6')
|
||||||
self.check_unsatisfiable('mpileaks^mpich@4.0^callpath@1.7', 'mpileaks^mpich@1:3^callpath@1.4:1.6')
|
self.check_unsatisfiable('mpileaks^mpich@4.0^callpath@1.7', '^mpich@1:3^callpath@1.4:1.6')
|
||||||
|
|
||||||
|
|
||||||
def test_satisfies_virtual_dependencies(self):
|
def test_satisfies_virtual_dependencies(self):
|
||||||
self.check_satisfies('mpileaks^mpi', 'mpileaks^mpi')
|
self.check_satisfies('mpileaks^mpi', '^mpi')
|
||||||
self.check_satisfies('mpileaks^mpi', 'mpileaks^mpich')
|
self.check_satisfies('mpileaks^mpi', '^mpich')
|
||||||
|
|
||||||
self.check_satisfies('mpileaks^mpi', 'mpileaks^zmpi')
|
self.check_satisfies('mpileaks^mpi', '^zmpi')
|
||||||
self.check_unsatisfiable('mpileaks^mpich', 'mpileaks^zmpi')
|
self.check_unsatisfiable('mpileaks^mpich', '^zmpi')
|
||||||
|
|
||||||
|
|
||||||
def test_satisfies_virtual_dependency_versions(self):
|
def test_satisfies_virtual_dependency_versions(self):
|
||||||
self.check_satisfies('mpileaks^mpi@1.5', 'mpileaks^mpi@1.2:1.6')
|
self.check_satisfies('mpileaks^mpi@1.5', '^mpi@1.2:1.6')
|
||||||
self.check_unsatisfiable('mpileaks^mpi@3', 'mpileaks^mpi@1.2:1.6')
|
self.check_unsatisfiable('mpileaks^mpi@3', '^mpi@1.2:1.6')
|
||||||
|
|
||||||
self.check_satisfies('mpileaks^mpi@2:', 'mpileaks^mpich')
|
self.check_satisfies('mpileaks^mpi@2:', '^mpich')
|
||||||
self.check_satisfies('mpileaks^mpi@2:', 'mpileaks^mpich@3.0.4')
|
self.check_satisfies('mpileaks^mpi@2:', '^mpich@3.0.4')
|
||||||
self.check_satisfies('mpileaks^mpi@2:', 'mpileaks^mpich2@1.4')
|
self.check_satisfies('mpileaks^mpi@2:', '^mpich2@1.4')
|
||||||
|
|
||||||
self.check_satisfies('mpileaks^mpi@1:', 'mpileaks^mpich2')
|
self.check_satisfies('mpileaks^mpi@1:', '^mpich2')
|
||||||
self.check_satisfies('mpileaks^mpi@2:', 'mpileaks^mpich2')
|
self.check_satisfies('mpileaks^mpi@2:', '^mpich2')
|
||||||
|
|
||||||
self.check_unsatisfiable('mpileaks^mpi@3:', 'mpileaks^mpich2@1.4')
|
self.check_unsatisfiable('mpileaks^mpi@3:', '^mpich2@1.4')
|
||||||
self.check_unsatisfiable('mpileaks^mpi@3:', 'mpileaks^mpich2')
|
self.check_unsatisfiable('mpileaks^mpi@3:', '^mpich2')
|
||||||
self.check_unsatisfiable('mpileaks^mpi@3:', 'mpileaks^mpich@1.0')
|
self.check_unsatisfiable('mpileaks^mpi@3:', '^mpich@1.0')
|
||||||
|
|
||||||
|
|
||||||
def test_constrain(self):
|
def test_constrain(self):
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import unittest
|
import unittest
|
||||||
import spack.spec
|
import spack.spec
|
||||||
from spack.spec import *
|
from spack.spec import *
|
||||||
from spack.parse import Token, ParseError
|
from spack.parse import Token
|
||||||
|
|
||||||
# Sample output for a complex lexing.
|
# Sample output for a complex lexing.
|
||||||
complex_lex = [Token(ID, 'mvapich_foo'),
|
complex_lex = [Token(ID, 'mvapich_foo'),
|
||||||
@ -96,10 +96,10 @@ def test_canonicalize(self):
|
|||||||
self.check_parse("x^y", "x@: ^y@:")
|
self.check_parse("x^y", "x@: ^y@:")
|
||||||
|
|
||||||
def test_parse_errors(self):
|
def test_parse_errors(self):
|
||||||
self.assertRaises(ParseError, self.check_parse, "x@@1.2")
|
self.assertRaises(SpecParseError, self.check_parse, "x@@1.2")
|
||||||
self.assertRaises(ParseError, self.check_parse, "x ^y@@1.2")
|
self.assertRaises(SpecParseError, self.check_parse, "x ^y@@1.2")
|
||||||
self.assertRaises(ParseError, self.check_parse, "x@1.2::")
|
self.assertRaises(SpecParseError, self.check_parse, "x@1.2::")
|
||||||
self.assertRaises(ParseError, self.check_parse, "x::")
|
self.assertRaises(SpecParseError, self.check_parse, "x::")
|
||||||
|
|
||||||
def test_duplicate_variant(self):
|
def test_duplicate_variant(self):
|
||||||
self.assertRaises(DuplicateVariantError, self.check_parse, "x@1.2+debug+debug")
|
self.assertRaises(DuplicateVariantError, self.check_parse, "x@1.2+debug+debug")
|
||||||
|
Loading…
Reference in New Issue
Block a user