8000 PEP440 normalization code structure suggestions by aignas · Pull Request #1 · vonschultz/rules_python · GitHub
[go: up one dir, main page]

Skip to content

PEP440 normalization code structure suggestions 8000 #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Aug 28, 2023
Merged
Changes from 1 commit
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor: restrict usage of contexts to the internal parser functions
  • Loading branch information
aignas committed Aug 27, 2023
commit f4be867575826d4e0c828f9852a94990dfe60add
90 changes: 48 additions & 42 deletions python/private/py_wheel_normalize_pep440.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -101,20 +101,27 @@ def _accept(self, predicate, value):

return False

def _tail(self):
return self.contexts[-1]

def _pop(self):
return self.contexts.pop()

def _new(version):
"""Create a new normalizer"""
self = struct(
version = version.strip(), # PEP 440: Leading and Trailing Whitespace
version = version,
contexts = [],
)
public = struct(
# methods: keep sorted
accept = mkmethod(self, _accept),
close_context = mkmethod(self, _close_context),
open_context = mkmethod(self, _open_context),
tail = mkmethod(self, _tail),
pop = mkmethod(self, _pop),

# attributes: keep sorted
contexts = self.contexts,
version = self.version,
)
return public
Expand All @@ -131,10 +138,10 @@ def accept_placeholder(parser):
actually be valid.

