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 2025-08-01 22:40:12
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-packaging (Old)
 and      /work/SRC/openSUSE:Factory/.python-packaging.new.1944 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-packaging"

Fri Aug  1 22:40:12 2025 rev:37 rq:1296839 version:25.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-packaging/python-packaging.changes        
2025-05-20 09:31:40.081136057 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-packaging.new.1944/python-packaging.changes  
    2025-08-01 22:40:25.785055033 +0200
@@ -1,0 +2,7 @@
+Thu Jul 31 11:44:29 UTC 2025 - marec <[email protected]>
+
+- update to 25.0:
+  * PEP 751: Add support for extras and dependency_groups markers. (#885)
+  * PEP 738: Add support for Android platform tags. (#880)
+
+-------------------------------------------------------------------

Old:
----
  packaging-24.2.tar.gz

New:
----
  packaging-25.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-packaging.spec ++++++
--- /var/tmp/diff_new_pack.qzqhD1/_old  2025-08-01 22:40:26.285075862 +0200
+++ /var/tmp/diff_new_pack.qzqhD1/_new  2025-08-01 22:40:26.285075862 +0200
@@ -53,7 +53,7 @@
 %endif
 
 Name:           %{pprefix}-packaging%{?psuffix}
-Version:        24.2
+Version:        25.0
 Release:        0
 Summary:        Core utilities for Python packages
 License:        Apache-2.0 AND BSD-2-Clause

++++++ packaging-24.2.tar.gz -> packaging-25.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/CHANGELOG.rst 
new/packaging-25.0/CHANGELOG.rst
--- old/packaging-24.2/CHANGELOG.rst    2024-11-08 10:47:13.100733500 +0100
+++ new/packaging-25.0/CHANGELOG.rst    2025-04-19 13:48:37.249769700 +0200
@@ -1,6 +1,12 @@
 Changelog
 ---------
 
+25.0 - 2025-04-19
+~~~~~~~~~~~~~~~~~
+
+* PEP 751: Add support for ``extras`` and ``dependency_groups`` markers. 
(:issue:`885`)
+* PEP 738: Add support for Android platform tags. (:issue:`880`)
+
 24.2 - 2024-11-08
 ~~~~~~~~~~~~~~~~~
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/PKG-INFO new/packaging-25.0/PKG-INFO
--- old/packaging-24.2/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
+++ new/packaging-25.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
-Metadata-Version: 2.3
+Metadata-Version: 2.4
 Name: packaging
-Version: 24.2
+Version: 25.0
 Summary: Core utilities for Python packages
 Author-email: Donald Stufft <[email protected]>
 Requires-Python: >=3.8
@@ -21,6 +21,9 @@
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Typing :: Typed
+License-File: LICENSE
+License-File: LICENSE.APACHE
+License-File: LICENSE.BSD
 Project-URL: Documentation, https://packaging.pypa.io/
 Project-URL: Source, https://github.com/pypa/packaging
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/docs/markers.rst 
new/packaging-25.0/docs/markers.rst
--- old/packaging-24.2/docs/markers.rst 2024-09-15 20:27:03.642005700 +0200
+++ new/packaging-25.0/docs/markers.rst 2025-04-19 13:45:16.853398600 +0200
@@ -64,6 +64,9 @@
 
     :param dict environment: A dictionary containing keys and values to
                              override the detected environment.
+    :param str context: A string representing the context in which the marker 
is evaluated.
+                        Acceptable values are "metadata" (for core metadata; 
default),
+                        "lock_file", and "requirement" (i.e. all other 
situations).
     :raises: UndefinedComparison: If the marker uses a comparison on strings
                                   which are not valid versions per the
                                   :ref:`specification of version specifiers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/docs/tags.rst 
new/packaging-25.0/docs/tags.rst
--- old/packaging-24.2/docs/tags.rst    2024-10-03 22:21:49.599062700 +0200
+++ new/packaging-25.0/docs/tags.rst    2025-04-19 13:45:16.853845000 +0200
@@ -168,6 +168,21 @@
         Behavior of this method is undefined if invoked on non-iOS platforms
         without providing explicit version and multiarch arguments.
 
+
+.. function:: android_platforms(api_level=None, abi=None)
+
+    Yields the :attr:`~Tag.platform` tags for Android. If this function is 
invoked on
+    non-Android platforms, the ``api_level`` and ``abi`` arguments are 
required.
+
+    :param int api_level: The maximum `API level
+        <https://developer.android.com/tools/releases/platforms>`__ to return. 
Defaults
+        to the current system's version, as returned by 
``platform.android_ver``.
+    :param str abi: The `Android ABI 
<https://developer.android.com/ndk/guides/abis>`__,
+        e.g. ``arm64_v8a``. Defaults to the current system's ABI , as returned 
by
+        ``sysconfig.get_platform``. Hyphens and periods will be replaced with
+        underscores.
+
+
 .. function:: platform_tags(version=None, arch=None)
 
     Yields the :attr:`~Tag.platform` tags for the running interpreter.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/pyproject.toml 
new/packaging-25.0/pyproject.toml
--- old/packaging-24.2/pyproject.toml   2024-11-08 10:41:39.082868600 +0100
+++ new/packaging-25.0/pyproject.toml   2025-04-19 13:45:16.854215000 +0200
@@ -78,6 +78,7 @@
 ]
 ignore = [
     "B027",
+    "F821",
     "N818",
     "RUF003",
     "RUF012",
@@ -95,6 +96,4 @@
     "Q003",
     "COM812",
     "COM819",
-    "ISC001",
-    "ISC002",
 ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/src/packaging/__init__.py 
new/packaging-25.0/src/packaging/__init__.py
--- old/packaging-24.2/src/packaging/__init__.py        2024-11-08 
10:47:13.101016300 +0100
+++ new/packaging-25.0/src/packaging/__init__.py        2025-04-19 
13:48:37.250069400 +0200
@@ -6,7 +6,7 @@
 __summary__ = "Core utilities for Python packages"
 __uri__ = "https://github.com/pypa/packaging";
 
-__version__ = "24.2"
+__version__ = "25.0"
 
 __author__ = "Donald Stufft and individual contributors"
 __email__ = "[email protected]"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/src/packaging/_elffile.py 
new/packaging-25.0/src/packaging/_elffile.py
--- old/packaging-24.2/src/packaging/_elffile.py        2024-09-15 
20:27:08.853526600 +0200
+++ new/packaging-25.0/src/packaging/_elffile.py        2025-04-19 
13:45:16.854780400 +0200
@@ -69,8 +69,7 @@
             }[(self.capacity, self.encoding)]
         except KeyError as e:
             raise ELFInvalid(
-                f"unrecognized capacity ({self.capacity}) or "
-                f"encoding ({self.encoding})"
+                f"unrecognized capacity ({self.capacity}) or encoding 
({self.encoding})"
             ) from e
 
         try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/src/packaging/_manylinux.py 
new/packaging-25.0/src/packaging/_manylinux.py
--- old/packaging-24.2/src/packaging/_manylinux.py      2024-09-15 
20:27:08.853865100 +0200
+++ new/packaging-25.0/src/packaging/_manylinux.py      2025-04-19 
13:45:16.855287800 +0200
@@ -161,8 +161,7 @@
     m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str)
     if not m:
         warnings.warn(
-            f"Expected glibc version with 2 components major.minor,"
-            f" got: {version_str}",
+            f"Expected glibc version with 2 components major.minor, got: 
{version_str}",
             RuntimeWarning,
             stacklevel=2,
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/src/packaging/_parser.py 
new/packaging-25.0/src/packaging/_parser.py
--- old/packaging-24.2/src/packaging/_parser.py 2024-10-03 22:21:49.599353000 
+0200
+++ new/packaging-25.0/src/packaging/_parser.py 2025-04-19 13:45:16.855672400 
+0200
@@ -349,6 +349,5 @@
         return Op(tokenizer.read().text)
     else:
         return tokenizer.raise_syntax_error(
-            "Expected marker operator, one of "
-            "<=, <, !=, ==, >=, >, ~=, ===, in, not in"
+            "Expected marker operator, one of <=, <, !=, ==, >=, >, ~=, ===, 
in, not in"
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/src/packaging/_tokenizer.py 
new/packaging-25.0/src/packaging/_tokenizer.py
--- old/packaging-24.2/src/packaging/_tokenizer.py      2024-06-10 
01:16:42.855516200 +0200
+++ new/packaging-25.0/src/packaging/_tokenizer.py      2025-04-19 
13:45:16.856002000 +0200
@@ -68,7 +68,8 @@
                 |platform[._](version|machine|python_implementation)
                 |python_implementation
                 |implementation_(name|version)
-                |extra
+                |extras?
+                |dependency_groups
             )\b
         """,
         re.VERBOSE,
@@ -119,9 +120,9 @@
         another check. If `peek` is set to `True`, the token is not loaded and
         would need to be checked again.
         """
-        assert (
-            self.next_token is None
-        ), f"Cannot check for {name!r}, already have {self.next_token!r}"
+        assert self.next_token is None, (
+            f"Cannot check for {name!r}, already have {self.next_token!r}"
+        )
         assert name in self.rules, f"Unknown token name: {name!r}"
 
         expression = self.rules[name]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/src/packaging/licenses/__init__.py 
new/packaging-25.0/src/packaging/licenses/__init__.py
--- old/packaging-24.2/src/packaging/licenses/__init__.py       2024-11-08 
10:41:39.083118200 +0100
+++ new/packaging-25.0/src/packaging/licenses/__init__.py       2025-04-19 
13:45:16.856330400 +0200
@@ -37,8 +37,8 @@
 from packaging.licenses._spdx import EXCEPTIONS, LICENSES
 
 __all__ = [
-    "NormalizedLicenseExpression",
     "InvalidLicenseExpression",
+    "NormalizedLicenseExpression",
     "canonicalize_license_expression",
 ]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/src/packaging/markers.py 
new/packaging-25.0/src/packaging/markers.py
--- old/packaging-24.2/src/packaging/markers.py 2024-09-15 20:27:08.854714400 
+0200
+++ new/packaging-25.0/src/packaging/markers.py 2025-04-19 13:45:16.856696100 
+0200
@@ -8,7 +8,7 @@
 import os
 import platform
 import sys
-from typing import Any, Callable, TypedDict, cast
+from typing import AbstractSet, Any, Callable, Literal, TypedDict, Union, cast
 
 from ._parser import MarkerAtom, MarkerList, Op, Value, Variable
 from ._parser import parse_marker as _parse_marker
@@ -17,6 +17,7 @@
 from .utils import canonicalize_name
 
 __all__ = [
+    "EvaluateContext",
     "InvalidMarker",
     "Marker",
     "UndefinedComparison",
@@ -24,7 +25,9 @@
     "default_environment",
 ]
 
-Operator = Callable[[str, str], bool]
+Operator = Callable[[str, Union[str, AbstractSet[str]]], bool]
+EvaluateContext = Literal["metadata", "lock_file", "requirement"]
+MARKERS_ALLOWING_SET = {"extras", "dependency_groups"}
 
 
 class InvalidMarker(ValueError):
@@ -174,13 +177,14 @@
 }
 
 
