Skip to content

Commit

Permalink
typing: Add more tests for TypeVar (python#104571)
Browse files Browse the repository at this point in the history
During the PEP 695 implementation at one point I made
TypeVar.__name__ return garbage, and all of test_typing passed.
So I decided to add a few more tests. In the process I discovered
a minor incompatibility from the C implementation of TypeVar:
empty constraints were returned as None instead of an empty tuple.
  • Loading branch information
JelleZijlstra committed May 18, 2023
1 parent dc957c7 commit 1f381f2
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 8 deletions.
14 changes: 7 additions & 7 deletions Lib/test/test_type_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,11 +425,11 @@ class Foo[T: Foo, U: (Foo, Foo)]:
type_params = Foo.__type_params__
self.assertEqual(len(type_params), 2)
self.assertEqual(type_params[0].__name__, "T")
self.assertEqual(type_params[0].__bound__, Foo)
self.assertEqual(type_params[0].__constraints__, None)
self.assertIs(type_params[0].__bound__, Foo)
self.assertEqual(type_params[0].__constraints__, ())

self.assertEqual(type_params[1].__name__, "U")
self.assertEqual(type_params[1].__bound__, None)
self.assertIs(type_params[1].__bound__, None)
self.assertEqual(type_params[1].__constraints__, (Foo, Foo))

def test_evaluation_error(self):
Expand All @@ -439,16 +439,16 @@ class Foo[T: Undefined, U: (Undefined,)]:
type_params = Foo.__type_params__
with self.assertRaises(NameError):
type_params[0].__bound__
self.assertEqual(type_params[0].__constraints__, None)
self.assertEqual(type_params[1].__bound__, None)
self.assertEqual(type_params[0].__constraints__, ())
self.assertIs(type_params[1].__bound__, None)
with self.assertRaises(NameError):
type_params[1].__constraints__

Undefined = "defined"
self.assertEqual(type_params[0].__bound__, "defined")
self.assertEqual(type_params[0].__constraints__, None)
self.assertEqual(type_params[0].__constraints__, ())

self.assertEqual(type_params[1].__bound__, None)
self.assertIs(type_params[1].__bound__, None)
self.assertEqual(type_params[1].__constraints__, ("defined",))


Expand Down
42 changes: 42 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,41 @@ def test_basic_plain(self):
self.assertEqual(T, T)
# T is an instance of TypeVar
self.assertIsInstance(T, TypeVar)
self.assertEqual(T.__name__, 'T')
self.assertEqual(T.__constraints__, ())
self.assertIs(T.__bound__, None)
self.assertIs(T.__covariant__, False)
self.assertIs(T.__contravariant__, False)
self.assertIs(T.__infer_variance__, False)

def test_attributes(self):
T_bound = TypeVar('T_bound', bound=int)
self.assertEqual(T_bound.__name__, 'T_bound')
self.assertEqual(T_bound.__constraints__, ())
self.assertIs(T_bound.__bound__, int)

T_constraints = TypeVar('T_constraints', int, str)
self.assertEqual(T_constraints.__name__, 'T_constraints')
self.assertEqual(T_constraints.__constraints__, (int, str))
self.assertIs(T_constraints.__bound__, None)

T_co = TypeVar('T_co', covariant=True)
self.assertEqual(T_co.__name__, 'T_co')
self.assertIs(T_co.__covariant__, True)
self.assertIs(T_co.__contravariant__, False)
self.assertIs(T_co.__infer_variance__, False)

T_contra = TypeVar('T_contra', contravariant=True)
self.assertEqual(T_contra.__name__, 'T_contra')
self.assertIs(T_contra.__covariant__, False)
self.assertIs(T_contra.__contravariant__, True)
self.assertIs(T_contra.__infer_variance__, False)

T_infer = TypeVar('T_infer', infer_variance=True)
self.assertEqual(T_infer.__name__, 'T_infer')
self.assertIs(T_infer.__covariant__, False)
self.assertIs(T_infer.__contravariant__, False)
self.assertIs(T_infer.__infer_variance__, True)

def test_typevar_instance_type_error(self):
T = TypeVar('T')
Expand Down Expand Up @@ -458,6 +493,12 @@ def test_no_bivariant(self):
with self.assertRaises(ValueError):
TypeVar('T', covariant=True, contravariant=True)

def test_cannot_combine_explicit_and_infer(self):
with self.assertRaises(ValueError):
TypeVar('T', covariant=True, infer_variance=True)
with self.assertRaises(ValueError):
TypeVar('T', contravariant=True, infer_variance=True)

def test_var_substitution(self):
T = TypeVar('T')
subst = T.__typing_subst__
Expand Down Expand Up @@ -7812,6 +7853,7 @@ def test_basic_plain(self):
P = ParamSpec('P')
self.assertEqual(P, P)
self.assertIsInstance(P, ParamSpec)
self.assertEqual(P.__name__, 'P')

def test_valid_uses(self):
P = ParamSpec('P')
Expand Down
2 changes: 1 addition & 1 deletion Objects/typevarobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ typevar_constraints(typevarobject *self, void *Py_UNUSED(ignored))
return Py_NewRef(self->constraints);
}
if (self->evaluate_constraints == NULL) {
Py_RETURN_NONE;
return PyTuple_New(0);
}
PyObject *constraints = PyObject_CallNoArgs(self->evaluate_constraints);
self->constraints = Py_XNewRef(constraints);
Expand Down

0 comments on commit 1f381f2

Please sign in to comment.