Skip to content

Commit 82ae60f

Browse files
committed
Merge remote-tracking branch 'origin/main' into gc-debug-ft-race
2 parents d5c8f14 + 9c15cc9 commit 82ae60f

21 files changed

Lines changed: 264 additions & 112 deletions

File tree

‎Doc/library/ctypes.rst‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1579,7 +1579,10 @@ way is to instantiate :py:class:`CDLL` or one of its subclasses:
15791579
:mod:`!ctypes` maintains a thread-local copy of the system's :data:`errno`
15801580
variable; if you call foreign functions created with ``use_errno=True`` then the
15811581
:data:`errno` value before the function call is swapped with the ctypes private
1582-
copy, the same happens immediately after the function call.
1582+
copy, the same happens immediately after the function call. This mechanism only
1583+
works for libraries that use the same C runtime library as the interpreter itself.
1584+
A library linked against a different C runtime (for example, a different CRT on
1585+
Windows) has its own :data:`errno`, which :mod:`!ctypes` cannot observe.
15831586

15841587
The function :func:`ctypes.get_errno` returns the value of the ctypes private
15851588
copy, and the function :func:`ctypes.set_errno` changes the ctypes private copy

‎Doc/library/tarfile.rst‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,17 @@ Some facts and figures:
123123
:exc:`ReadError` is raised. Use *mode* ``'r'`` to avoid this. If a
124124
compression method is not supported, :exc:`CompressionError` is raised.
125125

126+
.. note::
127+
128+
Compressed archives opened with modes like ``'r:gz'``, ``'r:bz2'``,
129+
``'r:xz'``, or ``'r:zst'`` support random access, but seeking backwards
130+
in the underlying compressed stream requires re-decompressing from the
131+
beginning. Extracting members in a different order than they appear in
132+
the archive can therefore be significantly slower — proportional to the
133+
total compressed data read rather than just the target member's size. For
134+
best performance, extract members in archive order or use
135+
:meth:`TarFile.extractall`.
136+
126137
If *fileobj* is specified, it is used as an alternative to a :term:`file object`
127138
opened in binary mode for *name*. It is supposed to be at position 0.
128139

‎Doc/whatsnew/3.16.rst‎

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ Other language changes
9898
they reference) alive indefinitely.
9999
(Contributed by Łukasz Langa in :gh:`102960`.)
100100

101+
* :exc:`TypeError` messages for some instance methods called with too many
102+
positional arguments now suggest checking whether the method definition is
103+
missing the ``self`` parameter. (Contributed by Suren Nihalani in
104+
:gh:`152315`.)
105+
101106

102107
New modules
103108
===========
@@ -180,6 +185,7 @@ ctypes
180185
from an annotation-based syntax, similar to how the :mod:`dataclasses` module
181186
is used.
182187
(Contributed by Peter Bierma in :gh:`104533`.)
188+
183189
* Add :func:`ctypes.util.wrap_dll_function` for generating function pointers
184190
through a function signature.
185191
(Contributed by Peter Bierma in :gh:`153903`.)
@@ -326,27 +332,6 @@ curses
326332
(Contributed by Serhiy Storchaka in :gh:`133031`.)
327333

328334

329-
ctypes
330-
------
331-
332-
* Add :func:`ctypes.util.struct` for generating :class:`~ctypes.Structure` types
333-
from an annotation-based syntax, similar to how the :mod:`dataclasses` module
334-
is used.
335-
(Contributed by Peter Bierma in :gh:`104533`.)
336-
* Add :func:`ctypes.util.wrap_dll_function` for generating function pointers
337-
through a function signature.
338-
(Contributed by Peter Bierma in :gh:`153903`.)
339-
340-
341-
concurrent.futures
342-
------------------
343-
344-
* The iterator returned by :meth:`concurrent.futures.Executor.map` is no longer
345-
automatically closed if a function call raises an exception.
346-
Use method :meth:`!close` to explicitly close the iterator.
347-
(Contributed by xzmeng and Serhiy Storchaka in :gh:`108518`.)
348-
349-
350335
decimal
351336
-------
352337