"""
context = parser.open_context(parser.contexts[-1]["start"])
context = parser.open_context(parser.tail()["start"])

if not parser.accept(_is("{"), str):
parser.contexts.pop()
parser.pop()
return False

start = context["start"]
Expand All @@ -143,7 +150,7 @@ def accept_placeholder(parser):
break

if not parser.accept(_is("}"), str):
parser.contexts.pop()
parser.pop()
return False

parser.close_context()
Expand All @@ -152,7 +159,7 @@ def accept_placeholder(parser):
def accept_digits(parser):
"""Accept multiple digits (or placeholders)."""

context = parser.open_context(parser.contexts[-1]["start"])
context = parser.open_context(parser.tail()["start"])
start = context["start"]

for i in range(start, len(parser.version) + 1):
Expand All @@ -165,16 +172,16 @@ def accept_digits(parser):
return True
break

parser.contexts.pop()
parser.pop()
return False

def accept_string(parser, string, replacement):
"""Accept a `string` in the input. Output `replacement`."""
context = parser.open_context(parser.contexts[-1]["start"])
context = parser.open_context(parser.tail()["start"])

for character in string.elems():
if not parser.accept(_in([character, character.upper()]), ""):
parser.contexts.pop()
parser.pop()
return False

context["norm"] = replacement
Expand All @@ -185,7 +192,7 @@ def accept_string(parser, string, replacement):
def accept_alnum(parser):
"""Accept an alphanumeric sequence."""

context = parser.open_context(parser.contexts[-1]["start"])
context = parser.open_context(parser.tail()["start"])
start = context["start"]

for i in range(start, len(parser.version) + 1):
Expand All @@ -195,23 +202,23 @@ def accept_alnum(parser):
return True
break

parser.contexts.pop()
parser.pop()
return False

def accept_dot_number(parser):
"""Accept a dot followed by digits."""
parser.open_context(parser.contexts[-1]["start"])
parser.open_context(parser.tail()["start"])

if parser.accept(_is("."), ".") and accept_digits(parser):
parser.close_context()
return True
else:
parser.contexts.pop()
parser.pop()
return False

def accept_dot_number_sequence(parser):
"""Accept a sequence of dot+digits."""
context = parser.contexts[-1]
context = parser.tail()
start = context["start"]
i = start

Expand All @@ -222,7 +229,7 @@ def accept_dot_number_sequence(parser):

def accept_separator_alnum(parser):
"""Accept a separator followed by an alphanumeric string."""
parser.open_context(parser.contexts[-1]["start"])
parser.open_context(parser.tail()["start"])

# PEP 440: Local version segments
if (
Expand All @@ -232,12 +239,12 @@ def accept_separator_alnum(parser):
parser.close_context()
return True

parser.contexts.pop()
parser.pop()
return False

def accept_separator_alnum_sequence(parser):
"""Accept a sequence of separator+alphanumeric."""
context = parser.contexts[-1]
context = parser.tail()
start = context["start"]
i = start

Expand All @@ -249,24 +256,24 @@ def accept_separator_alnum_sequence(parser):

def accept_epoch(parser):
"""PEP 440: Version epochs."""
context = parser.open_context(parser.contexts[-1]["start"])
context = parser.open_context(parser.tail()["start"])
if accept_digits(parser) and parser.accept(_is("!"), "!"):
if context["norm"] == "0!":
parser.contexts.pop()
parser.contexts[-1]["start"] = context["start"]
parser.pop()
parser.tail()["start"] = context["start"]
else:
parser.close_context()
return True
else:
parser.contexts.pop()
parser.pop()
return False

def accept_release(parser):
"""Accept the release segment, numbers separated by dots."""
parser.open_context(parser.contexts[-1]["start"])
parser.open_context(parser.tail()["start"])

if not accept_digits(parser):
parser.contexts.pop()
parser.pop()
return False

accept_dot_number_sequence(parser)
Expand All @@ -275,7 +282,7 @@ def accept_release(parser):

def accept_pre_l(parser):
"""PEP 440: Pre-release spelling."""
parser.open_context(parser.contexts[-1]["start"])
parser.open_context(parser.tail()["start"])

if (
accept_string(parser, "alpha", "a") or
Expand All @@ -290,18 +297,18 @@ def accept_pre_l(parser):
parser.close_context()
return True
else:
parser.contexts.pop()
parser.pop()
return False

def accept_prerelease(parser):
"""PEP 440: Pre-releases."""
context = parser.open_context(parser.contexts[-1]["start"])
context = parser.open_context(parser.tail()["start"])

# PEP 440: Pre-release separators
parser.accept(_in(["-", "_", "."]), "")

if not accept_pre_l(parser):
parser.contexts.pop()
parser.pop()
return False

parser.accept(_in(["-", "_", "."]), "")
Expand All @@ -315,19 +322,19 @@ def accept_prerelease(parser):

def accept_implicit_postrelease(parser):
"""PEP 440: Implicit post releases."""
context = parser.open_context(parser.contexts[-1]["start"])
context = parser.open_context(parser.tail()["start"])

if parser.accept(_is("-"), "") and accept_digits(parser):
context["norm"] = ".post" + context["norm"]
parser.close_context()
return True

parser.contexts.pop()
parser.pop()
return False

def accept_explicit_postrelease(parser):
"""PEP 440: Post-releases."""
context = parser.open_context(parser.contexts[-1]["start"])
context = parser.open_context(parser.tail()["start"])

# PEP 440: Post release separators
if not parser.accept(_in(["-", "_", "."]), "."):
Expand All @@ -348,23 +355,23 @@ def accept_explicit_postrelease(parser):
parser.close_context()
return True

parser.contexts.pop()
parser.pop()
return False

def accept_postrelease(parser):
"""PEP 440: Post-releases."""
parser.open_context(parser.contexts[-1]["start"])
parser.open_context(parser.tail()["start"])

if accept_implicit_postrelease(parser) or accept_explicit_postrelease(parser):
parser.close_context()
return True

parser.contexts.pop()
parser.pop()
return False

def accept_devrelease(parser):
"""PEP 440: Developmental releases."""
context = parser.open_context(parser.contexts[-1]["start"])
context = parser.open_context(parser.tail()["start"])

# PEP 440: Development release separators
if not parser.accept(_in(["-", "_", "."]), "."):
Expand All @@ -380,19 +387,19 @@ def accept_devrelease(parser):
parser.close_context()
return True

parser.contexts.pop()
parser.pop()
return False

def accept_local(parser):
"""PEP 440: Local version identifiers."""
parser.open_context(parser.contexts[-1]["start"])
parser.open_context(parser.tail()["start"])

if parser.accept(_is("+"), "+") and accept_alnum(parser):
accept_separator_alnum_sequence(parser)
parser.close_context()
return True

parser.contexts.pop()
parser.pop()
return False

def normalize_pep440(version):
Expand All @@ -407,8 +414,7 @@ def normalize_pep440(version):
Returns:
string containing the normalized version.
"""

parser = _new(version)
parser = _new(version.strip()) # PEP 440: Leading and Trailing Whitespace
parser.open_context(0)
parser.accept(_is("v"), "") # PEP 440: Preceding v character
accept_epoch(parser)
Expand All @@ -417,9 +423,9 @@ def normalize_pep440(version):
accept_postrelease(parser)
accept_devrelease(parser)
accept_local(parser)
if parser.version[parser.contexts[-1]["start"]:]:
if parser.version[parser.tail()["start"]:]:
fail(
"Failed to parse PEP 440 version identifier '%s'." % parser.version,
"Parse error at '%s'" % parser.version[parser.contexts[-1]["start"]:],
"Parse error at '%s'" % parser.version[parser.tail()["start"]:],
)
return parser.contexts[-1]["norm"]
return parser.tail()["norm"]
0