-def _eval_op(lhs: str, op: Op, rhs: str) -> bool:
-    try:
-        spec = Specifier("".join([op.serialize(), rhs]))
-    except InvalidSpecifier:
-        pass
-    else:
-        return spec.contains(lhs, prereleases=True)
+def _eval_op(lhs: str, op: Op, rhs: str | AbstractSet[str]) -> bool:
+    if isinstance(rhs, str):
+        try:
+            spec = Specifier("".join([op.serialize(), rhs]))
+        except InvalidSpecifier:
+            pass
+        else:
+            return spec.contains(lhs, prereleases=True)
 
     oper: Operator | None = _operators.get(op.serialize())
     if oper is None:
@@ -189,19 +193,29 @@
     return oper(lhs, rhs)
 
 
-def _normalize(*values: str, key: str) -> tuple[str, ...]:
+def _normalize(
+    lhs: str, rhs: str | AbstractSet[str], key: str
+) -> tuple[str, str | AbstractSet[str]]:
     # PEP 685 – Comparison of extra names for optional distribution 
dependencies
     # https://peps.python.org/pep-0685/
     # > When comparing extra names, tools MUST normalize the names being
     # > compared using the semantics outlined in PEP 503 for names
     if key == "extra":
-        return tuple(canonicalize_name(v) for v in values)
+        assert isinstance(rhs, str), "extra value must be a string"
+        return (canonicalize_name(lhs), canonicalize_name(rhs))
+    if key in MARKERS_ALLOWING_SET:
+        if isinstance(rhs, str):  # pragma: no cover
+            return (canonicalize_name(lhs), canonicalize_name(rhs))
+        else:
+            return (canonicalize_name(lhs), {canonicalize_name(v) for v in 
rhs})
 
     # other environment markers don't have such standards
