Skip to content
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

pattern match on base version in Version constructor #41

Merged
merged 5 commits into from
Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
43 changes: 39 additions & 4 deletions dunamai/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,8 @@ def __init__(
commit: str = None,
dirty: bool = None,
tagged_metadata: Optional[str] = None,
epoch: int = None
epoch: int = None,
pattern: str = _VERSION_PATTERN,
marnikow marked this conversation as resolved.
Show resolved Hide resolved
) -> None:
"""
:param base: Release segment, such as 0.1.0.
Expand All @@ -317,7 +318,44 @@ def __init__(
:param commit: Commit hash/identifier.
:param dirty: True if the working directory does not match the commit.
:param epoch: Optional PEP 440 epoch.
:param pattern: Regular expression matched against the base.
Refer to `from_any_vcs` for more info.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain the use case for this? I didn't really think anyone would need to turn a version string back into a Version instance.

If we do add it, I'd probably prefer it to be a separate function, like def parse_version(version: str) -> Version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's use full when you want to modify a version that is gathered from importlib.metadata. Since dunamai just grabs the string, everything is put inside base .

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's a great point.

Okay, let's separate this from the constructor and put it as Version.parse(cls, version: str, pattern: str = _VERSION_PATTERN) -> "Version". That way, the constructor stays simple and predictable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed an possible implementation. Version.parse allows a version as well so that you can use the function as follows: dunamai.Version.parse(dunamai.get_version("dunamai", third_choice=dunamai.Version.from_any_vcs))

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep parse() simpler, I think I'll just add a parser argument to get_version() after the merge. parser=Version would keep the existing behavior, and parser=Version.parse would enable the new behavior.

"""
try:
v_base = base if base.startswith("v") else f"v{base}"
matched_pattern = _match_version_pattern(pattern, [v_base], True)
base = matched_pattern.base
if stage is None:
stage = matched_pattern.stage_revision
if tagged_metadata is None:
tagged_metadata = matched_pattern.tagged_metadata
elif matched_pattern.tagged_metadata is not None:
tagged_metadata = f"{tagged_metadata}.{matched_pattern.tagged_metadata}"
if epoch is None:
epoch = matched_pattern.epoch
self._matched_tag = matched_pattern.matched_tag
self._newer_unmatched_tags = matched_pattern.newer_tags
except ValueError:
self._matched_tag = None # type: Optional[str]
self._newer_unmatched_tags = None # type: Optional[Sequence[str]]

if dirty is None and tagged_metadata:
if "dirty" in tagged_metadata.split("."):
dirty = True
tagged_metadata = ".".join(e for e in tagged_metadata.split(".") if e != "dirty")
if distance == 0 and tagged_metadata:
for m in tagged_metadata.split("."):
match = re.match(r"d(?P<dis>\d+)", m)
if match:
distance = int(match.group("dis"))
tagged_metadata = ".".join(e for e in tagged_metadata.split(".") if e != m)
if commit is None and tagged_metadata:
for m in tagged_metadata.split("."):
match = re.match(r"g(?P<commit>[\da-z]+)", m)
if match:
commit = match.group("commit")
tagged_metadata = ".".join(e for e in tagged_metadata.split(".") if e != m)

#: Release segment.
self.base = base
#: Alphabetical part of prerelease segment.
Expand All @@ -337,9 +375,6 @@ def __init__(
#: Optional PEP 440 epoch.
self.epoch = epoch

self._matched_tag = None # type: Optional[str]
self._newer_unmatched_tags = None # type: Optional[Sequence[str]]
mtkennerly marked this conversation as resolved.
Show resolved Hide resolved

def __str__(self) -> str:
return self.serialize()

Expand Down
4 changes: 0 additions & 4 deletions tests/unit/test_dunamai.py
Original file line number Diff line number Diff line change
Expand Up @@ -498,16 +498,12 @@ def test__check_version__semver() -> None:
Version("00.0.0").serialize(style=style)
with pytest.raises(ValueError):
Version("0.01.0").serialize(style=style)
with pytest.raises(ValueError):
Version("0.1.0-alpha.02").serialize(style=style)
mtkennerly marked this conversation as resolved.
Show resolved Hide resolved
# But leading zeroes are fine for non-numeric parts:
Version("0.1.0-alpha.02a").serialize(style=style)

# Identifiers can't be empty:
with pytest.raises(ValueError):
Version("0.1.0-.").serialize(style=style)
with pytest.raises(ValueError):
Version("0.1.0-a.").serialize(style=style)
with pytest.raises(ValueError):
Version("0.1.0-.a").serialize(style=style)

Expand Down