Skip to content

Commit 5890a6c

Browse files
serhiy-storchakablhsing
authored andcommitted
pythongh-118814: Fix the TypeVar constructor when name is passed by keyword (pythonGH-122664)
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.
1 parent db762d2 commit 5890a6c

File tree

6 files changed

+165
-7
lines changed

6 files changed

+165
-7
lines changed

Lib/test/test_clinic.py

+21-5
Original file line numberDiff line numberDiff line change
@@ -3334,11 +3334,27 @@ def test_vararg(self):
33343334
self.assertEqual(ac_tester.vararg(1, 2, 3, 4), (1, (2, 3, 4)))
33353335

33363336
def test_vararg_with_default(self):
3337-
with self.assertRaises(TypeError):
3338-
ac_tester.vararg_with_default()
3339-
self.assertEqual(ac_tester.vararg_with_default(1, b=False), (1, (), False))
3340-
self.assertEqual(ac_tester.vararg_with_default(1, 2, 3, 4), (1, (2, 3, 4), False))
3341-
self.assertEqual(ac_tester.vararg_with_default(1, 2, 3, 4, b=True), (1, (2, 3, 4), True))
3337+
fn = ac_tester.vararg_with_default
3338+
self.assertRaises(TypeError, fn)
3339+
self.assertRaises(TypeError, fn, 1, a=2)
3340+
self.assertEqual(fn(1, b=2), (1, (), True))
3341+
self.assertEqual(fn(1, 2, 3, 4), (1, (2, 3, 4), False))
3342+
self.assertEqual(fn(1, 2, 3, 4, b=5), (1, (2, 3, 4), True))
3343+
self.assertEqual(fn(a=1), (1, (), False))
3344+
self.assertEqual(fn(a=1, b=2), (1, (), True))
3345+
3346+
def test_vararg_with_default2(self):
3347+
fn = ac_tester.vararg_with_default2
3348+
self.assertRaises(TypeError, fn)
3349+
self.assertRaises(TypeError, fn, 1, a=2)
3350+
self.assertEqual(fn(1, b=2), (1, (), 2, None))
3351+
self.assertEqual(fn(1, b=2, c=3), (1, (), 2, 3))
3352+
self.assertEqual(fn(1, 2, 3), (1, (2, 3), None, None))
3353+
self.assertEqual(fn(1, 2, 3, b=4), (1, (2, 3), 4, None))
3354+
self.assertEqual(fn(1, 2, 3, b=4, c=5), (1, (2, 3), 4, 5))
3355+
self.assertEqual(fn(a=1), (1, (), None, None))
3356+
self.assertEqual(fn(a=1, b=2), (1, (), 2, None))
3357+
self.assertEqual(fn(a=1, b=2, c=3), (1, (), 2, 3))
33423358

33433359
def test_vararg_with_only_defaults(self):
33443360
self.assertEqual(ac_tester.vararg_with_only_defaults(), ((), None))

Lib/test/test_typing.py

+49
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,55 @@ 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.__default__, typing.NoDefault)
583+
self.assertIs(T.__covariant__, False)
584+
self.assertIs(T.__contravariant__, False)
585+
self.assertIs(T.__infer_variance__, False)
586+
587+
T = TypeVar(name="T", bound=type)
588+
self.assertEqual(T.__name__, "T")
589+
self.assertEqual(T.__constraints__, ())
590+
self.assertIs(T.__bound__, type)
591+
self.assertIs(T.__default__, typing.NoDefault)
592+
self.assertIs(T.__covariant__, False)
593+
self.assertIs(T.__contravariant__, False)
594+
self.assertIs(T.__infer_variance__, False)
595+
596+
T = TypeVar(name="T", default=())
597+
self.assertEqual(T.__name__, "T")
598+
self.assertEqual(T.__constraints__, ())
599+
self.assertIs(T.__bound__, None)
600+
self.assertIs(T.__default__, ())
601+
self.assertIs(T.__covariant__, False)
602+
self.assertIs(T.__contravariant__, False)
603+
self.assertIs(T.__infer_variance__, False)
604+
605+
T = TypeVar(name="T", covariant=True)
606+
self.assertEqual(T.__name__, "T")
607+
self.assertEqual(T.__constraints__, ())
608+
self.assertIs(T.__bound__, None)
609+
self.assertIs(T.__default__, typing.NoDefault)
610+
self.assertIs(T.__covariant__, True)
611+
self.assertIs(T.__contravariant__, False)
612+
self.assertIs(T.__infer_variance__, False)
613+
614+
T = TypeVar(name="T", contravariant=True)
615+
self.assertEqual(T.__name__, "T")
616+
self.assertEqual(T.__constraints__, ())
617+
self.assertIs(T.__bound__, None)
618+
self.assertIs(T.__default__, typing.NoDefault)
619+
self.assertIs(T.__covariant__, False)
620+
self.assertIs(T.__contravariant__, True)
621+
self.assertIs(T.__infer_variance__, False)
622+
623+
T = TypeVar(name="T", infer_variance=True)
624+
self.assertEqual(T.__name__, "T")
625+
self.assertEqual(T.__constraints__, ())
626+
self.assertIs(T.__bound__, None)
627+
self.assertIs(T.__default__, typing.NoDefault)
628+
self.assertIs(T.__covariant__, False)
629+
self.assertIs(T.__contravariant__, False)
630+
self.assertIs(T.__infer_variance__, True)
582631

583632

584633
class TypeParameterDefaultsTests(BaseTestCase):
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

+20
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,25 @@ vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args,
10331033
}
10341034

10351035

1036+
/*[clinic input]
1037+
vararg_with_default2
1038+
1039+
a: object
1040+
*args: object
1041+
b: object = None
1042+
c: object = None
1043+
1044+
[clinic start generated code]*/
1045+
1046+
static PyObject *
1047+
vararg_with_default2_impl(PyObject *module, PyObject *a, PyObject *args,
1048+
PyObject *b, PyObject *c)
1049+
/*[clinic end generated code: output=a0fb7c37796e2129 input=59fb22f5f0a8925f]*/
1050+
{
1051+
return pack_arguments_newref(4, a, args, b, c);
1052+
}
1053+
1054+
10361055
/*[clinic input]
10371056
vararg_with_only_defaults
10381057
@@ -1907,6 +1926,7 @@ static PyMethodDef tester_methods[] = {
19071926
VARARG_AND_POSONLY_METHODDEF
19081927
VARARG_METHODDEF
19091928
VARARG_WITH_DEFAULT_METHODDEF
1929+
VARARG_WITH_DEFAULT2_METHODDEF
19101930
VARARG_WITH_ONLY_DEFAULTS_METHODDEF
19111931
GH_32092_OOB_METHODDEF
19121932
GH_32092_KW_PASS_METHODDEF

Modules/clinic/_testclinic.c.h

+73-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/getargs.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2601,7 +2601,7 @@ _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs,
26012601
*
26022602
* Otherwise, we leave a place at `buf[vararg]` for vararg tuple
26032603
* so the index is `i + 1`. */
2604-
if (nargs < vararg && i != vararg) {
2604+
if (i < vararg) {
26052605
buf[i] = current_arg;
26062606
}
26072607
else {

0 commit comments

Comments
 (0)