-    return values
+    return lhs, rhs
 
 
-def _evaluate_markers(markers: MarkerList, environment: dict[str, str]) -> 
bool:
+def _evaluate_markers(
+    markers: MarkerList, environment: dict[str, str | AbstractSet[str]]
+) -> bool:
     groups: list[list[bool]] = [[]]
 
     for marker in markers:
@@ -220,7 +234,7 @@
                 lhs_value = lhs.value
                 environment_key = rhs.value
                 rhs_value = environment[environment_key]
-
+            assert isinstance(lhs_value, str), "lhs must be a string"
             lhs_value, rhs_value = _normalize(lhs_value, rhs_value, 
key=environment_key)
             groups[-1].append(_eval_op(lhs_value, op, rhs_value))
         else:
@@ -298,22 +312,36 @@
 
         return str(self) == str(other)
 
-    def evaluate(self, environment: dict[str, str] | None = None) -> bool:
+    def evaluate(
+        self,
+        environment: dict[str, str] | None = None,
+        context: EvaluateContext = "metadata",
+    ) -> bool:
         """Evaluate a marker.
 
         Return the boolean from evaluating the given marker against the
         environment. environment is an optional argument to override all or
-        part of the determined environment.
+        part of the determined environment. The *context* parameter specifies 
what
+        context the markers are being evaluated for, which influences what 
markers
+        are considered valid. Acceptable values are "metadata" (for core 
metadata;
+        default), "lock_file", and "requirement" (i.e. all other situations).
 
         The environment is determined from the current Python process.
         """
