summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <gamblin2@llnl.gov>2022-05-23 23:33:43 -0400
committerGitHub <noreply@github.com>2022-05-24 03:33:43 +0000
commit306bed48d747c907cfbd60073cdf6d92c3bca14a (patch)
tree3e06e6dd1eb4c8b34a8ddbf47128683784e8d3e9 /lib
parent63402c512b4d660e987dae6ad82f6ab7eac8a766 (diff)
downloadspack-306bed48d747c907cfbd60073cdf6d92c3bca14a.tar.gz
spack-306bed48d747c907cfbd60073cdf6d92c3bca14a.tar.bz2
spack-306bed48d747c907cfbd60073cdf6d92c3bca14a.tar.xz
spack-306bed48d747c907cfbd60073cdf6d92c3bca14a.zip
specs: emit better parsing errors for specs. (#24860)
Parse error information is kept for specs, but it doesn't seem like we propagate it to the user when we encounter an error. This fixes that. e.g., for this error in a package: ```python depends_on("python@:3.8", when="0.900:") ``` Before, with no context and no clue that it's even from a particular spec: ``` ==> Error: Unexpected token: ':' ``` With this PR: ``` ==> Error: Unexpected token: ':' Encountered when parsing spec: 0.900: ^ ```
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/cmd/__init__.py34
-rw-r--r--lib/spack/spack/parse.py4
-rw-r--r--lib/spack/spack/spec.py10
-rw-r--r--lib/spack/spack/test/cmd/spec.py11
-rw-r--r--lib/spack/spack/test/spec_syntax.py1
5 files changed, 33 insertions, 27 deletions
diff --git a/lib/spack/spack/cmd/__init__.py b/lib/spack/spack/cmd/__init__.py
index 9568ccc296..ff6c3d7bf4 100644
--- a/lib/spack/spack/cmd/__init__.py
+++ b/lib/spack/spack/cmd/__init__.py
@@ -155,31 +155,17 @@ def parse_specs(args, **kwargs):
normalize = kwargs.get('normalize', False)
tests = kwargs.get('tests', False)
- try:
- sargs = args
- if not isinstance(args, six.string_types):
- sargs = ' '.join(spack.util.string.quote(args))
- specs = spack.spec.parse(sargs)
- for spec in specs:
- if concretize:
- spec.concretize(tests=tests) # implies normalize
- elif normalize:
- spec.normalize(tests=tests)
-
- return specs
-
- except spack.spec.SpecParseError as e:
- msg = e.message + "\n" + str(e.string) + "\n"
- msg += (e.pos + 2) * " " + "^"
- raise spack.error.SpackError(msg)
-
- except spack.error.SpecError as e:
-
- msg = e.message
- if e.long_message:
- msg += e.long_message
+ sargs = args
+ if not isinstance(args, six.string_types):
+ sargs = ' '.join(spack.util.string.quote(args))
+ specs = spack.spec.parse(sargs)
+ for spec in specs:
+ if concretize:
+ spec.concretize(tests=tests) # implies normalize
+ elif normalize:
+ spec.normalize(tests=tests)
- raise spack.error.SpackError(msg)
+ return specs
def matching_spec_from_env(spec):
diff --git a/lib/spack/spack/parse.py b/lib/spack/spack/parse.py
index 603848a3a0..e06338e0c8 100644
--- a/lib/spack/spack/parse.py
+++ b/lib/spack/spack/parse.py
@@ -123,11 +123,11 @@ class Parser(object):
def next_token_error(self, message):
"""Raise an error about the next token in the stream."""
- raise ParseError(message, self.text, self.token.end)
+ raise ParseError(message, self.text[0], self.token.end)
def last_token_error(self, message):
"""Raise an error about the previous token in the stream."""
- raise ParseError(message, self.text, self.token.start)
+ raise ParseError(message, self.text[0], self.token.start)
def unexpected_token(self):
self.next_token_error("Unexpected token: '%s'" % self.next.value)
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index db6eafaf37..3046aa1d08 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -5386,6 +5386,16 @@ class SpecParseError(spack.error.SpecError):
self.string = parse_error.string
self.pos = parse_error.pos
+ @property
+ def long_message(self):
+ return "\n".join(
+ [
+ " Encountered when parsing spec:",
+ " %s" % self.string,
+ " %s^" % (" " * self.pos),
+ ]
+ )
+
class DuplicateDependencyError(spack.error.SpecError):
"""Raised when the same dependency occurs in a spec twice."""
diff --git a/lib/spack/spack/test/cmd/spec.py b/lib/spack/spack/test/cmd/spec.py
index 3fb25a3ea8..42f4c7a59a 100644
--- a/lib/spack/spack/test/cmd/spec.py
+++ b/lib/spack/spack/test/cmd/spec.py
@@ -124,6 +124,17 @@ def test_spec_returncode():
assert spec.returncode == 1
+def test_spec_parse_error():
+ with pytest.raises(spack.spec.SpecParseError) as e:
+ spec("1.15:")
+
+ # make sure the error is formatted properly
+ error_msg = """\
+ 1.15:
+ ^"""
+ assert error_msg in e.value.long_message
+
+
def test_env_aware_spec(mutable_mock_env_path):
env = ev.create('test')
env.add('mpileaks')
diff --git a/lib/spack/spack/test/spec_syntax.py b/lib/spack/spack/test/spec_syntax.py
index 3971e02d48..815a46847a 100644
--- a/lib/spack/spack/test/spec_syntax.py
+++ b/lib/spack/spack/test/spec_syntax.py
@@ -125,7 +125,6 @@ class TestSpecSyntax(object):
def _check_raises(self, exc_type, items):
for item in items:
with pytest.raises(exc_type):
- print("CHECKING: ", item, "=======================")
Spec(item)
# ========================================================================