From 45d22c3046780ea214e976e02929897d4fbfc95b Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 12 Feb 2026 21:23:00 -0500 Subject: [PATCH 1/2] fix: standardize repr style Signed-off-by: Henry Schreiner --- docs/markers.rst | 6 +++--- docs/metadata.rst | 2 +- docs/requirements.rst | 10 +++++----- docs/specifiers.rst | 12 ++++++------ docs/version.rst | 4 ++-- src/packaging/_parser.py | 2 +- src/packaging/markers.py | 2 +- src/packaging/requirements.py | 2 +- src/packaging/specifiers.py | 26 +++++++++++++------------- src/packaging/tags.py | 5 ++++- src/packaging/version.py | 16 ++++++++-------- tests/test_markers.py | 4 ++-- tests/test_requirements.py | 2 +- tests/test_specifiers.py | 4 ++-- tests/test_tags.py | 5 ++++- tests/test_version.py | 2 +- 16 files changed, 55 insertions(+), 49 deletions(-) diff --git a/docs/markers.rst b/docs/markers.rst index 8053e06ac..c562f2771 100644 --- a/docs/markers.rst +++ b/docs/markers.rst @@ -16,7 +16,7 @@ Usage >>> from packaging.markers import Marker, UndefinedEnvironmentName >>> marker = Marker("python_version>'2'") >>> marker - "2"')> + Marker('python_version > "2"') >>> # We can evaluate the marker to see if it is satisfied >>> marker.evaluate() True @@ -27,11 +27,11 @@ Usage >>> # Multiple markers can be ANDed >>> and_marker = Marker("os_name=='a' and os_name=='b'") >>> and_marker - + Marker('os_name == "a" and os_name == "b"') >>> # Multiple markers can be ORed >>> or_marker = Marker("os_name=='a' or os_name=='b'") >>> or_marker - + Marker('os_name == "a" or os_name == "b"') >>> # Markers can be also used with extras, to pull in dependencies if >>> # a certain extra is being installed >>> extra = Marker('extra == "bar"') diff --git a/docs/metadata.rst b/docs/metadata.rst index 7acaa81f9..bee765319 100644 --- a/docs/metadata.rst +++ b/docs/metadata.rst @@ -30,7 +30,7 @@ Usage >>> parsed.name 'packaging' >>> parsed.version - + Version('24.0') Reference diff --git a/docs/requirements.rst b/docs/requirements.rst index 003d4b8d7..49a4b23fe 100644 --- a/docs/requirements.rst +++ b/docs/requirements.rst @@ -16,7 +16,7 @@ Usage >>> from packaging.requirements import Requirement >>> simple_req = Requirement("name") >>> simple_req - + Requirement('name') >>> simple_req.name 'name' >>> simple_req.url is None @@ -24,7 +24,7 @@ Usage >>> simple_req.extras set() >>> simple_req.specifier - + SpecifierSet('') >>> simple_req.marker is None True >>> # Requirements can be specified with extras, specifiers and markers @@ -34,9 +34,9 @@ Usage >>> req.extras {'foo'} >>> req.specifier - =2')> + SpecifierSet('<3,>=2') >>> req.marker - "2.0"')> + Marker('python_version > "2.0"') >>> # Requirements can also be specified with a URL, but may not specify >>> # a version. >>> url_req = Requirement('name @ https://github.com/pypa ;os_name=="a"') @@ -47,7 +47,7 @@ Usage >>> url_req.extras set() >>> url_req.marker - + Marker('os_name == "a"') >>> # You can do simple comparisons between requirement objects: >>> Requirement("packaging") == Requirement("packaging") True diff --git a/docs/specifiers.rst b/docs/specifiers.rst index 934d9f6f8..cc78900ee 100644 --- a/docs/specifiers.rst +++ b/docs/specifiers.rst @@ -18,22 +18,22 @@ Usage >>> from packaging.version import Version >>> spec1 = SpecifierSet("~=1.0") >>> spec1 - + SpecifierSet('~=1.0') >>> spec2 = SpecifierSet(">=1.0") >>> spec2 - =1.0')> + SpecifierSet('>=1.0') >>> # We can combine specifiers >>> combined_spec = spec1 & spec2 >>> combined_spec - =1.0,~=1.0')> + SpecifierSet('>=1.0,~=1.0') >>> # We can also implicitly combine a string specifier >>> combined_spec &= "!=1.1" >>> combined_spec - =1.0,~=1.0')> + SpecifierSet('!=1.1,>=1.0,~=1.0') >>> # We can iterate over the SpecifierSet to recover the >>> # individual specifiers >>> sorted(combined_spec, key=str) - [, =1.0')>, ] + [Specifier('!=1.1'), Specifier('>=1.0'), Specifier('~=1.0')] >>> # Create a few versions to check for contains. >>> v1 = Version("1.0a5") >>> v2 = Version("1.0") @@ -48,7 +48,7 @@ Usage >>> # Finally we can filter a list of versions to get only those which are >>> # contained within our specifier. >>> list(combined_spec.filter([v1, v2, "1.4"])) - [, '1.4'] + [Version('1.0'), '1.4'] Reference diff --git a/docs/version.rst b/docs/version.rst index 2adf336e5..03b0335f7 100644 --- a/docs/version.rst +++ b/docs/version.rst @@ -18,9 +18,9 @@ Usage >>> v1 = parse("1.0a5") >>> v2 = Version("1.0") >>> v1 - + Version('1.0a5') >>> v2 - + Version('1.0') >>> v1 < v2 True >>> v1.epoch diff --git a/src/packaging/_parser.py b/src/packaging/_parser.py index f6c1f5cd2..7416939d5 100644 --- a/src/packaging/_parser.py +++ b/src/packaging/_parser.py @@ -22,7 +22,7 @@ def __str__(self) -> str: return self.value def __repr__(self) -> str: - return f"<{self.__class__.__name__}({self.value!r})>" + return f"{self.__class__.__name__}({self.value!r})" def serialize(self) -> str: raise NotImplementedError diff --git a/src/packaging/markers.py b/src/packaging/markers.py index daa29c630..d39793891 100644 --- a/src/packaging/markers.py +++ b/src/packaging/markers.py @@ -329,7 +329,7 @@ def __str__(self) -> str: return _format_marker(self._markers) def __repr__(self) -> str: - return f"<{self.__class__.__name__}({str(self)!r})>" + return f"{self.__class__.__name__}({str(self)!r})" def __hash__(self) -> int: return hash(str(self)) diff --git a/src/packaging/requirements.py b/src/packaging/requirements.py index 18640d438..b25efcb77 100644 --- a/src/packaging/requirements.py +++ b/src/packaging/requirements.py @@ -77,7 +77,7 @@ def __str__(self) -> str: return "".join(self._iter_parts(self.name)) def __repr__(self) -> str: - return f"<{self.__class__.__name__}({str(self)!r})>" + return f"{self.__class__.__name__}({str(self)!r})" def __hash__(self) -> int: return hash(tuple(self._iter_parts(canonicalize_name(self.name)))) diff --git a/src/packaging/specifiers.py b/src/packaging/specifiers.py index 13bc9bda5..49136600f 100644 --- a/src/packaging/specifiers.py +++ b/src/packaging/specifiers.py @@ -386,11 +386,11 @@ def __repr__(self) -> str: """A representation of the Specifier that shows all internal state. >>> Specifier('>=1.0.0') - =1.0.0')> + Specifier('>=1.0.0') >>> Specifier('>=1.0.0', prereleases=False) - =1.0.0', prereleases=False)> + Specifier('>=1.0.0', prereleases=False) >>> Specifier('>=1.0.0', prereleases=True) - =1.0.0', prereleases=True)> + Specifier('>=1.0.0', prereleases=True) """ pre = ( f", prereleases={self.prereleases!r}" @@ -398,7 +398,7 @@ def __repr__(self) -> str: else "" ) - return f"<{self.__class__.__name__}({str(self)!r}{pre})>" + return f"{self.__class__.__name__}({str(self)!r}{pre})" def __str__(self) -> str: """A string representation of the Specifier that can be round-tripped. @@ -688,7 +688,7 @@ def filter( >>> list(Specifier(">=1.2.3").filter(["1.2", "1.3", "1.5a1"])) ['1.3'] >>> list(Specifier(">=1.2.3").filter(["1.2", "1.2.3", "1.3", Version("1.4")])) - ['1.2.3', '1.3', ] + ['1.2.3', '1.3', Version('1.4')] >>> list(Specifier(">=1.2.3").filter(["1.2", "1.5a1"])) ['1.5a1'] >>> list(Specifier(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True)) @@ -922,11 +922,11 @@ def __repr__(self) -> str: match the input string. >>> SpecifierSet('>=1.0.0,!=2.0.0') - =1.0.0')> + SpecifierSet('!=2.0.0,>=1.0.0') >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=False) - =1.0.0', prereleases=False)> + SpecifierSet('!=2.0.0,>=1.0.0', prereleases=False) >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=True) - =1.0.0', prereleases=True)> + SpecifierSet('!=2.0.0,>=1.0.0', prereleases=True) """ pre = ( f", prereleases={self.prereleases!r}" @@ -934,7 +934,7 @@ def __repr__(self) -> str: else "" ) - return f"<{self.__class__.__name__}({str(self)!r}{pre})>" + return f"{self.__class__.__name__}({str(self)!r}{pre})" def __str__(self) -> str: """A string representation of the specifier set that can be round-tripped. @@ -958,9 +958,9 @@ def __and__(self, other: SpecifierSet | str) -> SpecifierSet: :param other: The other object to combine with. >>> SpecifierSet(">=1.0.0,!=1.0.1") & '<=2.0.0,!=2.0.1' - =1.0.0')> + SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0') >>> SpecifierSet(">=1.0.0,!=1.0.1") & SpecifierSet('<=2.0.0,!=2.0.1') - =1.0.0')> + SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0') """ if isinstance(other, str): other = SpecifierSet(other) @@ -1018,7 +1018,7 @@ def __iter__(self) -> Iterator[Specifier]: in this specifier set. >>> sorted(SpecifierSet(">=1.0.0,!=1.0.1"), key=str) - [, =1.0.0')>] + [Specifier('!=1.0.1'), Specifier('>=1.0.0')] """ return iter(self._specs) @@ -1122,7 +1122,7 @@ def filter( >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", "1.5a1"])) ['1.3'] >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", Version("1.4")])) - ['1.3', ] + ['1.3', Version('1.4')] >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.5a1"])) ['1.5a1'] >>> list(SpecifierSet(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True)) diff --git a/src/packaging/tags.py b/src/packaging/tags.py index e3cc602ec..bf9ba1248 100644 --- a/src/packaging/tags.py +++ b/src/packaging/tags.py @@ -114,7 +114,10 @@ def __str__(self) -> str: return f"{self._interpreter}-{self._abi}-{self._platform}" def __repr__(self) -> str: - return f"<{self} @ {id(self)}>" + return ( + f"{self.__class__.__name__}" + f"({self._interpreter!r}, {self._abi!r}, {self._interpreter!r})" + ) def __setstate__(self, state: tuple[None, dict[str, Any]]) -> None: # The cached _hash is wrong when unpickling. diff --git a/src/packaging/version.py b/src/packaging/version.py index a11d46398..b29f7de98 100644 --- a/src/packaging/version.py +++ b/src/packaging/version.py @@ -123,7 +123,7 @@ def parse(version: str) -> Version: This is identical to the :class:`Version` constructor. >>> parse('1.0.dev1') - + Version('1.0.dev1') :param version: The version string to parse. :raises InvalidVersion: When the version string is not a valid version. @@ -351,9 +351,9 @@ class Version(_BaseVersion): >>> v1 = Version("1.0a5") >>> v2 = Version("1.0") >>> v1 - + Version('1.0a5') >>> v2 - + Version('1.0') >>> v1 < v2 True >>> v1 == v2 @@ -451,9 +451,9 @@ def from_parts( ``release=`` keyword argument is required. >>> Version.from_parts(release=(1,2,3)) - + Version('1.2.3') >>> Version.from_parts(release=(0,1,0), pre=("b", 1)) - + Version('0.1.0b1') :param epoch: :param release: This version tuple is required @@ -489,7 +489,7 @@ def __replace__(self, **kwargs: Unpack[_VersionReplace]) -> Self: >>> v = Version("1.2.3") >>> v.__replace__(pre=("a", 1)) - + Version('1.2.3a1') :param int | None epoch: :param tuple[int, ...] | None release: @@ -570,9 +570,9 @@ def __repr__(self) -> str: """A representation of the Version that shows all internal state. >>> Version('1.0.0') - + Version('1.0.0') """ - return f"<{self.__class__.__name__}({str(self)!r})>" + return f"{self.__class__.__name__}({str(self)!r})" def __str__(self) -> str: """A string representation of the version that can be round-tripped. diff --git a/tests/test_markers.py b/tests/test_markers.py index 3937fbf7e..7328389ca 100644 --- a/tests/test_markers.py +++ b/tests/test_markers.py @@ -70,7 +70,7 @@ def test_str(self, value: str) -> None: @pytest.mark.parametrize("value", ["one", "two"]) def test_repr(self, value: str) -> None: - assert repr(Node(value)) == f"" + assert repr(Node(value)) == f"Node({str(value)!r})" def test_base_class(self) -> None: with pytest.raises(NotImplementedError): @@ -235,7 +235,7 @@ def test_parses_invalid(self, marker_string: str) -> None: def test_str_repr_eq_hash(self, marker_string: str, expected: str) -> None: m = Marker(marker_string) assert str(m) == expected - assert repr(m) == f"" + assert repr(m) == f"Marker({str(m)!r})" # Objects created from the same string should be equal. assert m == Marker(marker_string) # Objects created from the equivalent strings should also be equal. diff --git a/tests/test_requirements.py b/tests/test_requirements.py index 96da8465d..ac1ea766b 100644 --- a/tests/test_requirements.py +++ b/tests/test_requirements.py @@ -669,7 +669,7 @@ def test_str_and_repr( # THEN assert str(req) == to_parse.strip() - assert repr(req) == f"" + assert repr(req) == f"Requirement({to_parse.strip()!r})" @pytest.mark.parametrize(("dep1", "dep2"), EQUAL_DEPENDENCIES) def test_equal_reqs_equal_hashes(self, dep1: str, dep2: str) -> None: diff --git a/tests/test_specifiers.py b/tests/test_specifiers.py index f5949424a..86d2e5ed9 100644 --- a/tests/test_specifiers.py +++ b/tests/test_specifiers.py @@ -234,7 +234,7 @@ def test_specifiers_str_and_repr(self, specifier: str, expected: str) -> None: spec = Specifier(specifier) assert str(spec) == expected - assert repr(spec) == f"" + assert repr(spec) == f"Specifier({expected!r})" @pytest.mark.parametrize("specifier", SPECIFIERS) def test_specifiers_hash(self, specifier: str) -> None: @@ -1879,7 +1879,7 @@ def test_specifiers_str_and_repr(self, specifier: str, expected: str) -> None: spec = SpecifierSet(specifier) assert str(spec) == expected - assert repr(spec) == f"" + assert repr(spec) == f"SpecifierSet({expected!r})" @pytest.mark.parametrize("specifier", SPECIFIERS + LEGACY_SPECIFIERS) def test_specifiers_hash(self, specifier: str) -> None: diff --git a/tests/test_tags.py b/tests/test_tags.py index 0439377ac..24995a3c4 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -133,7 +133,10 @@ def test_str(self, example_tag: tags.Tag) -> None: assert str(example_tag) == "py3-none-any" def test_repr(self, example_tag: tags.Tag) -> None: - assert repr(example_tag) == f"" + assert ( + repr(example_tag) + == f"Tag({example_tag._interpreter!r}, {example_tag._abi!r}, {example_tag._interpreter!r})" + ) def test_attribute_access(self, example_tag: tags.Tag) -> None: assert example_tag.interpreter == "py3" diff --git a/tests/test_version.py b/tests/test_version.py index 68d5dbe44..375fc89e9 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -316,7 +316,7 @@ def test_normalized_versions(self, version: str, normalized: str) -> None: ) def test_version_str_repr(self, version: str, expected: str) -> None: assert str(Version(version)) == expected - assert repr(Version(version)) == f"" + assert repr(Version(version)) == f"Version({expected!r})" def test_version_rc_and_c_equals(self) -> None: assert Version("1.0rc1") == Version("1.0c1") From a50ac88f79bab79872cb039bf5f98a643a9f2a39 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 12 Feb 2026 21:38:09 -0500 Subject: [PATCH 2/2] fix: mistake in previous commit Signed-off-by: Henry Schreiner --- src/packaging/tags.py | 2 +- tests/test_tags.py | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/packaging/tags.py b/src/packaging/tags.py index bf9ba1248..d8458bfb1 100644 --- a/src/packaging/tags.py +++ b/src/packaging/tags.py @@ -116,7 +116,7 @@ def __str__(self) -> str: def __repr__(self) -> str: return ( f"{self.__class__.__name__}" - f"({self._interpreter!r}, {self._abi!r}, {self._interpreter!r})" + f"({self._interpreter!r}, {self._abi!r}, {self._platform!r})" ) def __setstate__(self, state: tuple[None, dict[str, Any]]) -> None: diff --git a/tests/test_tags.py b/tests/test_tags.py index 24995a3c4..548d8810b 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -133,10 +133,7 @@ def test_str(self, example_tag: tags.Tag) -> None: assert str(example_tag) == "py3-none-any" def test_repr(self, example_tag: tags.Tag) -> None: - assert ( - repr(example_tag) - == f"Tag({example_tag._interpreter!r}, {example_tag._abi!r}, {example_tag._interpreter!r})" - ) + assert repr(example_tag) == "Tag('py3', 'none', 'any')" def test_attribute_access(self, example_tag: tags.Tag) -> None: assert example_tag.interpreter == "py3"