-        current_environment = cast("dict[str, str]", default_environment())
-        current_environment["extra"] = ""
+        current_environment = cast(
+            "dict[str, str | AbstractSet[str]]", default_environment()
+        )
+        if context == "lock_file":
+            current_environment.update(
+                extras=frozenset(), dependency_groups=frozenset()
+            )
+        elif context == "metadata":
+            current_environment["extra"] = ""
         if environment is not None:
             current_environment.update(environment)
             # The API used to allow setting extra to None. We need to handle 
this
             # case for backwards compatibility.
-            if current_environment["extra"] is None:
+            if "extra" in current_environment and current_environment["extra"] 
is None:
                 current_environment["extra"] = ""
 
         return _evaluate_markers(
@@ -321,11 +349,14 @@
         )
 
 
-def _repair_python_full_version(env: dict[str, str]) -> dict[str, str]:
+def _repair_python_full_version(
+    env: dict[str, str | AbstractSet[str]],
+) -> dict[str, str | AbstractSet[str]]:
     """
     Work around platform.python_version() returning something that is not PEP 
440
     compliant for non-tagged Python builds.
     """
-    if env["python_full_version"].endswith("+"):
-        env["python_full_version"] += "local"
+    python_full_version = cast(str, env["python_full_version"])
+    if python_full_version.endswith("+"):
+        env["python_full_version"] = f"{python_full_version}local"
     return env
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/src/packaging/metadata.py 
new/packaging-25.0/src/packaging/metadata.py
--- old/packaging-24.2/src/packaging/metadata.py        2024-11-08 
10:41:39.083711000 +0100
+++ new/packaging-25.0/src/packaging/metadata.py        2025-04-19 
13:45:16.857118800 +0200
@@ -678,8 +678,7 @@
                 )
             if pathlib.PureWindowsPath(path).as_posix() != path:
                 raise self._invalid_metadata(
-                    f"{path!r} is invalid for {{field}}, "
-                    "paths must use '/' delimiter"
+                    f"{path!r} is invalid for {{field}}, paths must use '/' 
delimiter"
                 )
             paths.append(path)
         return paths
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/src/packaging/specifiers.py 
new/packaging-25.0/src/packaging/specifiers.py
--- old/packaging-24.2/src/packaging/specifiers.py      2024-11-08 
10:41:39.084588800 +0100
+++ new/packaging-25.0/src/packaging/specifiers.py      2025-04-19 
13:45:16.857555200 +0200
@@ -816,8 +816,7 @@
             specifier._prereleases = self._prereleases
         else:
             raise ValueError(
-                "Cannot combine SpecifierSets with True and False prerelease "
-                "overrides."
+                "Cannot combine SpecifierSets with True and False prerelease 
overrides."
             )
 
         return specifier
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/src/packaging/tags.py 
new/packaging-25.0/src/packaging/tags.py
--- old/packaging-24.2/src/packaging/tags.py    2024-11-08 10:41:39.084987400 
+0100
+++ new/packaging-25.0/src/packaging/tags.py    2025-04-19 13:45:16.857928000 
+0200
@@ -530,6 +530,43 @@
             )
 
 
