Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-105433: Add pickle tests for PEP695 #105443

Merged
merged 3 commits into from
Jun 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
69 changes: 65 additions & 4 deletions Lib/test/test_type_aliases.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,69 @@ def test_module(self):
self.assertEqual(mod_generics_cache.OldStyle.__module__,
mod_generics_cache.__name__)


# All these type aliases are used for pickling tests:
T = TypeVar('T')
type SimpleAlias = int
type RecursiveAlias = dict[str, RecursiveAlias]
type GenericAlias[X] = list[X]
type GenericAliasMultipleTypes[X, Y] = dict[X, Y]
type RecursiveGenericAlias[X] = dict[str, RecursiveAlias[X]]
type BoundGenericAlias[X: int] = set[X]
type ConstrainedGenericAlias[LongName: (str, bytes)] = list[LongName]
type AllTypesAlias[A, *B, **C] = Callable[C, A] | tuple[*B]


class TypeAliasPickleTest(unittest.TestCase):
def test_pickling(self):
pickled = pickle.dumps(mod_generics_cache.Alias)
self.assertIs(pickle.loads(pickled), mod_generics_cache.Alias)
pickled = pickle.dumps(mod_generics_cache.OldStyle)
self.assertIs(pickle.loads(pickled), mod_generics_cache.OldStyle)
things_to_test = [
SimpleAlias,
RecursiveAlias,

GenericAlias,
GenericAlias[T],
GenericAlias[int],

GenericAliasMultipleTypes,
GenericAliasMultipleTypes[str, T],
GenericAliasMultipleTypes[T, str],
GenericAliasMultipleTypes[int, str],

RecursiveGenericAlias,
RecursiveGenericAlias[T],
RecursiveGenericAlias[int],

BoundGenericAlias,
BoundGenericAlias[int],
BoundGenericAlias[T],

ConstrainedGenericAlias,
ConstrainedGenericAlias[str],
ConstrainedGenericAlias[T],

AllTypesAlias,
AllTypesAlias[int, str, T, [T, object]],

# Other modules:
mod_generics_cache.Alias,
mod_generics_cache.OldStyle,
]
for thing in things_to_test:
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
with self.subTest(thing=thing, proto=proto):
pickled = pickle.dumps(thing, protocol=proto)
self.assertEqual(pickle.loads(pickled), thing)

type ClassLevel = str

def test_pickling_local(self):
type A = int
things_to_test = [
self.ClassLevel,
A,
]
for thing in things_to_test:
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
with self.subTest(thing=thing, proto=proto):
with self.assertRaises(pickle.PickleError):
pickle.dumps(thing, protocol=proto)
66 changes: 66 additions & 0 deletions Lib/test/test_type_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import textwrap
import types
import unittest
import pickle
from test.support import requires_working_socket, check_syntax_error, run_code

from typing import Generic, Sequence, TypeVar, TypeVarTuple, ParamSpec, get_args
Expand Down Expand Up @@ -849,3 +850,68 @@ def func[A]():

ns = run_code(code)
self.assertEqual(ns["func"].__type_params__, ())



# All these type aliases are used for pickling tests:
T = TypeVar('T')
def func1[X](x: X) -> X: ...
def func2[X, Y](x: X | Y) -> X | Y: ...
def func3[X, *Y, **Z](x: X, y: tuple[*Y], z: Z) -> X: ...
def func4[X: int, Y: (bytes, str)](x: X, y: Y) -> X | Y: ...

class Class1[X]: ...
class Class2[X, Y]: ...
class Class3[X, *Y, **Z]: ...
class Class4[X: int, Y: (bytes, str)]: ...


class TypeParamsPickleTest(unittest.TestCase):
def test_pickling_functions(self):
things_to_test = [
func1,
func2,
func3,
func4,
]
for thing in things_to_test:
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
with self.subTest(thing=thing, proto=proto):
pickled = pickle.dumps(thing, protocol=proto)
self.assertEqual(pickle.loads(pickled), thing)

def test_pickling_classes(self):
things_to_test = [
Class1,
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved
Class1[int],
Class1[T],

Class2,
Class2[int, T],
Class2[T, int],
Class2[int, str],

Class3,
Class3[int, T, str, bytes, [float, object, T]],

Class4,
Class4[int, bytes],
Class4[T, bytes],
Class4[int, T],
Class4[T, T],
]
for thing in things_to_test:
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
with self.subTest(thing=thing, proto=proto):
pickled = pickle.dumps(thing, protocol=proto)
self.assertEqual(pickle.loads(pickled), thing)

for klass in things_to_test:
real_class = getattr(klass, '__origin__', klass)
thing = klass()
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
with self.subTest(thing=thing, proto=proto):
pickled = pickle.dumps(thing, protocol=proto)
# These instances are not equal,
# but class check is good enough:
self.assertIsInstance(pickle.loads(pickled), real_class)