‎Include/internal/pycore_modsupport.h‎

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,6 @@ extern PyObject ** _Py_VaBuildStack(
4141

4242
extern PyObject* _PyModule_CreateInitialized(PyModuleDef*, int apiver);
4343

44-
// Export for '_curses' shared extension
45-
PyAPI_FUNC(int) _PyArg_ParseStack(
46-
PyObject *const *args,
47-
Py_ssize_t nargs,
48-
const char *format,
49-
...);
50-
5144
extern int _PyArg_UnpackStack(
5245
PyObject *const *args,
5346
Py_ssize_t nargs,
@@ -65,7 +58,9 @@ PyAPI_FUNC(void) _PyArg_BadArgument(
6558

6659
// --- _PyArg_Parser API ---------------------------------------------------
6760

68-
// Export for '_dbm' shared extension
61+
// Similar to public PyArg_ParseArrayAndKeywords(), but faster thanks
62+
// to "struct _PyArg_Parser *parser" cache.
63+
// Export for '_dbm' shared extension.
6964
PyAPI_FUNC(int) _PyArg_ParseStackAndKeywords(
7065
PyObject *const *args,
7166
Py_ssize_t nargs,

‎Lib/test/clinic.test.c‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,7 +2049,7 @@ test_str_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
20492049
const char *h = "mn";
20502050
Py_ssize_t h_length;
20512051

2052-
if (!_PyArg_ParseStack(args, nargs, "|sssyzy#s#z#:test_str_converter",
2052+
if (!PyArg_ParseArray(args, nargs, "|sssyzy#s#z#:test_str_converter",
20532053
&a, &b, &c, &d, &e, &f, &f_length, &g, &g_length, &h, &h_length)) {
20542054
goto exit;
20552055
}
@@ -2065,7 +2065,7 @@ test_str_converter_impl(PyObject *module, const char *a, const char *b,
20652065
const char *f, Py_ssize_t f_length, const char *g,
20662066
Py_ssize_t g_length, const char *h,
20672067
Py_ssize_t h_length)
2068-
/*[clinic end generated code: output=82cb06d5237ef062 input=8afe9da8185cd38c]*/
2068+
/*[clinic end generated code: output=58dc0fad26cd4c5d input=8afe9da8185cd38c]*/
20692069

20702070

20712071
/*[clinic input]
@@ -2105,7 +2105,7 @@ test_str_converter_encoding(PyObject *module, PyObject *const *args, Py_ssize_t
21052105
char *e = NULL;
21062106
Py_ssize_t e_length;
21072107

2108-
if (!_PyArg_ParseStack(args, nargs, "esesetes#et#:test_str_converter_encoding",
2108+
if (!PyArg_ParseArray(args, nargs, "esesetes#et#:test_str_converter_encoding",
21092109
"idna", &a, "idna", &b, "idna", &c, "idna", &d, &d_length, "idna", &e, &e_length)) {
21102110
goto exit;
21112111
}
@@ -2129,7 +2129,7 @@ static PyObject *
21292129
test_str_converter_encoding_impl(PyObject *module, char *a, char *b, char *c,
21302130
char *d, Py_ssize_t d_length, char *e,
21312131
Py_ssize_t e_length)
2132-
/*[clinic end generated code: output=999c1deecfa15b0a input=eb4c38e1f898f402]*/
2132+
/*[clinic end generated code: output=5bab02bfd6a20cf4 input=eb4c38e1f898f402]*/
21332133

21342134

21352135
/*[clinic input]
@@ -2170,7 +2170,7 @@ test_Py_UNICODE_converter(PyObject *module, PyObject *const *args, Py_ssize_t na
21702170
const wchar_t *e = NULL;
21712171
Py_ssize_t e_length;
21722172

2173-
if (!_PyArg_ParseStack(args, nargs, "O&O&O&u#Z#:test_Py_UNICODE_converter",
2173+
if (!PyArg_ParseArray(args, nargs, "O&O&O&u#Z#:test_Py_UNICODE_converter",
21742174
_PyUnicode_WideCharString_Converter, &a, _PyUnicode_WideCharString_Converter, &b, _PyUnicode_WideCharString_Opt_Converter, &c, &d, &d_length, &e, &e_length)) {
21752175
goto exit;
21762176
}
@@ -2192,7 +2192,7 @@ test_Py_UNICODE_converter_impl(PyObject *module, const wchar_t *a,
21922192
const wchar_t *b, const wchar_t *c,
21932193
const wchar_t *d, Py_ssize_t d_length,
21942194
const wchar_t *e, Py_ssize_t e_length)
2195-
/*[clinic end generated code: output=529af9cda2a20349 input=064a3b68ad7f04b0]*/
2195+
/*[clinic end generated code: output=020370db41973be0 input=064a3b68ad7f04b0]*/
21962196

21972197

21982198
/*[clinic input]
@@ -2229,7 +2229,7 @@ test_Py_buffer_converter(PyObject *module, PyObject *const *args, Py_ssize_t nar
22292229
Py_buffer d = {NULL, NULL};
22302230
Py_buffer e = {NULL, NULL};
22312231

2232-
if (!_PyArg_ParseStack(args, nargs, "y*y*s*z*w*:test_Py_buffer_converter",
2232+
if (!PyArg_ParseArray(args, nargs, "y*y*s*z*w*:test_Py_buffer_converter",
22332233
&a, &b, &c, &d, &e)) {
22342234
goto exit;
22352235
}
@@ -2263,7 +2263,7 @@ test_Py_buffer_converter(PyObject *module, PyObject *const *args, Py_ssize_t nar
22632263
static PyObject *
22642264
test_Py_buffer_converter_impl(PyObject *module, Py_buffer *a, Py_buffer *b,
22652265
Py_buffer *c, Py_buffer *d, Py_buffer *e)
2266-
/*[clinic end generated code: output=a153b71b4f45f952 input=6a9da0f56f9525fd]*/
2266+
/*[clinic end generated code: output=14bb6138c13c4085 input=6a9da0f56f9525fd]*/
22672267

22682268

22692269
/*[clinic input]
@@ -6038,7 +6038,7 @@ Test__pyarg_parsestackandkeywords(PyObject *self, PyTypeObject *cls, PyObject *c
60386038
if (!_PyArg_NoKwnames("_pyarg_parsestackandkeywords", kwnames)) {
60396039
goto exit;
60406040
}
6041-
if (!_PyArg_ParseStack(args, nargs, "s#:_pyarg_parsestackandkeywords",
6041+
if (!PyArg_ParseArray(args, nargs, "s#:_pyarg_parsestackandkeywords",
60426042
&key, &key_length)) {
60436043
goto exit;
60446044
}
@@ -6052,7 +6052,7 @@ static PyObject *
60526052
Test__pyarg_parsestackandkeywords_impl(TestObj *self, PyTypeObject *cls,
60536053
const char *key,
60546054
Py_ssize_t key_length)
6055-
/*[clinic end generated code: output=21bbb9a8d0100d72 input=fc72ef4b4cfafabc]*/
6055+
/*[clinic end generated code: output=4acb456c0ebbbd40 input=fc72ef4b4cfafabc]*/
60566056

60576057

60586058
/*[clinic input]

‎Lib/test/test_call.py‎

Lines changed: 142 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -947,50 +947,170 @@ def f(self, *args, **kwargs):
947947
self.assertEqual(kwargs_captured, [{"baz": "bar"}])
948948

949949
class A:
950-
def method_two_args(self, x, y):
950+
def method_two_args(arg1=None, arg2=None):
951+
pass
952+
953+
def method_one_arg(arg1):
954+
pass
955+
956+
def method_zero_arg():
957+
pass
958+
959+
@classmethod
960+
def classmethod_one_arg(arg1):
951961
pass
952962

953963
@staticmethod
954964
def static_no_args():
955965
pass
956966

957967
@staticmethod
958-
def positional_only(arg, /):
968+
def static_positional_only_one_arg(arg1, /):
969+
pass
970+
971+
@staticmethod
972+
def static_one_arg(arg1):
973+
pass
974+
975+
def method_one_arg_named_self(self):
976+
pass
977+
978+
def method_one_arg_named_cls(cls):
979+
pass
980+
981+
def method_two_arg_second_param_self(arg1, self):
982+
pass
983+
984+
985+
class AMeta(type):
986+
987+
def method_one_arg(arg1):
988+
pass
989+
990+
def method_two_arg(arg1, arg2):
991+
pass
992+
993+
@classmethod
994+
def classmethod_one_arg(arg1):
959995
pass
960996

997+
@staticmethod
998+
def static_one_arg(arg1):
999+
pass
1000+
1001+
class AClassWithMetaclass(metaclass=AMeta):
1002+
pass
1003+
9611004
@cpython_only
962-
class TestErrorMessagesUseQualifiedName(unittest.TestCase):
1005+
class TestIncorrectNumberOfPositionalArgs(unittest.TestCase):
1006+
def test_too_many_positional_with_defaults_suggests_missing_self(self):
1007+
msg = r"\.method_two_args\(\) takes from 0 to 2 positional arguments but 3 were given\. Did you forget the 'self' parameter in the function definition\?"
1008+
with self.assertRaisesRegex(TypeError, msg):
1009+
A().method_two_args("woof", "loud")
9631010

964-
@contextlib.contextmanager
965-
def check_raises_type_error(self, message):
966-
with self.assertRaises(TypeError) as cm:
967-
yield
968-
self.assertEqual(str(cm.exception), message)
1011+
def test_too_many_positional_but_missing_self_no_args(self):
1012+
msg = r"takes 0 positional arguments but 1 was given\. Did you forget the 'self' parameter in the function definition\?"
1013+
with self.assertRaisesRegex(TypeError, msg):
1014+
A().method_zero_arg()
9691015

970-
def test_missing_arguments(self):
971-
msg = "A.method_two_args() missing 1 required positional argument: 'y'"
972-
with self.check_raises_type_error(msg):
973-
A().method_two_args("x")
1016+
def test_too_many_positional_but_missing_self(self):
1017+
msg = r"\.method_one_arg\(\) takes 1 positional argument but 2 were given\. Did you forget the 'self' parameter in the function definition\?"
1018+
with self.assertRaisesRegex(TypeError, msg):
1019+
A().method_one_arg("quiet")
9741020

9751021
def test_too_many_positional(self):
976-
msg = "A.static_no_args() takes 0 positional arguments but 1 was given"
977-
with self.check_raises_type_error(msg):
1022+
msg = r"takes 0 positional arguments but 1 was given"
1023+
with self.assertRaisesRegex(TypeError, msg):
9781024
A.static_no_args("oops it's an arg")
9791025

9801026
def test_positional_only_passed_as_keyword(self):
981-
msg = "A.positional_only() got some positional-only arguments passed as keyword arguments: 'arg'"
982-
with self.check_raises_type_error(msg):
983-
A.positional_only(arg="x")
1027+
msg = r"\.static_positional_only_one_arg\(\) got some positional-only arguments passed as keyword arguments: 'arg1'"
1028+
with self.assertRaisesRegex(TypeError, msg):
1029+
A.static_positional_only_one_arg(arg1="ball")
9841030

9851031
def test_unexpected_keyword(self):
986-
msg = "A.method_two_args() got an unexpected keyword argument 'bad'"
987-
with self.check_raises_type_error(msg):
1032+
msg = r"method_two_args\(\) got an unexpected keyword argument 'bad'"
1033+
with self.assertRaisesRegex(TypeError, msg):
9881034
A().method_two_args(bad="x")
9891035

9901036
def test_multiple_values(self):
991-
msg = "A.method_two_args() got multiple values for argument 'x'"
992-
with self.check_raises_type_error(msg):
993-
A().method_two_args("x", "y", x="oops")
1037+
msg = r"\.method_two_args\(\) got multiple values for argument 'arg1'"
1038+
with self.assertRaisesRegex(TypeError, msg):
1039+
A().method_two_args("quiet", "low", arg1="oops")
1040+
1041+
def test_unbound_method_with_self_keeps_missing_argument_error(self):
1042+
msg = r"\.method_one_arg\(\) missing 1 required positional argument: 'arg1'"
1043+
with self.assertRaisesRegex(TypeError, msg):
1044+
A.method_one_arg()
1045+
1046+
def test_classmethod_missing_cls_does_not_suggest_missing_self(self):
1047+
msg = r"\.classmethod_one_arg\(\) takes 1 positional argument but 2 were given"
1048+
with self.assertRaisesRegex(TypeError, msg) as cm:
1049+
A.classmethod_one_arg("arg1")
1050+
self.assertNotIn("Did you forget", str(cm.exception))
1051+
1052+
def test_classmethod_missing_cls_via_instance_does_not_suggest_missing_self(self):
1053+
msg = r"\.classmethod_one_arg\(\) takes 1 positional argument but 2 were given"
1054+
with self.assertRaisesRegex(TypeError, msg) as cm:
1055+
A().classmethod_one_arg("poodle")
1056+
self.assertNotIn("Did you forget", str(cm.exception))
1057+
1058+
def test_staticmethod_too_many_args_does_not_suggest_missing_self(self):
1059+
msg = r"\.static_one_arg\(\) takes 1 positional argument but 2 were given"
1060+
with self.assertRaisesRegex(TypeError, msg) as cm:
1061+
A.static_one_arg(1, 2)
1062+
self.assertNotIn("Did you forget", str(cm.exception))
1063+
1064+
def test_staticmethod_too_many_args_via_instance_does_not_suggest_missing_self(self):
1065+
msg = r"\.static_one_arg\(\) takes 1 positional argument but 2 were given"
1066+
with self.assertRaisesRegex(TypeError, msg) as cm:
1067+
A().static_one_arg(1, 2)
1068+
self.assertNotIn("Did you forget", str(cm.exception))
1069+
1070+
def test_metaclass_missing_receiver_does_not_suggest_missing_self(self):
1071+
msg = r"AMeta\.method_one_arg\(\) takes 1 positional argument but 2 were given"
1072+
with self.assertRaisesRegex(TypeError, msg) as cm:
1073+
AClassWithMetaclass.method_one_arg("standard")
1074+
self.assertNotIn("Did you forget", str(cm.exception))
1075+
1076+
def test_metaclass_method_too_many_args_does_not_suggest_missing_self(self):
1077+
msg = r"AMeta\.method_two_arg\(\) takes 2 positional arguments but 3 were given"
1078+
with self.assertRaisesRegex(TypeError, msg) as cm:
1079+
AClassWithMetaclass.method_two_arg("trail", "river")
1080+
self.assertNotIn("Did you forget", str(cm.exception))
1081+
1082+
def test_metaclass_classmethod_does_not_suggest_missing_self(self):
1083+
msg = r"AMeta\.classmethod_one_arg\(\) takes 1 positional argument but 2 were given"
1084+
with self.assertRaisesRegex(TypeError, msg) as cm:
1085+
AClassWithMetaclass.classmethod_one_arg("standard")
1086+
self.assertNotIn("Did you forget", str(cm.exception))
1087+
1088+
def test_metaclass_staticmethod_does_not_suggest_missing_self(self):
1089+
msg = r"AMeta\.static_one_arg\(\) takes 1 positional argument but 2 were given"
1090+
with self.assertRaisesRegex(TypeError, msg) as cm:
1091+
AClassWithMetaclass.static_one_arg("show", "working")
1092+
self.assertNotIn("Did you forget", str(cm.exception))
1093+
1094+
def test_more_than_two_surplus_args_does_not_suggest(self):
1095+
with self.assertRaises(TypeError) as cm:
1096+
A().method_one_arg("arg1", "arg2", "arg3")
1097+
self.assertNotIn("Did you forget", str(cm.exception))
1098+
1099+
def test_when_arg_named_self_does_not_suggest(self):
1100+
with self.assertRaises(TypeError) as cm:
1101+
A().method_one_arg_named_self("arg1")
1102+
self.assertNotIn("Did you forget", str(cm.exception))
1103+
1104+
def test_when_arg_named_cls_does_not_suggest(self):
1105+
with self.assertRaises(TypeError) as cm:
1106+
A().method_one_arg_named_cls("arg1")
1107+
self.assertNotIn("Did you forget", str(cm.exception))
1108+
1109+
def test_when_second_param_is_self(self):
1110+
with self.assertRaises(TypeError) as cm:
1111+
A().method_two_arg_second_param_self()
1112+
self.assertNotIn("Did you forget", str(cm.exception))
1113+
9941114

9951115
@cpython_only
9961116
class TestErrorMessagesSuggestions(unittest.TestCase):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:exc:`TypeError` messages for some instance methods called with too many
2+
positional arguments now suggest checking whether the method definition is
3+
missing the ``self`` parameter.

0 commit comments

Comments
 (0)