+def android_platforms(
+    api_level: int | None = None, abi: str | None = None
+) -> Iterator[str]:
+    """
+    Yields the :attr:`~Tag.platform` tags for Android. If this function is 
invoked on
+    non-Android platforms, the ``api_level`` and ``abi`` arguments are 
required.
+
+    :param int api_level: The maximum `API level
+        <https://developer.android.com/tools/releases/platforms>`__ to return. 
Defaults
+        to the current system's version, as returned by 
``platform.android_ver``.
+    :param str abi: The `Android ABI 
<https://developer.android.com/ndk/guides/abis>`__,
+        e.g. ``arm64_v8a``. Defaults to the current system's ABI , as returned 
by
+        ``sysconfig.get_platform``. Hyphens and periods will be replaced with
+        underscores.
+    """
+    if platform.system() != "Android" and (api_level is None or abi is None):
+        raise TypeError(
+            "on non-Android platforms, the api_level and abi arguments are 
required"
+        )
+
+    if api_level is None:
+        # Python 3.13 was the first version to return platform.system() == 
"Android",
+        # and also the first version to define platform.android_ver().
+        api_level = platform.android_ver().api_level  # type: 
ignore[attr-defined]
+
+    if abi is None:
+        abi = sysconfig.get_platform().split("-")[-1]
+    abi = _normalize_string(abi)
+
+    # 16 is the minimum API level known to have enough features to support 
CPython
+    # without major patching. Yield every API level from the maximum down to 
the
+    # minimum, inclusive.
+    min_api_level = 16
+    for ver in range(api_level, min_api_level - 1, -1):
+        yield f"android_{ver}_{abi}"
+
+
 def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]:
     linux = _normalize_string(sysconfig.get_platform())
     if not linux.startswith("linux_"):
@@ -561,6 +598,8 @@
         return mac_platforms()
     elif platform.system() == "iOS":
         return ios_platforms()
+    elif platform.system() == "Android":
+        return android_platforms()
     elif platform.system() == "Linux":
         return _linux_platforms()
     else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/tests/test_markers.py 
