diff --git a/src/packaging/tags.py b/src/packaging/tags.py index 8522f59c4..8864505ab 100644 --- a/src/packaging/tags.py +++ b/src/packaging/tags.py @@ -13,6 +13,7 @@ import sysconfig from importlib.machinery import EXTENSION_SUFFIXES from typing import ( + Any, Iterable, Iterator, Sequence, @@ -92,6 +93,13 @@ def __str__(self) -> str: def __repr__(self) -> str: return f"<{self} @ {id(self)}>" + def __setstate__(self, state: tuple[dict[str, Any], dict[str, Any]]) -> None: + # The cached _hash is wrong when unpickling. + _old_hash, slots = state + for k, v in slots.items(): + setattr(self, k, v) + self._hash = hash((self._interpreter, self._abi, self._platform)) + def parse_tag(tag: str) -> frozenset[Tag]: """ diff --git a/tests/test_tags.py b/tests/test_tags.py index 012acb130..63ad82483 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -13,6 +13,7 @@ import importlib import os import pathlib +import pickle import platform import struct import sys @@ -1571,3 +1572,9 @@ def _calcsize(fmt): monkeypatch.setattr(struct, "calcsize", _calcsize) importlib.reload(tags) assert tags._32_BIT_INTERPRETER == expected + + +def test_pickle(): + # Make sure equality works between a pickle/unpickle round trip. + tag = tags.Tag("py3", "none", "any") + assert pickle.loads(pickle.dumps(tag)) == tag