diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst index 9274a0c88ac4c8..7a0ccfd024beb3 100644 --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -1056,6 +1056,10 @@ AbstractBasicAuthHandler Objects authenticate for, *req* should be the (failed) :class:`Request` object, and *headers* should be the error headers. + *headers* must be a mapping-like object with case-insensitive lookup + that implements the ``get_all()`` method, + such as :class:`email.message.Message` or :class:`wsgiref.headers.Headers`. + *host* is either an authority (e.g. ``"python.org"``) or a URL containing an authority component (e.g. ``"https://python.org/"``). In either case, the authority must not contain a userinfo component (so, ``"python.org"`` and @@ -1097,6 +1101,9 @@ AbstractDigestAuthHandler Objects should be the (failed) :class:`Request` object, and *headers* should be the error headers. + *headers* must be a mapping-like object with case-insensitive lookup, + such as :class:`email.message.Message` or :class:`wsgiref.headers.Headers`. + .. _http-digest-auth-handler: diff --git a/Include/internal/pycore_interpframe.h b/Include/internal/pycore_interpframe.h index 812e1a28debef4..a85fa9bd32853c 100644 --- a/Include/internal/pycore_interpframe.h +++ b/Include/internal/pycore_interpframe.h @@ -345,7 +345,7 @@ _PyFrame_GetFrameObject(_PyInterpreterFrame *frame) { assert(!_PyFrame_IsIncomplete(frame)); - PyFrameObject *res = FT_ATOMIC_LOAD_PTR_ACQUIRE(frame->frame_obj); + PyFrameObject *res = (PyFrameObject*)FT_ATOMIC_LOAD_PTR_ACQUIRE(frame->frame_obj); if (res != NULL) { return res; } diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index c130259acb737a..7f4f225c0ad4fb 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -119,10 +119,11 @@ def _python_exit(): # On Windows, WaitForMultipleObjects is used to wait for processes to finish. -# It can wait on, at most, 63 objects. There is an overhead of two objects: +# It can wait on, at most, 64 objects. There is an overhead of three objects: # - the result queue reader # - the thread wakeup reader -_MAX_WINDOWS_WORKERS = 63 - 2 +# - the SIGINT handler +_MAX_WINDOWS_WORKERS = 64 - 3 # Hack to embed stringification of remote traceback in local traceback diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index df473d59fff3d8..959732fc6e4a83 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -63,6 +63,30 @@ def test_argument_handling(self): self.assertRaises(SyntaxError, exec, 'def f(a = 0, a = 1): pass') self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1') + def test_call_opcode_stack_use_limit(self): + def get_call_opcode(positional_count, keyword_count): + args = ["0"] * positional_count + args.extend(f"a{i}=0" for i in range(keyword_count)) + code = compile(f"f({', '.join(args)})", "", "exec") + return next( + instr.opname for instr in dis.get_instructions(code) + if instr.opname.startswith("CALL") + ) + + for positional_count, keyword_count, expected_opcode in [ + (0, 16, "CALL_KW"), + (15, 14, "CALL_KW"), + (15, 15, "CALL_FUNCTION_EX"), + ]: + with self.subTest( + positional_count=positional_count, + keyword_count=keyword_count, + ): + self.assertEqual( + get_call_opcode(positional_count, keyword_count), + expected_opcode, + ) + def test_syntax_error(self): self.assertRaises(SyntaxError, compile, "1+*3", "filename", "exec") diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-08-14-19-00-00.gh-issue-155141.call-kw.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-14-19-00-00.gh-issue-155141.call-kw.rst new file mode 100644 index 00000000000000..caee6e10168eab --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-14-19-00-00.gh-issue-155141.call-kw.rst @@ -0,0 +1,3 @@ +Compile pure-keyword calls with 16 to 29 keyword arguments using the faster +``CALL_KW`` instruction. This includes common cases such as dataclass +constructors with many fields. diff --git a/Python/codegen.c b/Python/codegen.c index 79b84f13e629c7..e2ef40b4e30490 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -87,6 +87,9 @@ typedef _PyCompile_FBlockInfo fblockinfo; #define LOC(x) SRC_LOCATION_FROM_AST(x) +#define CALL_STACK_USE(nargs, nkwds) \ + ((nargs) + (nkwds) + ((nkwds) != 0)) + #define NEW_JUMP_TARGET_LABEL(C, NAME) \ jump_target_label NAME = _PyInstructionSequence_NewLabel(INSTR_SEQUENCE(C)); \ if (!IS_JUMP_TARGET_LABEL(NAME)) { \ @@ -4147,7 +4150,7 @@ maybe_optimize_method_call(compiler *c, expr_ty e) /* Check that there aren't too many arguments */ argsl = asdl_seq_LEN(args); kwdsl = asdl_seq_LEN(kwds); - if (argsl + kwdsl + (kwdsl != 0) >= _PY_STACK_USE_GUIDELINE) { + if (CALL_STACK_USE(argsl, kwdsl) >= _PY_STACK_USE_GUIDELINE) { return 0; } /* Check that there are no *varargs types of arguments. */ @@ -4440,7 +4443,7 @@ codegen_call_helper_impl(compiler *c, location loc, nelts = asdl_seq_LEN(args); nkwelts = asdl_seq_LEN(keywords); - if (nelts + nkwelts*2 > _PY_STACK_USE_GUIDELINE) { + if (CALL_STACK_USE(nelts, nkwelts) > _PY_STACK_USE_GUIDELINE) { goto ex_call; } for (i = 0; i < nelts; i++) {