new/packaging-25.0/tests/test_markers.py
--- old/packaging-24.2/tests/test_markers.py    2024-09-15 20:27:08.856824000 
+0200
+++ new/packaging-25.0/tests/test_markers.py    2025-04-19 13:45:16.858205300 
+0200
@@ -290,20 +290,17 @@
                 True,
             ),
             (
-                "python_version ~= '2.7.0' and (os_name == 'foo' or "
-                "os_name == 'bar')",
+                "python_version ~= '2.7.0' and (os_name == 'foo' or os_name == 
'bar')",
                 {"os_name": "foo", "python_version": "2.7.4"},
                 True,
             ),
             (
-                "python_version ~= '2.7.0' and (os_name == 'foo' or "
-                "os_name == 'bar')",
+                "python_version ~= '2.7.0' and (os_name == 'foo' or os_name == 
'bar')",
                 {"os_name": "bar", "python_version": "2.7.4"},
                 True,
             ),
             (
-                "python_version ~= '2.7.0' and (os_name == 'foo' or "
-                "os_name == 'bar')",
+                "python_version ~= '2.7.0' and (os_name == 'foo' or os_name == 
'bar')",
                 {"os_name": "other", "python_version": "2.7.4"},
                 False,
             ),
@@ -350,8 +347,7 @@
                 False,
             ),
             (
-                "python_version == '2.5' and platform.python_implementation"
-                "!= 'Jython'",
+                "python_version == '2.5' and platform.python_implementation!= 
'Jython'",
                 {"python_version": "2.7"},
                 False,
             ),
@@ -398,3 +394,35 @@
     def test_python_full_version_untagged(self):
         with mock.patch("platform.python_version", return_value="3.11.1+"):
             assert Marker("python_full_version < '3.12'").evaluate()
+
+    @pytest.mark.parametrize("variable", ["extras", "dependency_groups"])
+    @pytest.mark.parametrize(
+        "expression,result",
+        [
+            pytest.param('"foo" in {0}', True, id="value-in-foo"),
+            pytest.param('"bar" in {0}', True, id="value-in-bar"),
+            pytest.param('"baz" in {0}', False, id="value-not-in"),
+            pytest.param('"baz" not in {0}', True, id="value-not-in-negated"),
+            pytest.param('"foo" in {0} and "bar" in {0}', True, id="and-in"),
+            pytest.param('"foo" in {0} or "bar" in {0}', True, id="or-in"),
+            pytest.param(
+                '"baz" in {0} and "foo" in {0}', False, id="short-circuit-and"
+            ),
+            pytest.param('"foo" in {0} or "baz" in {0}', True, 
id="short-circuit-or"),
+            pytest.param('"Foo" in {0}', True, id="case-sensitive"),
+        ],
+    )
+    def test_extras_and_dependency_groups(self, variable, expression, result):
+        environment = {variable: {"foo", "bar"}}
+        assert Marker(expression.format(variable)).evaluate(environment) == 
result
+
+    @pytest.mark.parametrize("variable", ["extras", "dependency_groups"])
+    def test_extras_and_dependency_groups_disallowed(self, variable):
+        marker = Marker(f'"foo" in {variable}')
+        assert not marker.evaluate(context="lock_file")
+
+        with pytest.raises(KeyError):
+            marker.evaluate()
+
+        with pytest.raises(KeyError):
+            marker.evaluate(context="requirement")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/tests/test_tags.py 
new/packaging-25.0/tests/test_tags.py
--- old/packaging-24.2/tests/test_tags.py       2024-10-03 22:21:49.600872800 
+0200
+++ new/packaging-25.0/tests/test_tags.py       2025-04-19 13:45:16.858640700 
+0200
@@ -77,6 +77,23 @@
         monkeypatch.setattr(platform, "ios_ver", mock_ios_ver)
 
 
[email protected]
+def mock_android(monkeypatch):
+    monkeypatch.setattr(sys, "platform", "android")
+    monkeypatch.setattr(platform, "system", lambda: "Android")
+    monkeypatch.setattr(sysconfig, "get_platform", lambda: 
"android-21-arm64_v8a")
+
+    AndroidVer = collections.namedtuple(
+        "AndroidVer", "release api_level manufacturer model device is_emulator"
+    )
+    monkeypatch.setattr(
+        platform,
+        "android_ver",
+        lambda: AndroidVer("5.0", 21, "Google", "sdk_gphone64_arm64", 
"emu64a", True),
+        raising=False,  # This function was added in Python 3.13.
+    )
+
+
 class TestTag:
     def test_lowercasing(self):
         tag = tags.Tag("PY3", "None", "ANY")
