Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 7 additions & 1 deletion src/packaging/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,13 @@ def __init__(self, version: str) -> None:
try:
self._release = tuple(map(int, version.split(".")))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We could keep version.split’s result and use that instead of splitting again.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I tried that and it causes a minor slow down of simple version construction.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Interesting, do you know why? Is it because it keeps around the reference for a bit longer?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not a blocker by the way

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I can only speculate here, but yeah, it seems like storing a value and then accessing it has a measurable performance impact at the level of optimization we're at now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It still gets stored, though - the only difference should be that the ref lives longer (and gets bumped one more pair of times, probably). Unless it can reduce this (not impossible, but unlikely - numpy can do this sort of thing on unix but not windows).

I wonder if del'ing the variable afterwords would affect it.

except ValueError:
raise InvalidVersion(f"Invalid version: {version!r}") from None
# Empty parts (from "1..2", ".1", etc.) are invalid versions.
# Any other ValueError (e.g. int str-digits limit) should
# propagate to the caller.
if "" in version.split("."):
raise InvalidVersion(f"Invalid version: {version!r}") from None
# TODO: remove "no cover" when Python 3.9 is dropped.
raise # pragma: no cover

self._epoch = 0
self._pre = None
Expand Down
22 changes: 22 additions & 0 deletions tests/test_specifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import itertools
import operator
import re
import sys
import typing

import pytest
Expand Down Expand Up @@ -2065,6 +2066,27 @@ def test_contains_rejects_invalid_specifier(
spec = SpecifierSet(specifier, prereleases=True)
assert not spec.contains(input)

@pytest.mark.skipif(
not hasattr(sys, "get_int_max_str_digits"),
reason="requires int max str digits limit",
)
@pytest.mark.parametrize(
"specifier",
[
">=" + "1" * 5000,
">=1.0a" + "1" * 5000,
],
)
def test_contains_oversized_version_raises_valueerror(self, specifier: str) -> None:
old = sys.get_int_max_str_digits()
sys.set_int_max_str_digits(4300)
try:
spec = SpecifierSet(specifier)
with pytest.raises(ValueError, match="Exceeds the limit"):
spec.contains("1.0")
finally:
sys.set_int_max_str_digits(old)

@pytest.mark.parametrize(
("version", "specifier", "expected"),
[
Expand Down
22 changes: 22 additions & 0 deletions tests/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,28 @@ def test_invalid_versions(self, version: str) -> None:
with pytest.raises(InvalidVersion):
Version(version)

@pytest.mark.skipif(
not hasattr(sys, "get_int_max_str_digits"),
reason="requires int max str digits limit",
)
@pytest.mark.parametrize(
"version",
[
# Simple path (digits only)
"1" * 5000,
# Regex path (has pre-release)
"1.0a" + "1" * 5000,
],
)
def test_oversized_version_raises_valueerror(self, version: str) -> None:
old = sys.get_int_max_str_digits()
sys.set_int_max_str_digits(4300)
try:
with pytest.raises(ValueError, match="Exceeds the limit"):
Version(version)
finally:
sys.set_int_max_str_digits(old)

@pytest.mark.parametrize(
("version", "normalized"),
[
Expand Down
Loading