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]]

Reply via email to