@@ -437,6 +454,69 @@
         ]
 
 
+class TestAndroidPlatforms:
+    def test_non_android(self):
+        non_android_error = pytest.raises(TypeError)
+        with non_android_error:
+            list(tags.android_platforms())
+        with non_android_error:
+            list(tags.android_platforms(api_level=18))
+        with non_android_error:
+            list(tags.android_platforms(abi="x86_64"))
+
+        # The function can only be called on non-Android platforms if both 
arguments are
+        # provided.
+        assert list(tags.android_platforms(api_level=18, abi="x86_64")) == [
+            "android_18_x86_64",
+            "android_17_x86_64",
+            "android_16_x86_64",
+        ]
+
+    def test_detection(self, mock_android):
+        assert list(tags.android_platforms()) == [
+            "android_21_arm64_v8a",
+            "android_20_arm64_v8a",
+            "android_19_arm64_v8a",
+            "android_18_arm64_v8a",
+            "android_17_arm64_v8a",
+            "android_16_arm64_v8a",
+        ]
+
+    def test_api_level(self):
+        # API levels below the minimum should return nothing.
+        assert list(tags.android_platforms(api_level=14, abi="x86")) == []
+        assert list(tags.android_platforms(api_level=15, abi="x86")) == []
+
+        assert list(tags.android_platforms(api_level=16, abi="x86")) == [
+            "android_16_x86",
+        ]
+        assert list(tags.android_platforms(api_level=17, abi="x86")) == [
+            "android_17_x86",
+            "android_16_x86",
+        ]
+        assert list(tags.android_platforms(api_level=18, abi="x86")) == [
+            "android_18_x86",
+            "android_17_x86",
+            "android_16_x86",
+        ]
+
+    def test_abi(self):
+        # Real ABI, normalized.
+        assert list(tags.android_platforms(api_level=16, abi="armeabi_v7a")) 
== [
+            "android_16_armeabi_v7a",
+        ]
+
+        # Real ABI, not normalized.
+        assert list(tags.android_platforms(api_level=16, abi="armeabi-v7a")) 
== [
+            "android_16_armeabi_v7a",
+        ]
+
+        # Nonexistent ABIs should still be accepted and normalized.
+        assert list(tags.android_platforms(api_level=16, abi="myarch-4.2")) == 
[
+            "android_16_myarch_4_2",
+        ]
+
+
 class TestManylinuxPlatform:
     def teardown_method(self):
         # Clear the version cache
@@ -722,6 +802,7 @@
     [
         ("Darwin", "mac_platforms"),
         ("iOS", "ios_platforms"),
+        ("Android", "android_platforms"),
         ("Linux", "_linux_platforms"),
         ("Generic", "_generic_platforms"),
     ],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/packaging-24.2/tests/test_utils.py 
new/packaging-25.0/tests/test_utils.py
--- old/packaging-24.2/tests/test_utils.py      2023-10-01 14:58:59.375378600 
+0200
+++ new/packaging-25.0/tests/test_utils.py      2025-04-19 13:45:16.858939600 
+0200
@@ -123,6 +123,20 @@
             (1000, "abc"),
             {Tag("py3", "none", "any")},
         ),
+        (
+            "foo_bár-1.0-py3-none-any.whl",
+            "foo-bár",
+            Version("1.0"),
+            (),
+            {Tag("py3", "none", "any")},
+        ),
+        (
+            "foo_bár-1.0-1000-py3-none-any.whl",
+            "foo-bár",
+            Version("1.0"),
+            (1000, ""),
+            {Tag("py3", "none", "any")},
+        ),
     ],
 )
 def test_parse_wheel_filename(filename, name, version, build, tags):

Reply via email to