-
Notifications
You must be signed in to change notification settings - Fork 39
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
NormalizedMatcher
fails to parse dev versions like 0.8.1dev
#200
Comments
0.8.1dev
NormaizeMatcher
fails to parse dev versions like 0.8.1dev
I suspect there is more fineprint in PEP 440, that distlib just ignores. E.g. that all letters should be matched case-insenitively, or:
or:
|
NormaizeMatcher
fails to parse dev versions like 0.8.1dev
NormalizedMatcher
fails to parse dev versions like 0.8.1dev
This was auto-closed via commit message, but I'm not sure if it's actually fixed yet. I'm not sure if PEP440 had revisions after |
OK, tests all seem to be passing. You might want to try the latest version in this repository and report your findings. (Only |
PEP 440 even specifies a regex for the version spec, that is much more complex than the one in distlib. VERSION_PATTERN = r"""
v?
(?:
(?:(?P<epoch>[0-9]+)!)? # epoch
(?P<release>[0-9]+(?:\.[0-9]+)*) # release segment
(?P<pre> # pre-release
[-_\.]?
(?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
[-_\.]?
(?P<pre_n>[0-9]+)?
)?
(?P<post> # post release
(?:-(?P<post_n1>[0-9]+))
|
(?:
[-_\.]?
(?P<post_l>post|rev|r)
[-_\.]?
(?P<post_n2>[0-9]+)?
)
)?
(?P<dev> # dev release
[-_\.]?
(?P<dev_l>dev)
[-_\.]?
(?P<dev_n>[0-9]+)?
)?
)
(?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
"""
_regex = re.compile(
r"^\s*" + VERSION_PATTERN + r"\s*$",
re.VERBOSE | re.IGNORECASE,
) For implementation, you should probably use this verbatim and use the matching groups and |
It's better but not fixed: python -c 'from distlib.version import NormalizedMatcher; print(NormalizedMatcher("0.8.1DEV"))'
0.8.1DEV PEP 440 states that it should be normalized to lower case with dot separator and zero at the end, i.e.:
|
I'm pretty sure that regex wasn't in the spec when distlib implemented its version code, or I'd have used it (parts of it might even predate PEP440, it was around the time of Python 3.3 - it started off with taking the PEP3.3 aborted packaging code, which included versions). I'm not sure I have time at the moment to do a change as big as the whole regex (and then work though all the tests etc. as necessary), though I may look at that later.
|
Have you found any more errors in the version parsing? The |
I don't think I found any further bugs, but if you wanted to add an actual normalizer, it might go something like this: import re
VERSION_PATTERN = r"""
v?
(?:
(?:(?P<epoch>[0-9]+)!)? # epoch
(?P<release>[0-9]+(?:\.[0-9]+)*) # release segment
(?P<pre> # pre-release
[-_\.]?
(?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
[-_\.]?
(?P<pre_n>[0-9]+)?
)?
(?P<post> # post release
(?:-(?P<post_n1>[0-9]+))
|
(?:
[-_\.]?
(?P<post_l>post|rev|r)
[-_\.]?
(?P<post_n2>[0-9]+)?
)
)?
(?P<dev> # dev release
[-_\.]?
(?P<dev_l>dev)
[-_\.]?
(?P<dev_n>[0-9]+)?
)?
)
(?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
"""
_regex = re.compile(
r"^\s*" + VERSION_PATTERN + r"\s*$",
re.VERBOSE | re.IGNORECASE,
)
def normalize(maybe_version):
segments = _regex.match(maybe_version.lower())
if segments is None:
raise ValueError("Not a valid PEP 440 version")
epoch = segments["epoch"]
epoch = "" if epoch is None else f"{int(epoch)}!"
release = ".".join(str(int(r)) for r in segments["release"].split("."))
pre = ""
if segments["pre"] is not None:
pre = int(segments["pre_n"] or 0)
pre = f".pre{pre}"
post = ""
if segments["post"] is not None:
if segments["post_n1"] is None:
post = int(segments["post_n2"] or 0)
else:
post = int(segments["post_n1"] or 0)
post = f".post{post}"
dev = ""
if segments["dev"] is not None:
dev = int(segments["dev_n"] or 0)
dev = f".dev{dev}"
local = ""
if segments["local"] is not None:
local = f"+{segments['local']}"
return f"{epoch}{release}{pre}{post}{dev}{local}"
# Smoke Tests:
assert normalize("8.0.1DEV") == "8.0.1.dev0"
assert normalize("1r7") == "1.post7"
assert normalize("1") == "1"
assert normalize("0000.0002-rc12345") == "0.2.pre12345"
assert normalize("017!0_dEv") == "17!0.dev0"
assert normalize("17+gAefF123_a_7.7af") == "17+gaeff123_a_7.7af"
assert normalize("1-post_") == "1.post0" (No guaranty it actually works in all edge cases) I can make a pull request if you're interested. I think it would be functionality that might be very useful to users. To be honest, I find the PEP 404 normalization rules a bit weird, because things like
So PEP 440 definitely has deep pitfalls. And yeah, like you, I find it pretty strange, that accepted and established PEPs are subject to change (that one as late as Oct. 2022 - eight years after it was accepted), despite it saying, its state was "Final - Accepted and implementation complete, or no longer active". |
That's helpful of you to flesh it out for me, thanks very much. There's actually a |
Describe the bug
dislib.version.NormaizeMatcher
errors when called with something like0.8.1dev
. I.e. development version specifiers that either omit the trailing number or the dot separator.PEP 440 specifies that development release separators may omit the separator and number entirely:
To Reproduce
Expected behavior
The text was updated successfully, but these errors were encountered: