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: ^ ```
This commit is contained in:
parent
63402c512b
commit
306bed48d7
5 changed files with 33 additions and 27 deletions
|
@ -155,7 +155,6 @@ 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))
|
||||
|
@ -168,19 +167,6 @@ def parse_specs(args, **kwargs):
|
|||
|
||||
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
|
||||
|
||||
raise spack.error.SpackError(msg)
|
||||
|
||||
|
||||
def matching_spec_from_env(spec):
|
||||
"""
|
||||
|
|
|
@ -123,11 +123,11 @@ def accept(self, id):
|
|||
|
||||
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)
|
||||
|
|
|
@ -5386,6 +5386,16 @@ def __init__(self, parse_error):
|
|||
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."""
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -125,7 +125,6 @@ def check_lex(self, tokens, spec):
|
|||
def _check_raises(self, exc_type, items):
|
||||
for item in items:
|
||||
with pytest.raises(exc_type):
|
||||
print("CHECKING: ", item, "=======================")
|
||||
Spec(item)
|
||||
|
||||
# ========================================================================
|
||||
|
|
Loading…
Reference in a new issue