Skip to content

Commit f2cc8ad

Browse files
[3.12] gh-118814: Fix the TypeVar constructor when name is passed by keyword (GH-122664) (GH-122807)
Fix _PyArg_UnpackKeywordsWithVararg for the case when argument for positional-or-keyword parameter is passed by keyword. There was only one such case in the stdlib -- the TypeVar constructor. (cherry picked from commit 540fcc6)
1 parent 8f4892a commit f2cc8ad

File tree

6 files changed

+151
-7
lines changed

6 files changed

+151
-7
lines changed

Lib/test/test_clinic.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,11 +2093,27 @@ def test_vararg(self):
20932093
self.assertEqual(ac_tester.vararg(1, 2, 3, 4), (1, (2, 3, 4)))
20942094

20952095
def test_vararg_with_default(self):
2096-
with self.assertRaises(TypeError):
2097-
ac_tester.vararg_with_default()
2098-
self.assertEqual(ac_tester.vararg_with_default(1, b=False), (1, (), False))
2099-
self.assertEqual(ac_tester.vararg_with_default(1, 2, 3, 4), (1, (2, 3, 4), False))
2100-
self.assertEqual(ac_tester.vararg_with_default(1, 2, 3, 4, b=True), (1, (2, 3, 4), True))
2096+
fn = ac_tester.vararg_with_default
2097+
self.assertRaises(TypeError, fn)
2098+
self.assertRaises(TypeError, fn, 1, a=2)
2099+
self.assertEqual(fn(1, b=2), (1, (), True))
2100+
self.assertEqual(fn(1, 2, 3, 4), (1, (2, 3, 4), False))
2101+
self.assertEqual(fn(1, 2, 3, 4, b=5), (1, (2, 3, 4), True))
2102+
self.assertEqual(fn(a=1), (1, (), False))
2103+
self.assertEqual(fn(a=1, b=2), (1, (), True))
2104+
2105+
def test_vararg_with_default2(self):
2106+
fn = ac_tester.vararg_with_default2
2107+
self.assertRaises(TypeError, fn)
2108+
self.assertRaises(TypeError, fn, 1, a=2)
2109+
self.assertEqual(fn(1, b=2), (1, (), 2, None))
2110+
self.assertEqual(fn(1, b=2, c=3), (1, (), 2, 3))
2111+
self.assertEqual(fn(1, 2, 3), (1, (2, 3), None, None))
2112+
self.assertEqual(fn(1, 2, 3, b=4), (1, (2, 3), 4, None))
2113+
self.assertEqual(fn(1, 2, 3, b=4, c=5), (1, (2, 3), 4, 5))
2114+
self.assertEqual(fn(a=1), (1, (), None, None))
2115+
self.assertEqual(fn(a=1, b=2), (1, (), 2, None))
2116+
self.assertEqual(fn(a=1, b=2, c=3), (1, (), 2, 3))
21012117

21022118
def test_vararg_with_only_defaults(self):
21032119
self.assertEqual(ac_tester.vararg_with_only_defaults(), ((), None))

Lib/test/test_typing.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,41 @@ def test_constructor(self):
579579
self.assertEqual(T.__name__, "T")
580580
self.assertEqual(T.__constraints__, ())
581581
self.assertIs(T.__bound__, None)
582+
self.assertIs(T.__covariant__, False)
583+
self.assertIs(T.__contravariant__, False)
584+
self.assertIs(T.__infer_variance__, False)
585+
586+
T = TypeVar(name="T", bound=type)
587+
self.assertEqual(T.__name__, "T")
588+
self.assertEqual(T.__constraints__, ())
589+
self.assertIs(T.__bound__, type)
590+
self.assertIs(T.__covariant__, False)
591+
self.assertIs(T.__contravariant__, False)
592+
self.assertIs(T.__infer_variance__, False)
593+
594+
T = TypeVar(name="T", covariant=True)
595+
self.assertEqual(T.__name__, "T")
596+
self.assertEqual(T.__constraints__, ())
597+
self.assertIs(T.__bound__, None)
598+
self.assertIs(T.__covariant__, True)
599+
self.assertIs(T.__contravariant__, False)
600+
self.assertIs(T.__infer_variance__, False)
601+
602+
T = TypeVar(name="T", contravariant=True)
603+
self.assertEqual(T.__name__, "T")
604+
self.assertEqual(T.__constraints__, ())
605+
self.assertIs(T.__bound__, None)
606+
self.assertIs(T.__covariant__, False)
607+
self.assertIs(T.__contravariant__, True)
608+
self.assertIs(T.__infer_variance__, False)
609+
610+
T = TypeVar(name="T", infer_variance=True)
611+
self.assertEqual(T.__name__, "T")
612+
self.assertEqual(T.__constraints__, ())
613+
self.assertIs(T.__bound__, None)
614+
self.assertIs(T.__covariant__, False)
615+
self.assertIs(T.__contravariant__, False)
616+
self.assertIs(T.__infer_variance__, True)
582617

583618

584619
def template_replace(templates: list[str], replacements: dict[str, list[str]]) -> list[tuple[str]]:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix the :class:`typing.TypeVar` constructor when name is passed by keyword.

Modules/_testclinic.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,25 @@ vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args,
10341034
}
10351035

10361036

1037+
/*[clinic input]
1038+
vararg_with_default2
1039+
1040+
a: object
1041+
*args: object
1042+
b: object = None
1043+
c: object = None
1044+
1045+
[clinic start generated code]*/
1046+
1047+
static PyObject *
1048+
vararg_with_default2_impl(PyObject *module, PyObject *a, PyObject *args,
1049+
PyObject *b, PyObject *c)
1050+
/*[clinic end generated code: output=a0fb7c37796e2129 input=59fb22f5f0a8925f]*/
1051+
{
1052+
return pack_arguments_newref(4, a, args, b, c);
1053+
}
1054+
1055+
10371056
/*[clinic input]
10381057
vararg_with_only_defaults
10391058
@@ -1274,6 +1293,7 @@ static PyMethodDef tester_methods[] = {
12741293
VARARG_AND_POSONLY_METHODDEF
12751294
VARARG_METHODDEF
12761295
VARARG_WITH_DEFAULT_METHODDEF
1296+
VARARG_WITH_DEFAULT2_METHODDEF
12771297
VARARG_WITH_ONLY_DEFAULTS_METHODDEF
12781298
GH_32092_OOB_METHODDEF
12791299
GH_32092_KW_PASS_METHODDEF

Modules/clinic/_testclinic.c.h

Lines changed: 73 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/getargs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2640,7 +2640,7 @@ _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs,
26402640
*
26412641
* Otherwise, we leave a place at `buf[vararg]` for vararg tuple
26422642
* so the index is `i + 1`. */
2643-
if (nargs < vararg) {
2643+
if (i < vararg) {
26442644
buf[i] = current_arg;
26452645
}
26462646
else {

0 commit comments

Comments
 (0)