From 917612f5774571a99902b5fe04d06099b9e8b667 Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Wed, 17 Aug 2022 16:58:21 -0400 Subject: [PATCH 1/4] Use `Iterator` instead of `Iterable` for specifier filter methods (#584) --- CHANGELOG.rst | 2 ++ packaging/specifiers.py | 16 ++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7885906b5..d8170e8b8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,8 @@ Changelog Evaluating markers like ``"extra == 'xyz'"`` without passing any extra in the ``environment`` will no longer raise an exception. * Remove dependency on ``pyparsing``, by replacing it with a hand-written parser. This package now has no runtime dependencies (:issue:`468`) +* Update return type hint for ``Specifier.filter`` and ``SpecifierSet.filter`` + to use ``Iterator`` instead of ``Iterable`` 21.3 - 2021-11-17 ~~~~~~~~~~~~~~~~~ diff --git a/packaging/specifiers.py b/packaging/specifiers.py index 9220739a7..5afafe3f0 100644 --- a/packaging/specifiers.py +++ b/packaging/specifiers.py @@ -86,7 +86,7 @@ def contains(self, item: str, prereleases: Optional[bool] = None) -> bool: @abc.abstractmethod def filter( self, iterable: Iterable[UnparsedVersion], prereleases: Optional[bool] = None - ) -> Iterable[UnparsedVersion]: + ) -> Iterator[UnparsedVersion]: """ Takes an iterable of items and filters them so that only items which are contained within this specifier are allowed in it. @@ -564,14 +564,14 @@ def contains( def filter( self, iterable: Iterable[UnparsedVersion], prereleases: Optional[bool] = None - ) -> Iterable[UnparsedVersion]: + ) -> Iterator[UnparsedVersion]: """Filter items in the given iterable, that match the specifier. :param iterable: An iterable that can contain version strings and :class:`Version` instances. The items in the iterable will be filtered according to the specifier. :param prereleases: - Whether or not to allow prereleases in the returned iterable. If set to + Whether or not to allow prereleases in the returned iterator. If set to ``None`` (the default), it will be intelligently decide whether to allow prereleases or not (based on the :attr:`prereleases` attribute, and whether the only versions matching are prereleases). @@ -914,14 +914,14 @@ def contains( def filter( self, iterable: Iterable[UnparsedVersion], prereleases: Optional[bool] = None - ) -> Iterable[UnparsedVersion]: + ) -> Iterator[UnparsedVersion]: """Filter items in the given iterable, that match the specifiers in this set. :param iterable: An iterable that can contain version strings and :class:`Version` instances. The items in the iterable will be filtered according to the specifier. :param prereleases: - Whether or not to allow prereleases in the returned iterable. If set to + Whether or not to allow prereleases in the returned iterator. If set to ``None`` (the default), it will be intelligently decide whether to allow prereleases or not (based on the :attr:`prereleases` attribute, and whether the only versions matching are prereleases). @@ -965,7 +965,7 @@ def filter( if self._specs: for spec in self._specs: iterable = spec.filter(iterable, prereleases=bool(prereleases)) - return iterable + return iter(iterable) # If we do not have any specifiers, then we need to have a rough filter # which will filter out any pre-releases, unless there are no final # releases. @@ -987,6 +987,6 @@ def filter( # If we've found no items except for pre-releases, then we'll go # ahead and use the pre-releases if not filtered and found_prereleases and prereleases is None: - return found_prereleases + return iter(found_prereleases) - return filtered + return iter(filtered) From 12800518fc4045ae2112c98f039a1a065cda24d0 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 19 Aug 2022 17:42:22 -0400 Subject: [PATCH 2/4] Better output on linter failure in CI (#478) Co-authored-by: Brett Cannon --- .github/workflows/lint.yml | 2 +- noxfile.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4c09e0213..df4390a06 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -31,7 +31,7 @@ jobs: cache: "pip" - name: Run `nox -s lint` - run: pipx run nox --error-on-missing-interpreters -s lint + run: pipx run nox --error-on-missing-interpreters -s lint -- --show-diff-on-failure build: name: Build sdist and wheel diff --git a/noxfile.py b/noxfile.py index b61a713bb..ae2eb4449 100644 --- a/noxfile.py +++ b/noxfile.py @@ -57,7 +57,7 @@ def coverage(*args): def lint(session): # Run the linters (via pre-commit) session.install("pre-commit") - session.run("pre-commit", "run", "--all-files") + session.run("pre-commit", "run", "--all-files", *session.posargs) # Check the distribution session.install("build", "twine") From b8b2f8aa47c0676628f336487a31f602bea0c857 Mon Sep 17 00:00:00 2001 From: Thimo Date: Sat, 20 Aug 2022 00:10:48 +0200 Subject: [PATCH 3/4] Add a "cpNNN-none-any" tag (#541) Closes #511 See https://github.com/pypa/pip/issues/10923 for motivation. Co-authored-by: Brett Cannon --- packaging/tags.py | 7 +++++-- tests/test_tags.py | 13 +++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packaging/tags.py b/packaging/tags.py index 5b6c5ffd0..a0e1ea23a 100644 --- a/packaging/tags.py +++ b/packaging/tags.py @@ -499,6 +499,9 @@ def sys_tags(*, warn: bool = False) -> Iterator[Tag]: yield from generic_tags() if interp_name == "pp": - yield from compatible_tags(interpreter="pp3") + interp = "pp3" + elif interp_name == "cp": + interp = "cp" + interpreter_version(warn=warn) else: - yield from compatible_tags() + interp = None + yield from compatible_tags(interpreter=interp) diff --git a/tests/test_tags.py b/tests/test_tags.py index 06cd3b4a2..39515e8d1 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -1226,3 +1226,16 @@ def test_pypy_first_none_any_tag(self, monkeypatch): break assert tag == tags.Tag("pp3", "none", "any") + + def test_cpython_first_none_any_tag(self, monkeypatch): + # When building the complete list of cpython tags, make sure the first + # -none-any one is cpxx-none-any + monkeypatch.setattr(tags, "interpreter_name", lambda: "cp") + + # Find the first tag that is ABI- and platform-agnostic. + for tag in tags.sys_tags(): + if tag.abi == "none" and tag.platform == "any": + break + + interpreter = f"cp{tags.interpreter_version()}" + assert tag == tags.Tag(interpreter, "none", "any") From cb2b89f5ac9faf5d87af0ab3d4c345bc2727a0c5 Mon Sep 17 00:00:00 2001 From: Blazej Michalik <6691643+MrMino@users.noreply.github.com> Date: Sat, 20 Aug 2022 00:17:42 +0200 Subject: [PATCH 4/4] Document exceptions raised by functions in `utils` (#544) CLoses #543 Co-authored-by: Brett Cannon --- docs/utils.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/utils.rst b/docs/utils.rst index 192def74f..7a4c2f74d 100644 --- a/docs/utils.rst +++ b/docs/utils.rst @@ -63,6 +63,8 @@ Reference instance of :class:`~packaging.tags.Tag`. :param str filename: The name of the wheel file. + :raises InvalidWheelFilename: If the filename in question + does not follow conventions outlined in `PEP 427`_. .. doctest:: @@ -87,6 +89,9 @@ Reference represented by an instance of :class:`~packaging.version.Version`. :param str filename: The name of the sdist file. + :raises InvalidSdistFilename: If the filename does not end + with an sdist extension (``.zip`` or ``.tar.gz``), or if it does not + contain a dash separating the name and the version of the distribution. .. doctest:: @@ -98,4 +103,14 @@ Reference >>> ver == Version('1.0') True + +.. exception:: InvalidWheelFilename + + Raised when a file name for a wheel is invalid. + +.. exception:: InvalidSdistFilename + + Raised when a source distribution file name is considered invalid. + .. _Source distribution format: https://packaging.python.org/specifications/source-distribution-format/#source-distribution-file-name +.. _`PEP 427`: https://peps.python.org/pep-0427/#file-name-convention