From cb093310093edf691bc2dd263d623b660335c79a Mon Sep 17 00:00:00 2001 From: Pradyun Gedam Date: Wed, 7 Dec 2022 00:44:17 +0000 Subject: [PATCH] Enforce word boundaries in operators and names This ensures that these are only parsed when they're independent words. --- packaging/_tokenizer.py | 12 ++++++------ tests/test_requirements.py | 22 ++++++++++++++++++++-- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/packaging/_tokenizer.py b/packaging/_tokenizer.py index da6e7b06..de389cb3 100644 --- a/packaging/_tokenizer.py +++ b/packaging/_tokenizer.py @@ -53,12 +53,12 @@ def __str__(self) -> str: re.VERBOSE, ), "OP": r"(===|==|~=|!=|<=|>=|<|>)", - "BOOLOP": r"(or|and)", - "IN": r"in", - "NOT": r"not", + "BOOLOP": r"\b(or|and)\b", + "IN": r"\bin\b", + "NOT": r"\bnot\b", "VARIABLE": re.compile( r""" - ( + \b( python_version |python_full_version |os[._]name @@ -68,14 +68,14 @@ def __str__(self) -> str: |python_implementation |implementation_(name|version) |extra - ) + )\b """, re.VERBOSE, ), "VERSION": re.compile(Specifier._version_regex_str, re.VERBOSE | re.IGNORECASE), "AT": r"\@", "URL": r"[^ \t]+", - "IDENTIFIER": r"[a-zA-Z0-9][a-zA-Z0-9._-]*", + "IDENTIFIER": r"\b[a-zA-Z0-9][a-zA-Z0-9._-]*\b", "WS": r"[ \t]+", "END": r"$", } diff --git a/tests/test_requirements.py b/tests/test_requirements.py index 86516fd7..93839d69 100644 --- a/tests/test_requirements.py +++ b/tests/test_requirements.py @@ -390,9 +390,27 @@ def test_error_invalid_marker_notin_without_whitespace(self) -> None: # THEN assert ctx.exconly() == ( "packaging.requirements.InvalidRequirement: " - "Expected whitespace after 'not'\n" + "Expected marker operator, one of <=, <, !=, ==, >=, >, ~=, ===, " + "not, not in\n" " name; '3.7' notin python_version\n" - " ^" + " ^" + ) + + def test_error_when_no_word_boundary(self) -> None: + # GIVEN + to_parse = "name; '3.6'inpython_version" + + # WHEN + with pytest.raises(InvalidRequirement) as ctx: + Requirement(to_parse) + + # THEN + assert ctx.exconly() == ( + "packaging.requirements.InvalidRequirement: " + "Expected marker operator, one of <=, <, !=, ==, >=, >, ~=, ===, " + "not, not in\n" + " name; '3.6'inpython_version\n" + " ^" ) def test_error_invalid_marker_not_without_in(self) -> None: