Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-packaging for openSUSE:Factory checked in at 2024-03-20 21:09:31 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-packaging (Old) and /work/SRC/openSUSE:Factory/.python-packaging.new.1905 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-packaging" Wed Mar 20 21:09:31 2024 rev:33 rq:1158406 version:24.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-packaging/python-packaging.changes 2023-11-13 22:15:43.236125174 +0100 +++ /work/SRC/openSUSE:Factory/.python-packaging.new.1905/python-packaging.changes 2024-03-20 21:09:33.055379098 +0100 @@ -1,0 +2,18 @@ +Sat Mar 16 09:28:29 UTC 2024 - Dirk Müller <dmuel...@suse.com> + +- update to 24.0: + * Do specifier matching correctly when the specifier contains + an epoch number and has more components than the version + (:issue:`683`) + * Support the experimental --disable-gil builds in + packaging.tags (:issue:`727`) + * BREAKING: Make optional metadata.Metadata attributes default + to None (:issue:`733`) + * Fix errors when trying to access the + description_content_type, keywords, and requires_python + attributes on metadata.Metadata when those values have not + been provided (:issue:`733`) + * Fix a bug preventing the use of the built in ExceptionGroup + on versions of Python that support it (:issue:`725`) + +------------------------------------------------------------------- Old: ---- packaging-23.2.tar.gz New: ---- packaging-24.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-packaging.spec ++++++ --- /var/tmp/diff_new_pack.DVMlvt/_old 2024-03-20 21:09:33.867408938 +0100 +++ /var/tmp/diff_new_pack.DVMlvt/_new 2024-03-20 21:09:33.871409085 +0100 @@ -1,7 +1,7 @@ # -# spec file +# spec file for package python-packaging # -# Copyright (c) 2023 SUSE LLC +# Copyright (c) 2024 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -53,7 +53,7 @@ %endif Name: %{pprefix}-packaging%{?psuffix} -Version: 23.2 +Version: 24.0 Release: 0 Summary: Core utilities for Python packages License: Apache-2.0 AND BSD-2-Clause ++++++ packaging-23.2.tar.gz -> packaging-24.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/CHANGELOG.rst new/packaging-24.0/CHANGELOG.rst --- old/packaging-23.2/CHANGELOG.rst 2023-10-01 15:49:25.447660000 +0200 +++ new/packaging-24.0/CHANGELOG.rst 2024-03-10 10:38:57.045243300 +0100 @@ -1,6 +1,20 @@ Changelog --------- +24.0 - 2024-03-10 +~~~~~~~~~~~~~~~~~ + +* Do specifier matching correctly when the specifier contains an epoch number + and has more components than the version (:issue:`683`) +* Support the experimental ``--disable-gil`` builds in packaging.tags + (:issue:`727`) +* BREAKING: Make optional ``metadata.Metadata`` attributes default to ``None`` (:issue:`733`) +* Fix errors when trying to access the ``description_content_type``, ``keywords``, + and ``requires_python`` attributes on ``metadata.Metadata`` when those values + have not been provided (:issue:`733`) +* Fix a bug preventing the use of the built in ``ExceptionGroup`` on versions of + Python that support it (:issue:`725`) + 23.2 - 2023-10-01 ~~~~~~~~~~~~~~~~~ @@ -9,7 +23,7 @@ * Requirement parsing no longer automatically validates the URL (:issue:`120`) * Canonicalize names for requirements comparison (:issue:`644`) * Introduce ``metadata.Metadata`` (along with ``metadata.ExceptionGroup`` and ``metadata.InvalidMetadata``; :issue:`570`) -* Introduce the ``validate`` keyword parameter to ``utils.validate_name()`` (:issue:`570`) +* Introduce the ``validate`` keyword parameter to ``utils.normalize_name()`` (:issue:`570`) * Introduce ``utils.is_normalized_name()`` (:issue:`570`) * Make ``utils.parse_sdist_filename()`` and ``utils.parse_wheel_filename()`` raise ``InvalidSdistFilename`` and ``InvalidWheelFilename``, respectively, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/PKG-INFO new/packaging-24.0/PKG-INFO --- old/packaging-23.2/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 +++ new/packaging-24.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: packaging -Version: 23.2 +Version: 24.0 Summary: Core utilities for Python packages Author-email: Donald Stufft <don...@stufft.io> Requires-Python: >=3.7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/docs/development/getting-started.rst new/packaging-24.0/docs/development/getting-started.rst --- old/packaging-23.2/docs/development/getting-started.rst 2023-01-30 16:24:13.025143900 +0100 +++ new/packaging-24.0/docs/development/getting-started.rst 2024-03-10 10:34:41.955998400 +0100 @@ -73,5 +73,5 @@ .. _`virtualenv`: https://pypi.org/project/virtualenv/ .. _`pip`: https://pypi.org/project/pip/ .. _`sphinx`: https://pypi.org/project/Sphinx/ -.. _`reStructured Text`: http://sphinx-doc.org/rest.html +.. _`reStructured Text`: https://www.sphinx-doc.org/en/master/usage/restructuredtext/ .. _`pre-commit`: https://pre-commit.com diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/docs/development/index.rst new/packaging-24.0/docs/development/index.rst --- old/packaging-23.2/docs/development/index.rst 2021-07-23 09:28:26.383909700 +0200 +++ new/packaging-24.0/docs/development/index.rst 2024-03-10 10:34:41.956156300 +0100 @@ -16,4 +16,4 @@ release-process .. _`GitHub`: https://github.com/pypa/packaging -.. _`what to put in your bug report`: http://www.contribution-guide.org/#what-to-put-in-your-bug-report +.. _`what to put in your bug report`: https://www.contribution-guide.org/#what-to-put-in-your-bug-report diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/docs/development/submitting-patches.rst new/packaging-24.0/docs/development/submitting-patches.rst --- old/packaging-23.2/docs/development/submitting-patches.rst 2022-04-02 15:23:31.358636600 +0200 +++ new/packaging-24.0/docs/development/submitting-patches.rst 2024-03-10 10:34:41.956318600 +0100 @@ -70,5 +70,5 @@ .. |black| replace:: ``black`` .. _black: https://pypi.org/project/black/ .. _`Write comments as complete sentences.`: https://nedbatchelder.com/blog/201401/comments_should_be_sentences.html -.. _`syntax`: http://sphinx-doc.org/domains.html#info-field-lists -.. _`Studies have shown`: http://www.ibm.com/developerworks/rational/library/11-proven-practices-for-peer-review/ +.. _`syntax`: https://www.sphinx-doc.org/en/master/usage/restructuredtext/field-lists.html +.. _`Studies have shown`: https://www.microsoft.com/en-us/research/publication/characteristics-of-useful-code-reviews-an-empirical-study-at-microsoft/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/docs/markers.rst new/packaging-24.0/docs/markers.rst --- old/packaging-23.2/docs/markers.rst 2023-01-30 16:24:13.025342500 +0100 +++ new/packaging-24.0/docs/markers.rst 2024-01-06 21:39:23.974311800 +0100 @@ -5,7 +5,8 @@ One extra requirement of dealing with dependencies is the ability to specify if it is required depending on the operating system or Python version in use. -`PEP 508`_ defines the scheme which has been implemented by this module. +The :ref:`specification of dependency specifiers <pypug:dependency-specifiers>` +defines the scheme which has been implemented by this module. Usage ----- @@ -51,7 +52,7 @@ This class abstracts handling markers for dependencies of a project. It can be passed a single marker or multiple markers that are ANDed or ORed - together. Each marker will be parsed according to PEP 508. + together. Each marker will be parsed according to the specification. :param str markers: The string representation of a marker or markers. :raises InvalidMarker: If the given ``markers`` are not parseable, then @@ -63,8 +64,10 @@ :param dict environment: A dictionary containing keys and values to override the detected environment. - :raises: UndefinedComparison: If the marker uses a PEP 440 comparison on - strings which are not valid PEP 440 versions. + :raises: UndefinedComparison: If the marker uses a comparison on strings + which are not valid versions per the + :ref:`specification of version specifiers + <pypug:version-specifiers>`. :raises: UndefinedEnvironmentName: If the marker accesses a value that isn't present inside of the environment dictionary. @@ -72,19 +75,18 @@ .. exception:: InvalidMarker Raised when attempting to create a :class:`Marker` with a string that - does not conform to PEP 508. + does not conform to the specification. .. exception:: UndefinedComparison - Raised when attempting to evaluate a :class:`Marker` with a PEP 440 - comparison operator against values that are not valid PEP 440 versions. + Raised when attempting to evaluate a :class:`Marker` with a + comparison operator against values that are not valid + versions per the :ref:`specification of version specifiers + <pypug:version-specifiers>`. .. exception:: UndefinedEnvironmentName Raised when attempting to evaluate a :class:`Marker` with a value that is missing from the evaluation environment. - - -.. _`PEP 508`: https://www.python.org/dev/peps/pep-0508/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/docs/requirements.rst new/packaging-24.0/docs/requirements.rst --- old/packaging-23.2/docs/requirements.rst 2023-10-01 14:58:59.369405300 +0200 +++ new/packaging-24.0/docs/requirements.rst 2024-01-06 21:39:23.974455600 +0100 @@ -4,8 +4,9 @@ .. currentmodule:: packaging.requirements Parse a given requirements line for specifying dependencies of a Python -project, using `PEP 508`_ which defines the scheme that has been implemented -by this module. +project, using the :ref:`specification of dependency specifiers +<pypug:dependency-specifiers>`, which defines the scheme that has been +implemented by this module. Usage ----- @@ -60,8 +61,8 @@ When a requirement is specified with a URL, the :class:`Requirement` class used to check the URL and reject values containing invalid scheme and - netloc combinations. This is no longer performed since PEP 508 does not - specify such rules, and the check incorrectly disallows valid requirement + netloc combinations. This is no longer performed since the specification does + not have such rules, and the check incorrectly disallows valid requirement strings from being parsed. Reference @@ -70,7 +71,7 @@ .. class:: Requirement(requirement) This class abstracts handling the details of a requirement for a project. - Each requirement will be parsed according to PEP 508. + Each requirement will be parsed according to the specification. :param str requirement: The string representation of a requirement. :raises InvalidRequirement: If the given ``requirement`` is not parseable, @@ -99,6 +100,4 @@ .. exception:: InvalidRequirement Raised when attempting to create a :class:`Requirement` with a string that - does not conform to PEP 508. - -.. _`PEP 508`: https://www.python.org/dev/peps/pep-0508/ + does not conform to the specification. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/docs/utils.rst new/packaging-24.0/docs/utils.rst --- old/packaging-23.2/docs/utils.rst 2023-10-01 14:58:59.369609600 +0200 +++ new/packaging-24.0/docs/utils.rst 2024-01-06 21:39:23.974585000 +0100 @@ -85,7 +85,8 @@ :param str filename: The name of the wheel file. :raises InvalidWheelFilename: If the filename in question - does not follow conventions outlined in `PEP 427`_. + does not follow the :ref:`wheel specification + <pypug:binary-distribution-format>`. .. doctest:: @@ -137,4 +138,3 @@ 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/pyproject.toml new/packaging-24.0/pyproject.toml --- old/packaging-23.2/pyproject.toml 2023-10-01 14:58:59.370197300 +0200 +++ new/packaging-24.0/pyproject.toml 2024-01-06 21:39:23.974710700 +0100 @@ -42,7 +42,6 @@ [tool.coverage.run] branch = true -omit = ["packaging/_compat.py"] [tool.coverage.report] exclude_lines = ["pragma: no cover", "@abc.abstractmethod", "@abc.abstractproperty"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/src/packaging/__init__.py new/packaging-24.0/src/packaging/__init__.py --- old/packaging-23.2/src/packaging/__init__.py 2023-10-01 15:49:25.447881500 +0200 +++ new/packaging-24.0/src/packaging/__init__.py 2024-03-10 10:38:57.045582800 +0100 @@ -6,7 +6,7 @@ __summary__ = "Core utilities for Python packages" __uri__ = "https://github.com/pypa/packaging" -__version__ = "23.2" +__version__ = "24.0" __author__ = "Donald Stufft and individual contributors" __email__ = "don...@stufft.io" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/src/packaging/_manylinux.py new/packaging-24.0/src/packaging/_manylinux.py --- old/packaging-23.2/src/packaging/_manylinux.py 2023-10-01 14:58:59.370645000 +0200 +++ new/packaging-24.0/src/packaging/_manylinux.py 2024-03-10 10:34:41.956493400 +0100 @@ -55,7 +55,15 @@ return _is_linux_armhf(executable) if "i686" in archs: return _is_linux_i686(executable) - allowed_archs = {"x86_64", "aarch64", "ppc64", "ppc64le", "s390x", "loongarch64"} + allowed_archs = { + "x86_64", + "aarch64", + "ppc64", + "ppc64le", + "s390x", + "loongarch64", + "riscv64", + } return any(arch in allowed_archs for arch in archs) @@ -82,7 +90,7 @@ # https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183 try: # Should be a string like "glibc 2.17". - version_string: str = getattr(os, "confstr")("CS_GNU_LIBC_VERSION") + version_string: Optional[str] = os.confstr("CS_GNU_LIBC_VERSION") assert version_string is not None _, version = version_string.rsplit() except (AssertionError, AttributeError, OSError, ValueError): @@ -174,7 +182,7 @@ return False # Check for presence of _manylinux module. try: - import _manylinux # noqa + import _manylinux except ImportError: return True if hasattr(_manylinux, "manylinux_compatible"): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/src/packaging/_parser.py new/packaging-24.0/src/packaging/_parser.py --- old/packaging-23.2/src/packaging/_parser.py 2023-04-21 00:00:17.821521300 +0200 +++ new/packaging-24.0/src/packaging/_parser.py 2024-03-10 10:34:41.956662700 +0100 @@ -324,10 +324,7 @@ def process_env_var(env_var: str) -> Variable: - if ( - env_var == "platform_python_implementation" - or env_var == "python_implementation" - ): + if env_var in ("platform_python_implementation", "python_implementation"): return Variable("platform_python_implementation") else: return Variable(env_var) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/src/packaging/metadata.py new/packaging-24.0/src/packaging/metadata.py --- old/packaging-23.2/src/packaging/metadata.py 2023-10-01 14:58:59.371100400 +0200 +++ new/packaging-24.0/src/packaging/metadata.py 2024-01-06 21:39:23.974911200 +0100 @@ -41,10 +41,10 @@ try: - ExceptionGroup = __builtins__.ExceptionGroup # type: ignore[attr-defined] -except AttributeError: + ExceptionGroup +except NameError: # pragma: no cover - class ExceptionGroup(Exception): # type: ignore[no-redef] # noqa: N818 + class ExceptionGroup(Exception): # noqa: N818 """A minimal implementation of :external:exc:`ExceptionGroup` from Python 3.11. If :external:exc:`ExceptionGroup` is already defined by Python itself, @@ -61,6 +61,9 @@ def __repr__(self) -> str: return f"{self.__class__.__name__}({self.message!r}, {self.exceptions!r})" +else: # pragma: no cover + ExceptionGroup = ExceptionGroup + class InvalidMetadata(ValueError): """A metadata field contains invalid data.""" @@ -505,24 +508,19 @@ # No need to check the cache as attribute lookup will resolve into the # instance's __dict__ before __get__ is called. cache = instance.__dict__ - try: - value = instance._raw[self.name] # type: ignore[literal-required] - except KeyError: - if self.name in _STRING_FIELDS: - value = "" - elif self.name in _LIST_FIELDS: - value = [] - elif self.name in _DICT_FIELDS: - value = {} - else: # pragma: no cover - assert False + value = instance._raw.get(self.name) - try: - converter: Callable[[Any], T] = getattr(self, f"_process_{self.name}") - except AttributeError: - pass - else: - value = converter(value) + # To make the _process_* methods easier, we'll check if the value is None + # and if this field is NOT a required attribute, and if both of those + # things are true, we'll skip the the converter. This will mean that the + # converters never have to deal with the None union. + if self.name in _REQUIRED_ATTRS or value is not None: + try: + converter: Callable[[Any], T] = getattr(self, f"_process_{self.name}") + except AttributeError: + pass + else: + value = converter(value) cache[self.name] = value try: @@ -677,7 +675,7 @@ ins._raw = data.copy() # Mutations occur due to caching enriched values. if validate: - exceptions: List[InvalidMetadata] = [] + exceptions: List[Exception] = [] try: metadata_version = ins.metadata_version metadata_age = _VALID_METADATA_VERSIONS.index(metadata_version) @@ -732,10 +730,10 @@ If *validate* is true, the metadata will be validated. All exceptions related to validation will be gathered and raised as an :class:`ExceptionGroup`. """ - exceptions: list[InvalidMetadata] = [] raw, unparsed = parse_email(data) if validate: + exceptions: list[Exception] = [] for unparsed_key in unparsed: if unparsed_key in _EMAIL_TO_RAW_MAPPING: message = f"{unparsed_key!r} has invalid data" @@ -749,8 +747,9 @@ try: return cls.from_raw(raw, validate=validate) except ExceptionGroup as exc_group: - exceptions.extend(exc_group.exceptions) - raise ExceptionGroup("invalid or unparsed metadata", exceptions) from None + raise ExceptionGroup( + "invalid or unparsed metadata", exc_group.exceptions + ) from None metadata_version: _Validator[_MetadataVersion] = _Validator() """:external:ref:`core-metadata-metadata-version` @@ -761,62 +760,66 @@ *validate* parameter)""" version: _Validator[version_module.Version] = _Validator() """:external:ref:`core-metadata-version` (required)""" - dynamic: _Validator[List[str]] = _Validator( + dynamic: _Validator[Optional[List[str]]] = _Validator( added="2.2", ) """:external:ref:`core-metadata-dynamic` (validated against core metadata field names and lowercased)""" - platforms: _Validator[List[str]] = _Validator() + platforms: _Validator[Optional[List[str]]] = _Validator() """:external:ref:`core-metadata-platform`""" - supported_platforms: _Validator[List[str]] = _Validator(added="1.1") + supported_platforms: _Validator[Optional[List[str]]] = _Validator(added="1.1") """:external:ref:`core-metadata-supported-platform`""" - summary: _Validator[str] = _Validator() + summary: _Validator[Optional[str]] = _Validator() """:external:ref:`core-metadata-summary` (validated to contain no newlines)""" - description: _Validator[str] = _Validator() # TODO 2.1: can be in body + description: _Validator[Optional[str]] = _Validator() # TODO 2.1: can be in body """:external:ref:`core-metadata-description`""" - description_content_type: _Validator[str] = _Validator(added="2.1") + description_content_type: _Validator[Optional[str]] = _Validator(added="2.1") """:external:ref:`core-metadata-description-content-type` (validated)""" - keywords: _Validator[List[str]] = _Validator() + keywords: _Validator[Optional[List[str]]] = _Validator() """:external:ref:`core-metadata-keywords`""" - home_page: _Validator[str] = _Validator() + home_page: _Validator[Optional[str]] = _Validator() """:external:ref:`core-metadata-home-page`""" - download_url: _Validator[str] = _Validator(added="1.1") + download_url: _Validator[Optional[str]] = _Validator(added="1.1") """:external:ref:`core-metadata-download-url`""" - author: _Validator[str] = _Validator() + author: _Validator[Optional[str]] = _Validator() """:external:ref:`core-metadata-author`""" - author_email: _Validator[str] = _Validator() + author_email: _Validator[Optional[str]] = _Validator() """:external:ref:`core-metadata-author-email`""" - maintainer: _Validator[str] = _Validator(added="1.2") + maintainer: _Validator[Optional[str]] = _Validator(added="1.2") """:external:ref:`core-metadata-maintainer`""" - maintainer_email: _Validator[str] = _Validator(added="1.2") + maintainer_email: _Validator[Optional[str]] = _Validator(added="1.2") """:external:ref:`core-metadata-maintainer-email`""" - license: _Validator[str] = _Validator() + license: _Validator[Optional[str]] = _Validator() """:external:ref:`core-metadata-license`""" - classifiers: _Validator[List[str]] = _Validator(added="1.1") + classifiers: _Validator[Optional[List[str]]] = _Validator(added="1.1") """:external:ref:`core-metadata-classifier`""" - requires_dist: _Validator[List[requirements.Requirement]] = _Validator(added="1.2") + requires_dist: _Validator[Optional[List[requirements.Requirement]]] = _Validator( + added="1.2" + ) """:external:ref:`core-metadata-requires-dist`""" - requires_python: _Validator[specifiers.SpecifierSet] = _Validator(added="1.2") + requires_python: _Validator[Optional[specifiers.SpecifierSet]] = _Validator( + added="1.2" + ) """:external:ref:`core-metadata-requires-python`""" # Because `Requires-External` allows for non-PEP 440 version specifiers, we # don't do any processing on the values. - requires_external: _Validator[List[str]] = _Validator(added="1.2") + requires_external: _Validator[Optional[List[str]]] = _Validator(added="1.2") """:external:ref:`core-metadata-requires-external`""" - project_urls: _Validator[Dict[str, str]] = _Validator(added="1.2") + project_urls: _Validator[Optional[Dict[str, str]]] = _Validator(added="1.2") """:external:ref:`core-metadata-project-url`""" # PEP 685 lets us raise an error if an extra doesn't pass `Name` validation # regardless of metadata version. - provides_extra: _Validator[List[utils.NormalizedName]] = _Validator( + provides_extra: _Validator[Optional[List[utils.NormalizedName]]] = _Validator( added="2.1", ) """:external:ref:`core-metadata-provides-extra`""" - provides_dist: _Validator[List[str]] = _Validator(added="1.2") + provides_dist: _Validator[Optional[List[str]]] = _Validator(added="1.2") """:external:ref:`core-metadata-provides-dist`""" - obsoletes_dist: _Validator[List[str]] = _Validator(added="1.2") + obsoletes_dist: _Validator[Optional[List[str]]] = _Validator(added="1.2") """:external:ref:`core-metadata-obsoletes-dist`""" - requires: _Validator[List[str]] = _Validator(added="1.1") + requires: _Validator[Optional[List[str]]] = _Validator(added="1.1") """``Requires`` (deprecated)""" - provides: _Validator[List[str]] = _Validator(added="1.1") + provides: _Validator[Optional[List[str]]] = _Validator(added="1.1") """``Provides`` (deprecated)""" - obsoletes: _Validator[List[str]] = _Validator(added="1.1") + obsoletes: _Validator[Optional[List[str]]] = _Validator(added="1.1") """``Obsoletes`` (deprecated)""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/src/packaging/requirements.py new/packaging-24.0/src/packaging/requirements.py --- old/packaging-23.2/src/packaging/requirements.py 2023-10-01 14:58:59.371256600 +0200 +++ new/packaging-24.0/src/packaging/requirements.py 2024-03-10 10:34:41.956819000 +0100 @@ -38,7 +38,7 @@ self.name: str = parsed.name self.url: Optional[str] = parsed.url or None - self.extras: Set[str] = set(parsed.extras if parsed.extras else []) + self.extras: Set[str] = set(parsed.extras or []) self.specifier: SpecifierSet = SpecifierSet(parsed.specifier) self.marker: Optional[Marker] = None if parsed.marker is not None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/src/packaging/specifiers.py new/packaging-24.0/src/packaging/specifiers.py --- old/packaging-23.2/src/packaging/specifiers.py 2023-04-12 18:05:06.674899300 +0200 +++ new/packaging-24.0/src/packaging/specifiers.py 2024-03-10 10:34:41.957051500 +0100 @@ -11,17 +11,7 @@ import abc import itertools import re -from typing import ( - Callable, - Iterable, - Iterator, - List, - Optional, - Set, - Tuple, - TypeVar, - Union, -) +from typing import Callable, Iterable, Iterator, List, Optional, Tuple, TypeVar, Union from .utils import canonicalize_version from .version import Version @@ -383,7 +373,7 @@ # We want everything but the last item in the version, but we want to # ignore suffix segments. - prefix = ".".join( + prefix = _version_join( list(itertools.takewhile(_is_not_suffix, _version_split(spec)))[:-1] ) @@ -404,13 +394,13 @@ ) # Get the normalized version string ignoring the trailing .* normalized_spec = canonicalize_version(spec[:-2], strip_trailing_zero=False) - # Split the spec out by dots, and pretend that there is an implicit - # dot in between a release segment and a pre-release segment. + # Split the spec out by bangs and dots, and pretend that there is + # an implicit dot in between a release segment and a pre-release segment. split_spec = _version_split(normalized_spec) - # Split the prospective version out by dots, and pretend that there - # is an implicit dot in between a release segment and a pre-release - # segment. + # Split the prospective version out by bangs and dots, and pretend + # that there is an implicit dot in between a release segment and + # a pre-release segment. split_prospective = _version_split(normalized_prospective) # 0-pad the prospective version before shortening it to get the correct @@ -644,8 +634,19 @@ def _version_split(version: str) -> List[str]: + """Split version into components. + + The split components are intended for version comparison. The logic does + not attempt to retain the original version string, so joining the + components back with :func:`_version_join` may not produce the original + version string. + """ result: List[str] = [] - for item in version.split("."): + + epoch, _, rest = version.rpartition("!") + result.append(epoch or "0") + + for item in rest.split("."): match = _prefix_regex.search(item) if match: result.extend(match.groups()) @@ -654,6 +655,17 @@ return result +def _version_join(components: List[str]) -> str: + """Join split version components into a version string. + + This function assumes the input came from :func:`_version_split`, where the + first component must be the epoch (either empty or numeric), and all other + components numeric. + """ + epoch, *rest = components + return f"{epoch}!{'.'.join(rest)}" + + def _is_not_suffix(segment: str) -> bool: return not any( segment.startswith(prefix) for prefix in ("dev", "a", "b", "rc", "post") @@ -675,7 +687,10 @@ left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0]))) right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0]))) - return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split))) + return ( + list(itertools.chain.from_iterable(left_split)), + list(itertools.chain.from_iterable(right_split)), + ) class SpecifierSet(BaseSpecifier): @@ -707,14 +722,8 @@ # strip each item to remove leading/trailing whitespace. split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] - # Parsed each individual specifier, attempting first to make it a - # Specifier. - parsed: Set[Specifier] = set() - for specifier in split_specifiers: - parsed.add(Specifier(specifier)) - - # Turn our parsed specifiers into a frozen set and save them for later. - self._specs = frozenset(parsed) + # Make each individual specifier a Specifier and save in a frozen set for later. + self._specs = frozenset(map(Specifier, split_specifiers)) # Store our prereleases value so we can use it later to determine if # we accept prereleases or not. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/src/packaging/tags.py new/packaging-24.0/src/packaging/tags.py --- old/packaging-23.2/src/packaging/tags.py 2023-10-01 14:58:59.371487600 +0200 +++ new/packaging-24.0/src/packaging/tags.py 2024-01-06 21:39:23.975305000 +0100 @@ -4,6 +4,7 @@ import logging import platform +import re import struct import subprocess import sys @@ -124,20 +125,37 @@ return string.replace(".", "_").replace("-", "_").replace(" ", "_") -def _abi3_applies(python_version: PythonVersion) -> bool: +def _is_threaded_cpython(abis: List[str]) -> bool: + """ + Determine if the ABI corresponds to a threaded (`--disable-gil`) build. + + The threaded builds are indicated by a "t" in the abiflags. + """ + if len(abis) == 0: + return False + # expect e.g., cp313 + m = re.match(r"cp\d+(.*)", abis[0]) + if not m: + return False + abiflags = m.group(1) + return "t" in abiflags + + +def _abi3_applies(python_version: PythonVersion, threading: bool) -> bool: """ Determine if the Python version supports abi3. - PEP 384 was first implemented in Python 3.2. + PEP 384 was first implemented in Python 3.2. The threaded (`--disable-gil`) + builds do not support abi3. """ - return len(python_version) > 1 and tuple(python_version) >= (3, 2) + return len(python_version) > 1 and tuple(python_version) >= (3, 2) and not threading def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> List[str]: py_version = tuple(py_version) # To allow for version comparison. abis = [] version = _version_nodot(py_version[:2]) - debug = pymalloc = ucs4 = "" + threading = debug = pymalloc = ucs4 = "" with_debug = _get_config_var("Py_DEBUG", warn) has_refcount = hasattr(sys, "gettotalrefcount") # Windows doesn't set Py_DEBUG, so checking for support of debug-compiled @@ -146,6 +164,8 @@ has_ext = "_d.pyd" in EXTENSION_SUFFIXES if with_debug or (with_debug is None and (has_refcount or has_ext)): debug = "d" + if py_version >= (3, 13) and _get_config_var("Py_GIL_DISABLED", warn): + threading = "t" if py_version < (3, 8): with_pymalloc = _get_config_var("WITH_PYMALLOC", warn) if with_pymalloc or with_pymalloc is None: @@ -159,13 +179,8 @@ elif debug: # Debug builds can also load "normal" extension modules. # We can also assume no UCS-4 or pymalloc requirement. - abis.append(f"cp{version}") - abis.insert( - 0, - "cp{version}{debug}{pymalloc}{ucs4}".format( - version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4 - ), - ) + abis.append(f"cp{version}{threading}") + abis.insert(0, f"cp{version}{threading}{debug}{pymalloc}{ucs4}") return abis @@ -213,11 +228,14 @@ for abi in abis: for platform_ in platforms: yield Tag(interpreter, abi, platform_) - if _abi3_applies(python_version): + + threading = _is_threaded_cpython(abis) + use_abi3 = _abi3_applies(python_version, threading) + if use_abi3: yield from (Tag(interpreter, "abi3", platform_) for platform_ in platforms) yield from (Tag(interpreter, "none", platform_) for platform_ in platforms) - if _abi3_applies(python_version): + if use_abi3: for minor_version in range(python_version[1] - 1, 1, -1): for platform_ in platforms: interpreter = "cp{version}".format( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/tests/test_manylinux.py new/packaging-24.0/tests/test_manylinux.py --- old/packaging-23.2/tests/test_manylinux.py 2023-10-01 14:58:59.374029000 +0200 +++ new/packaging-24.0/tests/test_manylinux.py 2024-01-06 21:39:23.975467200 +0100 @@ -140,6 +140,7 @@ assert _glibc_version_string_ctypes() is None +@pytest.mark.xfail(ctypes is None, reason="ctypes not available") def test_glibc_version_string_ctypes_raise_oserror(monkeypatch): def patched_cdll(name): raise OSError("Dynamic loading not supported") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/tests/test_metadata.py new/packaging-24.0/tests/test_metadata.py --- old/packaging-23.2/tests/test_metadata.py 2023-10-01 14:58:59.374242300 +0200 +++ new/packaging-24.0/tests/test_metadata.py 2024-01-06 21:39:23.975622200 +0100 @@ -251,7 +251,7 @@ individual_exception = Exception("not important") exc = metadata.ExceptionGroup("message", [individual_exception]) assert exc.message == "message" - assert exc.exceptions == [individual_exception] + assert list(exc.exceptions) == [individual_exception] def test_repr(self): individual_exception = RuntimeError("not important") @@ -378,12 +378,6 @@ with pytest.raises(ExceptionGroup): metadata.Metadata.from_raw(raw, validate=True) - @pytest.mark.parametrize("field", metadata._DICT_FIELDS) - def test_dict_default(self, field): - empty_meta = metadata.Metadata.from_raw({}, validate=False) - - assert getattr(empty_meta, field) == {} - @pytest.mark.parametrize( "attribute", [ @@ -403,10 +397,6 @@ assert getattr(meta, attribute) == value - empty_meta = metadata.Metadata.from_raw({}, validate=False) - - assert getattr(empty_meta, attribute) == "" - @pytest.mark.parametrize( "attribute", [ @@ -426,14 +416,6 @@ assert getattr(meta, attribute) == values - empty_meta = metadata.Metadata.from_raw({}, validate=False) - assert getattr(empty_meta, attribute) == [] - - def test_mapping_default_attribute(self): - empty_meta = metadata.Metadata.from_raw({}, validate=False) - - assert empty_meta.project_urls == {} - @pytest.mark.parametrize("version", ["1.0", "1.1", "1.2", "2.1", "2.2", "2.3"]) def test_valid_metadata_version(self, version): meta = metadata.Metadata.from_raw({"metadata_version": version}, validate=False) @@ -628,3 +610,11 @@ with pytest.raises(metadata.InvalidMetadata): meta.dynamic + + @pytest.mark.parametrize( + "field_name", + sorted(metadata._RAW_TO_EMAIL_MAPPING.keys() - metadata._REQUIRED_ATTRS), + ) + def test_optional_defaults_to_none(self, field_name): + meta = metadata.Metadata.from_raw({}, validate=False) + assert getattr(meta, field_name) is None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/tests/test_specifiers.py new/packaging-24.0/tests/test_specifiers.py --- old/packaging-23.2/tests/test_specifiers.py 2023-04-12 18:05:06.676737300 +0200 +++ new/packaging-24.0/tests/test_specifiers.py 2024-03-10 10:34:41.957288300 +0100 @@ -235,8 +235,7 @@ @pytest.mark.parametrize( ("left", "right", "op"), - itertools.chain( - * + itertools.chain.from_iterable( # Verify that the equal (==) operator works correctly [[(x, x, operator.eq) for x in SPECIFIERS]] + @@ -260,8 +259,7 @@ @pytest.mark.parametrize( ("left", "right", "op"), - itertools.chain( - * + itertools.chain.from_iterable( # Verify that the equal (==) operator works correctly [[(x, x, operator.ne) for x in SPECIFIERS]] + @@ -369,6 +367,7 @@ ("2!1.0", "==2!1.*"), ("2!1.0", "==2!1.0"), ("2!1.0", "!=1.0"), + ("2!1.0.0", "==2!1.0.0.0.*"), ("2!1.0.0", "==2!1.0.*"), ("2!1.0.0", "==2!1.*"), ("1.0", "!=2!1.0"), @@ -467,6 +466,8 @@ ("2!1.0", "~=1.0"), ("2!1.0", "==1.0"), ("1.0", "==2!1.0"), + ("2!1.0", "==1.0.0.*"), + ("1.0", "==2!1.0.0.*"), ("2!1.0", "==1.*"), ("1.0", "==2!1.*"), ("2!1.0", "!=2!1.0"), @@ -812,8 +813,7 @@ @pytest.mark.parametrize( ("left", "right", "op"), - itertools.chain( - * + itertools.chain.from_iterable( # Verify that the equal (==) operator works correctly [[(x, x, operator.eq) for x in SPECIFIERS]] + @@ -833,8 +833,7 @@ @pytest.mark.parametrize( ("left", "right", "op"), - itertools.chain( - * + itertools.chain.from_iterable( # Verify that the equal (==) operator works correctly [[(x, x, operator.ne) for x in SPECIFIERS]] + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/tests/test_structures.py new/packaging-24.0/tests/test_structures.py --- old/packaging-23.2/tests/test_structures.py 2022-04-02 15:23:31.364833000 +0200 +++ new/packaging-24.0/tests/test_structures.py 2024-03-10 10:34:41.957458300 +0100 @@ -8,11 +8,11 @@ def test_infinity_repr(): - repr(Infinity) == "Infinity" + assert repr(Infinity) == "Infinity" def test_negative_infinity_repr(): - repr(NegativeInfinity) == "-Infinity" + assert repr(NegativeInfinity) == "-Infinity" def test_infinity_hash(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/tests/test_tags.py new/packaging-24.0/tests/test_tags.py --- old/packaging-23.2/tests/test_tags.py 2023-10-01 14:58:59.375138500 +0200 +++ new/packaging-24.0/tests/test_tags.py 2024-01-06 21:39:23.976038500 +0100 @@ -781,6 +781,14 @@ tags.Tag("cp32", "abi3", "plat2"), ] + result = list(tags.cpython_tags((3, 13), ["cp313t"], ["plat1", "plat2"])) + assert result == [ + tags.Tag("cp313", "cp313t", "plat1"), + tags.Tag("cp313", "cp313t", "plat2"), + tags.Tag("cp313", "none", "plat1"), + tags.Tag("cp313", "none", "plat2"), + ] + def test_python_version_defaults(self): tag = next(tags.cpython_tags(abis=["abi3"], platforms=["any"])) interpreter = "cp" + tags._version_nodot(sys.version_info[:2]) @@ -894,6 +902,17 @@ monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) assert tags._generic_abi() == ["graalpy_38_native"] + def test__generic_abi_disable_gil(self, monkeypatch): + config = { + "Py_DEBUG": False, + "EXT_SUFFIX": ".cpython-313t-x86_64-linux-gnu.so", + "WITH_PYMALLOC": 0, + "Py_GIL_DISABLED": 1, + } + monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) + assert tags._generic_abi() == ["cp313t"] + assert tags._generic_abi() == tags._cpython_abis((3, 13)) + def test__generic_abi_none(self, monkeypatch): config = {"EXT_SUFFIX": "..so"} monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) @@ -922,6 +941,7 @@ "EXT_SUFFIX": ".pyd", "Py_DEBUG": 0, "WITH_PYMALLOC": 0, + "Py_GIL_DISABLED": 0, } monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) assert tags._generic_abi() == tags._cpython_abis(sys.version_info[:2]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/packaging-23.2/tests/test_version.py new/packaging-24.0/tests/test_version.py --- old/packaging-23.2/tests/test_version.py 2023-01-30 16:24:13.040571200 +0100 +++ new/packaging-24.0/tests/test_version.py 2024-03-10 10:34:41.957671900 +0100 @@ -667,8 +667,7 @@ ("left", "right", "op"), # Below we'll generate every possible combination of VERSIONS that # should be True for the given operator - itertools.chain( - * + itertools.chain.from_iterable( # Verify that the less than (<) operator works correctly [ [(x, y, operator.lt) for y in VERSIONS[i + 1 :]] @@ -710,8 +709,7 @@ ("left", "right", "op"), # Below we'll generate every possible combination of VERSIONS that # should be False for the given operator - itertools.chain( - * + itertools.chain.from_iterable( # Verify that the less than (<) operator works correctly [ [(x, y, operator.lt) for y in VERSIONS[: i + 1]]