summaryrefslogtreecommitdiffstats
path: root/contrib/python/packaging
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2026-05-09 20:16:07 +0300
committerrobot-piglet <[email protected]>2026-05-09 21:04:03 +0300
commit6defa095368134f62323c48cabee1a95304cf742 (patch)
treea508c87e5023c332e1a6dfdfa48204bf1752ff46 /contrib/python/packaging
parente35e9fd54f83531a7344939b5313fcc40cfb89f0 (diff)
Intermediate changes
commit_hash:700c24e95953f7be1a6c425a35dbf7d41492469a
Diffstat (limited to 'contrib/python/packaging')
-rw-r--r--contrib/python/packaging/py3/.dist-info/METADATA10
-rw-r--r--contrib/python/packaging/py3/README.rst8
-rw-r--r--contrib/python/packaging/py3/packaging/__init__.py2
-rw-r--r--contrib/python/packaging/py3/packaging/_parser.py28
-rw-r--r--contrib/python/packaging/py3/packaging/_structures.py33
-rw-r--r--contrib/python/packaging/py3/packaging/markers.py39
-rw-r--r--contrib/python/packaging/py3/packaging/metadata.py1
-rw-r--r--contrib/python/packaging/py3/packaging/requirements.py34
-rw-r--r--contrib/python/packaging/py3/packaging/specifiers.py156
-rw-r--r--contrib/python/packaging/py3/packaging/tags.py56
-rw-r--r--contrib/python/packaging/py3/packaging/version.py77
-rw-r--r--contrib/python/packaging/py3/ya.make3
12 files changed, 429 insertions, 18 deletions
diff --git a/contrib/python/packaging/py3/.dist-info/METADATA b/contrib/python/packaging/py3/.dist-info/METADATA
index c1b3d36f8d2..d7ca4566284 100644
--- a/contrib/python/packaging/py3/.dist-info/METADATA
+++ b/contrib/python/packaging/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: packaging
-Version: 26.1
+Version: 26.2
Summary: Core utilities for Python packages
Author-email: Donald Stufft <[email protected]>
Requires-Python: >=3.8
@@ -53,10 +53,14 @@ The `documentation`_ provides information and the API for the following:
- Version Handling
- Specifiers
- Markers
+- Licenses
- Requirements
-- Tags
- Metadata
-- Lockfiles
+- Tags
+- Lockfiles (pylock)
+- Direct URL helpers
+- Dependency groups
+- Errors
- Utilities
Installation
diff --git a/contrib/python/packaging/py3/README.rst b/contrib/python/packaging/py3/README.rst
index 4b47730e51a..c39830e124f 100644
--- a/contrib/python/packaging/py3/README.rst
+++ b/contrib/python/packaging/py3/README.rst
@@ -23,10 +23,14 @@ The `documentation`_ provides information and the API for the following:
- Version Handling
- Specifiers
- Markers
+- Licenses
- Requirements
-- Tags
- Metadata
-- Lockfiles
+- Tags
+- Lockfiles (pylock)
+- Direct URL helpers
+- Dependency groups
+- Errors
- Utilities
Installation
diff --git a/contrib/python/packaging/py3/packaging/__init__.py b/contrib/python/packaging/py3/packaging/__init__.py
index 3c6400263b8..a6bdf59cd71 100644
--- a/contrib/python/packaging/py3/packaging/__init__.py
+++ b/contrib/python/packaging/py3/packaging/__init__.py
@@ -6,7 +6,7 @@ __title__ = "packaging"
__summary__ = "Core utilities for Python packages"
__uri__ = "https://github.com/pypa/packaging"
-__version__ = "26.1"
+__version__ = "26.2"
__author__ = "Donald Stufft and individual contributors"
__email__ = "[email protected]"
diff --git a/contrib/python/packaging/py3/packaging/_parser.py b/contrib/python/packaging/py3/packaging/_parser.py
index f6c1f5cd226..d320269e153 100644
--- a/contrib/python/packaging/py3/packaging/_parser.py
+++ b/contrib/python/packaging/py3/packaging/_parser.py
@@ -27,6 +27,34 @@ class Node:
def serialize(self) -> str:
raise NotImplementedError
+ def __getstate__(self) -> str:
+ # Return just the value string for compactness and stability.
+ return self.value
+
+ def _restore_value(self, value: object) -> None:
+ if not isinstance(value, str):
+ raise TypeError(
+ f"Cannot restore {self.__class__.__name__} value from {value!r}"
+ )
+ self.value = value
+
+ def __setstate__(self, state: object) -> None:
+ if isinstance(state, str):
+ # New format (26.2+): just the value string.
+ self._restore_value(state)
+ return
+ if isinstance(state, tuple) and len(state) == 2:
+ # Old format (packaging <= 26.0, __slots__): (None, {slot: value}).
+ _, slot_dict = state
+ if isinstance(slot_dict, dict) and "value" in slot_dict:
+ self._restore_value(slot_dict["value"])
+ return
+ if isinstance(state, dict) and "value" in state:
+ # Old format (packaging <= 25.0, no __slots__): plain __dict__.
+ self._restore_value(state["value"])
+ return
+ raise TypeError(f"Cannot restore {self.__class__.__name__} from {state!r}")
+
class Variable(Node):
__slots__ = ()
diff --git a/contrib/python/packaging/py3/packaging/_structures.py b/contrib/python/packaging/py3/packaging/_structures.py
new file mode 100644
index 00000000000..4306784d9a2
--- /dev/null
+++ b/contrib/python/packaging/py3/packaging/_structures.py
@@ -0,0 +1,33 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+"""Backward-compatibility shim for unpickling Version objects serialized before
+packaging 26.1.
+
+Old pickles reference ``packaging._structures.InfinityType`` and
+``packaging._structures.NegativeInfinityType``. This module provides minimal
+stand-in classes so that ``pickle.loads()`` can resolve those references.
+The deserialized objects are not used for comparisons — ``Version.__setstate__``
+discards the stale ``_key`` cache and recomputes it from the core version fields.
+"""
+
+from __future__ import annotations
+
+
+class InfinityType:
+ """Stand-in for the removed ``InfinityType`` used in old comparison keys."""
+
+ def __repr__(self) -> str:
+ return "Infinity"
+
+
+class NegativeInfinityType:
+ """Stand-in for the removed ``NegativeInfinityType`` used in old comparison keys."""
+
+ def __repr__(self) -> str:
+ return "-Infinity"
+
+
+Infinity = InfinityType()
+NegativeInfinity = NegativeInfinityType()
diff --git a/contrib/python/packaging/py3/packaging/markers.py b/contrib/python/packaging/py3/packaging/markers.py
index 65d7f330b0c..564451f530b 100644
--- a/contrib/python/packaging/py3/packaging/markers.py
+++ b/contrib/python/packaging/py3/packaging/markers.py
@@ -322,6 +322,16 @@ class Marker:
:param marker: The string representation of a marker expression.
:raises InvalidMarker: If ``marker`` cannot be parsed.
+
+ Instances are safe to serialize with :mod:`pickle`. They use a stable
+ format so the same pickle can be loaded in future packaging releases.
+
+ .. versionchanged:: 26.2
+
+ Added a stable pickle format. Pickles created with packaging 26.2+ can
+ be unpickled with future releases. Backward compatibility with pickles
+ from packaging < 26.2 is supported but may be removed in a future
+ release.
"""
__slots__ = ("_markers",)
@@ -381,6 +391,35 @@ class Marker:
return str(self) == str(other)
+ def __getstate__(self) -> str:
+ # Return the marker expression string for compactness and stability.
+ # Internal Node objects are excluded; the string is re-parsed on load.
+ return str(self)
+
+ def __setstate__(self, state: object) -> None:
+ if isinstance(state, str):
+ # New format (26.2+): just the marker expression string.
+ try:
+ self._markers = _normalize_extra_values(_parse_marker(state))
+ except ParserSyntaxError as exc:
+ raise TypeError(f"Cannot restore Marker from {state!r}") from exc
+ return
+ if isinstance(state, dict) and "_markers" in state:
+ # Old format (packaging <= 26.1, no __slots__): plain __dict__.
+ markers = state["_markers"]
+ if isinstance(markers, list):
+ self._markers = markers
+ return
+ if isinstance(state, tuple) and len(state) == 2:
+ # Old format (packaging <= 26.1, __slots__): (None, {slot: value}).
+ _, slot_dict = state
+ if isinstance(slot_dict, dict) and "_markers" in slot_dict:
+ markers = slot_dict["_markers"]
+ if isinstance(markers, list):
+ self._markers = markers
+ return
+ raise TypeError(f"Cannot restore Marker from {state!r}")
+
def __and__(self, other: Marker) -> Marker:
if not isinstance(other, Marker):
return NotImplemented
diff --git a/contrib/python/packaging/py3/packaging/metadata.py b/contrib/python/packaging/py3/packaging/metadata.py
index b3269a45e9c..dccb627dea3 100644
--- a/contrib/python/packaging/py3/packaging/metadata.py
+++ b/contrib/python/packaging/py3/packaging/metadata.py
@@ -27,6 +27,7 @@ T = typing.TypeVar("T")
__all__ = [
+ "ExceptionGroup", # Keep this for a bit (makes mypy happy w/ 26.0 compat)
"InvalidMetadata",
"Metadata",
"RFC822Message",
diff --git a/contrib/python/packaging/py3/packaging/requirements.py b/contrib/python/packaging/py3/packaging/requirements.py
index 18640d4386e..5892aee6ee2 100644
--- a/contrib/python/packaging/py3/packaging/requirements.py
+++ b/contrib/python/packaging/py3/packaging/requirements.py
@@ -33,6 +33,16 @@ class Requirement:
Parse a given requirement string into its parts, such as name, specifier,
URL, and extras. Raises InvalidRequirement on a badly-formed requirement
string.
+
+ Instances are safe to serialize with :mod:`pickle`. They use a stable
+ format so the same pickle can be loaded in future packaging releases.
+
+ .. versionchanged:: 26.2
+
+ Added a stable pickle format. Pickles created with packaging 26.2+ can
+ be unpickled with future releases. Backward compatibility with pickles
+ from packaging < 26.2 is supported but may be removed in a future
+ release.
"""
# TODO: Can we test whether something is contained within a requirement?
@@ -73,6 +83,30 @@ class Requirement:
if self.marker:
yield f"; {self.marker}"
+ def __getstate__(self) -> str:
+ # Return the requirement string for compactness and stability.
+ # Re-parsed on load to reconstruct all fields.
+ return str(self)
+
+ def __setstate__(self, state: object) -> None:
+ if isinstance(state, str):
+ # New format (26.2+): just the requirement string.
+ try:
+ tmp = Requirement(state)
+ except InvalidRequirement as exc:
+ raise TypeError(f"Cannot restore Requirement from {state!r}") from exc
+ self.name = tmp.name
+ self.url = tmp.url
+ self.extras = tmp.extras
+ self.specifier = tmp.specifier
+ self.marker = tmp.marker
+ return
+ if isinstance(state, dict):
+ # Old format (packaging <= 26.1, no __slots__): plain __dict__.
+ self.__dict__.update(state)
+ return
+ raise TypeError(f"Cannot restore Requirement from {state!r}")
+
def __str__(self) -> str:
return "".join(self._iter_parts(self.name))
diff --git a/contrib/python/packaging/py3/packaging/specifiers.py b/contrib/python/packaging/py3/packaging/specifiers.py
index d0aa9a6cd33..b165dc0f7c8 100644
--- a/contrib/python/packaging/py3/packaging/specifiers.py
+++ b/contrib/python/packaging/py3/packaging/specifiers.py
@@ -15,12 +15,28 @@ import enum
import functools
import itertools
import re
+import sys
import typing
-from typing import Any, Callable, Final, Iterable, Iterator, Sequence, TypeVar, Union
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Callable,
+ Final,
+ Iterable,
+ Iterator,
+ Sequence,
+ TypeVar,
+ Union,
+)
from .utils import canonicalize_version
from .version import InvalidVersion, Version
+if sys.version_info >= (3, 10):
+ from typing import TypeGuard # pragma: no cover
+elif TYPE_CHECKING:
+ from typing_extensions import TypeGuard
+
__all__ = [
"BaseSpecifier",
"InvalidSpecifier",
@@ -33,6 +49,19 @@ def __dir__() -> list[str]:
return __all__
+def _validate_spec(spec: object, /) -> TypeGuard[tuple[str, str]]:
+ return (
+ isinstance(spec, tuple)
+ and len(spec) == 2
+ and isinstance(spec[0], str)
+ and isinstance(spec[1], str)
+ )
+
+
+def _validate_pre(pre: object, /) -> TypeGuard[bool | None]:
+ return pre is None or isinstance(pre, bool)
+
+
T = TypeVar("T")
UnparsedVersion = Union[Version, str]
UnparsedVersionVar = TypeVar("UnparsedVersionVar", bound=UnparsedVersion)
@@ -414,6 +443,16 @@ class Specifier(BaseSpecifier):
It is generally not required to instantiate this manually. You should instead
prefer to work with :class:`SpecifierSet` instead, which can parse
comma-separated version specifiers (which is what package metadata contains).
+
+ Instances are safe to serialize with :mod:`pickle`. They use a stable
+ format so the same pickle can be loaded in future packaging releases.
+
+ .. versionchanged:: 26.2
+
+ Added a stable pickle format. Pickles created with packaging 26.2+ can
+ be unpickled with future releases. Backward compatibility with pickles
+ from packaging < 26.2 is supported but may be removed in a future
+ release.
"""
__slots__ = (
@@ -722,6 +761,46 @@ class Specifier(BaseSpecifier):
def prereleases(self, value: bool | None) -> None:
self._prereleases = value
+ def __getstate__(self) -> tuple[tuple[str, str], bool | None]:
+ # Return state as a 2-item tuple for compactness:
+ # ((operator, version), prereleases)
+ # Cache members are excluded and will be recomputed on demand.
+ return (self._spec, self._prereleases)
+
+ def __setstate__(self, state: object) -> None:
+ # Always discard cached values - they will be recomputed on demand.
+ self._spec_version = None
+ self._wildcard_split = None
+ self._ranges = None
+
+ if isinstance(state, tuple):
+ if len(state) == 2:
+ # New format (26.2+): ((operator, version), prereleases)
+ spec, prereleases = state
+ if _validate_spec(spec) and _validate_pre(prereleases):
+ self._spec = spec
+ self._prereleases = prereleases
+ return
+ if len(state) == 2 and isinstance(state[1], dict):
+ # Format (packaging 26.0-26.1): (None, {slot: value}).
+ _, slot_dict = state
+ spec = slot_dict.get("_spec")
+ prereleases = slot_dict.get("_prereleases", "invalid")
+ if _validate_spec(spec) and _validate_pre(prereleases):
+ self._spec = spec
+ self._prereleases = prereleases
+ return
+ if isinstance(state, dict):
+ # Old format (packaging <= 25.x, no __slots__): state is a plain dict.
+ spec = state.get("_spec")
+ prereleases = state.get("_prereleases", "invalid")
+ if _validate_spec(spec) and _validate_pre(prereleases):
+ self._spec = spec
+ self._prereleases = prereleases
+ return
+
+ raise TypeError(f"Cannot restore Specifier from {state!r}")
+
@property
def operator(self) -> str:
"""The operator of this specifier.
@@ -1257,6 +1336,18 @@ class SpecifierSet(BaseSpecifier):
It can be passed a single specifier (``>=3.0``), a comma-separated list of
specifiers (``>=3.0,!=3.1``), or no specifier at all.
+
+ Instances are safe to serialize with :mod:`pickle`. They use a stable
+ format so the same pickle can be loaded in future packaging
+ releases.
+
+ .. versionchanged:: 26.2
+
+ Added a stable pickle format. Pickles created with
+ packaging 26.2+ can be unpickled with future releases.
+ Backward compatibility with pickles from
+ packaging < 26.2 is supported but may be removed in a future
+ release.
"""
__slots__ = (
@@ -1347,6 +1438,69 @@ class SpecifierSet(BaseSpecifier):
self._prereleases = value
self._is_unsatisfiable = None
+ def __getstate__(self) -> tuple[tuple[Specifier, ...], bool | None]:
+ # Return state as a 2-item tuple for compactness:
+ # (specs, prereleases)
+ # Cache members are excluded and will be recomputed on demand.
+ return (self._specs, self._prereleases)
+
+ def __setstate__(self, state: object) -> None:
+ # Always discard cached values - they will be recomputed on demand.
+ self._resolved_ops = None
+ self._is_unsatisfiable = None
+
+ if isinstance(state, tuple):
+ if len(state) == 2:
+ # New format (26.2+): (specs, prereleases)
+ specs, prereleases = state
+ if (
+ isinstance(specs, tuple)
+ and all(isinstance(s, Specifier) for s in specs)
+ and _validate_pre(prereleases)
+ ):
+ self._specs = specs
+ self._prereleases = prereleases
+ self._canonicalized = len(specs) <= 1
+ self._has_arbitrary = any("===" in str(s) for s in specs)
+ return
+ if len(state) == 2 and isinstance(state[1], dict):
+ # Format (packaging 26.0-26.1): (None, {slot: value}).
+ _, slot_dict = state
+ specs = slot_dict.get("_specs", ())
+ prereleases = slot_dict.get("_prereleases")
+ # Convert frozenset to tuple (26.0 stored as frozenset)
+ if isinstance(specs, frozenset):
+ specs = tuple(sorted(specs, key=str))
+ if (
+ isinstance(specs, tuple)
+ and all(isinstance(s, Specifier) for s in specs)
+ and _validate_pre(prereleases)
+ ):
+ self._specs = specs
+ self._prereleases = prereleases
+ self._canonicalized = len(self._specs) <= 1
+ self._has_arbitrary = any("===" in str(s) for s in self._specs)
+ return
+ if isinstance(state, dict):
+ # Old format (packaging <= 25.x, no __slots__): state is a plain dict.
+ specs = state.get("_specs", ())
+ prereleases = state.get("_prereleases")
+ # Convert frozenset to tuple (26.0 stored as frozenset)
+ if isinstance(specs, frozenset):
+ specs = tuple(sorted(specs, key=str))
+ if (
+ isinstance(specs, tuple)
+ and all(isinstance(s, Specifier) for s in specs)
+ and _validate_pre(prereleases)
+ ):
+ self._specs = specs
+ self._prereleases = prereleases
+ self._canonicalized = len(self._specs) <= 1
+ self._has_arbitrary = any("===" in str(s) for s in self._specs)
+ return
+
+ raise TypeError(f"Cannot restore SpecifierSet from {state!r}")
+
def __repr__(self) -> str:
"""A representation of the specifier set that shows all internal state.
diff --git a/contrib/python/packaging/py3/packaging/tags.py b/contrib/python/packaging/py3/packaging/tags.py
index 7f71e3910e5..9980ab3c63c 100644
--- a/contrib/python/packaging/py3/packaging/tags.py
+++ b/contrib/python/packaging/py3/packaging/tags.py
@@ -15,7 +15,6 @@ import sysconfig
from importlib.machinery import EXTENSION_SUFFIXES
from typing import (
TYPE_CHECKING,
- Any,
Iterable,
Iterator,
Sequence,
@@ -92,6 +91,16 @@ class Tag:
Instances are considered immutable and thus are hashable. Equality checking
is also supported.
+
+ Instances are safe to serialize with :mod:`pickle`. They use a stable
+ format so the same pickle can be loaded in future packaging releases.
+
+ .. versionchanged:: 26.2
+
+ Added a stable pickle format. Pickles created with packaging 26.2+ can
+ be unpickled with future releases. Backward compatibility with pickles
+ from packaging < 26.2 is supported but may be removed in a future
+ release.
"""
__slots__ = ["_abi", "_hash", "_interpreter", "_platform"]
@@ -158,12 +167,37 @@ class Tag:
def __repr__(self) -> str:
return f"<{self} @ {id(self)}>"
- def __setstate__(self, state: tuple[None, dict[str, Any]]) -> None:
- # The cached _hash is wrong when unpickling.
- _, slots = state
- for k, v in slots.items():
- setattr(self, k, v)
- self._hash = hash((self._interpreter, self._abi, self._platform))
+ def __getstate__(self) -> tuple[str, str, str]:
+ # Return state as a 3-item tuple: (interpreter, abi, platform).
+ # Cache member _hash is excluded and will be recomputed.
+ return (self._interpreter, self._abi, self._platform)
+
+ def __setstate__(self, state: object) -> None:
+ if isinstance(state, tuple):
+ if len(state) == 3 and all(isinstance(s, str) for s in state):
+ # New format (26.2+): (interpreter, abi, platform)
+ self._interpreter, self._abi, self._platform = state
+ self._hash = hash((self._interpreter, self._abi, self._platform))
+ return
+ if len(state) == 2 and isinstance(state[1], dict):
+ # Old format (packaging <= 26.1, __slots__): (None, {slot: value}).
+ _, slots = state
+ try:
+ interpreter = slots["_interpreter"]
+ abi = slots["_abi"]
+ platform = slots["_platform"]
+ except KeyError:
+ raise TypeError(f"Cannot restore Tag from {state!r}") from None
+ if not all(
+ isinstance(value, str) for value in (interpreter, abi, platform)
+ ):
+ raise TypeError(f"Cannot restore Tag from {state!r}")
+ self._interpreter = interpreter.lower()
+ self._abi = abi.lower()
+ self._platform = platform.lower()
+ self._hash = hash((self._interpreter, self._abi, self._platform))
+ return
+ raise TypeError(f"Cannot restore Tag from {state!r}")
def parse_tag(tag: str, *, validate_order: bool = False) -> frozenset[Tag]:
@@ -749,9 +783,11 @@ def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]:
def _emscripten_platforms() -> Iterator[str]:
- pyemscripten_abi_version = sysconfig.get_config_var("PYEMSCRIPTEN_ABI_VERSION")
- if pyemscripten_abi_version:
- yield f"pyemscripten_{pyemscripten_abi_version}_wasm32"
+ pyemscripten_platform_version = sysconfig.get_config_var(
+ "PYEMSCRIPTEN_PLATFORM_VERSION"
+ )
+ if pyemscripten_platform_version:
+ yield f"pyemscripten_{pyemscripten_platform_version}_wasm32"
yield from _generic_platforms()
diff --git a/contrib/python/packaging/py3/packaging/version.py b/contrib/python/packaging/py3/packaging/version.py
index f872b85df90..97f23fd9ad6 100644
--- a/contrib/python/packaging/py3/packaging/version.py
+++ b/contrib/python/packaging/py3/packaging/version.py
@@ -358,6 +358,16 @@ class Version(_BaseVersion):
:class:`Version` is immutable; use :meth:`__replace__` to change
part of a version.
+
+ Instances are safe to serialize with :mod:`pickle`. They use a stable
+ format so the same pickle can be loaded in future packaging releases.
+
+ .. versionchanged:: 26.2
+
+ Added a stable pickle format. Pickles created with packaging 26.2+ can
+ be unpickled with future releases. Backward compatibility with pickles
+ from packaging < 26.2 is supported but may be removed in a future
+ release.
"""
__slots__ = (
@@ -741,6 +751,73 @@ class Version(_BaseVersion):
return super().__ne__(other)
+ def __getstate__(
+ self,
+ ) -> tuple[
+ int,
+ tuple[int, ...],
+ tuple[str, int] | None,
+ tuple[str, int] | None,
+ tuple[str, int] | None,
+ LocalType | None,
+ ]:
+ # Return state as a 6-item tuple for compactness:
+ # (epoch, release, pre, post, dev, local)
+ # Cache members are excluded and will be recomputed on demand
+ return (
+ self._epoch,
+ self._release,
+ self._pre,
+ self._post,
+ self._dev,
+ self._local,
+ )
+
+ def __setstate__(self, state: object) -> None:
+ # Always discard cached values — they may contain stale references
+ # (e.g. packaging._structures.InfinityType from pre-26.1 pickles)
+ # and will be recomputed on demand from the core fields above.
+ self._key_cache = None
+ self._hash_cache = None
+
+ if isinstance(state, tuple):
+ if len(state) == 6:
+ # New format (26.2+): (epoch, release, pre, post, dev, local)
+ (
+ self._epoch,
+ self._release,
+ self._pre,
+ self._post,
+ self._dev,
+ self._local,
+ ) = state
+ return
+ if len(state) == 2:
+ # Format (packaging 26.0-26.1): (None, {slot: value}).
+ _, slot_dict = state
+ if isinstance(slot_dict, dict):
+ self._epoch = slot_dict["_epoch"]
+ self._release = slot_dict["_release"]
+ self._pre = slot_dict.get("_pre")
+ self._post = slot_dict.get("_post")
+ self._dev = slot_dict.get("_dev")
+ self._local = slot_dict.get("_local")
+ return
+ if isinstance(state, dict):
+ # Old format (packaging <= 25.x, no __slots__): state is a plain
+ # dict with "_version" (_Version NamedTuple) and "_key" entries.
+ version_nt = state.get("_version")
+ if version_nt is not None:
+ self._epoch = version_nt.epoch
+ self._release = version_nt.release
+ self._pre = version_nt.pre
+ self._post = version_nt.post
+ self._dev = version_nt.dev
+ self._local = version_nt.local
+ return
+
+ raise TypeError(f"Cannot restore Version from {state!r}")
+
@property
@_deprecated("Version._version is private and will be removed soon")
def _version(self) -> _Version:
diff --git a/contrib/python/packaging/py3/ya.make b/contrib/python/packaging/py3/ya.make
index d1ccae20d2c..c8b64dc7944 100644
--- a/contrib/python/packaging/py3/ya.make
+++ b/contrib/python/packaging/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(26.1)
+VERSION(26.2)
LICENSE(BSD-2-Clause AND Apache-2.0)
@@ -15,6 +15,7 @@ PY_SRCS(
packaging/_manylinux.py
packaging/_musllinux.py
packaging/_parser.py
+ packaging/_structures.py
packaging/_tokenizer.py
packaging/dependency_groups.py
packaging/direct_url.py