Skip to content

Commit

Permalink
Improve the message around expecting a semicolon
Browse files Browse the repository at this point in the history
This makes it clearer that another character can be used.
  • Loading branch information
pradyunsg committed Sep 15, 2024
1 parent a716c52 commit b788481
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 11 deletions.
15 changes: 9 additions & 6 deletions src/packaging/_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ def _parse_requirement_details(
return (url, specifier, marker)

marker = _parse_requirement_marker(
tokenizer, span_start=url_start, after="URL and whitespace"
tokenizer,
span_start=url_start,
expected="semicolon (after URL and whitespace)",
)
else:
specifier_start = tokenizer.position
Expand All @@ -124,27 +126,28 @@ def _parse_requirement_details(
marker = _parse_requirement_marker(
tokenizer,
span_start=specifier_start,
after=(
"version specifier"
expected=(
"comma (within version specifier), semicolon (after version specifier)"
if specifier
else "name and no valid version specifier"
else "semicolon (after name with no version specifier)"
),
)

return (url, specifier, marker)


def _parse_requirement_marker(
tokenizer: Tokenizer, *, span_start: int, after: str
tokenizer: Tokenizer, *, span_start: int, expected: str
) -> MarkerList:
"""
requirement_marker = SEMICOLON marker WS?
"""

if not tokenizer.check("SEMICOLON"):
tokenizer.raise_syntax_error(
f"Expected end or semicolon (after {after})",
f"Expected {expected} or end",
span_start=span_start,
span_end=None,
)
tokenizer.read()

Expand Down
29 changes: 24 additions & 5 deletions tests/test_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ def test_error_no_space_after_url(self) -> None:
# THEN
assert ctx.exconly() == (
"packaging.requirements.InvalidRequirement: "
"Expected end or semicolon (after URL and whitespace)\n"
"Expected semicolon (after URL and whitespace) or end\n"
" name @ https://example.com/; extra == 'example'\n"
" ~~~~~~~~~~~~~~~~~~~~~~^"
)
Expand Down Expand Up @@ -521,7 +521,8 @@ def test_error_on_legacy_version_outside_triple_equals(self) -> None:
# THEN
assert ctx.exconly() == (
"packaging.requirements.InvalidRequirement: "
"Expected end or semicolon (after version specifier)\n"
"Expected comma (within version specifier), "
"semicolon (after version specifier) or end\n"
" name==1.0.org1\n"
" ~~~~~^"
)
Expand All @@ -537,7 +538,7 @@ def test_error_on_missing_version_after_op(self) -> None:
# THEN
assert ctx.exconly() == (
"packaging.requirements.InvalidRequirement: "
"Expected end or semicolon (after name and no valid version specifier)\n"
"Expected semicolon (after name with no version specifier) or end\n"
" name==\n"
" ^"
)
Expand All @@ -553,7 +554,7 @@ def test_error_on_missing_op_after_name(self) -> None:
# THEN
assert ctx.exconly() == (
"packaging.requirements.InvalidRequirement: "
"Expected end or semicolon (after name and no valid version specifier)\n"
"Expected semicolon (after name with no version specifier) or end\n"
" name 1.0\n"
" ^"
)
Expand All @@ -569,11 +570,29 @@ def test_error_on_random_char_after_specifier(self) -> None:
# THEN
assert ctx.exconly() == (
"packaging.requirements.InvalidRequirement: "
"Expected end or semicolon (after version specifier)\n"
"Expected comma (within version specifier), "
"semicolon (after version specifier) or end\n"
" name >= 1.0 #\n"
" ~~~~~~~^"
)

def test_error_on_missing_comma_in_specifier(self) -> None:
# GIVEN
to_parse = "name >= 1.0 <= 2.0"

# WHEN
with pytest.raises(InvalidRequirement) as ctx:
Requirement(to_parse)

# THEN
assert ctx.exconly() == (
"packaging.requirements.InvalidRequirement: "
"Expected comma (within version specifier), "
"semicolon (after version specifier) or end\n"
" name >= 1.0 <= 2.0\n"
" ~~~~~~~^"
)


class TestRequirementBehaviour:
def test_types_with_nothing(self) -> None:
Expand Down

0 comments on commit b788481

Please sign in to comment.