[Python-checkins] typing: Add more tests for TypeVar (#104571)

JelleZijlstra webhook-mailer at python.org
Wed May 17 09:08:29 EDT 2023


https://github.com/python/cpython/commit/26931944dd8abd6554249239344fa62b789b9028
commit: 26931944dd8abd6554249239344fa62b789b9028
branch: main
author: Jelle Zijlstra <jelle.zijlstra at gmail.com>
committer: JelleZijlstra <jelle.zijlstra at gmail.com>
date: 2023-05-17T06:08:21-07:00
summary:

typing: Add more tests for TypeVar (#104571)

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.

files:
M Lib/test/test_type_params.py
M Lib/test/test_typing.py
M Objects/typevarobject.c

diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py
index 3ca13c21c61a..96bd1fa0bab9 100644
--- a/Lib/test/test_type_params.py
+++ b/Lib/test/test_type_params.py
@@ -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):
@@ -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",))
 
 
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 0cd67c51e508..045f2a3b4dfe 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -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')
@@ -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__
@@ -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')
diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c
index b0578756f7df..4464e7a9da89 100644
--- a/Objects/typevarobject.c
+++ b/Objects/typevarobject.c
@@ -271,7 +271,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);



More information about the Python-checkins mailing list