Imported Upstream version 3.9.2 upstream/3.9.2
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 25 Jan 2022 23:27:40 +0000 (08:27 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 25 Jan 2022 23:27:40 +0000 (08:27 +0900)
283 files changed:
Doc/c-api/bool.rst
Doc/c-api/bytearray.rst
Doc/c-api/bytes.rst
Doc/c-api/capsule.rst
Doc/c-api/cell.rst
Doc/c-api/code.rst
Doc/c-api/complex.rst
Doc/c-api/conversion.rst
Doc/c-api/coro.rst
Doc/c-api/datetime.rst
Doc/c-api/dict.rst
Doc/c-api/float.rst
Doc/c-api/function.rst
Doc/c-api/gen.rst
Doc/c-api/init.rst
Doc/c-api/iter.rst
Doc/c-api/iterator.rst
Doc/c-api/list.rst
Doc/c-api/long.rst
Doc/c-api/memoryview.rst
Doc/c-api/method.rst
Doc/c-api/module.rst
Doc/c-api/set.rst
Doc/c-api/slice.rst
Doc/c-api/tuple.rst
Doc/c-api/type.rst
Doc/c-api/unicode.rst
Doc/c-api/weakref.rst
Doc/copyright.rst
Doc/howto/descriptor.rst
Doc/howto/urllib2.rst
Doc/install/index.rst
Doc/library/argparse.rst
Doc/library/asyncio-eventloop.rst
Doc/library/asyncio-future.rst
Doc/library/asyncio-policy.rst
Doc/library/asyncio-stream.rst
Doc/library/asyncio-subprocess.rst
Doc/library/asyncio-sync.rst
Doc/library/asyncio-task.rst
Doc/library/cgi.rst
Doc/library/codecs.rst
Doc/library/compileall.rst
Doc/library/concurrent.futures.rst
Doc/library/contextvars.rst
Doc/library/ctypes.rst
Doc/library/curses.rst
Doc/library/datetime.rst
Doc/library/dialog.rst
Doc/library/email.contentmanager.rst
Doc/library/email.headerregistry.rst
Doc/library/email.policy.rst
Doc/library/enum.rst
Doc/library/fnmatch.rst
Doc/library/functions.rst
Doc/library/functools.rst
Doc/library/idle.rst
Doc/library/importlib.metadata.rst
Doc/library/importlib.rst
Doc/library/inspect.rst
Doc/library/itertools.rst
Doc/library/logging.config.rst
Doc/library/logging.rst
Doc/library/lzma.rst
Doc/library/multiprocessing.rst
Doc/library/os.rst
Doc/library/pickle.rst
Doc/library/plistlib.rst
Doc/library/profile.rst
Doc/library/pyexpat.rst
Doc/library/random.rst
Doc/library/shutil.rst
Doc/library/socket.rst
Doc/library/sqlite3.rst
Doc/library/stdtypes.rst
Doc/library/string.rst
Doc/library/subprocess.rst
Doc/library/symtable.rst
Doc/library/sysconfig.rst
Doc/library/tarfile.rst
Doc/library/test.rst
Doc/library/trace.rst
Doc/library/turtle.rst
Doc/library/types.rst
Doc/library/typing.rst
Doc/library/urllib.parse.rst
Doc/library/warnings.rst
Doc/library/winreg.rst
Doc/license.rst
Doc/reference/compound_stmts.rst
Doc/reference/datamodel.rst
Doc/tools/susp-ignored.csv
Doc/using/venv-create.inc
Doc/using/windows.rst
Doc/whatsnew/3.6.rst
Doc/whatsnew/3.7.rst
Doc/whatsnew/3.8.rst
Doc/whatsnew/3.9.rst
Grammar/python.gram
Include/cpython/abstract.h
Include/cpython/unicodeobject.h
Include/patchlevel.h
Include/pylifecycle.h
LICENSE
Lib/_collections_abc.py
Lib/asyncio/tasks.py
Lib/asyncio/unix_events.py
Lib/base64.py
Lib/cProfile.py
Lib/cgi.py
Lib/codecs.py
Lib/collections/__init__.py
Lib/collections/abc.py
Lib/ctypes/test/test_parameters.py
Lib/datetime.py
Lib/distutils/spawn.py
Lib/distutils/tests/test_build_ext.py
Lib/enum.py
Lib/fnmatch.py
Lib/html/parser.py
Lib/http/client.py
Lib/idlelib/NEWS.txt
Lib/idlelib/codecontext.py
Lib/idlelib/configdialog.py
Lib/idlelib/debugger_r.py
Lib/idlelib/editor.py
Lib/idlelib/extend.txt
Lib/idlelib/filelist.py
Lib/idlelib/idle_test/mock_tk.py
Lib/idlelib/idle_test/test_autocomplete.py
Lib/idlelib/idle_test/test_calltip.py
Lib/idlelib/idle_test/test_codecontext.py
Lib/idlelib/idle_test/test_configdialog.py
Lib/idlelib/idle_test/test_debugger_r.py
Lib/idlelib/idle_test/test_format.py
Lib/idlelib/idle_test/test_help_about.py
Lib/idlelib/idle_test/test_mainmenu.py
Lib/idlelib/idle_test/test_pyparse.py
Lib/idlelib/idle_test/test_replace.py
Lib/idlelib/idle_test/test_run.py
Lib/idlelib/idle_test/test_searchengine.py
Lib/idlelib/idle_test/test_squeezer.py
Lib/idlelib/idle_test/test_zzdummy.py [new file with mode: 0644]
Lib/idlelib/iomenu.py
Lib/idlelib/pyshell.py
Lib/idlelib/rpc.py
Lib/idlelib/run.py
Lib/idlelib/runscript.py
Lib/idlelib/searchengine.py
Lib/idlelib/squeezer.py
Lib/idlelib/tooltip.py
Lib/idlelib/zzdummy.py
Lib/lib2to3/Grammar.txt
Lib/lib2to3/tests/test_parser.py
Lib/logging/__init__.py
Lib/pdb.py
Lib/platform.py
Lib/profile.py
Lib/pydoc_data/topics.py
Lib/random.py
Lib/smtplib.py
Lib/sqlite3/test/hooks.py
Lib/subprocess.py
Lib/sysconfig.py
Lib/test/crashers/bogus_code_obj.py
Lib/test/mock_socket.py
Lib/test/pickletester.py
Lib/test/test_asyncio/test_asyncio_waitfor.py [new file with mode: 0644]
Lib/test/test_builtin.py
Lib/test/test_cgi.py
Lib/test/test_collections.py
Lib/test/test_curses.py
Lib/test/test_descr.py
Lib/test/test_dict.py
Lib/test/test_enum.py
Lib/test/test_enumerate.py
Lib/test/test_epoll.py
Lib/test/test_fstring.py
Lib/test/test_genericalias.py
Lib/test/test_htmlparser.py
Lib/test/test_httplib.py
Lib/test/test_idle.py
Lib/test/test_itertools.py
Lib/test/test_logging.py
Lib/test/test_nntplib.py
Lib/test/test_ordered_dict.py
Lib/test/test_os.py
Lib/test/test_pdb.py
Lib/test/test_platform.py
Lib/test/test_posix.py
Lib/test/test_random.py
Lib/test/test_smtplib.py
Lib/test/test_subprocess.py
Lib/test/test_sysconfig.py
Lib/test/test_tcl.py
Lib/test/test_traceback.py
Lib/test/test_tracemalloc.py
Lib/test/test_typing.py
Lib/test/test_unpack_ex.py
Lib/test/test_urllib2.py
Lib/test/test_urlparse.py
Lib/tkinter/__init__.py
Lib/tkinter/colorchooser.py
Lib/tkinter/commondialog.py
Lib/tkinter/font.py
Lib/tkinter/simpledialog.py
Lib/tkinter/test/support.py
Lib/tkinter/test/test_tkinter/test_colorchooser.py [new file with mode: 0644]
Lib/tkinter/test/test_tkinter/test_font.py
Lib/tkinter/test/test_tkinter/test_images.py
Lib/tkinter/test/test_tkinter/test_misc.py
Lib/tkinter/test/test_tkinter/test_simpledialog.py [new file with mode: 0644]
Lib/tkinter/test/test_tkinter/test_variables.py
Lib/tkinter/test/test_tkinter/test_widgets.py
Lib/tkinter/test/test_ttk/test_extensions.py
Lib/tkinter/test/test_ttk/test_widgets.py
Lib/tkinter/test/widget_tests.py
Lib/tkinter/tix.py
Lib/tkinter/ttk.py
Lib/traceback.py
Lib/tracemalloc.py
Lib/typing.py
Lib/unittest/async_case.py
Lib/unittest/mock.py
Lib/unittest/test/test_async_case.py
Lib/unittest/test/testmock/testmock.py
Lib/urllib/parse.py
Lib/urllib/request.py
Mac/BuildScript/build-installer.py
Mac/BuildScript/openssl-mac-arm64.patch [deleted file]
Mac/BuildScript/scripts/postflight.patch-profile
Mac/IDLE/IDLE.app/Contents/Info.plist
Mac/PythonLauncher/Info.plist.in
Mac/Resources/app/Info.plist.in
Misc/ACKS
Misc/NEWS
Modules/_ctypes/callproc.c
Modules/_ctypes/malloc_closure.c
Modules/_curses_panel.c
Modules/_cursesmodule.c
Modules/_functoolsmodule.c
Modules/_posixsubprocess.c
Modules/_sqlite/connection.c
Modules/_sqlite/cursor.c
Modules/_tkinter.c
Modules/_zoneinfo.c
Modules/clinic/_cursesmodule.c.h
Modules/itertoolsmodule.c
Modules/md5module.c
Modules/posixmodule.c
Modules/posixmodule.h
Modules/readline.c
Modules/sha1module.c
Modules/sha256module.c
Modules/sha512module.c
Modules/socketmodule.c
Objects/call.c
Objects/dictobject.c
Objects/enumobject.c
Objects/exceptions.c
Objects/genericaliasobject.c
Objects/odictobject.c
PC/python3.def
PC/python_ver_rc.h
PCbuild/get_externals.bat
PCbuild/pyproject.props
PCbuild/python.props
PCbuild/readme.txt
Parser/pegen/parse.c
Parser/pegen/parse_string.c
Python/bltinmodule.c
Python/fileutils.c
Python/getcopyright.c
Python/pythonrun.c
Python/traceback.c
README.rst
Tools/freeze/freeze.py
Tools/gdb/libpython.py
Tools/msi/uploadrelease.ps1
Tools/pynche/PyncheWidget.py
configure
configure.ac
setup.py

index ce8de6e22f44caf19026385b597cdbb1df40f767..c197d447e9618c9998851c7fe2c6d1df5aefd731 100644 (file)
@@ -13,7 +13,8 @@ are available, however.
 
 .. c:function:: int PyBool_Check(PyObject *o)
 
-   Return true if *o* is of type :c:data:`PyBool_Type`.
+   Return true if *o* is of type :c:data:`PyBool_Type`.  This function always
+   succeeds.
 
 
 .. c:var:: PyObject* Py_False
index b2f409c15abb7a15b035b8896bb41b362e9cd6ed..30bcfc7cf9f500802a297a50553dc7beec13b971 100644 (file)
@@ -25,13 +25,13 @@ Type check macros
 .. c:function:: int PyByteArray_Check(PyObject *o)
 
    Return true if the object *o* is a bytearray object or an instance of a
-   subtype of the bytearray type.
+   subtype of the bytearray type.  This function always succeeds.
 
 
 .. c:function:: int PyByteArray_CheckExact(PyObject *o)
 
    Return true if the object *o* is a bytearray object, but not an instance of a
-   subtype of the bytearray type.
+   subtype of the bytearray type.  This function always succeeds.
 
 
 Direct API functions
index 0e33ed2c7c94037a34cbaee53299ed7b7afc81b6..de65701037a7c1471402a8c54ad9f9b3ee2b9368 100644 (file)
@@ -25,13 +25,13 @@ called with a non-bytes parameter.
 .. c:function:: int PyBytes_Check(PyObject *o)
 
    Return true if the object *o* is a bytes object or an instance of a subtype
-   of the bytes type.
+   of the bytes type.  This function always succeeds.
 
 
 .. c:function:: int PyBytes_CheckExact(PyObject *o)
 
    Return true if the object *o* is a bytes object, but not an instance of a
-   subtype of the bytes type.
+   subtype of the bytes type.  This function always succeeds.
 
 
 .. c:function:: PyObject* PyBytes_FromString(const char *v)
index 5eb313c89bfd5920907208cf2d1f775a19b71913..908e92653dd483791159e466e4c3fd0260a430c3 100644 (file)
@@ -34,7 +34,8 @@ Refer to :ref:`using-capsules` for more information on using these objects.
 
 .. c:function:: int PyCapsule_CheckExact(PyObject *p)
 
-   Return true if its argument is a :c:type:`PyCapsule`.
+   Return true if its argument is a :c:type:`PyCapsule`.  This function always
+   succeeds.
 
 
 .. c:function:: PyObject* PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
index 8408f7e398db7b63e99e77fe578d271100f7d0e3..ac4ef5adc5cc20f8b95d3a892a43080a08e5f719 100644 (file)
@@ -27,7 +27,8 @@ Cell objects are not likely to be useful elsewhere.
 
 .. c:function:: int PyCell_Check(ob)
 
-   Return true if *ob* is a cell object; *ob* must not be ``NULL``.
+   Return true if *ob* is a cell object; *ob* must not be ``NULL``.  This
+   function always succeeds.
 
 
 .. c:function:: PyObject* PyCell_New(PyObject *ob)
index 6f8c41ccbf6e853d9728f101e4f0b4e9dbb63203..b3a17f1898e8e19974741b4f10c1b1a235d0fa54 100644 (file)
@@ -27,7 +27,7 @@ bound into a function.
 
 .. c:function:: int PyCode_Check(PyObject *co)
 
-   Return true if *co* is a :class:`code` object.
+   Return true if *co* is a :class:`code` object.  This function always succeeds.
 
 .. c:function:: int PyCode_GetNumFree(PyCodeObject *co)
 
index 06dbb2572725ee7b6b5f84cdb85610fc576a8a9f..e2ea766b3a32a759d93fbd3f12dc6c1439898c50 100644 (file)
@@ -94,13 +94,13 @@ Complex Numbers as Python Objects
 .. c:function:: int PyComplex_Check(PyObject *p)
 
    Return true if its argument is a :c:type:`PyComplexObject` or a subtype of
-   :c:type:`PyComplexObject`.
+   :c:type:`PyComplexObject`.  This function always succeeds.
 
 
 .. c:function:: int PyComplex_CheckExact(PyObject *p)
 
    Return true if its argument is a :c:type:`PyComplexObject`, but not a subtype of
-   :c:type:`PyComplexObject`.
+   :c:type:`PyComplexObject`.  This function always succeeds.
 
 
 .. c:function:: PyObject* PyComplex_FromCComplex(Py_complex v)
index b310fcb5e4f91e4908b4bdc9ecb427177b377bfe..ee76accae62b8d940b9c1a49d758ae0691ee73e4 100644 (file)
@@ -11,14 +11,14 @@ Functions for number conversion and formatted string output.
 .. c:function:: int PyOS_snprintf(char *str, size_t size,  const char *format, ...)
 
    Output not more than *size* bytes to *str* according to the format string
-   *format* and the extra arguments. See the Unix man page :manpage:`snprintf(2)`.
+   *format* and the extra arguments. See the Unix man page :manpage:`snprintf(3)`.
 
 
 .. c:function:: int PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va)
 
    Output not more than *size* bytes to *str* according to the format string
    *format* and the variable argument list *va*. Unix man page
-   :manpage:`vsnprintf(2)`.
+   :manpage:`vsnprintf(3)`.
 
 :c:func:`PyOS_snprintf` and :c:func:`PyOS_vsnprintf` wrap the Standard C library
 functions :c:func:`snprintf` and :c:func:`vsnprintf`. Their purpose is to
index 2260944a9a93a9e897e9dbc4b04723e79a02ecab..caa855a10d20ca93c66e33967671f1116d491efd 100644 (file)
@@ -24,6 +24,7 @@ return.
 .. c:function:: int PyCoro_CheckExact(PyObject *ob)
 
    Return true if *ob*'s type is :c:type:`PyCoro_Type`; *ob* must not be ``NULL``.
+   This function always succeeds.
 
 
 .. c:function:: PyObject* PyCoro_New(PyFrameObject *frame, PyObject *name, PyObject *qualname)
index bd4f1ff446bcf4c44195b09f78de30dd999d69a0..66f148df28680770490a6a14f1440b3e37ba1815 100644 (file)
@@ -28,61 +28,66 @@ Type-check macros:
 .. c:function:: int PyDate_Check(PyObject *ob)
 
    Return true if *ob* is of type :c:data:`PyDateTime_DateType` or a subtype of
-   :c:data:`PyDateTime_DateType`.  *ob* must not be ``NULL``.
+   :c:data:`PyDateTime_DateType`.  *ob* must not be ``NULL``.  This function always
+   succeeds.
 
 
 .. c:function:: int PyDate_CheckExact(PyObject *ob)
 
    Return true if *ob* is of type :c:data:`PyDateTime_DateType`. *ob* must not be
-   ``NULL``.
+   ``NULL``.  This function always succeeds.
 
 
 .. c:function:: int PyDateTime_Check(PyObject *ob)
 
    Return true if *ob* is of type :c:data:`PyDateTime_DateTimeType` or a subtype of
-   :c:data:`PyDateTime_DateTimeType`.  *ob* must not be ``NULL``.
+   :c:data:`PyDateTime_DateTimeType`.  *ob* must not be ``NULL``.  This function always
+   succeeds.
 
 
 .. c:function:: int PyDateTime_CheckExact(PyObject *ob)
 
    Return true if *ob* is of type :c:data:`PyDateTime_DateTimeType`. *ob* must not
-   be ``NULL``.
+   be ``NULL``.  This function always succeeds.
 
 
 .. c:function:: int PyTime_Check(PyObject *ob)
 
    Return true if *ob* is of type :c:data:`PyDateTime_TimeType` or a subtype of
-   :c:data:`PyDateTime_TimeType`.  *ob* must not be ``NULL``.
+   :c:data:`PyDateTime_TimeType`.  *ob* must not be ``NULL``.  This function always
+   succeeds.
 
 
 .. c:function:: int PyTime_CheckExact(PyObject *ob)
 
    Return true if *ob* is of type :c:data:`PyDateTime_TimeType`. *ob* must not be
-   ``NULL``.
+   ``NULL``.  This function always succeeds.
 
 
 .. c:function:: int PyDelta_Check(PyObject *ob)
 
    Return true if *ob* is of type :c:data:`PyDateTime_DeltaType` or a subtype of
-   :c:data:`PyDateTime_DeltaType`.  *ob* must not be ``NULL``.
+   :c:data:`PyDateTime_DeltaType`.  *ob* must not be ``NULL``.  This function always
+   succeeds.
 
 
 .. c:function:: int PyDelta_CheckExact(PyObject *ob)
 
    Return true if *ob* is of type :c:data:`PyDateTime_DeltaType`. *ob* must not be
-   ``NULL``.
+   ``NULL``.  This function always succeeds.
 
 
 .. c:function:: int PyTZInfo_Check(PyObject *ob)
 
    Return true if *ob* is of type :c:data:`PyDateTime_TZInfoType` or a subtype of
-   :c:data:`PyDateTime_TZInfoType`.  *ob* must not be ``NULL``.
+   :c:data:`PyDateTime_TZInfoType`.  *ob* must not be ``NULL``.  This function always
+   succeeds.
 
 
 .. c:function:: int PyTZInfo_CheckExact(PyObject *ob)
 
    Return true if *ob* is of type :c:data:`PyDateTime_TZInfoType`. *ob* must not be
-   ``NULL``.
+   ``NULL``.  This function always succeeds.
 
 
 Macros to create objects:
index 8c626c7d4a9403cea4d1f1d392dc391c51b00d37..5803ac2ad97adb8bc548e160b9f4fcab086ea492 100644 (file)
@@ -22,13 +22,13 @@ Dictionary Objects
 .. c:function:: int PyDict_Check(PyObject *p)
 
    Return true if *p* is a dict object or an instance of a subtype of the dict
-   type.
+   type.  This function always succeeds.
 
 
 .. c:function:: int PyDict_CheckExact(PyObject *p)
 
    Return true if *p* is a dict object, but not an instance of a subtype of
-   the dict type.
+   the dict type.  This function always succeeds.
 
 
 .. c:function:: PyObject* PyDict_New()
index b29937dbecdcfdac966de4d6468c77a0fc65fa3a..c107243a88dfc66bc444eaee44b8725db7a3949d 100644 (file)
@@ -22,13 +22,13 @@ Floating Point Objects
 .. c:function:: int PyFloat_Check(PyObject *p)
 
    Return true if its argument is a :c:type:`PyFloatObject` or a subtype of
-   :c:type:`PyFloatObject`.
+   :c:type:`PyFloatObject`.  This function always succeeds.
 
 
 .. c:function:: int PyFloat_CheckExact(PyObject *p)
 
    Return true if its argument is a :c:type:`PyFloatObject`, but not a subtype of
-   :c:type:`PyFloatObject`.
+   :c:type:`PyFloatObject`.  This function always succeeds.
 
 
 .. c:function:: PyObject* PyFloat_FromString(PyObject *str)
index bb416f4bb63aa2b16bba3cd6a1b30bc5abc7566e..20968828e0bb36ef127fdd148fb6ba09639dfa20 100644 (file)
@@ -26,7 +26,7 @@ There are a few functions specific to Python functions.
 .. c:function:: int PyFunction_Check(PyObject *o)
 
    Return true if *o* is a function object (has type :c:data:`PyFunction_Type`).
-   The parameter must not be ``NULL``.
+   The parameter must not be ``NULL``.  This function always succeeds.
 
 
 .. c:function:: PyObject* PyFunction_New(PyObject *code, PyObject *globals)
index 74410927bfde107c8a8c1e4a5ee1f0a4a9302a0a..0eb5922f6da75f25803ced5b45f0f9cd3e01514a 100644 (file)
@@ -22,12 +22,14 @@ than explicitly calling :c:func:`PyGen_New` or :c:func:`PyGen_NewWithQualName`.
 
 .. c:function:: int PyGen_Check(PyObject *ob)
 
-   Return true if *ob* is a generator object; *ob* must not be ``NULL``.
+   Return true if *ob* is a generator object; *ob* must not be ``NULL``.  This
+   function always succeeds.
 
 
 .. c:function:: int PyGen_CheckExact(PyObject *ob)
 
-   Return true if *ob*'s type is :c:type:`PyGen_Type`; *ob* must not be ``NULL``.
+   Return true if *ob*'s type is :c:type:`PyGen_Type`; *ob* must not be
+   ``NULL``.  This function always succeeds.
 
 
 .. c:function:: PyObject* PyGen_New(PyFrameObject *frame)
index 7f06648bcb4572f3b981c5d5b36281c8ecb7c5b8..eb0bd14587145be1a5755fa7329fb0f3df0371d2 100644 (file)
@@ -1155,7 +1155,7 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
 
    .. versionadded:: 3.9
 
-.. c:function:: void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame);
+.. c:function:: void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame)
 
    Set the frame evaluation function.
 
index a2992b3452f91c3c1fb9d3fc9a5ebd4a75e3be3d..189f80b9b8193255dbfec462298ea1d71ed2b4c5 100644 (file)
@@ -9,7 +9,8 @@ There are two functions specifically for working with iterators.
 
 .. c:function:: int PyIter_Check(PyObject *o)
 
-   Return true if the object *o* supports the iterator protocol.
+   Return true if the object *o* supports the iterator protocol.  This
+   function always succeeds.
 
 
 .. c:function:: PyObject* PyIter_Next(PyObject *o)
index 4d91e4a224fe82c119a450fedba4c36d70d6eb7b..3fcf099134d4dd418ca6da2692433d6103baef5d 100644 (file)
@@ -21,7 +21,8 @@ sentinel value is returned.
 
 .. c:function:: int PySeqIter_Check(op)
 
-   Return true if the type of *op* is :c:data:`PySeqIter_Type`.
+   Return true if the type of *op* is :c:data:`PySeqIter_Type`.  This function
+   always succeeds.
 
 
 .. c:function:: PyObject* PySeqIter_New(PyObject *seq)
@@ -39,7 +40,8 @@ sentinel value is returned.
 
 .. c:function:: int PyCallIter_Check(op)
 
-   Return true if the type of *op* is :c:data:`PyCallIter_Type`.
+   Return true if the type of *op* is :c:data:`PyCallIter_Type`.  This
+   function always succeeds.
 
 
 .. c:function:: PyObject* PyCallIter_New(PyObject *callable, PyObject *sentinel)
index 0bc0785f200d4cf5f6e9c683f1b30a25e8a4f9fc..f338e2ae0668956d68fd2fb95cb92a67bb65faff 100644 (file)
@@ -22,13 +22,13 @@ List Objects
 .. c:function:: int PyList_Check(PyObject *p)
 
    Return true if *p* is a list object or an instance of a subtype of the list
-   type.
+   type.  This function always succeeds.
 
 
 .. c:function:: int PyList_CheckExact(PyObject *p)
 
    Return true if *p* is a list object, but not an instance of a subtype of
-   the list type.
+   the list type.  This function always succeeds.
 
 
 .. c:function:: PyObject* PyList_New(Py_ssize_t len)
index 22e59ce1e5357fe8b575aa44e003413ceefc0614..60e1791df9a4510cd3d41639fc5ab7b40678f4df 100644 (file)
@@ -27,13 +27,13 @@ distinguished from a number.  Use :c:func:`PyErr_Occurred` to disambiguate.
 .. c:function:: int PyLong_Check(PyObject *p)
 
    Return true if its argument is a :c:type:`PyLongObject` or a subtype of
-   :c:type:`PyLongObject`.
+   :c:type:`PyLongObject`.  This function always succeeds.
 
 
 .. c:function:: int PyLong_CheckExact(PyObject *p)
 
    Return true if its argument is a :c:type:`PyLongObject`, but not a subtype of
-   :c:type:`PyLongObject`.
+   :c:type:`PyLongObject`.  This function always succeeds.
 
 
 .. c:function:: PyObject* PyLong_FromLong(long v)
index de429e5c11dc76252061da135e97ef3122f44e72..24f8c935302e8ebaf0bd47dc59df2ca2cde77b8a 100644 (file)
@@ -45,7 +45,8 @@ any other object.
 .. c:function:: int PyMemoryView_Check(PyObject *obj)
 
    Return true if the object *obj* is a memoryview object.  It is not
-   currently allowed to create subclasses of :class:`memoryview`.
+   currently allowed to create subclasses of :class:`memoryview`.  This
+   function always succeeds.
 
 
 .. c:function:: Py_buffer *PyMemoryView_GET_BUFFER(PyObject *mview)
index 0a5341cbbdf15293c83d57b5b0219a853fed12a7..23852251dfe020bdb3da5c2f41eb2abb978a7144 100644 (file)
@@ -22,6 +22,7 @@ to bind a :c:data:`PyCFunction` to a class object. It replaces the former call
 
    Return true if *o* is an instance method object (has type
    :c:data:`PyInstanceMethod_Type`).  The parameter must not be ``NULL``.
+   This function always succeeds.
 
 
 .. c:function:: PyObject* PyInstanceMethod_New(PyObject *func)
@@ -64,7 +65,7 @@ no longer available.
 .. c:function:: int PyMethod_Check(PyObject *o)
 
    Return true if *o* is a method object (has type :c:data:`PyMethod_Type`).  The
-   parameter must not be ``NULL``.
+   parameter must not be ``NULL``.  This function always succeeds.
 
 
 .. c:function:: PyObject* PyMethod_New(PyObject *func, PyObject *self)
index 6e9474bfa40ebaff3ef226e62c362862c684fcce..90766dca78bfa759143593a6aa5b4d867776c8c5 100644 (file)
@@ -19,12 +19,13 @@ Module Objects
 .. c:function:: int PyModule_Check(PyObject *p)
 
    Return true if *p* is a module object, or a subtype of a module object.
+   This function always succeeds.
 
 
 .. c:function:: int PyModule_CheckExact(PyObject *p)
 
    Return true if *p* is a module object, but not a subtype of
-   :c:data:`PyModule_Type`.
+   :c:data:`PyModule_Type`.  This function always succeeds.
 
 
 .. c:function:: PyObject* PyModule_NewObject(PyObject *name)
index 879f394d966cd07461c253e08bd8b5165cf0254a..84f34e7dae80be42757f4f369a4dda8148fc9dd3 100644 (file)
@@ -53,28 +53,29 @@ the constructor functions work with any iterable Python object.
 .. c:function:: int PySet_Check(PyObject *p)
 
    Return true if *p* is a :class:`set` object or an instance of a subtype.
+   This function always succeeds.
 
 .. c:function:: int PyFrozenSet_Check(PyObject *p)
 
    Return true if *p* is a :class:`frozenset` object or an instance of a
-   subtype.
+   subtype.  This function always succeeds.
 
 .. c:function:: int PyAnySet_Check(PyObject *p)
 
    Return true if *p* is a :class:`set` object, a :class:`frozenset` object, or an
-   instance of a subtype.
+   instance of a subtype.  This function always succeeds.
 
 
 .. c:function:: int PyAnySet_CheckExact(PyObject *p)
 
    Return true if *p* is a :class:`set` object or a :class:`frozenset` object but
-   not an instance of a subtype.
+   not an instance of a subtype.  This function always succeeds.
 
 
 .. c:function:: int PyFrozenSet_CheckExact(PyObject *p)
 
    Return true if *p* is a :class:`frozenset` object but not an instance of a
-   subtype.
+   subtype.  This function always succeeds.
 
 
 .. c:function:: PyObject* PySet_New(PyObject *iterable)
index 48a58c6c6f7e3652fe38ded7a9d4cac18e36cff1..8271d9acfb645e182beda6727c6dd3c039b0d9bc 100644 (file)
@@ -14,7 +14,8 @@ Slice Objects
 
 .. c:function:: int PySlice_Check(PyObject *ob)
 
-   Return true if *ob* is a slice object; *ob* must not be ``NULL``.
+   Return true if *ob* is a slice object; *ob* must not be ``NULL``.  This
+   function always succeeds.
 
 
 .. c:function:: PyObject* PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
index bf751e44acde094ff0e341e3253336a77ea3aba0..1dbf7dbb67ccd4ca24712a787cbc906e93f01eaf 100644 (file)
@@ -21,14 +21,14 @@ Tuple Objects
 
 .. c:function:: int PyTuple_Check(PyObject *p)
 
-   Return true if *p* is a tuple object or an instance of a subtype of the tuple
-   type.
+   Return true if *p* is a tuple object or an instance of a subtype of the
+   tuple type.  This function always succeeds.
 
 
 .. c:function:: int PyTuple_CheckExact(PyObject *p)
 
    Return true if *p* is a tuple object, but not an instance of a subtype of the
-   tuple type.
+   tuple type.  This function always succeeds.
 
 
 .. c:function:: PyObject* PyTuple_New(Py_ssize_t len)
index 822360e06170d961c96ca5d5c03b7bffbad56446..ee76f52289387fb7ff750408f491dc3caeb95037 100644 (file)
@@ -23,12 +23,14 @@ Type Objects
 
    Return non-zero if the object *o* is a type object, including instances of
    types derived from the standard type object.  Return 0 in all other cases.
+   This function always succeeds.
 
 
 .. c:function:: int PyType_CheckExact(PyObject *o)
 
-   Return non-zero if the object *o* is a type object, but not a subtype of the
-   standard type object.  Return 0 in all other cases.
+   Return non-zero if the object *o* is a type object, but not a subtype of
+   the standard type object.  Return 0 in all other cases.  This function
+   always succeeds.
 
 
 .. c:function:: unsigned int PyType_ClearCache()
index 8a312ae90ed6412e743cc40d33d54b6a241799cd..62295b4c52934d8c110272fb7857cfc7320dab6f 100644 (file)
@@ -91,13 +91,13 @@ access internal read-only data of Unicode objects:
 .. c:function:: int PyUnicode_Check(PyObject *o)
 
    Return true if the object *o* is a Unicode object or an instance of a Unicode
-   subtype.
+   subtype.  This function always succeeds.
 
 
 .. c:function:: int PyUnicode_CheckExact(PyObject *o)
 
    Return true if the object *o* is a Unicode object, but not an instance of a
-   subtype.
+   subtype.  This function always succeeds.
 
 
 .. c:function:: int PyUnicode_READY(PyObject *o)
index e3a9bda54d671a52634b158e7197a00c34d6d178..67698de77fef1d023c4656744abb613afb8d6324 100644 (file)
@@ -13,17 +13,18 @@ as much as it can.
 
 .. c:function:: int PyWeakref_Check(ob)
 
-   Return true if *ob* is either a reference or proxy object.
+   Return true if *ob* is either a reference or proxy object.  This function
+   always succeeds.
 
 
 .. c:function:: int PyWeakref_CheckRef(ob)
 
-   Return true if *ob* is a reference object.
+   Return true if *ob* is a reference object.  This function always succeeds.
 
 
 .. c:function:: int PyWeakref_CheckProxy(ob)
 
-   Return true if *ob* is a proxy object.
+   Return true if *ob* is a proxy object.  This function always succeeds.
 
 
 .. c:function:: PyObject* PyWeakref_NewRef(PyObject *ob, PyObject *callback)
index 1b90d9f172c992e852a95fd128f92e06dd776cc4..4191c0bb63a2c1fde73c0457472d646006fb9343 100644 (file)
@@ -4,7 +4,7 @@ Copyright
 
 Python and this documentation is:
 
-Copyright © 2001-2020 Python Software Foundation. All rights reserved.
+Copyright © 2001-2021 Python Software Foundation. All rights reserved.
 
 Copyright © 2000 BeOpen.com. All rights reserved.
 
index ab5a573c6a06d10b704baeaeea6efc9a531317b7..0f999c95596aafe51cc37d221efb286c896ce1f6 100644 (file)
@@ -497,7 +497,7 @@ Definition and introduction
 
 In general, a descriptor is an attribute value that has one of the methods in
 the descriptor protocol.  Those methods are :meth:`__get__`, :meth:`__set__`,
-and :meth:`__delete__`.  If any of those methods are defined for an the
+and :meth:`__delete__`.  If any of those methods are defined for an
 attribute, it is said to be a :term:`descriptor`.
 
 The default behavior for attribute access is to get, set, or delete the
index 046a88af62f0b3e31ddb2ce9cfc69642cc9cf366..12d525771ddc2876c5c6b3eb93722d5fdf01de35 100644 (file)
@@ -97,7 +97,7 @@ schemes.  For example, you can make an FTP request like so::
 
 In the case of HTTP, there are two extra things that Request objects allow you
 to do: First, you can pass data to be sent to the server.  Second, you can pass
-extra information ("metadata") *about* the data or the about request itself, to
+extra information ("metadata") *about* the data or about the request itself, to
 the server - this information is sent as HTTP "headers".  Let's look at each of
 these in turn.
 
index e6d5a3e6ebde6031a7e33791daed86885cdc2036..ae0d0294ef777380a908f67457052ff5531b5d6b 100644 (file)
@@ -1064,8 +1064,7 @@ normal libraries do.
 .. [#] This also means you could replace all existing COFF-libraries with OMF-libraries
    of the same name.
 
-.. [#] Check https://www.sourceware.org/cygwin/ and http://www.mingw.org/ for more
-   information
+.. [#] Check https://www.sourceware.org/cygwin/ for more information
 
 .. [#] Then you have no POSIX emulation available, but you also don't need
    :file:`cygwin1.dll`.
index 02cd70f4f71cd6e688055a4a7c2c8c012f2289de..4542961d7816ea5ba26c427c41f859bdb45cb941 100644 (file)
@@ -1050,63 +1050,70 @@ command-line argument was not present::
 type
 ^^^^
 
-By default, :class:`ArgumentParser` objects read command-line arguments in as simple
+By default, the parser reads command-line arguments in as simple
 strings. However, quite often the command-line string should instead be
-interpreted as another type, like a :class:`float` or :class:`int`.  The
-``type`` keyword argument of :meth:`~ArgumentParser.add_argument` allows any
-necessary type-checking and type conversions to be performed.  Common built-in
-types and functions can be used directly as the value of the ``type`` argument::
+interpreted as another type, such as a :class:`float` or :class:`int`.  The
+``type`` keyword for :meth:`~ArgumentParser.add_argument` allows any
+necessary type-checking and type conversions to be performed.
 
-   >>> parser = argparse.ArgumentParser()
-   >>> parser.add_argument('foo', type=int)
-   >>> parser.add_argument('bar', type=open)
-   >>> parser.parse_args('2 temp.txt'.split())
-   Namespace(bar=<_io.TextIOWrapper name='temp.txt' encoding='UTF-8'>, foo=2)
+If the type_ keyword is used with the default_ keyword, the type converter
+is only applied if the default is a string.
 
-See the section on the default_ keyword argument for information on when the
-``type`` argument is applied to default arguments.
+The argument to ``type`` can be any callable that accepts a single string.
+If the function raises :exc:`ArgumentTypeError`, :exc:`TypeError`, or
+:exc:`ValueError`, the exception is caught and a nicely formatted error
+message is displayed.  No other exception types are handled.
 
-To ease the use of various types of files, the argparse module provides the
-factory FileType which takes the ``mode=``, ``bufsize=``, ``encoding=`` and
-``errors=`` arguments of the :func:`open` function.  For example,
-``FileType('w')`` can be used to create a writable file::
+Common built-in types and functions can be used as type converters:
 
-   >>> parser = argparse.ArgumentParser()
-   >>> parser.add_argument('bar', type=argparse.FileType('w'))
-   >>> parser.parse_args(['out.txt'])
-   Namespace(bar=<_io.TextIOWrapper name='out.txt' encoding='UTF-8'>)
-
-``type=`` can take any callable that takes a single string argument and returns
-the converted value::
-
-   >>> def perfect_square(string):
-   ...     value = int(string)
-   ...     sqrt = math.sqrt(value)
-   ...     if sqrt != int(sqrt):
-   ...         msg = "%r is not a perfect square" % string
-   ...         raise argparse.ArgumentTypeError(msg)
-   ...     return value
+.. testcode::
+
+   import argparse
+   import pathlib
+
+   parser = argparse.ArgumentParser()
+   parser.add_argument('count', type=int)
+   parser.add_argument('distance', type=float)
+   parser.add_argument('street', type=ascii)
+   parser.add_argument('code_point', type=ord)
+   parser.add_argument('source_file', type=open)
+   parser.add_argument('dest_file', type=argparse.FileType('w', encoding='latin-1'))
+   parser.add_argument('datapath', type=pathlib.Path)
+
+User defined functions can be used as well:
+
+.. doctest::
+
+   >>> def hyphenated(string):
+   ...     return '-'.join([word[:4] for word in string.casefold().split()])
    ...
-   >>> parser = argparse.ArgumentParser(prog='PROG')
-   >>> parser.add_argument('foo', type=perfect_square)
-   >>> parser.parse_args(['9'])
-   Namespace(foo=9)
-   >>> parser.parse_args(['7'])
-   usage: PROG [-h] foo
-   PROG: error: argument foo: '7' is not a perfect square
+   >>> parser = argparse.ArgumentParser()
+   >>> _ = parser.add_argument('short_title', type=hyphenated)
+   >>> parser.parse_args(['"The Tale of Two Cities"'])
+   Namespace(short_title='"the-tale-of-two-citi')
 
-The choices_ keyword argument may be more convenient for type checkers that
-simply check against a range of values::
+The :func:`bool` function is not recommended as a type converter.  All it does
+is convert empty strings to ``False`` and non-empty strings to ``True``.
+This is usually not what is desired.
 
-   >>> parser = argparse.ArgumentParser(prog='PROG')
-   >>> parser.add_argument('foo', type=int, choices=range(5, 10))
-   >>> parser.parse_args(['7'])
-   Namespace(foo=7)
-   >>> parser.parse_args(['11'])
-   usage: PROG [-h] {5,6,7,8,9}
-   PROG: error: argument foo: invalid choice: 11 (choose from 5, 6, 7, 8, 9)
+In general, the ``type`` keyword is a convenience that should only be used for
+simple conversions that can only raise one of the three supported exceptions.
+Anything with more interesting error-handling or resource management should be
+done downstream after the arguments are parsed.
 
-See the choices_ section for more details.
+For example, JSON or YAML conversions have complex error cases that require
+better reporting than can be given by the ``type`` keyword.  An
+:exc:`~json.JSONDecodeError` would not be well formatted and a
+:exc:`FileNotFound` exception would not be handled at all.
+
+Even :class:`~argparse.FileType` has its limitations for use with the ``type``
+keyword.  If one argument uses *FileType* and then a subsequent argument fails,
+an error is reported but the file is not automatically closed.  In this case, it
+would be better to wait until after the parser has run and then use the
+:keyword:`with`-statement to manage the files.
+
+For type checkers that simply check against a fixed set of values, consider
+using the choices_ keyword instead.
 
 
 choices
@@ -1145,6 +1152,11 @@ Any container can be passed as the *choices* value, so :class:`list` objects,
 Use of :class:`enum.Enum` is not recommended because it is difficult to
 control its appearance in usage, help, and error messages.
 
+Formatted choices overrides the default *metavar* which is normally derived
+from *dest*.  This is usually what you want because the user never sees the
+*dest* parameter.  If this display isn't desirable (perhaps because there are
+many choices), just specify an explicit metavar_.
+
 
 required
 ^^^^^^^^
index b1e73189a7a4cfc07f4a7f78fdb9b3a353d8c02b..be43ca4aebe81a5ca4e1ff43caeb205157c41ad7 100644 (file)
@@ -321,7 +321,7 @@ Creating Futures and Tasks
 
    .. versionadded:: 3.5.2
 
-.. method:: loop.create_task(coro, \*, name=None)
+.. method:: loop.create_task(coro, *, name=None)
 
    Schedule the execution of a :ref:`coroutine`.
    Return a :class:`Task` object.
@@ -356,7 +356,7 @@ Opening network connections
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 .. coroutinemethod:: loop.create_connection(protocol_factory, \
-                          host=None, port=None, \*, ssl=None, \
+                          host=None, port=None, *, ssl=None, \
                           family=0, proto=0, flags=0, sock=None, \
                           local_addr=None, server_hostname=None, \
                           ssl_handshake_timeout=None, \
@@ -482,7 +482,7 @@ Opening network connections
       that can be used directly in async/await code.
 
 .. coroutinemethod:: loop.create_datagram_endpoint(protocol_factory, \
-                        local_addr=None, remote_addr=None, \*, \
+                        local_addr=None, remote_addr=None, *, \
                         family=0, proto=0, flags=0, \
                         reuse_address=None, reuse_port=None, \
                         allow_broadcast=None, sock=None)
@@ -559,7 +559,7 @@ Opening network connections
       Added support for Windows.
 
 .. coroutinemethod:: loop.create_unix_connection(protocol_factory, \
-                        path=None, \*, ssl=None, sock=None, \
+                        path=None, *, ssl=None, sock=None, \
                         server_hostname=None, ssl_handshake_timeout=None)
 
    Create a Unix connection.
@@ -592,7 +592,7 @@ Creating network servers
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
 .. coroutinemethod:: loop.create_server(protocol_factory, \
-                        host=None, port=None, \*, \
+                        host=None, port=None, *, \
                         family=socket.AF_UNSPEC, \
                         flags=socket.AI_PASSIVE, \
                         sock=None, backlog=100, ssl=None, \
@@ -683,7 +683,7 @@ Creating network servers
 
 
 .. coroutinemethod:: loop.create_unix_server(protocol_factory, path=None, \
-                          \*, sock=None, backlog=100, ssl=None, \
+                          *, sock=None, backlog=100, ssl=None, \
                           ssl_handshake_timeout=None, start_serving=True)
 
    Similar to :meth:`loop.create_server` but works with the
@@ -708,7 +708,7 @@ Creating network servers
       The *path* parameter can now be a :class:`~pathlib.Path` object.
 
 .. coroutinemethod:: loop.connect_accepted_socket(protocol_factory, \
-                        sock, \*, ssl=None, ssl_handshake_timeout=None)
+                        sock, *, ssl=None, ssl_handshake_timeout=None)
 
    Wrap an already accepted connection into a transport/protocol pair.
 
@@ -773,7 +773,7 @@ TLS Upgrade
 ^^^^^^^^^^^
 
 .. coroutinemethod:: loop.start_tls(transport, protocol, \
-                        sslcontext, \*, server_side=False, \
+                        sslcontext, *, server_side=False, \
                         server_hostname=None, ssl_handshake_timeout=None)
 
    Upgrade an existing transport-based connection to TLS.
@@ -806,7 +806,7 @@ TLS Upgrade
 Watching file descriptors
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-.. method:: loop.add_reader(fd, callback, \*args)
+.. method:: loop.add_reader(fd, callback, *args)
 
    Start monitoring the *fd* file descriptor for read availability and
    invoke *callback* with the specified arguments once *fd* is available for
@@ -816,7 +816,7 @@ Watching file descriptors
 
    Stop monitoring the *fd* file descriptor for read availability.
 
-.. method:: loop.add_writer(fd, callback, \*args)
+.. method:: loop.add_writer(fd, callback, *args)
 
    Start monitoring the *fd* file descriptor for write availability and
    invoke *callback* with the specified arguments once *fd* is available for
@@ -930,7 +930,7 @@ convenient.
       :meth:`loop.create_server` and :func:`start_server`.
 
 .. coroutinemethod:: loop.sock_sendfile(sock, file, offset=0, count=None, \
-                                        \*, fallback=True)
+                                        *, fallback=True)
 
    Send a file using high-performance :mod:`os.sendfile` if possible.
    Return the total number of bytes sent.
@@ -964,7 +964,7 @@ convenient.
 DNS
 ^^^
 
-.. coroutinemethod:: loop.getaddrinfo(host, port, \*, family=0, \
+.. coroutinemethod:: loop.getaddrinfo(host, port, *, family=0, \
                         type=0, proto=0, flags=0)
 
    Asynchronous version of :meth:`socket.getaddrinfo`.
@@ -1029,7 +1029,7 @@ Working with pipes
 Unix signals
 ^^^^^^^^^^^^
 
-.. method:: loop.add_signal_handler(signum, callback, \*args)
+.. method:: loop.add_signal_handler(signum, callback, *args)
 
    Set *callback* as the handler for the *signum* signal.
 
@@ -1064,7 +1064,7 @@ Unix signals
 Executing code in thread or process pools
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-.. awaitablemethod:: loop.run_in_executor(executor, func, \*args)
+.. awaitablemethod:: loop.run_in_executor(executor, func, *args)
 
    Arrange for *func* to be called in the specified executor.
 
@@ -1234,9 +1234,9 @@ async/await code consider using the high-level
    subprocesses. See :ref:`Subprocess Support on Windows
    <asyncio-windows-subprocess>` for details.
 
-.. coroutinemethod:: loop.subprocess_exec(protocol_factory, \*args, \
+.. coroutinemethod:: loop.subprocess_exec(protocol_factory, *args, \
                       stdin=subprocess.PIPE, stdout=subprocess.PIPE, \
-                      stderr=subprocess.PIPE, \*\*kwargs)
+                      stderr=subprocess.PIPE, **kwargs)
 
    Create a subprocess from one or more string arguments specified by
    *args*.
@@ -1316,9 +1316,9 @@ async/await code consider using the high-level
    conforms to the :class:`asyncio.SubprocessTransport` base class and
    *protocol* is an object instantiated by the *protocol_factory*.
 
-.. coroutinemethod:: loop.subprocess_shell(protocol_factory, cmd, \*, \
+.. coroutinemethod:: loop.subprocess_shell(protocol_factory, cmd, *, \
                         stdin=subprocess.PIPE, stdout=subprocess.PIPE, \
-                        stderr=subprocess.PIPE, \*\*kwargs)
+                        stderr=subprocess.PIPE, **kwargs)
 
    Create a subprocess from *cmd*, which can be a :class:`str` or a
    :class:`bytes` string encoded to the
index e1ac18eaf0988280290f79788dff2962e398e86e..939d4c1a84523a057cc9e360c7782dda459dc761 100644 (file)
@@ -31,7 +31,7 @@ Future Functions
    .. versionadded:: 3.5
 
 
-.. function:: ensure_future(obj, \*, loop=None)
+.. function:: ensure_future(obj, *, loop=None)
 
    Return:
 
@@ -58,7 +58,7 @@ Future Functions
       The function accepts any :term:`awaitable` object.
 
 
-.. function:: wrap_future(future, \*, loop=None)
+.. function:: wrap_future(future, *, loop=None)
 
    Wrap a :class:`concurrent.futures.Future` object in a
    :class:`asyncio.Future` object.
@@ -67,7 +67,7 @@ Future Functions
 Future Object
 =============
 
-.. class:: Future(\*, loop=None)
+.. class:: Future(*, loop=None)
 
    A Future represents an eventual result of an asynchronous
    operation.  Not thread-safe.
index 5e69525e90dd27443916acec3bf8469f4d963726..ef6a0588506b52bcc81ecd97cbebc11772a027ac 100644 (file)
@@ -159,7 +159,7 @@ implementation used by the asyncio event loop:
 
 .. class:: AbstractChildWatcher
 
-   .. method:: add_child_handler(pid, callback, \*args)
+   .. method:: add_child_handler(pid, callback, *args)
 
       Register a new child handler.
 
index b76ed379c7f4c88d5bbeefd10c1b28cb590689b9..714de8d41a3503cfde0c4131d9983c32932f7e5c 100644 (file)
@@ -48,7 +48,7 @@ The following top-level asyncio functions can be used to create
 and work with streams:
 
 
-.. coroutinefunction:: open_connection(host=None, port=None, \*, \
+.. coroutinefunction:: open_connection(host=None, port=None, *, \
                           loop=None, limit=None, ssl=None, family=0, \
                           proto=0, flags=0, sock=None, local_addr=None, \
                           server_hostname=None, ssl_handshake_timeout=None)
@@ -74,7 +74,7 @@ and work with streams:
       The *ssl_handshake_timeout* parameter.
 
 .. coroutinefunction:: start_server(client_connected_cb, host=None, \
-                          port=None, \*, loop=None, limit=None, \
+                          port=None, *, loop=None, limit=None, \
                           family=socket.AF_UNSPEC, \
                           flags=socket.AI_PASSIVE, sock=None, \
                           backlog=100, ssl=None, reuse_address=None, \
@@ -109,7 +109,7 @@ and work with streams:
 
 .. rubric:: Unix Sockets
 
-.. coroutinefunction:: open_unix_connection(path=None, \*, loop=None, \
+.. coroutinefunction:: open_unix_connection(path=None, *, loop=None, \
                         limit=None, ssl=None, sock=None, \
                         server_hostname=None, ssl_handshake_timeout=None)
 
@@ -132,7 +132,7 @@ and work with streams:
 
 
 .. coroutinefunction:: start_unix_server(client_connected_cb, path=None, \
-                          \*, loop=None, limit=None, sock=None, \
+                          *, loop=None, limit=None, sock=None, \
                           backlog=100, ssl=None, ssl_handshake_timeout=None, \
                           start_serving=True)
 
index b0330349dfb651927917879b9369a3299fd0f5ad..fb98552c86d4c131301d46b27f9b69f79a075dd1 100644 (file)
@@ -61,9 +61,9 @@ See also the `Examples`_ subsection.
 Creating Subprocesses
 =====================
 
-.. coroutinefunction:: create_subprocess_exec(program, \*args, stdin=None, \
+.. coroutinefunction:: create_subprocess_exec(program, *args, stdin=None, \
                           stdout=None, stderr=None, loop=None, \
-                          limit=None, \*\*kwds)
+                          limit=None, **kwds)
 
    Create a subprocess.
 
@@ -82,7 +82,7 @@ Creating Subprocesses
 
 .. coroutinefunction:: create_subprocess_shell(cmd, stdin=None, \
                           stdout=None, stderr=None, loop=None, \
-                          limit=None, \*\*kwds)
+                          limit=None, **kwds)
 
    Run the *cmd* shell command.
 
index 84a52cb2d575710591308d1768a8f3c88209a806..f62ce670fccbf9eb14ebe41f89f2f7bc60fab230 100644 (file)
@@ -104,8 +104,8 @@ Event
    that some event has happened.
 
    An Event object manages an internal flag that can be set to *true*
-   with the :meth:`set` method and reset to *false* with the
-   :meth:`clear` method.  The :meth:`wait` method blocks until the
+   with the :meth:`~Event.set` method and reset to *false* with the
+   :meth:`clear` method.  The :meth:`~Event.wait` method blocks until the
    flag is set to *true*.  The flag is set to *false* initially.
 
 
@@ -142,7 +142,7 @@ Event
       Wait until the event is set.
 
       If the event is set, return ``True`` immediately.
-      Otherwise block until another task calls :meth:`set`.
+      Otherwise block until another task calls :meth:`~Event.set`.
 
    .. method:: set()
 
@@ -155,8 +155,8 @@ Event
 
       Clear (unset) the event.
 
-      Tasks awaiting on :meth:`wait` will now block until the
-      :meth:`set` method is called again.
+      Tasks awaiting on :meth:`~Event.wait` will now block until the
+      :meth:`~Event.set` method is called again.
 
    .. method:: is_set()
 
index c638f1263fdaa1ca5d5915bccaa83d62b6340577..201678b0a3d57e9526572448d8e624aeee43b7b1 100644 (file)
@@ -210,7 +210,7 @@ is :meth:`loop.run_in_executor`.
 Running an asyncio Program
 ==========================
 
-.. function:: run(coro, \*, debug=False)
+.. function:: run(coro, *, debug=False)
 
     Execute the :term:`coroutine` *coro* and return the result.
 
@@ -247,7 +247,7 @@ Running an asyncio Program
 Creating Tasks
 ==============
 
-.. function:: create_task(coro, \*, name=None)
+.. function:: create_task(coro, *, name=None)
 
    Wrap the *coro* :ref:`coroutine <coroutine>` into a :class:`Task`
    and schedule its execution.  Return the Task object.
@@ -283,7 +283,7 @@ Creating Tasks
 Sleeping
 ========
 
-.. coroutinefunction:: sleep(delay, result=None, \*, loop=None)
+.. coroutinefunction:: sleep(delay, result=None, *, loop=None)
 
    Block for *delay* seconds.
 
@@ -319,7 +319,7 @@ Sleeping
 Running Tasks Concurrently
 ==========================
 
-.. awaitablefunction:: gather(\*aws, loop=None, return_exceptions=False)
+.. awaitablefunction:: gather(*aws, loop=None, return_exceptions=False)
 
    Run :ref:`awaitable objects <asyncio-awaitables>` in the *aws*
    sequence *concurrently*.
@@ -403,7 +403,7 @@ Running Tasks Concurrently
 Shielding From Cancellation
 ===========================
 
-.. awaitablefunction:: shield(aw, \*, loop=None)
+.. awaitablefunction:: shield(aw, *, loop=None)
 
    Protect an :ref:`awaitable object <asyncio-awaitables>`
    from being :meth:`cancelled <Task.cancel>`.
@@ -443,7 +443,7 @@ Shielding From Cancellation
 Timeouts
 ========
 
-.. coroutinefunction:: wait_for(aw, timeout, \*, loop=None)
+.. coroutinefunction:: wait_for(aw, timeout, *, loop=None)
 
    Wait for the *aw* :ref:`awaitable <asyncio-awaitables>`
    to complete with a timeout.
@@ -500,7 +500,7 @@ Timeouts
 Waiting Primitives
 ==================
 
-.. coroutinefunction:: wait(aws, \*, loop=None, timeout=None,\
+.. coroutinefunction:: wait(aws, *, loop=None, timeout=None,\
                             return_when=ALL_COMPLETED)
 
    Run :ref:`awaitable objects <asyncio-awaitables>` in the *aws*
@@ -590,7 +590,7 @@ Waiting Primitives
       deprecated.
 
 
-.. function:: as_completed(aws, \*, loop=None, timeout=None)
+.. function:: as_completed(aws, *, loop=None, timeout=None)
 
    Run :ref:`awaitable objects <asyncio-awaitables>` in the *aws*
    iterable concurrently.  Return an iterator of coroutines.
@@ -613,7 +613,7 @@ Waiting Primitives
 Running in Threads
 ==================
 
-.. coroutinefunction:: to_thread(func, /, \*args, \*\*kwargs)
+.. coroutinefunction:: to_thread(func, /, *args, **kwargs)
 
    Asynchronously run function *func* in a separate thread.
 
@@ -743,7 +743,7 @@ Introspection
 Task Object
 ===========
 
-.. class:: Task(coro, \*, loop=None, name=None)
+.. class:: Task(coro, *, loop=None, name=None)
 
    A :class:`Future-like <Future>` object that runs a Python
    :ref:`coroutine <coroutine>`.  Not thread-safe.
@@ -909,7 +909,7 @@ Task Object
       See the documentation of :meth:`Future.remove_done_callback`
       for more details.
 
-   .. method:: get_stack(\*, limit=None)
+   .. method:: get_stack(*, limit=None)
 
       Return the list of stack frames for this Task.
 
@@ -930,7 +930,7 @@ Task Object
       stack are returned, but the oldest frames of a traceback are
       returned.  (This matches the behavior of the traceback module.)
 
-   .. method:: print_stack(\*, limit=None, file=None)
+   .. method:: print_stack(*, limit=None, file=None)
 
       Print the stack or traceback for this Task.
 
index 4048592e7361f705b2bcf93e8bafc1284eb5bd99..e60a3f13595cf00dcf09d3a01ab51ca06b1f1d98 100644 (file)
@@ -277,14 +277,14 @@ These are useful if you want more control, or if you want to employ some of the
 algorithms implemented in this module in other circumstances.
 
 
-.. function:: parse(fp=None, environ=os.environ, keep_blank_values=False, strict_parsing=False)
+.. function:: parse(fp=None, environ=os.environ, keep_blank_values=False, strict_parsing=False, separator="&")
 
    Parse a query in the environment or from a file (the file defaults to
-   ``sys.stdin``).  The *keep_blank_values* and *strict_parsing* parameters are
+   ``sys.stdin``).  The *keep_blank_values*, *strict_parsing* and *separator* parameters are
    passed to :func:`urllib.parse.parse_qs` unchanged.
 
 
-.. function:: parse_multipart(fp, pdict, encoding="utf-8", errors="replace")
+.. function:: parse_multipart(fp, pdict, encoding="utf-8", errors="replace", separator="&")
 
    Parse input of type :mimetype:`multipart/form-data` (for  file uploads).
    Arguments are *fp* for the input file, *pdict* for a dictionary containing
@@ -303,6 +303,9 @@ algorithms implemented in this module in other circumstances.
       Added the *encoding* and *errors* parameters.  For non-file fields, the
       value is now a list of strings, not bytes.
 
+   .. versionchanged:: 3.9.2
+      Added the *separator* parameter.
+
 
 .. function:: parse_header(string)
 
index f071057293eece49e95ad58ea70a8c45d8d39df2..6eb907afce3c6c30f05f2b7d7113d9b0e82df3cc 100644 (file)
@@ -694,7 +694,7 @@ compatible with the Python codec registry.
 
    .. method:: reset()
 
-      Flushes and resets the codec buffers used for keeping state.
+      Resets the codec buffers used for keeping internal state.
 
       Calling this method should ensure that the data on the output is put into
       a clean state that allows appending of new fresh data without having to
@@ -789,7 +789,7 @@ compatible with the Python codec registry.
 
    .. method:: reset()
 
-      Resets the codec buffers used for keeping state.
+      Resets the codec buffers used for keeping internal state.
 
       Note that no stream repositioning should take place. This method is
       primarily intended to be able to recover from decoding errors.
index 9b914b1f0d9c6ded97d84e187aed724857096939..5c6e68f93047537085ec0265fc5e0bd16c3c158d 100644 (file)
@@ -148,7 +148,7 @@ runtime.
 Public functions
 ----------------
 
-.. function:: compile_dir(dir, maxlevels=sys.getrecursionlimit(), ddir=None, force=False, rx=None, quiet=0, legacy=False, optimize=-1, workers=1, invalidation_mode=None, \*, stripdir=None, prependdir=None, limit_sl_dest=None, hardlink_dupes=False)
+.. function:: compile_dir(dir, maxlevels=sys.getrecursionlimit(), ddir=None, force=False, rx=None, quiet=0, legacy=False, optimize=-1, workers=1, invalidation_mode=None, *, stripdir=None, prependdir=None, limit_sl_dest=None, hardlink_dupes=False)
 
    Recursively descend the directory tree named by *dir*, compiling all :file:`.py`
    files along the way. Return a true value if all the files compiled successfully,
@@ -231,7 +231,7 @@ Public functions
       Added *stripdir*, *prependdir*, *limit_sl_dest* and *hardlink_dupes* arguments.
       Default value of *maxlevels* was changed from ``10`` to ``sys.getrecursionlimit()``
 
-.. function:: compile_file(fullname, ddir=None, force=False, rx=None, quiet=0, legacy=False, optimize=-1, invalidation_mode=None, \*, stripdir=None, prependdir=None, limit_sl_dest=None, hardlink_dupes=False)
+.. function:: compile_file(fullname, ddir=None, force=False, rx=None, quiet=0, legacy=False, optimize=-1, invalidation_mode=None, *, stripdir=None, prependdir=None, limit_sl_dest=None, hardlink_dupes=False)
 
    Compile the file with path *fullname*. Return a true value if the file
    compiled successfully, and a false value otherwise.
index 61d6c1143cfdd53ef307c97c22e496e68f869fe8..d57f8ce23d12c49c43e27881cd635228d5a3be0f 100644 (file)
@@ -67,7 +67,7 @@ Executor Objects
        .. versionchanged:: 3.5
           Added the *chunksize* argument.
 
-    .. method:: shutdown(wait=True, \*, cancel_futures=False)
+    .. method:: shutdown(wait=True, *, cancel_futures=False)
 
        Signal the executor that it should free any resources that it is using
        when the currently pending futures are done executing.  Calls to
index 8805661c456edb611c877ee1823cf8a1feb47f7c..14ac47f4c9eb164050749ff5b7431b720c11145d 100644 (file)
@@ -26,7 +26,7 @@ See also :pep:`567` for additional details.
 Context Variables
 -----------------
 
-.. class:: ContextVar(name, [\*, default])
+.. class:: ContextVar(name, [*, default])
 
    This class is used to declare a new Context Variable, e.g.::
 
@@ -146,7 +146,7 @@ Manual Context Management
 
    Context implements the :class:`collections.abc.Mapping` interface.
 
-   .. method:: run(callable, \*args, \*\*kwargs)
+   .. method:: run(callable, *args, **kwargs)
 
       Execute ``callable(*args, **kwargs)`` code in the context object
       the *run* method is called on.  Return the result of the execution
index bf32d3e549b4809f397fcafab40f79d37ed0ed91..7313148721dac60cc49cc70218f13e80871b9367 100644 (file)
@@ -2508,7 +2508,7 @@ other data types containing pointer type fields.
 Arrays and pointers
 ^^^^^^^^^^^^^^^^^^^
 
-.. class:: Array(\*args)
+.. class:: Array(*args)
 
    Abstract base class for arrays.
 
index 7a13295f482eeb0e4bda74fa18f67c77c33b1075..c72840a07c192ef3949f4f86d0145f209916a012 100644 (file)
@@ -112,14 +112,15 @@ The module :mod:`curses` defines the following functions:
 .. function:: color_content(color_number)
 
    Return the intensity of the red, green, and blue (RGB) components in the color
-   *color_number*, which must be between ``0`` and :const:`COLORS`.  Return a 3-tuple,
+   *color_number*, which must be between ``0`` and ``COLORS - 1``.  Return a 3-tuple,
    containing the R,G,B values for the given color, which will be between
    ``0`` (no component) and ``1000`` (maximum amount of component).
 
 
-.. function:: color_pair(color_number)
+.. function:: color_pair(pair_number)
 
-   Return the attribute value for displaying text in the specified color.  This
+   Return the attribute value for displaying text in the specified color pair.
+   Only the first 256 color pairs are supported. This
    attribute value can be combined with :const:`A_STANDOUT`, :const:`A_REVERSE`,
    and the other :const:`A_\*` attributes.  :func:`pair_number` is the counterpart
    to this function.
@@ -278,7 +279,7 @@ The module :mod:`curses` defines the following functions:
    Change the definition of a color, taking the number of the color to be changed
    followed by three RGB values (for the amounts of red, green, and blue
    components).  The value of *color_number* must be between ``0`` and
-   :const:`COLORS`.  Each of *r*, *g*, *b*, must be a value between ``0`` and
+   `COLORS - 1`.  Each of *r*, *g*, *b*, must be a value between ``0`` and
    ``1000``.  When :func:`init_color` is used, all occurrences of that color on the
    screen immediately change to the new definition.  This function is a no-op on
    most terminals; it is active only if :func:`can_change_color` returns ``True``.
@@ -291,7 +292,8 @@ The module :mod:`curses` defines the following functions:
    color number.  The value of *pair_number* must be between ``1`` and
    ``COLOR_PAIRS - 1`` (the ``0`` color pair is wired to white on black and cannot
    be changed).  The value of *fg* and *bg* arguments must be between ``0`` and
-   :const:`COLORS`.  If the color-pair was previously initialized, the screen is
+   ``COLORS - 1``, or, after calling :func:`use_default_colors`, ``-1``.
+   If the color-pair was previously initialized, the screen is
    refreshed and all occurrences of that color-pair are changed to the new
    definition.
 
@@ -441,7 +443,7 @@ The module :mod:`curses` defines the following functions:
 .. function:: pair_content(pair_number)
 
    Return a tuple ``(fg, bg)`` containing the colors for the requested color pair.
-   The value of *pair_number* must be between ``1`` and ``COLOR_PAIRS - 1``.
+   The value of *pair_number* must be between ``0`` and ``COLOR_PAIRS - 1``.
 
 
 .. function:: pair_number(attr)
index 508bc88e7f4b8a3ef76d14d7a24f1cc8e9f09cb8..dae0dd7aa55898d84c9a43f18f69411bba719948 100644 (file)
@@ -1219,7 +1219,7 @@ Instance methods:
 
 .. method:: datetime.replace(year=self.year, month=self.month, day=self.day, \
    hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, \
-   tzinfo=self.tzinfo, * fold=0)
+   tzinfo=self.tzinfo, *, fold=0)
 
    Return a datetime with the same attributes, except for those attributes given
    new values by whichever keyword arguments are specified. Note that
@@ -1783,7 +1783,7 @@ Other constructor:
 Instance methods:
 
 .. method:: time.replace(hour=self.hour, minute=self.minute, second=self.second, \
-   microsecond=self.microsecond, tzinfo=self.tzinfo, * fold=0)
+   microsecond=self.microsecond, tzinfo=self.tzinfo, *, fold=0)
 
    Return a :class:`.time` with the same value, except for those attributes given
    new values by whichever keyword arguments are specified. Note that
index dc82a974ce095d8937b9a908faeb8caa8ca7a7a3..53f98c1018988f8394526658bbd8c1e0813ddf70 100644 (file)
@@ -198,7 +198,7 @@ These do not emulate the native look-and-feel of the platform.
    A subclass of FileDialog that creates a dialog window for selecting a
    destination file.
 
-    .. method:: ok_command()
+   .. method:: ok_command()
 
       Test whether or not the selection points to a valid file that is not a
       directory. Confirmation is required if an already existing file is
index e09c7c0e402bbcbebc8c9c941ca889c8ca43416b..918fc55677e72390833e06c7b8c515305a9455c4 100644 (file)
@@ -116,7 +116,7 @@ Currently the email package provides only one concrete content manager,
       decoding the payload to unicode.  The default error handler is
       ``replace``.
 
-   .. method:: set_content(msg, <'str'>, subtype="plain", charset='utf-8' \
+   .. method:: set_content(msg, <'str'>, subtype="plain", charset='utf-8', \
                            cte=None, \
                            disposition=None, filename=None, cid=None, \
                            params=None, headers=None)
index 9376da2b8d39ce78eec59ba70005457b85c65f6d..3e1d97a03264b2df2032a33afb8607af3fb081b4 100644 (file)
@@ -289,7 +289,7 @@ variant, :attr:`~.BaseHeader.max_count` is set to 1.
     A :class:`ParameterizedMIMEHeader` class that handles the
     :mailheader:`Content-Disposition` header.
 
-    .. attribute:: content-disposition
+    .. attribute:: content_disposition
 
        ``inline`` and ``attachment`` are the only valid values in common use.
 
index 8e7076259810f55bb75727fb67f0cb0e1447cb3c..bf53b9520fc723e0fb4e9570e0934398f537c764 100644 (file)
@@ -210,7 +210,7 @@ added matters.  To illustrate::
       :meth:`register_defect` method.
 
 
-   .. attribute:: mangle_from\_
+   .. attribute:: mangle_from_
 
       If :const:`True`, lines starting with *"From "* in the body are
       escaped by putting a ``>`` in front of them. This parameter is used when
index a3c51655576ba5f8000786eadac79ce8f7c7e3dd..8836b24912e9e35b3c339ffd216db87c9cdc5813 100644 (file)
@@ -56,7 +56,7 @@ helper, :class:`auto`.
     the bitwise operations without losing their :class:`Flag` membership.
 
 .. function:: unique
-   :noindex:
+    :noindex:
 
     Enum class decorator that ensures only one name is bound to any one value.
 
@@ -1121,6 +1121,15 @@ and raise an error if the two do not match::
     In Python 2 code the :attr:`_order_` attribute is necessary as definition
     order is lost before it can be recorded.
 
+
+_Private__names
+"""""""""""""""
+
+Private names will be normal attributes in Python 3.10 instead of either an error
+or a member (depending on if the name ends with an underscore). Using these names
+in 3.9 will issue a :exc:`DeprecationWarning`.
+
+
 ``Enum`` member type
 """"""""""""""""""""
 
index ce07d326b395d80605e4b712343a6b79feb5a37e..925f08e914685e89c5c176a53ad39fc368d4d7db 100644 (file)
@@ -75,7 +75,7 @@ patterns.
 
 .. function:: filter(names, pattern)
 
-   Return the subset of the list of *names* that match *pattern*. It is the same as
+   Construct a list from those elements of the iterable *names* that match *pattern*. It is the same as
    ``[n for n in names if fnmatch(n, pattern)]``, but implemented more efficiently.
 
 
index 9c12b6c48d8ff08c12cc1760d92c36db8737d60a..990fc10c8cc9745bc1146b97549b88fc2f650f12 100644 (file)
@@ -508,7 +508,8 @@ are always available.  They are listed here in alphabetical order.
    occurs). [#]_ If it is a code object, it is simply executed.  In all cases,
    the code that's executed is expected to be valid as file input (see the
    section "File input" in the Reference Manual). Be aware that the
-   :keyword:`return` and :keyword:`yield` statements may not be used outside of
+   :keyword:`nonlocal`, :keyword:`yield`,  and :keyword:`return`
+   statements may not be used outside of
    function definitions even within the context of code passed to the
    :func:`exec` function. The return value is ``None``.
 
@@ -1687,18 +1688,19 @@ are always available.  They are listed here in alphabetical order.
 
 
    With three arguments, return a new type object.  This is essentially a
-   dynamic form of the :keyword:`class` statement. The *name* string is the
-   class name and becomes the :attr:`~definition.__name__` attribute; the *bases*
-   tuple itemizes the base classes and becomes the :attr:`~class.__bases__`
-   attribute; and the *dict* dictionary is the namespace containing definitions
-   for class body and is copied to a standard dictionary to become the
-   :attr:`~object.__dict__` attribute.  For example, the following two
-   statements create identical :class:`type` objects:
+   dynamic form of the :keyword:`class` statement. The *name* string is
+   the class name and becomes the :attr:`~definition.__name__` attribute.
+   The *bases* tuple contains the base classes and becomes the
+   :attr:`~class.__bases__` attribute; if empty, :class:`object`, the
+   ultimate base of all classes, is added.  The *dict* dictionary contains
+   attribute and method definitions for the class body; it may be copied
+   or wrapped before becoming the :attr:`~object.__dict__` attribute.
+   The following two statements create identical :class:`type` objects:
 
       >>> class X:
       ...     a = 1
       ...
-      >>> X = type('X', (object,), dict(a=1))
+      >>> X = type('X', (), dict(a=1))
 
    See also :ref:`bltin-type-objects`.
 
index 4869b67cb941647a8993cb157f7d5f40ef277ec2..85d4e74698d2f1302b1ba8885df6c6db1c208775 100644 (file)
@@ -62,16 +62,26 @@ The :mod:`functools` module defines the following functions:
    Example::
 
        class DataSet:
+
            def __init__(self, sequence_of_numbers):
-               self._data = sequence_of_numbers
+               self._data = tuple(sequence_of_numbers)
 
            @cached_property
            def stdev(self):
                return statistics.stdev(self._data)
 
-           @cached_property
-           def variance(self):
-               return statistics.variance(self._data)
+   The mechanics of :func:`cached_property` are somewhat different from
+   :func:`property`.  A regular property blocks attribute writes unless a
+   setter is defined. In contrast, a *cached_property* allows writes.
+
+   The *cached_property* decorator only runs on lookups and only when an
+   attribute of the same name doesn't exist.  When it does run, the
+   *cached_property* writes to the attribute with the same name. Subsequent
+   attribute reads and writes take precedence over the *cached_property*
+   method and it works like a normal attribute.
+
+   The cached value can be cleared by deleting the attribute.  This
+   allows the *cached_property* method to run again.
 
    Note, this decorator interferes with the operation of :pep:`412`
    key-sharing dictionaries.  This means that instance dictionaries
index a59a5d3a465703c1a09c3e518626e903e47bc8fd..e7eaabd8bfa25a209c1ab9cc38cb59cb57dbb341 100644 (file)
@@ -250,7 +250,7 @@ View Last Restart
   Scroll the shell window to the last Shell restart.
 
 Restart Shell
-  Restart the shell to clean the environment.
+  Restart the shell to clean the environment and reset display and exception handling.
 
 Previous History
   Cycle through earlier commands in history which match the current entry.
index 21da143f3bebf9a41fb927eb6935c3f70b764715..0dd3daaa54892bab4f560de775e2660551750dfa 100644 (file)
@@ -206,9 +206,9 @@ Thus, an alternative way to get the version number is through the
 There are all kinds of additional metadata available on the ``Distribution``
 instance::
 
-    >>> d.metadata['Requires-Python']  # doctest: +SKIP
+    >>> dist.metadata['Requires-Python']  # doctest: +SKIP
     '>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
-    >>> d.metadata['License']  # doctest: +SKIP
+    >>> dist.metadata['License']  # doctest: +SKIP
     'MIT'
 
 The full set of available metadata is not described here.  See :pep:`566`
index 9027ba58acb20a886b348ff54bcec484eeae1d77..cb2a5686a95a50023a4ccee8d570a26ab516694a 100644 (file)
@@ -1135,7 +1135,7 @@ find and load modules.
       directory for ``''`` (i.e. the empty string).
 
 
-.. class:: FileFinder(path, \*loader_details)
+.. class:: FileFinder(path, *loader_details)
 
    A concrete implementation of :class:`importlib.abc.PathEntryFinder` which
    caches results from the file system.
@@ -1178,7 +1178,7 @@ find and load modules.
 
       Clear out the internal cache.
 
-   .. classmethod:: path_hook(\*loader_details)
+   .. classmethod:: path_hook(*loader_details)
 
       A class method which returns a closure for use on :attr:`sys.path_hooks`.
       An instance of :class:`FileFinder` is returned by the closure using the
@@ -1473,7 +1473,7 @@ an :term:`importer`.
 
    If  **name** has no leading dots, then **name** is simply returned. This
    allows for usage such as
-   ``importlib.util.resolve_name('sys', __package__)`` without doing a
+   ``importlib.util.resolve_name('sys', __spec__.parent)`` without doing a
    check to see if the **package** argument is needed.
 
    :exc:`ImportError` is raised if **name** is a relative module name but
index d00a30ff0040631656a161a349ec56b066808ab6..b53a9421fbca612b0f3ab729e4a8a02197adc028 100644 (file)
@@ -556,7 +556,7 @@ The Signature object represents the call signature of a callable object and its
 return annotation.  To retrieve a Signature object, use the :func:`signature`
 function.
 
-.. function:: signature(callable, \*, follow_wrapped=True)
+.. function:: signature(callable, *, follow_wrapped=True)
 
    Return a :class:`Signature` object for the given ``callable``::
 
@@ -597,7 +597,7 @@ function.
       C provide no metadata about their arguments.
 
 
-.. class:: Signature(parameters=None, \*, return_annotation=Signature.empty)
+.. class:: Signature(parameters=None, *, return_annotation=Signature.empty)
 
    A Signature object represents the call signature of a function and its return
    annotation.  For each parameter accepted by the function it stores a
@@ -668,7 +668,7 @@ function.
          >>> str(new_sig)
          "(a, b) -> 'new return anno'"
 
-   .. classmethod:: Signature.from_callable(obj, \*, follow_wrapped=True)
+   .. classmethod:: Signature.from_callable(obj, *, follow_wrapped=True)
 
        Return a :class:`Signature` (or its subclass) object for a given callable
        ``obj``.  Pass ``follow_wrapped=False`` to get a signature of ``obj``
@@ -684,7 +684,7 @@ function.
        .. versionadded:: 3.5
 
 
-.. class:: Parameter(name, kind, \*, default=Parameter.empty, annotation=Parameter.empty)
+.. class:: Parameter(name, kind, *, default=Parameter.empty, annotation=Parameter.empty)
 
    Parameter objects are *immutable*.  Instead of modifying a Parameter object,
    you can use :meth:`Parameter.replace` to create a modified copy.
index 3de66c934928157752b388d79b8871f37422f3e3..6da55f8a3f49cf08ffdc3ac64037325b58e8e30f 100644 (file)
@@ -565,7 +565,7 @@ loops that truncate the stream.
 
    Before :func:`product` runs, it completely consumes the input iterables,
    keeping pools of values in memory to generate the products.  Accordingly,
-   it only useful with finite inputs.
+   it is only useful with finite inputs.
 
 .. function:: repeat(object[, times])
 
@@ -769,6 +769,18 @@ which incur interpreter overhead.
    def dotproduct(vec1, vec2):
        return sum(map(operator.mul, vec1, vec2))
 
+   def convolve(signal, kernel):
+       # See:  https://betterexplained.com/articles/intuitive-convolution/
+       # convolve(data, [0.25, 0.25, 0.25, 0.25]) --> Moving average (blur)
+       # convolve(data, [1, -1]) --> 1st finite difference (1st derivative)
+       # convolve(data, [1, -2, 1]) --> 2nd finite difference (2nd derivative)
+       kernel = tuple(kernel)[::-1]
+       n = len(kernel)
+       window = collections.deque([0], maxlen=n) * n
+       for x in chain(signal, repeat(0, n-1)):
+           window.append(x)
+           yield sum(map(operator.mul, kernel, window))
+
    def flatten(list_of_lists):
        "Flatten one level of nesting"
        return chain.from_iterable(list_of_lists)
index 683d6ed5e8ba525739db836bb6f6aeca13ee8770..0b5e2fc2a658d5f04175d8ea04db2563b355f659 100644 (file)
@@ -35,45 +35,45 @@ in :mod:`logging` itself) and defining handlers which are declared either in
 
 .. function:: dictConfig(config)
 
-    Takes the logging configuration from a dictionary.  The contents of
-    this dictionary are described in :ref:`logging-config-dictschema`
-    below.
-
-    If an error is encountered during configuration, this function will
-    raise a :exc:`ValueError`, :exc:`TypeError`, :exc:`AttributeError`
-    or :exc:`ImportError` with a suitably descriptive message.  The
-    following is a (possibly incomplete) list of conditions which will
-    raise an error:
-
-    * A ``level`` which is not a string or which is a string not
-      corresponding to an actual logging level.
-    * A ``propagate`` value which is not a boolean.
-    * An id which does not have a corresponding destination.
-    * A non-existent handler id found during an incremental call.
-    * An invalid logger name.
-    * Inability to resolve to an internal or external object.
-
-    Parsing is performed by the :class:`DictConfigurator` class, whose
-    constructor is passed the dictionary used for configuration, and
-    has a :meth:`configure` method.  The :mod:`logging.config` module
-    has a callable attribute :attr:`dictConfigClass`
-    which is initially set to :class:`DictConfigurator`.
-    You can replace the value of :attr:`dictConfigClass` with a
-    suitable implementation of your own.
-
-    :func:`dictConfig` calls :attr:`dictConfigClass` passing
-    the specified dictionary, and then calls the :meth:`configure` method on
-    the returned object to put the configuration into effect::
-
-          def dictConfig(config):
-              dictConfigClass(config).configure()
-
-    For example, a subclass of :class:`DictConfigurator` could call
-    ``DictConfigurator.__init__()`` in its own :meth:`__init__()`, then
-    set up custom prefixes which would be usable in the subsequent
-    :meth:`configure` call. :attr:`dictConfigClass` would be bound to
-    this new subclass, and then :func:`dictConfig` could be called exactly as
-    in the default, uncustomized state.
+   Takes the logging configuration from a dictionary.  The contents of
+   this dictionary are described in :ref:`logging-config-dictschema`
+   below.
+
+   If an error is encountered during configuration, this function will
+   raise a :exc:`ValueError`, :exc:`TypeError`, :exc:`AttributeError`
+   or :exc:`ImportError` with a suitably descriptive message.  The
+   following is a (possibly incomplete) list of conditions which will
+   raise an error:
+
+   * A ``level`` which is not a string or which is a string not
+     corresponding to an actual logging level.
+   * A ``propagate`` value which is not a boolean.
+   * An id which does not have a corresponding destination.
+   * A non-existent handler id found during an incremental call.
+   * An invalid logger name.
+   * Inability to resolve to an internal or external object.
+
+   Parsing is performed by the :class:`DictConfigurator` class, whose
+   constructor is passed the dictionary used for configuration, and
+   has a :meth:`configure` method.  The :mod:`logging.config` module
+   has a callable attribute :attr:`dictConfigClass`
+   which is initially set to :class:`DictConfigurator`.
+   You can replace the value of :attr:`dictConfigClass` with a
+   suitable implementation of your own.
+
+   :func:`dictConfig` calls :attr:`dictConfigClass` passing
+   the specified dictionary, and then calls the :meth:`configure` method on
+   the returned object to put the configuration into effect::
+
+         def dictConfig(config):
+             dictConfigClass(config).configure()
+
+   For example, a subclass of :class:`DictConfigurator` could call
+   ``DictConfigurator.__init__()`` in its own :meth:`__init__()`, then
+   set up custom prefixes which would be usable in the subsequent
+   :meth:`configure` call. :attr:`dictConfigClass` would be bound to
+   this new subclass, and then :func:`dictConfig` could be called exactly as
+   in the default, uncustomized state.
 
    .. versionadded:: 3.2
 
index 7267f812cc1925bdea4a9c14f5e7e514c3632194..e63475d3b5a024a27a1b0ac833e7421ee90eae37 100644 (file)
@@ -1089,8 +1089,8 @@ functions.
    suitable value.
 
    .. versionchanged:: 3.7
-      The *level* parameter was defaulted to level ``CRITICAL``. See Issue
-      #28524 for more information about this change.
+      The *level* parameter was defaulted to level ``CRITICAL``. See
+      :issue:`28524` for more information about this change.
 
 .. function:: addLevelName(level, levelName)
 
index 4bfff9c6147ed4c9e00e7b5f7e3a9294b106a986..633c87873cd8ce4c32557616f0919cefd9fd471d 100644 (file)
@@ -33,7 +33,7 @@ from multiple threads, it is necessary to protect it with a lock.
 Reading and writing compressed files
 ------------------------------------
 
-.. function:: open(filename, mode="rb", \*, format=None, check=-1, preset=None, filters=None, encoding=None, errors=None, newline=None)
+.. function:: open(filename, mode="rb", *, format=None, check=-1, preset=None, filters=None, encoding=None, errors=None, newline=None)
 
    Open an LZMA-compressed file in binary or text mode, returning a :term:`file
    object`.
@@ -69,7 +69,7 @@ Reading and writing compressed files
       Accepts a :term:`path-like object`.
 
 
-.. class:: LZMAFile(filename=None, mode="r", \*, format=None, check=-1, preset=None, filters=None)
+.. class:: LZMAFile(filename=None, mode="r", *, format=None, check=-1, preset=None, filters=None)
 
    Open an LZMA-compressed file in binary mode.
 
index ab84d39ed051634ee3439ed8358f36f4a97d88e2..352f48f513df99661fc13621dfbed667023dd64e 100644 (file)
@@ -2661,6 +2661,46 @@ The :mod:`multiprocessing.dummy` module
 :mod:`multiprocessing.dummy` replicates the API of :mod:`multiprocessing` but is
 no more than a wrapper around the :mod:`threading` module.
 
+.. currentmodule:: multiprocessing.pool
+
+In particular, the ``Pool`` function provided by :mod:`multiprocessing.dummy`
+returns an instance of :class:`ThreadPool`, which is a subclass of
+:class:`Pool` that supports all the same method calls but uses a pool of
+worker threads rather than worker processes.
+
+
+.. class:: ThreadPool([processes[, initializer[, initargs]]])
+
+   A thread pool object which controls a pool of worker threads to which jobs
+   can be submitted.  :class:`ThreadPool` instances are fully interface
+   compatible with :class:`Pool` instances, and their resources must also be
+   properly managed, either by using the pool as a context manager or by
+   calling :meth:`~multiprocessing.pool.Pool.close` and
+   :meth:`~multiprocessing.pool.Pool.terminate` manually.
+
+   *processes* is the number of worker threads to use.  If *processes* is
+   ``None`` then the number returned by :func:`os.cpu_count` is used.
+
+   If *initializer* is not ``None`` then each worker process will call
+   ``initializer(*initargs)`` when it starts.
+
+   Unlike :class:`Pool`, *maxtasksperchild* and *context* cannot be provided.
+
+    .. note::
+
+        A :class:`ThreadPool` shares the same interface as :class:`Pool`, which
+        is designed around a pool of processes and predates the introduction of
+        the :class:`concurrent.futures` module.  As such, it inherits some
+        operations that don't make sense for a pool backed by threads, and it
+        has its own type for representing the status of asynchronous jobs,
+        :class:`AsyncResult`, that is not understood by any other libraries.
+
+        Users should generally prefer to use
+        :class:`concurrent.futures.ThreadPoolExecutor`, which has a simpler
+        interface that was designed around threads from the start, and which
+        returns :class:`concurrent.futures.Future` instances that are
+        compatible with many other libraries, including :mod:`asyncio`.
+
 
 .. _multiprocessing-programming:
 
index 6e287abb6f78aa5f4883c8bf25e1e2b07aee0880..9d206f46aebeb2515d3bb1f3e34619ba50c4a7a0 100644 (file)
@@ -1869,7 +1869,7 @@ features:
       Accepts a :term:`path-like object`.
 
 
-.. function:: lstat(path, \*, dir_fd=None)
+.. function:: lstat(path, *, dir_fd=None)
 
    Perform the equivalent of an :c:func:`lstat` system call on the given path.
    Similar to :func:`~os.stat`, but does not follow symbolic links. Return a
@@ -2376,7 +2376,7 @@ features:
       On the first, uncached call, a system call is required on Windows but
       not on Unix.
 
-   .. method:: is_dir(\*, follow_symlinks=True)
+   .. method:: is_dir(*, follow_symlinks=True)
 
       Return ``True`` if this entry is a directory or a symbolic link pointing
       to a directory; return ``False`` if the entry is or points to any other
@@ -2400,7 +2400,7 @@ features:
       This method can raise :exc:`OSError`, such as :exc:`PermissionError`,
       but :exc:`FileNotFoundError` is caught and not raised.
 
-   .. method:: is_file(\*, follow_symlinks=True)
+   .. method:: is_file(*, follow_symlinks=True)
 
       Return ``True`` if this entry is a file or a symbolic link pointing to a
       file; return ``False`` if the entry is or points to a directory or other
@@ -2430,7 +2430,7 @@ features:
       This method can raise :exc:`OSError`, such as :exc:`PermissionError`,
       but :exc:`FileNotFoundError` is caught and not raised.
 
-   .. method:: stat(\*, follow_symlinks=True)
+   .. method:: stat(*, follow_symlinks=True)
 
       Return a :class:`stat_result` object for this entry. This method
       follows symbolic links by default; to stat a symbolic link add the
@@ -2462,7 +2462,7 @@ features:
       for :class:`bytes` paths on Windows.
 
 
-.. function:: stat(path, \*, dir_fd=None, follow_symlinks=True)
+.. function:: stat(path, *, dir_fd=None, follow_symlinks=True)
 
    Get the status of a file or a file descriptor. Perform the equivalent of a
    :c:func:`stat` system call on the given path. *path* may be specified as
index b7c34527719486ccf839da564d403409dde77ab7..be48561ed10ac8024077e8f66d2f75bcfa469eac 100644 (file)
@@ -213,7 +213,7 @@ The :mod:`pickle` module provides the following constants:
 The :mod:`pickle` module provides the following functions to make the pickling
 process more convenient:
 
-.. function:: dump(obj, file, protocol=None, \*, fix_imports=True, buffer_callback=None)
+.. function:: dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None)
 
    Write the pickled representation of the object *obj* to the open
    :term:`file object` *file*.  This is equivalent to
@@ -225,7 +225,7 @@ process more convenient:
    .. versionchanged:: 3.8
       The *buffer_callback* argument was added.
 
-.. function:: dumps(obj, protocol=None, \*, fix_imports=True, buffer_callback=None)
+.. function:: dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None)
 
    Return the pickled representation of the object *obj* as a :class:`bytes` object,
    instead of writing it to a file.
@@ -236,7 +236,7 @@ process more convenient:
    .. versionchanged:: 3.8
       The *buffer_callback* argument was added.
 
-.. function:: load(file, \*, fix_imports=True, encoding="ASCII", errors="strict", buffers=None)
+.. function:: load(file, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None)
 
    Read the pickled representation of an object from the open :term:`file object`
    *file* and return the reconstituted object hierarchy specified therein.
@@ -252,7 +252,7 @@ process more convenient:
    .. versionchanged:: 3.8
       The *buffers* argument was added.
 
-.. function:: loads(data, /, \*, fix_imports=True, encoding="ASCII", errors="strict", buffers=None)
+.. function:: loads(data, /, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None)
 
    Return the reconstituted object hierarchy of the pickled representation
    *data* of an object. *data* must be a :term:`bytes-like object`.
@@ -296,7 +296,7 @@ The :mod:`pickle` module defines three exceptions:
 The :mod:`pickle` module exports three classes, :class:`Pickler`,
 :class:`Unpickler` and :class:`PickleBuffer`:
 
-.. class:: Pickler(file, protocol=None, \*, fix_imports=True, buffer_callback=None)
+.. class:: Pickler(file, protocol=None, *, fix_imports=True, buffer_callback=None)
 
    This takes a binary file for writing a pickle data stream.
 
@@ -391,7 +391,7 @@ The :mod:`pickle` module exports three classes, :class:`Pickler`,
       Use :func:`pickletools.optimize` if you need more compact pickles.
 
 
-.. class:: Unpickler(file, \*, fix_imports=True, encoding="ASCII", errors="strict", buffers=None)
+.. class:: Unpickler(file, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None)
 
    This takes a binary file for reading a pickle data stream.
 
index 6def72b3736b91d6290a054d0f0f2922ed824758..ce6d4a85bf5e9d2668d3afd92219de729360acb9 100644 (file)
@@ -52,7 +52,7 @@ or :class:`datetime.datetime` objects.
 
 This module defines the following functions:
 
-.. function:: load(fp, \*, fmt=None, dict_type=dict)
+.. function:: load(fp, *, fmt=None, dict_type=dict)
 
    Read a plist file. *fp* should be a readable and binary file object.
    Return the unpacked root object (which usually is a
@@ -80,7 +80,7 @@ This module defines the following functions:
    .. versionadded:: 3.4
 
 
-.. function:: loads(data, \*, fmt=None, dict_type=dict)
+.. function:: loads(data, *, fmt=None, dict_type=dict)
 
    Load a plist from a bytes object. See :func:`load` for an explanation of
    the keyword arguments.
@@ -88,7 +88,7 @@ This module defines the following functions:
    .. versionadded:: 3.4
 
 
-.. function:: dump(value, fp, \*, fmt=FMT_XML, sort_keys=True, skipkeys=False)
+.. function:: dump(value, fp, *, fmt=FMT_XML, sort_keys=True, skipkeys=False)
 
    Write *value* to a plist file. *Fp* should be a writable, binary
    file object.
@@ -116,7 +116,7 @@ This module defines the following functions:
    .. versionadded:: 3.4
 
 
-.. function:: dumps(value, \*, fmt=FMT_XML, sort_keys=True, skipkeys=False)
+.. function:: dumps(value, *, fmt=FMT_XML, sort_keys=True, skipkeys=False)
 
    Return *value* as a plist-formatted bytes object. See
    the documentation for :func:`dump` for an explanation of the keyword
index 34525a96f55c43682a770b601896d82edc59afc3..774d46d0e9624781588efde530aa880c628b1faa 100644 (file)
@@ -525,16 +525,16 @@ Analysis of the profiler data is done using the :class:`~pstats.Stats` class.
       ordering are identical to the :meth:`~pstats.Stats.print_callers` method.
 
 
-    .. method:: get_stats_profile()
+   .. method:: get_stats_profile()
 
       This method returns an instance of StatsProfile, which contains a mapping
       of function names to instances of FunctionProfile. Each FunctionProfile
       instance holds information related to the function's profile such as how
       long the function took to run, how many times it was called, etc...
 
-       .. versionadded:: 3.9
-          Added the following dataclasses: StatsProfile, FunctionProfile.
-          Added the following function: get_stats_profile.
+      .. versionadded:: 3.9
+         Added the following dataclasses: StatsProfile, FunctionProfile.
+         Added the following function: get_stats_profile.
 
 .. _deterministic-profiling:
 
index e43b9aecd86835a212b9bfa2367c4bc388f149d5..034e579315de00f9d6516534b46fb583f8ddb87e 100644 (file)
@@ -665,14 +665,14 @@ The ``errors`` module has the following attributes:
 
 .. data:: codes
 
-   A dictionary mapping numeric error codes to their string descriptions.
+   A dictionary mapping string descriptions to their error codes.
 
    .. versionadded:: 3.2
 
 
 .. data:: messages
 
-   A dictionary mapping string descriptions to their error codes.
+   A dictionary mapping numeric error codes to their string descriptions.
 
    .. versionadded:: 3.2
 
index 8154dfc18ccc6db63d48f84082e4d0e203a127c3..0e703251259aa756ebcf5c665e03f7fb59b52f84 100644 (file)
@@ -142,10 +142,11 @@ Functions for integers
 
 .. function:: getrandbits(k)
 
-   Returns a Python integer with *k* random bits. This method is supplied with
-   the MersenneTwister generator and some other generators may also provide it
-   as an optional part of the API. When available, :meth:`getrandbits` enables
-   :meth:`randrange` to handle arbitrarily large ranges.
+   Returns a non-negative Python integer with *k* random bits. This method
+   is supplied with the MersenneTwister generator and some other generators
+   may also provide it as an optional part of the API. When available,
+   :meth:`getrandbits` enables :meth:`randrange` to handle arbitrarily large
+   ranges.
 
    .. versionchanged:: 3.9
       This method now accepts zero for *k*.
index 3f5122760ee16f116adea666f3908375a395a3d9..d5080da15bba41b3c6d2eb996b9871bd38fcd55a 100644 (file)
@@ -218,7 +218,7 @@ Directory and files operations
       copy the file more efficiently. See
       :ref:`shutil-platform-dependent-efficient-copy-operations` section.
 
-.. function:: ignore_patterns(\*patterns)
+.. function:: ignore_patterns(*patterns)
 
    This factory function creates a function that can be used as a callable for
    :func:`copytree`\'s *ignore* argument, ignoring files and directories that
@@ -443,8 +443,9 @@ Directory and files operations
 Platform-dependent efficient copy operations
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Starting from Python 3.8 all functions involving a file copy (:func:`copyfile`,
-:func:`copy`, :func:`copy2`, :func:`copytree`, and :func:`move`) may use
+Starting from Python 3.8, all functions involving a file copy
+(:func:`copyfile`, :func:`~shutil.copy`, :func:`copy2`,
+:func:`copytree`, and :func:`move`) may use
 platform-specific "fast-copy" syscalls in order to copy the file more
 efficiently (see :issue:`33671`).
 "fast-copy" means that the copying operation occurs within the kernel, avoiding
index faf8a76251420e27d791184ba3aa403640f1411b..2fc170a0bc0bd30d2fd17ca387b382fd1dc759e8 100755 (executable)
@@ -56,12 +56,12 @@ created.  Socket addresses are represented as follows:
   bytes-like object can be used for either type of address when
   passing it as an argument.
 
-   .. versionchanged:: 3.3
-      Previously, :const:`AF_UNIX` socket paths were assumed to use UTF-8
-      encoding.
+  .. versionchanged:: 3.3
+     Previously, :const:`AF_UNIX` socket paths were assumed to use UTF-8
+     encoding.
 
-   .. versionchanged:: 3.5
-      Writable :term:`bytes-like object` is now accepted.
+  .. versionchanged:: 3.5
+     Writable :term:`bytes-like object` is now accepted.
 
 .. _host_port:
 
index ccb82278bdaa13368f30bc78ed6fce5efd483cc6..2e2e5e9cdae377c4a637d46447f4957dbea2ad78 100644 (file)
@@ -99,10 +99,6 @@ This example uses the iterator form::
 
 .. seealso::
 
-   https://github.com/ghaering/pysqlite
-      The pysqlite web page -- sqlite3 is developed externally under the name
-      "pysqlite".
-
    https://www.sqlite.org
       The SQLite web page; the documentation describes the syntax and the
       available data types for the supported SQL dialect.
@@ -197,7 +193,9 @@ Module functions and constants
 
    *detect_types* defaults to 0 (i. e. off, no type detection), you can set it to
    any combination of :const:`PARSE_DECLTYPES` and :const:`PARSE_COLNAMES` to turn
-   type detection on.
+   type detection on. Due to SQLite behaviour, types can't be detected for generated
+   fields (for example ``max(data)``), even when *detect_types* parameter is set. In
+   such case, the returned type is :class:`str`.
 
    By default, *check_same_thread* is :const:`True` and only the creating thread may
    use the connection. If set :const:`False`, the returned connection may be shared
@@ -543,7 +541,7 @@ Connection Objects
          con.close()
 
 
-   .. method:: backup(target, *, pages=0, progress=None, name="main", sleep=0.250)
+   .. method:: backup(target, *, pages=-1, progress=None, name="main", sleep=0.250)
 
       This method makes a backup of a SQLite database even while it's being accessed
       by other clients, or concurrently by the same connection.  The copy will be
@@ -1091,19 +1089,6 @@ committed:
 .. literalinclude:: ../includes/sqlite3/ctx_manager.py
 
 
-Common issues
--------------
-
-Multithreading
-^^^^^^^^^^^^^^
-
-Older SQLite versions had issues with sharing connections between threads.
-That's why the Python module disallows sharing connections and cursors between
-threads. If you still try to do so, you will get an exception at runtime.
-
-The only exception is calling the :meth:`~Connection.interrupt` method, which
-only makes sense to call from a different thread.
-
 .. rubric:: Footnotes
 
 .. [#f1] The sqlite3 module is not built with loadable extension support by
index a48cfa1327791027f80cfed07633faa6916cae60..0667a60157616575caba643493f523f0415fa48e 100644 (file)
@@ -478,7 +478,7 @@ class`. In addition, it provides a few more methods:
 
     .. versionadded:: 3.1
 
-.. method:: int.to_bytes(length, byteorder, \*, signed=False)
+.. method:: int.to_bytes(length, byteorder, *, signed=False)
 
     Return an array of bytes representing an integer.
 
@@ -510,7 +510,7 @@ class`. In addition, it provides a few more methods:
 
     .. versionadded:: 3.2
 
-.. classmethod:: int.from_bytes(bytes, byteorder, \*, signed=False)
+.. classmethod:: int.from_bytes(bytes, byteorder, *, signed=False)
 
     Return the integer represented by the given array of bytes.
 
@@ -5196,8 +5196,8 @@ types, where they are relevant.  Some of these are not reported by the
 .. method:: class.__subclasses__
 
    Each class keeps a list of weak references to its immediate subclasses.  This
-   method returns a list of all those references still alive.
-   Example::
+   method returns a list of all those references still alive.  The list is in
+   definition order.  Example::
 
       >>> int.__subclasses__()
       [<class 'bool'>]
index 5542e9b727a6b8d8995dd8826509e64f37e96193..54786d0c2ab0dfb3247f2ea406d3793f0b9a06c6 100644 (file)
@@ -514,6 +514,8 @@ The available presentation types for :class:`float` and
    |         | this rounds the number to ``p`` significant digits and   |
    |         | then formats the result in either fixed-point format     |
    |         | or in scientific notation, depending on its magnitude.   |
+   |         | A precision of ``0`` is treated as equivalent to a       |
+   |         | precision of ``1``.                                      |
    |         |                                                          |
    |         | The precise rules are as follows: suppose that the       |
    |         | result formatted with presentation type ``'e'`` and      |
@@ -528,16 +530,19 @@ The available presentation types for :class:`float` and
    |         | removed if there are no remaining digits following it,   |
    |         | unless the ``'#'`` option is used.                       |
    |         |                                                          |
+   |         | With no precision given, uses a precision of ``6``       |
+   |         | significant digits for :class:`float`. For               |
+   |         | :class:`~decimal.Decimal`, the coefficient of the result |
+   |         | is formed from the coefficient digits of the value;      |
+   |         | scientific notation is used for values smaller than      |
+   |         | ``1e-6`` in absolute value and values where the place    |
+   |         | value of the least significant digit is larger than 1,   |
+   |         | and fixed-point notation is used otherwise.              |
+   |         |                                                          |
    |         | Positive and negative infinity, positive and negative    |
    |         | zero, and nans, are formatted as ``inf``, ``-inf``,      |
    |         | ``0``, ``-0`` and ``nan`` respectively, regardless of    |
    |         | the precision.                                           |
-   |         |                                                          |
-   |         | A precision of ``0`` is treated as equivalent to a       |
-   |         | precision of ``1``. With no precision given, uses a      |
-   |         | precision of ``6`` significant digits for                |
-   |         | :class:`float`, and shows all coefficient digits         |
-   |         | for :class:`~decimal.Decimal`.                           |
    +---------+----------------------------------------------------------+
    | ``'G'`` | General format. Same as ``'g'`` except switches to       |
    |         | ``'E'`` if the number gets too large. The                |
@@ -550,12 +555,18 @@ The available presentation types for :class:`float` and
    | ``'%'`` | Percentage. Multiplies the number by 100 and displays    |
    |         | in fixed (``'f'``) format, followed by a percent sign.   |
    +---------+----------------------------------------------------------+
-   | None    | Similar to ``'g'``, except that fixed-point notation,    |
-   |         | when used, has at least one digit past the decimal point.|
-   |         | The default precision is as high as needed to represent  |
-   |         | the particular value. The overall effect is to match the |
-   |         | output of :func:`str` as altered by the other format     |
-   |         | modifiers.                                               |
+   | None    | For :class:`float` this is the same as ``'g'``, except   |
+   |         | that when fixed-point notation is used to format the     |
+   |         | result, it always includes at least one digit past the   |
+   |         | decimal point. The precision used is as large as needed  |
+   |         | to represent the given value faithfully.                 |
+   |         |                                                          |
+   |         | For :class:`~decimal.Decimal`, this is the same as       |
+   |         | either ``'g'`` or ``'G'`` depending on the value of      |
+   |         | ``context.capitals`` for the current decimal context.    |
+   |         |                                                          |
+   |         | The overall effect is to match the output of :func:`str` |
+   |         | as altered by the other format modifiers.                |
    +---------+----------------------------------------------------------+
 
 
index e37cc980e97575070d6ab9803a5bd487b2dee063..3150aa60700ee709f4490bac39f0ee5600c86064 100644 (file)
@@ -339,7 +339,7 @@ functions.
                  stderr=None, preexec_fn=None, close_fds=True, shell=False, \
                  cwd=None, env=None, universal_newlines=None, \
                  startupinfo=None, creationflags=0, restore_signals=True, \
-                 start_new_session=False, pass_fds=(), \*, group=None, \
+                 start_new_session=False, pass_fds=(), *, group=None, \
                  extra_groups=None, user=None, umask=-1, \
                  encoding=None, errors=None, text=None)
 
@@ -1163,8 +1163,9 @@ calls these functions.
    The arguments shown above are merely some common ones.
    The full function signature is largely the same as that of :func:`run` -
    most arguments are passed directly through to that interface.
-   However, explicitly passing ``input=None`` to inherit the parent's
-   standard input file handle is not supported.
+   One API deviation from :func:`run` behavior exists: passing ``input=None``
+   will behave the same as ``input=b''`` (or ``input=''``, depending on other
+   arguments) rather than using the parent's standard input file handle.
 
    By default, this function will return the data as encoded bytes. The actual
    encoding of the output data may depend on the command being invoked, so the
index 3efdecb5af7102f19bff70c342c38c6b9c0f9b3e..e364232247c2004fda1b5534c9658c5e985e1e96 100644 (file)
@@ -156,6 +156,12 @@ Examining Symbol Tables
 
       Return ``True`` if the symbol is local to its block.
 
+   .. method:: is_annotated()
+
+      Return ``True`` if the symbol is annotated.
+
+      .. versionadded:: 3.6
+
    .. method:: is_free()
 
       Return ``True`` if the symbol is referenced in its block, but not assigned
index 78a1dfce9ae05cd799e1c4b2a30f00384f7d0a29..c9306e9bf9de162c23f6686b951fbe178e000229 100644 (file)
@@ -32,7 +32,7 @@ can be accessed using :func:`get_config_vars` or :func:`get_config_var`.
 
 Notice that on Windows, it's a much smaller set.
 
-.. function:: get_config_vars(\*args)
+.. function:: get_config_vars(*args)
 
    With no arguments, return a dictionary of all configuration variables
    relevant for the current platform.
index 7a114fdf5d54b1ccb6b933e70fdc9de03236bd3d..13088a10d77c57603c8c3f882df5164f04f84ded 100644 (file)
@@ -37,7 +37,7 @@ Some facts and figures:
    Added support for :mod:`lzma` compression.
 
 
-.. function:: open(name=None, mode='r', fileobj=None, bufsize=10240, \*\*kwargs)
+.. function:: open(name=None, mode='r', fileobj=None, bufsize=10240, **kwargs)
 
    Return a :class:`TarFile` object for the pathname *name*. For detailed
    information on :class:`TarFile` objects and the keyword arguments that are
index e24f69cda8c868f38c3bf2ac4a2c18c079107c90..bb1bd29bf698ed690aa362d77f491b62dac9ba9b 100644 (file)
@@ -546,7 +546,7 @@ The :mod:`test.support` module defines the following functions:
    Define match test with regular expression *patterns*.
 
 
-.. function:: run_unittest(\*classes)
+.. function:: run_unittest(*classes)
 
    Execute :class:`unittest.TestCase` subclasses passed to the function. The
    function scans the classes for methods starting with the prefix ``test_``
index c2732d900bc138a0616c4b49cd6d4a8b9fc50691..40cf198f1287d78f378d454e5f9560b382c33b4a 100644 (file)
@@ -153,47 +153,47 @@ Programmatic Interface
    count information.  *timing* enables a timestamp relative to when tracing was
    started to be displayed.
 
-    .. method:: run(cmd)
+   .. method:: run(cmd)
 
-       Execute the command and gather statistics from the execution with
-       the current tracing parameters.  *cmd* must be a string or code object,
-       suitable for passing into :func:`exec`.
+      Execute the command and gather statistics from the execution with
+      the current tracing parameters.  *cmd* must be a string or code object,
+      suitable for passing into :func:`exec`.
 
-    .. method:: runctx(cmd, globals=None, locals=None)
+   .. method:: runctx(cmd, globals=None, locals=None)
 
-       Execute the command and gather statistics from the execution with the
-       current tracing parameters, in the defined global and local
-       environments.  If not defined, *globals* and *locals* default to empty
-       dictionaries.
+      Execute the command and gather statistics from the execution with the
+      current tracing parameters, in the defined global and local
+      environments.  If not defined, *globals* and *locals* default to empty
+      dictionaries.
 
-    .. method:: runfunc(func, /, *args, **kwds)
+   .. method:: runfunc(func, /, *args, **kwds)
 
-       Call *func* with the given arguments under control of the :class:`Trace`
-       object with the current tracing parameters.
+      Call *func* with the given arguments under control of the :class:`Trace`
+      object with the current tracing parameters.
 
-    .. method:: results()
+   .. method:: results()
 
-       Return a :class:`CoverageResults` object that contains the cumulative
-       results of all previous calls to ``run``, ``runctx`` and ``runfunc``
-       for the given :class:`Trace` instance.  Does not reset the accumulated
-       trace results.
+      Return a :class:`CoverageResults` object that contains the cumulative
+      results of all previous calls to ``run``, ``runctx`` and ``runfunc``
+      for the given :class:`Trace` instance.  Does not reset the accumulated
+      trace results.
 
 .. class:: CoverageResults
 
    A container for coverage results, created by :meth:`Trace.results`.  Should
    not be created directly by the user.
 
-    .. method:: update(other)
+   .. method:: update(other)
 
-       Merge in data from another :class:`CoverageResults` object.
+      Merge in data from another :class:`CoverageResults` object.
 
-    .. method:: write_results(show_missing=True, summary=False, coverdir=None)
+   .. method:: write_results(show_missing=True, summary=False, coverdir=None)
 
-       Write coverage results.  Set *show_missing* to show lines that had no
-       hits.  Set *summary* to include in the output the coverage summary per
-       module.  *coverdir* specifies the directory into which the coverage
-       result files will be output.  If ``None``, the results for each source
-       file are placed in its directory.
+      Write coverage results.  Set *show_missing* to show lines that had no
+      hits.  Set *summary* to include in the output the coverage summary per
+      module.  *coverdir* specifies the directory into which the coverage
+      result files will be output.  If ``None``, the results for each source
+      file are placed in its directory.
 
 A simple example demonstrating the use of the programmatic interface::
 
index d3487537df99a9546eeaf39fde6b382519ff9985..6a9d61916ad1a584cc069ba29f3d7d50dbd885ea 100644 (file)
@@ -662,7 +662,7 @@ Tell Turtle's state
 
    Return the angle between the line from turtle position to position specified
    by (x,y), the vector or the other turtle.  This depends on the turtle's start
-   orientation which depends on the mode - "standard"/"world" or "logo").
+   orientation which depends on the mode - "standard"/"world" or "logo".
 
    .. doctest::
       :skipif: _tkinter is None
@@ -913,8 +913,8 @@ Color control
       Set pencolor to the RGB color represented by *r*, *g*, and *b*.  Each of
       *r*, *g*, and *b* must be in the range 0..colormode.
 
-    If turtleshape is a polygon, the outline of that polygon is drawn with the
-    newly set pencolor.
+   If turtleshape is a polygon, the outline of that polygon is drawn with the
+   newly set pencolor.
 
    .. doctest::
       :skipif: _tkinter is None
@@ -962,8 +962,8 @@ Color control
       Set fillcolor to the RGB color represented by *r*, *g*, and *b*.  Each of
       *r*, *g*, and *b* must be in the range 0..colormode.
 
-    If turtleshape is a polygon, the interior of that polygon is drawn
-    with the newly set fillcolor.
+   If turtleshape is a polygon, the interior of that polygon is drawn
+   with the newly set fillcolor.
 
    .. doctest::
       :skipif: _tkinter is None
@@ -1001,8 +1001,8 @@ Color control
       Equivalent to ``pencolor(colorstring1)`` and ``fillcolor(colorstring2)``
       and analogously if the other input format is used.
 
-    If turtleshape is a polygon, outline and interior of that polygon is drawn
-    with the newly set colors.
+   If turtleshape is a polygon, outline and interior of that polygon is drawn
+   with the newly set colors.
 
    .. doctest::
       :skipif: _tkinter is None
@@ -1105,7 +1105,7 @@ More drawing control
    :param font: a triple (fontname, fontsize, fonttype)
 
    Write text - the string representation of *arg* - at the current turtle
-   position according to *align* ("left", "center" or right") and with the given
+   position according to *align* ("left", "center" or "right") and with the given
    font.  If *move* is true, the pen is moved to the bottom-right corner of the
    text.  By default, *move* is ``False``.
 
@@ -1192,7 +1192,7 @@ Appearance
      :func:`shapesize`.
    - "noresize": no adaption of the turtle's appearance takes place.
 
-   resizemode("user") is called by :func:`shapesize` when used with arguments.
+   ``resizemode("user")`` is called by :func:`shapesize` when used with arguments.
 
    .. doctest::
       :skipif: _tkinter is None
@@ -1330,7 +1330,7 @@ Appearance
    matrix as a tuple of 4 elements.
    Otherwise set the given elements and transform the turtleshape
    according to the matrix consisting of first row t11, t12 and
-   second row t21, 22. The determinant t11 * t22 - t12 * t21 must not be
+   second row t21, t22. The determinant t11 * t22 - t12 * t21 must not be
    zero, otherwise an error is raised.
    Modify stretchfactor, shearfactor and tiltangle according to the
    given matrix.
@@ -1513,7 +1513,7 @@ Special Turtle methods
 
    :param size: an integer or ``None``
 
-   Set or disable undobuffer.  If *size* is an integer an empty undobuffer of
+   Set or disable undobuffer.  If *size* is an integer, an empty undobuffer of
    given size is installed.  *size* gives the maximum number of turtle actions
    that can be undone by the :func:`undo` method/function.  If *size* is
    ``None``, the undobuffer is disabled.
@@ -1821,7 +1821,7 @@ Using screen events
    existing bindings are removed.
 
    Example for a TurtleScreen instance named ``screen`` and a Turtle instance
-   named turtle:
+   named ``turtle``:
 
    .. doctest::
       :skipif: _tkinter is None
@@ -2048,7 +2048,7 @@ Methods specific to Screen, not inherited from TurtleScreen
 
 .. function:: exitonclick()
 
-   Bind bye() method to mouse clicks on the Screen.
+   Bind ``bye()`` method to mouse clicks on the Screen.
 
 
    If the value "using_IDLE" in the configuration dictionary is ``False``
index 0fe3822fa542e333930dffd608b9a8a378bbbe8a..d83d9667ba3a7ca761bde03060a611ee552733e7 100644 (file)
@@ -260,6 +260,9 @@ Standard names are defined for the following types:
 
    .. versionadded:: 3.9
 
+   .. versionchanged:: 3.9.2
+      This type can now be subclassed.
+
 
 .. class:: TracebackType(tb_next, tb_frame, tb_lasti, tb_lineno)
 
index af2cafb8b9969cee5a35bf380dab4bfebe59d044..688564f1d24f5199579232869b4a27d5bb5a7a3f 100644 (file)
@@ -1714,6 +1714,8 @@ Introspection helpers
    ``list[ForwardRef("SomeClass")]``.  This class should not be instantiated by
    a user, but may be used by introspection tools.
 
+   .. versionadded:: 3.7.4
+
 Constant
 --------
 
index 536cf952bda43434e1ef8e0147e3cf6352d49f66..38e2986334c807aa755849dc167f9a3d1b53f5e3 100644 (file)
@@ -165,7 +165,7 @@ or on combining URL components into a URL string.
       now raise :exc:`ValueError`.
 
 
-.. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None)
+.. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None, separator='&')
 
    Parse a query string given as a string argument (data of type
    :mimetype:`application/x-www-form-urlencoded`).  Data are returned as a
@@ -190,6 +190,9 @@ or on combining URL components into a URL string.
    read. If set, then throws a :exc:`ValueError` if there are more than
    *max_num_fields* fields read.
 
+   The optional argument *separator* is the symbol to use for separating the
+   query arguments. It defaults to ``&``.
+
    Use the :func:`urllib.parse.urlencode` function (with the ``doseq``
    parameter set to ``True``) to convert such dictionaries into query
    strings.
@@ -201,8 +204,14 @@ or on combining URL components into a URL string.
    .. versionchanged:: 3.8
       Added *max_num_fields* parameter.
 
+   .. versionchanged:: 3.9.2
+      Added *separator* parameter with the default value of ``&``. Python
+      versions earlier than Python 3.9.2 allowed using both ``;`` and ``&`` as
+      query parameter separator. This has been changed to allow only a single
+      separator key, with ``&`` as the default separator.
+
 
-.. function:: parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None)
+.. function:: parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None, separator='&')
 
    Parse a query string given as a string argument (data of type
    :mimetype:`application/x-www-form-urlencoded`).  Data are returned as a list of
@@ -226,6 +235,8 @@ or on combining URL components into a URL string.
    read. If set, then throws a :exc:`ValueError` if there are more than
    *max_num_fields* fields read.
 
+   The optional argument *separator* is the symbol to use for separating the query arguments. It defaults to ``&``.
+
    Use the :func:`urllib.parse.urlencode` function to convert such lists of pairs into
    query strings.
 
@@ -235,6 +246,12 @@ or on combining URL components into a URL string.
    .. versionchanged:: 3.8
       Added *max_num_fields* parameter.
 
+   .. versionchanged:: 3.9.2
+      Added *separator* parameter with the default value of ``&``. Python
+      versions earlier than Python 3.9.2 allowed using both ``;`` and ``&`` as
+      query parameter separator. This has been changed to allow only a single
+      separator key, with ``&`` as the default separator.
+
 
 .. function:: urlunparse(parts)
 
index a481a3509d4ec83770ea3cfe8679f6859a6d8d8e..9c1743cad23cb780529479b2056ce327499e800a 100644 (file)
@@ -491,7 +491,7 @@ Available Functions
 Available Context Managers
 --------------------------
 
-.. class:: catch_warnings(\*, record=False, module=None)
+.. class:: catch_warnings(*, record=False, module=None)
 
     A context manager that copies and, upon exit, restores the warnings filter
     and the :func:`showwarning` function.
index dccb7db27e90cc0df30976b213af0d816dc8f7e6..487856a3ac6c60050e7e4e320333d935f3d88522 100644 (file)
@@ -791,7 +791,7 @@ integer handle, and also disconnect the Windows handle from the handle object.
 
 
 .. method:: PyHKEY.__enter__()
-            PyHKEY.__exit__(\*exc_info)
+            PyHKEY.__exit__(*exc_info)
 
    The HKEY object implements :meth:`~object.__enter__` and
    :meth:`~object.__exit__` and thus supports the context protocol for the
index 4030825bbd28ee045eee2dadf80881aad5b96b6b..f487d98b2b43a3b596c80158790c70828ec01908 100644 (file)
@@ -100,7 +100,7 @@ PSF LICENSE AGREEMENT FOR PYTHON |release|
       analyze, test, perform and/or display publicly, prepare derivative works,
       distribute, and otherwise use Python |release| alone or in any derivative
       version, provided, however, that PSF's License Agreement and PSF's notice of
-      copyright, i.e., "Copyright © 2001-2020 Python Software Foundation; All Rights
+      copyright, i.e., "Copyright © 2001-2021 Python Software Foundation; All Rights
       Reserved" are retained in Python |release| alone or in any derivative version
       prepared by Licensee.
 
index b4e06e5b10d5af219f9477803ac3a8ca69351e07..7e666351b1b31e2750cafa5533b86c7e6a9a09fd 100644 (file)
@@ -254,7 +254,8 @@ present, must be last; it matches any exception.  For an except clause with an
 expression, that expression is evaluated, and the clause matches the exception
 if the resulting object is "compatible" with the exception.  An object is
 compatible with an exception if it is the class or a base class of the exception
-object or a tuple containing an item compatible with the exception.
+object, or a tuple containing an item that is the class or a base class of
+the exception object.
 
 If no except clause matches the exception, the search for an exception handler
 continues in the surrounding code and on the invocation stack.  [#]_
@@ -799,12 +800,12 @@ The :keyword:`!async for` statement
 .. productionlist:: python-grammar
    async_for_stmt: "async" `for_stmt`
 
-An :term:`asynchronous iterable` is able to call asynchronous code in its
-*iter* implementation, and :term:`asynchronous iterator` can call asynchronous
-code in its *next* method.
+An :term:`asynchronous iterable` provides an ``__aiter__`` method that directly
+returns an :term:`asynchronous iterator`, which can call asynchronous code in
+its ``__anext__`` method.
 
 The ``async for`` statement allows convenient iteration over asynchronous
-iterators.
+iterables.
 
 The following code::
 
index 89063876ccc9ed918774d371c4352cc47082a969..3b3bd5524ec5dcea852bf06622365c2acf3a459b 100644 (file)
@@ -217,7 +217,6 @@ Ellipsis
       There are two types of integers:
 
       Integers (:class:`int`)
-
          These represent numbers in an unlimited range, subject to available (virtual)
          memory only.  For the purpose of shift and mask operations, a binary
          representation is assumed, and negative numbers are represented in a variant of
index c9777c6be9334d03cb282eb49e2b454b698d18ba..9f0c42a9bb5abc9dc21ee7b9389ec6c7b5c15f2c 100644 (file)
@@ -171,6 +171,7 @@ library/ipaddress,,:db00,2001:db00::0/ffff:ff00::
 library/ipaddress,,::,2001:db00::0/ffff:ff00::
 library/itertools,,:step,elements from seq[start:stop:step]
 library/itertools,,:stop,elements from seq[start:stop:step]
+library/itertools,,::,kernel = tuple(kernel)[::-1]
 library/logging.handlers,,:port,host:port
 library/mmap,,:i2,obj[i1:i2]
 library/multiprocessing,,`,# Add more tasks using `put()`
index 5e724cd5794ce48a38929aa467998bc5c456c7b3..ddb36f94667d9f5e5d83b302217b91acf33c16b1 100644 (file)
@@ -126,6 +126,10 @@ directory containing the virtual environment):
 |             | PowerShell      | PS C:\\> <venv>\\Scripts\\Activate.ps1  |
 +-------------+-----------------+-----------------------------------------+
 
+When a virtual environment is active, the :envvar:`VIRTUAL_ENV` environment
+variable is set to the path of the virtual environment. This can be used to
+check if one is running inside a virtual environment.
+
 You don't specifically *need* to activate an environment; activation just
 prepends the virtual environment's binary directory to your path, so that
 "python" invokes the virtual environment's Python interpreter and you can run
index d0c342e1dad86811b97eaed19799ebc053dd3f59..4699e37509e6f3c1912e8ea4652eb3f328492aa6 100644 (file)
@@ -339,6 +339,11 @@ full write access to shared locations such as ``TEMP`` and the registry.
 Instead, it will write to a private copy. If your scripts must modify the
 shared locations, you will need to install the full installer.
 
+For more detail on the technical basis for these limitations, please consult
+Microsoft's documentation on packaged full-trust apps, currently available at
+`docs.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-behind-the-scenes
+<https://docs.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-behind-the-scenes>`_
+
 
 .. _windows-nuget:
 
@@ -1150,8 +1155,6 @@ For extension modules, consult :ref:`building-on-windows`.
       MinGW gcc under Windows" or "Installing Python extension with distutils
       and without Microsoft Visual C++" by Sébastien Sauvage, 2003
 
-   `MingW -- Python extensions <http://www.mingw.org/wiki/FAQ#toc14>`_
-
 
 Other Platforms
 ===============
index 85a6657fdfbdacccc870ba0d8a7116322cc6c34a..03a877a3d9178586bafb00767fc242557b9fe2f5 100644 (file)
@@ -2443,3 +2443,16 @@ because of the behavior of the socket option ``SO_REUSEADDR`` in UDP. For more
 details, see the documentation for ``loop.create_datagram_endpoint()``.
 (Contributed by Kyle Stanley, Antoine Pitrou, and Yury Selivanov in
 :issue:`37228`.)
+
+Notable changes in Python 3.6.13
+================================
+
+Earlier Python versions allowed using both ``;`` and ``&`` as
+query parameter separators in :func:`urllib.parse.parse_qs` and
+:func:`urllib.parse.parse_qsl`.  Due to security concerns, and to conform with
+newer W3C recommendations, this has been changed to allow only a single
+separator key, with ``&`` as the default.  This change also affects
+:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected
+functions internally. For more details, please see their respective
+documentation.
+(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.)
index 25b1e1e33e325cf4e2e4faddb41ae4b3e739f176..9204cc7fbf8c47235baeb9d9885488784e491fb9 100644 (file)
@@ -2556,3 +2556,16 @@ because of the behavior of the socket option ``SO_REUSEADDR`` in UDP. For more
 details, see the documentation for ``loop.create_datagram_endpoint()``.
 (Contributed by Kyle Stanley, Antoine Pitrou, and Yury Selivanov in
 :issue:`37228`.)
+
+Notable changes in Python 3.7.10
+================================
+
+Earlier Python versions allowed using both ``;`` and ``&`` as
+query parameter separators in :func:`urllib.parse.parse_qs` and
+:func:`urllib.parse.parse_qsl`.  Due to security concerns, and to conform with
+newer W3C recommendations, this has been changed to allow only a single
+separator key, with ``&`` as the default.  This change also affects
+:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected
+functions internally. For more details, please see their respective
+documentation.
+(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.)
index 0b4820f3333e13a2f5d92c24985bc1103bea7608..dbc3875aae61b3888cc2ecae3eb270d7c96a00d6 100644 (file)
@@ -2234,3 +2234,16 @@ because of the behavior of the socket option ``SO_REUSEADDR`` in UDP. For more
 details, see the documentation for ``loop.create_datagram_endpoint()``.
 (Contributed by Kyle Stanley, Antoine Pitrou, and Yury Selivanov in
 :issue:`37228`.)
+
+Notable changes in Python 3.8.8
+===============================
+
+Earlier Python versions allowed using both ``;`` and ``&`` as
+query parameter separators in :func:`urllib.parse.parse_qs` and
+:func:`urllib.parse.parse_qsl`.  Due to security concerns, and to conform with
+newer W3C recommendations, this has been changed to allow only a single
+separator key, with ``&`` as the default.  This change also affects
+:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected
+functions internally. For more details, please see their respective
+documentation.
+(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.)
index f8f421bdda1c7c6bac32358ccdc29b51ea3e0973..3086930569dc9884886f19f27ab9f9d342e3983f 100644 (file)
@@ -1497,3 +1497,35 @@ functions and options conditionally available based on the operating system
 version in use at runtime ("weaklinking").
 
 (Contributed by Ronald Oussoren and Lawrence D'Anna in :issue:`41100`.)
+
+Notable changes in Python 3.9.2
+===============================
+
+collections.abc
+---------------
+
+:class:`collections.abc.Callable` generic now flattens type parameters, similar
+to what :data:`typing.Callable` currently does.  This means that
+``collections.abc.Callable[[int, str], str]`` will have ``__args__`` of
+``(int, str, str)``; previously this was ``([int, str], str)``.  To allow this
+change, :class:`types.GenericAlias` can now be subclassed, and a subclass will
+be returned when subscripting the :class:`collections.abc.Callable` type.
+Code which accesses the arguments via :func:`typing.get_args` or ``__args__``
+need to account for this change.  A :exc:`DeprecationWarning` may be emitted for
+invalid forms of parameterizing :class:`collections.abc.Callable` which may have
+passed silently in Python 3.9.1.  This :exc:`DeprecationWarning` will
+become a :exc:`TypeError` in Python 3.10.
+(Contributed by Ken Jin in :issue:`42195`.)
+
+urllib.parse
+------------
+
+Earlier Python versions allowed using both ``;`` and ``&`` as
+query parameter separators in :func:`urllib.parse.parse_qs` and
+:func:`urllib.parse.parse_qsl`.  Due to security concerns, and to conform with
+newer W3C recommendations, this has been changed to allow only a single
+separator key, with ``&`` as the default.  This change also affects
+:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected
+functions internally. For more details, please see their respective
+documentation.
+(Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.)
index ce783971968dc52412e55f6153ef463146e07fa3..64e205e7fd815443164764e083926203fd6ac475 100644 (file)
@@ -563,18 +563,23 @@ star_targets[expr_ty]:
     | a=star_target !',' { a }
     | a=star_target b=(',' c=star_target { c })* [','] {
         _Py_Tuple(CHECK(_PyPegen_seq_insert_in_front(p, a, b)), Store, EXTRA) }
-star_targets_seq[asdl_seq*]: a=','.star_target+ [','] { a }
+star_targets_list_seq[asdl_seq*]: a=','.star_target+ [','] { a }
+star_targets_tuple_seq[asdl_seq*]:
+    | a=star_target b=(',' c=star_target { c })+ [','] { _PyPegen_seq_insert_in_front(p, a, b) }
+    | a=star_target ',' { _PyPegen_singleton_seq(p, a) }
 star_target[expr_ty] (memo):
     | '*' a=(!'*' star_target) {
         _Py_Starred(CHECK(_PyPegen_set_expr_context(p, a, Store)), Store, EXTRA) }
+    | target_with_star_atom
+target_with_star_atom[expr_ty] (memo):
     | a=t_primary '.' b=NAME !t_lookahead { _Py_Attribute(a, b->v.Name.id, Store, EXTRA) }
     | a=t_primary '[' b=slices ']' !t_lookahead { _Py_Subscript(a, b, Store, EXTRA) }
     | star_atom
 star_atom[expr_ty]:
     | a=NAME { _PyPegen_set_expr_context(p, a, Store) }
-    | '(' a=star_target ')' { _PyPegen_set_expr_context(p, a, Store) }
-    | '(' a=[star_targets_seq] ')' { _Py_Tuple(a, Store, EXTRA) }
-    | '[' a=[star_targets_seq] ']' { _Py_List(a, Store, EXTRA) }
+    | '(' a=target_with_star_atom ')' { _PyPegen_set_expr_context(p, a, Store) }
+    | '(' a=[star_targets_tuple_seq] ')' { _Py_Tuple(a, Store, EXTRA) }
+    | '[' a=[star_targets_list_seq] ']' { _Py_List(a, Store, EXTRA) }
 
 single_target[expr_ty]:
     | single_subscript_attribute_target
index 7bc80833a746ef00f1e1ae805511489aedc423a3..0f1304d26af335881960445544bd8491f9d810e1 100644 (file)
@@ -67,7 +67,7 @@ PyVectorcall_Function(PyObject *callable)
 {
     PyTypeObject *tp;
     Py_ssize_t offset;
-    vectorcallfunc *ptr;
+    vectorcallfunc ptr;
 
     assert(callable != NULL);
     tp = Py_TYPE(callable);
@@ -77,8 +77,8 @@ PyVectorcall_Function(PyObject *callable)
     assert(PyCallable_Check(callable));
     offset = tp->tp_vectorcall_offset;
     assert(offset > 0);
-    ptr = (vectorcallfunc *)(((char *)callable) + offset);
-    return *ptr;
+    memcpy(&ptr, (char *) callable + offset, sizeof(ptr));
+    return ptr;
 }
 
 /* Call the callable object 'callable' with the "vectorcall" calling
index 1fc732abeb5553cc467ebceba2f71b50e48a2373..17db79cffbc547bdb4a5567219c707aa17dd9e72 100644 (file)
@@ -22,7 +22,7 @@ extern "C" {
 
  */
 #define Py_UNICODE_ISSPACE(ch) \
-    ((ch) < 128U ? _Py_ascii_whitespace[(ch)] : _PyUnicode_IsWhitespace(ch))
+    ((Py_UCS4)(ch) < 128U ? _Py_ascii_whitespace[(ch)] : _PyUnicode_IsWhitespace(ch))
 
 #define Py_UNICODE_ISLOWER(ch) _PyUnicode_IsLowercase(ch)
 #define Py_UNICODE_ISUPPER(ch) _PyUnicode_IsUppercase(ch)
@@ -760,13 +760,6 @@ PyAPI_FUNC(const char *) PyUnicode_AsUTF8AndSize(
 
    Use of this API is DEPRECATED since no size information can be
    extracted from the returned data.
-
-   *** This API is for interpreter INTERNAL USE ONLY and will likely
-   *** be removed or changed for Python 3.1.
-
-   *** If you need to access the Unicode object as UTF-8 bytes string,
-   *** please use PyUnicode_AsUTF8String() instead.
-
 */
 
 PyAPI_FUNC(const char *) PyUnicode_AsUTF8(PyObject *unicode);
index 0b5d280bd4fd4b2187b018040d0a4702b9c04721..a23b2f15f79f9340786be311e5d973b3d1cf35bd 100644 (file)
 /*--start constants--*/
 #define PY_MAJOR_VERSION        3
 #define PY_MINOR_VERSION        9
-#define PY_MICRO_VERSION        1
+#define PY_MICRO_VERSION        2
 #define PY_RELEASE_LEVEL        PY_RELEASE_LEVEL_FINAL
 #define PY_RELEASE_SERIAL       0
 
 /* Version as a string */
-#define PY_VERSION              "3.9.1"
+#define PY_VERSION              "3.9.2"
 /*--end constants--*/
 
 /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
index c5368b3c5edaa08c7db2ca2f30d291127e1839d8..783fcb455eb5289eeb1babca79b99ceb32cdd5bd 100644 (file)
@@ -32,6 +32,8 @@ PyAPI_FUNC(void) _Py_NO_RETURN Py_Exit(int);
 /* Bootstrap __main__ (defined in Modules/main.c) */
 PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv);
 
+PyAPI_FUNC(int) Py_FrozenMain(int argc, char **argv);
+
 PyAPI_FUNC(int) Py_BytesMain(int argc, char **argv);
 
 /* In pathconfig.c */
diff --git a/LICENSE b/LICENSE
index f42f8adbed845d6a8c3cb07b12ffd186f6c23bc4..473861da1be7c5f24f405814ef1370de6ab946c9 100644 (file)
--- a/LICENSE
+++ b/LICENSE
@@ -84,7 +84,7 @@ analyze, test, perform and/or display publicly, prepare derivative works,
 distribute, and otherwise use Python alone or in any derivative version,
 provided, however, that PSF's License Agreement and PSF's notice of copyright,
 i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation;
+2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Python Software Foundation;
 All Rights Reserved" are retained in Python alone or in any derivative version
 prepared by Licensee.
 
index 36cd993000347520be16ee3a2a1eb600cff56a8d..b6ecf8eac6368b8e21c1666516fa04b156d9e73c 100644 (file)
@@ -10,6 +10,10 @@ from abc import ABCMeta, abstractmethod
 import sys
 
 GenericAlias = type(list[int])
+EllipsisType = type(...)
+def _f(): pass
+FunctionType = type(_f)
+del _f
 
 __all__ = ["Awaitable", "Coroutine",
            "AsyncIterable", "AsyncIterator", "AsyncGenerator",
@@ -409,6 +413,86 @@ class Collection(Sized, Iterable, Container):
         return NotImplemented
 
 
+class _CallableGenericAlias(GenericAlias):
+    """ Represent `Callable[argtypes, resulttype]`.
+
+    This sets ``__args__`` to a tuple containing the flattened``argtypes``
+    followed by ``resulttype``.
+
+    Example: ``Callable[[int, str], float]`` sets ``__args__`` to
+    ``(int, str, float)``.
+    """
+
+    __slots__ = ()
+
+    def __new__(cls, origin, args):
+        try:
+            return cls.__create_ga(origin, args)
+        except TypeError as exc:
+            import warnings
+            warnings.warn(f'{str(exc)} '
+                          f'(This will raise a TypeError in Python 3.10.)',
+                          DeprecationWarning)
+            return GenericAlias(origin, args)
+
+    @classmethod
+    def __create_ga(cls, origin, args):
+        if not isinstance(args, tuple) or len(args) != 2:
+            raise TypeError(
+                "Callable must be used as Callable[[arg, ...], result].")
+        t_args, t_result = args
+        if isinstance(t_args, (list, tuple)):
+            ga_args = tuple(t_args) + (t_result,)
+        # This relaxes what t_args can be on purpose to allow things like
+        # PEP 612 ParamSpec.  Responsibility for whether a user is using
+        # Callable[...] properly is deferred to static type checkers.
+        else:
+            ga_args = args
+        return super().__new__(cls, origin, ga_args)
+
+    def __repr__(self):
+        if len(self.__args__) == 2 and self.__args__[0] is Ellipsis:
+            return super().__repr__()
+        return (f'collections.abc.Callable'
+                f'[[{", ".join([_type_repr(a) for a in self.__args__[:-1]])}], '
+                f'{_type_repr(self.__args__[-1])}]')
+
+    def __reduce__(self):
+        args = self.__args__
+        if not (len(args) == 2 and args[0] is Ellipsis):
+            args = list(args[:-1]), args[-1]
+        return _CallableGenericAlias, (Callable, args)
+
+    def __getitem__(self, item):
+        # Called during TypeVar substitution, returns the custom subclass
+        # rather than the default types.GenericAlias object.
+        ga = super().__getitem__(item)
+        args = ga.__args__
+        t_result = args[-1]
+        t_args = args[:-1]
+        args = (t_args, t_result)
+        return _CallableGenericAlias(Callable, args)
+
+
+def _type_repr(obj):
+    """Return the repr() of an object, special-casing types (internal helper).
+
+    Copied from :mod:`typing` since collections.abc
+    shouldn't depend on that module.
+    """
+    if isinstance(obj, GenericAlias):
+        return repr(obj)
+    if isinstance(obj, type):
+        if obj.__module__ == 'builtins':
+            return obj.__qualname__
+        return f'{obj.__module__}.{obj.__qualname__}'
+    if obj is Ellipsis:
+        return '...'
+    if isinstance(obj, FunctionType):
+        return obj.__name__
+    return repr(obj)
+
+
 class Callable(metaclass=ABCMeta):
 
     __slots__ = ()
@@ -423,7 +507,7 @@ class Callable(metaclass=ABCMeta):
             return _check_methods(C, "__call__")
         return NotImplemented
 
-    __class_getitem__ = classmethod(GenericAlias)
+    __class_getitem__ = classmethod(_CallableGenericAlias)
 
 
 ### SETS ###
index f486b6722941119b896d97412ec425dbe2a7a9db..d6262ae75e6569eee152d52a76a8d85aa36d7a19 100644 (file)
@@ -471,7 +471,10 @@ async def wait_for(fut, timeout, *, loop=None):
                 return fut.result()
             else:
                 fut.remove_done_callback(cb)
-                fut.cancel()
+                # We must ensure that the task is not running
+                # after wait_for() returns.
+                # See https://bugs.python.org/issue32751
+                await _cancel_and_wait(fut, loop=loop)
                 raise
 
         if fut.done():
index f34a5b4b4437364c14e0f97278201e458a5fb4fc..3efa6698b89ced4673687957be769602c20c0af0 100644 (file)
@@ -1230,13 +1230,15 @@ class MultiLoopChildWatcher(AbstractChildWatcher):
 
     def close(self):
         self._callbacks.clear()
-        if self._saved_sighandler is not None:
-            handler = signal.getsignal(signal.SIGCHLD)
-            if handler != self._sig_chld:
-                logger.warning("SIGCHLD handler was changed by outside code")
-            else:
-                signal.signal(signal.SIGCHLD, self._saved_sighandler)
-            self._saved_sighandler = None
+        if self._saved_sighandler is None:
+            return
+
+        handler = signal.getsignal(signal.SIGCHLD)
+        if handler != self._sig_chld:
+            logger.warning("SIGCHLD handler was changed by outside code")
+        else:
+            signal.signal(signal.SIGCHLD, self._saved_sighandler)
+        self._saved_sighandler = None
 
     def __enter__(self):
         return self
@@ -1263,15 +1265,17 @@ class MultiLoopChildWatcher(AbstractChildWatcher):
         # The reason to do it here is that attach_loop() is called from
         # unix policy only for the main thread.
         # Main thread is required for subscription on SIGCHLD signal
+        if self._saved_sighandler is not None:
+            return
+
+        self._saved_sighandler = signal.signal(signal.SIGCHLD, self._sig_chld)
         if self._saved_sighandler is None:
-            self._saved_sighandler = signal.signal(signal.SIGCHLD, self._sig_chld)
-            if self._saved_sighandler is None:
-                logger.warning("Previous SIGCHLD handler was set by non-Python code, "
-                               "restore to default handler on watcher close.")
-                self._saved_sighandler = signal.SIG_DFL
+            logger.warning("Previous SIGCHLD handler was set by non-Python code, "
+                           "restore to default handler on watcher close.")
+            self._saved_sighandler = signal.SIG_DFL
 
-            # Set SA_RESTART to limit EINTR occurrences.
-            signal.siginterrupt(signal.SIGCHLD, False)
+        # Set SA_RESTART to limit EINTR occurrences.
+        signal.siginterrupt(signal.SIGCHLD, False)
 
     def _do_waitpid_all(self):
         for pid in list(self._callbacks):
index a28109f8a7f9c3667d5b5ee0c3e8e52bb374a8f9..ec3823b724a37e31ec828e1547dbed873ed1038b 100755 (executable)
@@ -320,7 +320,7 @@ def a85encode(b, *, foldspaces=False, wrapcol=0, pad=False, adobe=False):
     global _a85chars, _a85chars2
     # Delay the initialization of tables to not waste memory
     # if the function is never called
-    if _a85chars is None:
+    if _a85chars2 is None:
         _a85chars = [bytes((i,)) for i in range(33, 118)]
         _a85chars2 = [(a + b) for a in _a85chars for b in _a85chars]
 
@@ -428,7 +428,7 @@ def b85encode(b, pad=False):
     global _b85chars, _b85chars2
     # Delay the initialization of tables to not waste memory
     # if the function is never called
-    if _b85chars is None:
+    if _b85chars2 is None:
         _b85chars = [bytes((i,)) for i in _b85alphabet]
         _b85chars2 = [(a + b) for a in _b85chars for b in _b85chars]
     return _85encode(b, _b85chars, _b85chars2, pad)
index 59b4699feb5062aef3fef5110be0acf8d7ae4e61..22a7d0aade855fd83e72d251cdf6ee4336e41765 100755 (executable)
@@ -175,7 +175,12 @@ def main():
                 '__package__': None,
                 '__cached__': None,
             }
-        runctx(code, globs, None, options.outfile, options.sort)
+        try:
+            runctx(code, globs, None, options.outfile, options.sort)
+        except BrokenPipeError as exc:
+            # Prevent "Exception ignored" during interpreter shutdown.
+            sys.stdout = None
+            sys.exit(exc.errno)
     else:
         parser.print_usage()
     return parser
index 77ab703cc036004a980e5e014d69120fa8e5e072..1e880e51848af2c80f922401b61020e5155b0562 100755 (executable)
@@ -115,7 +115,8 @@ log = initlog           # The current logging function
 # 0 ==> unlimited input
 maxlen = 0
 
-def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
+def parse(fp=None, environ=os.environ, keep_blank_values=0,
+          strict_parsing=0, separator='&'):
     """Parse a query in the environment or from a file (default stdin)
 
         Arguments, all optional:
@@ -134,6 +135,9 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
         strict_parsing: flag indicating what to do with parsing errors.
             If false (the default), errors are silently ignored.
             If true, errors raise a ValueError exception.
+
+        separator: str. The symbol to use for separating the query arguments.
+            Defaults to &.
     """
     if fp is None:
         fp = sys.stdin
@@ -154,7 +158,7 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
     if environ['REQUEST_METHOD'] == 'POST':
         ctype, pdict = parse_header(environ['CONTENT_TYPE'])
         if ctype == 'multipart/form-data':
-            return parse_multipart(fp, pdict)
+            return parse_multipart(fp, pdict, separator=separator)
         elif ctype == 'application/x-www-form-urlencoded':
             clength = int(environ['CONTENT_LENGTH'])
             if maxlen and clength > maxlen:
@@ -178,10 +182,10 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
             qs = ""
         environ['QUERY_STRING'] = qs    # XXX Shouldn't, really
     return urllib.parse.parse_qs(qs, keep_blank_values, strict_parsing,
-                                 encoding=encoding)
+                                 encoding=encoding, separator=separator)
 
 
-def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"):
+def parse_multipart(fp, pdict, encoding="utf-8", errors="replace", separator='&'):
     """Parse multipart input.
 
     Arguments:
@@ -205,7 +209,7 @@ def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"):
     except KeyError:
         pass
     fs = FieldStorage(fp, headers=headers, encoding=encoding, errors=errors,
-        environ={'REQUEST_METHOD': 'POST'})
+        environ={'REQUEST_METHOD': 'POST'}, separator=separator)
     return {k: fs.getlist(k) for k in fs}
 
 def _parseparam(s):
@@ -315,7 +319,7 @@ class FieldStorage:
     def __init__(self, fp=None, headers=None, outerboundary=b'',
                  environ=os.environ, keep_blank_values=0, strict_parsing=0,
                  limit=None, encoding='utf-8', errors='replace',
-                 max_num_fields=None):
+                 max_num_fields=None, separator='&'):
         """Constructor.  Read multipart/* until last part.
 
         Arguments, all optional:
@@ -363,6 +367,7 @@ class FieldStorage:
         self.keep_blank_values = keep_blank_values
         self.strict_parsing = strict_parsing
         self.max_num_fields = max_num_fields
+        self.separator = separator
         if 'REQUEST_METHOD' in environ:
             method = environ['REQUEST_METHOD'].upper()
         self.qs_on_post = None
@@ -589,7 +594,7 @@ class FieldStorage:
         query = urllib.parse.parse_qsl(
             qs, self.keep_blank_values, self.strict_parsing,
             encoding=self.encoding, errors=self.errors,
-            max_num_fields=self.max_num_fields)
+            max_num_fields=self.max_num_fields, separator=self.separator)
         self.list = [MiniFieldStorage(key, value) for key, value in query]
         self.skip_lines()
 
@@ -605,7 +610,7 @@ class FieldStorage:
             query = urllib.parse.parse_qsl(
                 self.qs_on_post, self.keep_blank_values, self.strict_parsing,
                 encoding=self.encoding, errors=self.errors,
-                max_num_fields=self.max_num_fields)
+                max_num_fields=self.max_num_fields, separator=self.separator)
             self.list.extend(MiniFieldStorage(key, value) for key, value in query)
 
         klass = self.FieldStorageClass or self.__class__
@@ -649,7 +654,7 @@ class FieldStorage:
                 else self.limit - self.bytes_read
             part = klass(self.fp, headers, ib, environ, keep_blank_values,
                          strict_parsing, limit,
-                         self.encoding, self.errors, max_num_fields)
+                         self.encoding, self.errors, max_num_fields, self.separator)
 
             if max_num_fields is not None:
                 max_num_fields -= 1
index 7f23e9775df804e79e4d0869a29dc05e1396a892..d2edd148a290aa487df9719e8725739317f48c1e 100644 (file)
@@ -386,7 +386,7 @@ class StreamWriter(Codec):
 
     def reset(self):
 
-        """ Flushes and resets the codec buffers used for keeping state.
+        """ Resets the codec buffers used for keeping internal state.
 
             Calling this method should ensure that the data on the
             output is put into a clean state, that allows appending
@@ -620,7 +620,7 @@ class StreamReader(Codec):
 
     def reset(self):
 
-        """ Resets the codec buffers used for keeping state.
+        """ Resets the codec buffers used for keeping internal state.
 
             Note that no stream repositioning should take place.
             This method is primarily intended to be able to recover
index bc69a6757f29483dad16ea47c7217925c70226a4..5bdd3b3516d3b2c6ddd206745a4ca02a9901def4 100644 (file)
@@ -424,7 +424,7 @@ def namedtuple(typename, field_names, *, rename=False, defaults=None, module=Non
 
     namespace = {
         '_tuple_new': tuple_new,
-        '__builtins__': None,
+        '__builtins__': {},
         '__name__': f'namedtuple_{typename}',
     }
     code = f'lambda _cls, {arg_list}: _tuple_new(_cls, ({arg_list}))'
index 891600d16bee9e2463573cdda511ad71d9b8e07d..86ca8b8a8414b3860aa80599394e806e156f4b5b 100644 (file)
@@ -1,2 +1,3 @@
 from _collections_abc import *
 from _collections_abc import __all__
+from _collections_abc import _CallableGenericAlias
index e4c25fd880cefbbe1b62b65382a7ca1f4f588c54..38af7ac13d756c225af7fbc514668476f66d0184 100644 (file)
@@ -201,6 +201,49 @@ class SimpleTypesTestCase(unittest.TestCase):
         with self.assertRaises(ZeroDivisionError):
             WorseStruct().__setstate__({}, b'foo')
 
+    def test_parameter_repr(self):
+        from ctypes import (
+            c_bool,
+            c_char,
+            c_wchar,
+            c_byte,
+            c_ubyte,
+            c_short,
+            c_ushort,
+            c_int,
+            c_uint,
+            c_long,
+            c_ulong,
+            c_longlong,
+            c_ulonglong,
+            c_float,
+            c_double,
+            c_longdouble,
+            c_char_p,
+            c_wchar_p,
+            c_void_p,
+        )
+        self.assertRegex(repr(c_bool.from_param(True)), r"^<cparam '\?' at 0x[A-Fa-f0-9]+>$")
+        self.assertEqual(repr(c_char.from_param(97)), "<cparam 'c' ('a')>")
+        self.assertRegex(repr(c_wchar.from_param('a')), r"^<cparam 'u' at 0x[A-Fa-f0-9]+>$")
+        self.assertEqual(repr(c_byte.from_param(98)), "<cparam 'b' (98)>")
+        self.assertEqual(repr(c_ubyte.from_param(98)), "<cparam 'B' (98)>")
+        self.assertEqual(repr(c_short.from_param(511)), "<cparam 'h' (511)>")
+        self.assertEqual(repr(c_ushort.from_param(511)), "<cparam 'H' (511)>")
+        self.assertRegex(repr(c_int.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
+        self.assertRegex(repr(c_uint.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
+        self.assertRegex(repr(c_long.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
+        self.assertRegex(repr(c_ulong.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
+        self.assertRegex(repr(c_longlong.from_param(20000)), r"^<cparam '[liq]' \(20000\)>$")
+        self.assertRegex(repr(c_ulonglong.from_param(20000)), r"^<cparam '[LIQ]' \(20000\)>$")
+        self.assertEqual(repr(c_float.from_param(1.5)), "<cparam 'f' (1.5)>")
+        self.assertEqual(repr(c_double.from_param(1.5)), "<cparam 'd' (1.5)>")
+        self.assertEqual(repr(c_double.from_param(1e300)), "<cparam 'd' (1e+300)>")
+        self.assertRegex(repr(c_longdouble.from_param(1.5)), r"^<cparam ('d' \(1.5\)|'g' at 0x[A-Fa-f0-9]+)>$")
+        self.assertRegex(repr(c_char_p.from_param(b'hihi')), r"^<cparam 'z' \(0x[A-Fa-f0-9]+\)>$")
+        self.assertRegex(repr(c_wchar_p.from_param('hihi')), r"^<cparam 'Z' \(0x[A-Fa-f0-9]+\)>$")
+        self.assertRegex(repr(c_void_p.from_param(0x12)), r"^<cparam 'P' \(0x0*12\)>$")
+
 ################################################################
 
 if __name__ == '__main__':
index e508d996fb1ed199ed638eaf6990aa696efec481..23d2bf0918145fcaff915a1330582a4be06f6ea9 100644 (file)
@@ -2358,7 +2358,7 @@ _EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
 #    This is again a requirement for a sane tzinfo class.
 #
 # 4. (x+k).s = x.s
-#    This follows from #2, and that datimetimetz+timedelta preserves tzinfo.
+#    This follows from #2, and that datetime.timetz+timedelta preserves tzinfo.
 #
 # 5. (x+k).n = x.n + k
 #    Again follows from how arithmetic is defined.
index f50edd2da9710068324ff48d4ec275347370716b..0d1bd0391e6f1134e4472d7e133d8302d564a7dc 100644 (file)
@@ -54,8 +54,8 @@ def spawn(cmd, search_path=1, verbose=0, dry_run=0):
         global _cfg_target, _cfg_target_split
         if _cfg_target is None:
             from distutils import sysconfig
-            _cfg_target = str(sysconfig.get_config_var(
-                                  'MACOSX_DEPLOYMENT_TARGET') or '')
+            _cfg_target = sysconfig.get_config_var(
+                                  'MACOSX_DEPLOYMENT_TARGET') or ''
             if _cfg_target:
                 _cfg_target_split = [int(x) for x in _cfg_target.split('.')]
         if _cfg_target:
index 1b034c93025213f659e92667bd7f314d77e2d12e..808c0dc2874cd5354684aa8ea999e150429cde3f 100644 (file)
@@ -455,7 +455,7 @@ class BuildExtTestCase(TempdirManager,
         deptarget = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
         if deptarget:
             # increment the minor version number (i.e. 10.6 -> 10.7)
-            deptarget = [int(x) for x in str(deptarget).split('.')]
+            deptarget = [int(x) for x in deptarget.split('.')]
             deptarget[-1] += 1
             deptarget = '.'.join(str(i) for i in deptarget)
             self._try_compile_deployment_target('<', deptarget)
@@ -488,7 +488,7 @@ class BuildExtTestCase(TempdirManager,
 
         # get the deployment target that the interpreter was built with
         target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
-        target = tuple(map(int, str(target).split('.')[0:2]))
+        target = tuple(map(int, target.split('.')[0:2]))
         # format the target value as defined in the Apple
         # Availability Macros.  We can't use the macro names since
         # at least one value we test with will not exist yet.
index ebadd9f662a13894013c29c2c0abfb1759c811d8..1fddb1c75e8be44ccb253d8845c6f4e655704923 100644 (file)
@@ -10,31 +10,54 @@ __all__ = [
 
 
 def _is_descriptor(obj):
-    """Returns True if obj is a descriptor, False otherwise."""
+    """
+    Returns True if obj is a descriptor, False otherwise.
+    """
     return (
             hasattr(obj, '__get__') or
             hasattr(obj, '__set__') or
-            hasattr(obj, '__delete__'))
-
+            hasattr(obj, '__delete__')
+            )
 
 def _is_dunder(name):
-    """Returns True if a __dunder__ name, False otherwise."""
-    return (len(name) > 4 and
+    """
+    Returns True if a __dunder__ name, False otherwise.
+    """
+    return (
+            len(name) > 4 and
             name[:2] == name[-2:] == '__' and
             name[2] != '_' and
-            name[-3] != '_')
-
+            name[-3] != '_'
+            )
 
 def _is_sunder(name):
-    """Returns True if a _sunder_ name, False otherwise."""
-    return (len(name) > 2 and
+    """
+    Returns True if a _sunder_ name, False otherwise.
+    """
+    return (
+            len(name) > 2 and
             name[0] == name[-1] == '_' and
             name[1:2] != '_' and
-            name[-2:-1] != '_')
-
+            name[-2:-1] != '_'
+            )
+
+def _is_private(cls_name, name):
+    # do not use `re` as `re` imports `enum`
+    pattern = '_%s__' % (cls_name, )
+    if (
+            len(name) >= 5
+            and name.startswith(pattern)
+            and name[len(pattern)] != '_'
+            and (name[-1] != '_' or name[-2] != '_')
+        ):
+        return True
+    else:
+        return False
 
 def _make_class_unpicklable(cls):
-    """Make the given class un-picklable."""
+    """
+    Make the given class un-picklable.
+    """
     def _break_on_call_reduce(self, proto):
         raise TypeError('%r cannot be pickled' % self)
     cls.__reduce_ex__ = _break_on_call_reduce
@@ -49,11 +72,11 @@ class auto:
 
 
 class _EnumDict(dict):
-    """Track enum member order and ensure member names are not reused.
+    """
+    Track enum member order and ensure member names are not reused.
 
     EnumMeta will use the names found in self._member_names as the
     enumeration member names.
-
     """
     def __init__(self):
         super().__init__()
@@ -63,14 +86,22 @@ class _EnumDict(dict):
         self._auto_called = False
 
     def __setitem__(self, key, value):
-        """Changes anything not dundered or not a descriptor.
+        """
+        Changes anything not dundered or not a descriptor.
 
         If an enum member name is used twice, an error is raised; duplicate
         values are not checked for.
 
         Single underscore (sunder) names are reserved.
-
         """
+        if _is_private(self._cls_name, key):
+            import warnings
+            warnings.warn(
+                    "private variables, such as %r, will be normal attributes in 3.10"
+                        % (key, ),
+                    DeprecationWarning,
+                    stacklevel=2,
+                    )
         if _is_sunder(key):
             if key not in (
                     '_order_', '_create_pseudo_member_',
@@ -90,7 +121,10 @@ class _EnumDict(dict):
                 self._ignore = value
                 already = set(value) & set(self._member_names)
                 if already:
-                    raise ValueError('_ignore_ cannot specify already set names: %r' % (already, ))
+                    raise ValueError(
+                            '_ignore_ cannot specify already set names: %r'
+                            % (already, )
+                            )
         elif _is_dunder(key):
             if key == '__order__':
                 key = '_order_'
@@ -105,7 +139,12 @@ class _EnumDict(dict):
                 raise TypeError('%r already defined as: %r' % (key, self[key]))
             if isinstance(value, auto):
                 if value.value == _auto_null:
-                    value.value = self._generate_next_value(key, 1, len(self._member_names), self._last_values[:])
+                    value.value = self._generate_next_value(
+                            key,
+                            1,
+                            len(self._member_names),
+                            self._last_values[:],
+                            )
                     self._auto_called = True
                 value = value.value
             self._member_names.append(key)
@@ -118,22 +157,26 @@ class _EnumDict(dict):
 # This is also why there are checks in EnumMeta like `if Enum is not None`
 Enum = None
 
-
 class EnumMeta(type):
-    """Metaclass for Enum"""
+    """
+    Metaclass for Enum
+    """
     @classmethod
-    def __prepare__(metacls, cls, bases):
+    def __prepare__(metacls, cls, bases, **kwds):
         # check that previous enum members do not exist
         metacls._check_for_existing_members(cls, bases)
         # create the namespace dict
         enum_dict = _EnumDict()
+        enum_dict._cls_name = cls
         # inherit previous flags and _generate_next_value_ function
         member_type, first_enum = metacls._get_mixins_(cls, bases)
         if first_enum is not None:
-            enum_dict['_generate_next_value_'] = getattr(first_enum, '_generate_next_value_', None)
+            enum_dict['_generate_next_value_'] = getattr(
+                    first_enum, '_generate_next_value_', None,
+                    )
         return enum_dict
 
-    def __new__(metacls, cls, bases, classdict):
+    def __new__(metacls, cls, bases, classdict, **kwds):
         # an Enum class is final once enumeration items have been defined; it
         # cannot be mixed with other types (int, float, etc.) if it has an
         # inherited __new__ unless a new __new__ is defined (or the resulting
@@ -145,8 +188,9 @@ class EnumMeta(type):
         for key in ignore:
             classdict.pop(key, None)
         member_type, first_enum = metacls._get_mixins_(cls, bases)
-        __new__, save_new, use_args = metacls._find_new_(classdict, member_type,
-                                                        first_enum)
+        __new__, save_new, use_args = metacls._find_new_(
+                classdict, member_type, first_enum,
+                )
 
         # save enum items into separate mapping so they don't get baked into
         # the new class
@@ -167,17 +211,18 @@ class EnumMeta(type):
         if '__doc__' not in classdict:
             classdict['__doc__'] = 'An enumeration.'
 
-        # create our new Enum type
-        enum_class = super().__new__(metacls, cls, bases, classdict)
+        enum_class = super().__new__(metacls, cls, bases, classdict, **kwds)
         enum_class._member_names_ = []               # names in definition order
         enum_class._member_map_ = {}                 # name->value map
         enum_class._member_type_ = member_type
 
         # save DynamicClassAttribute attributes from super classes so we know
         # if we can take the shortcut of storing members in the class dict
-        dynamic_attributes = {k for c in enum_class.mro()
-                              for k, v in c.__dict__.items()
-                              if isinstance(v, DynamicClassAttribute)}
+        dynamic_attributes = {
+                k for c in enum_class.mro()
+                for k, v in c.__dict__.items()
+                if isinstance(v, DynamicClassAttribute)
+                }
 
         # Reverse value->name map for hashable values.
         enum_class._value2member_map_ = {}
@@ -287,7 +332,8 @@ class EnumMeta(type):
         return True
 
     def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1):
-        """Either returns an existing member, or creates a new enum class.
+        """
+        Either returns an existing member, or creates a new enum class.
 
         This method is used both when an enum class is given a value to match
         to an enumeration member (i.e. Color(3)) and for the functional API
@@ -309,12 +355,18 @@ class EnumMeta(type):
         not correct, unpickling will fail in some circumstances.
 
         `type`, if set, will be mixed in as the first base class.
-
         """
         if names is None:  # simple value lookup
             return cls.__new__(cls, value)
         # otherwise, functional API: we're creating a new Enum type
-        return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
+        return cls._create_(
+                value,
+                names,
+                module=module,
+                qualname=qualname,
+                type=type,
+                start=start,
+                )
 
     def __contains__(cls, member):
         if not isinstance(member, Enum):
@@ -327,22 +379,23 @@ class EnumMeta(type):
         # nicer error message when someone tries to delete an attribute
         # (see issue19025).
         if attr in cls._member_map_:
-            raise AttributeError(
-                    "%s: cannot delete Enum member." % cls.__name__)
+            raise AttributeError("%s: cannot delete Enum member." % cls.__name__)
         super().__delattr__(attr)
 
     def __dir__(self):
-        return (['__class__', '__doc__', '__members__', '__module__'] +
-                self._member_names_)
+        return (
+                ['__class__', '__doc__', '__members__', '__module__']
+                + self._member_names_
+                )
 
     def __getattr__(cls, name):
-        """Return the enum member matching `name`
+        """
+        Return the enum member matching `name`
 
         We use __getattr__ instead of descriptors or inserting into the enum
         class' __dict__ in order to support `name` and `value` being both
         properties for enum members (which live in the class' __dict__) and
         enum members themselves.
-
         """
         if _is_dunder(name):
             raise AttributeError(name)
@@ -355,6 +408,9 @@ class EnumMeta(type):
         return cls._member_map_[name]
 
     def __iter__(cls):
+        """
+        Returns members in definition order.
+        """
         return (cls._member_map_[name] for name in cls._member_names_)
 
     def __len__(cls):
@@ -362,11 +418,11 @@ class EnumMeta(type):
 
     @property
     def __members__(cls):
-        """Returns a mapping of member name->value.
+        """
+        Returns a mapping of member name->value.
 
         This mapping lists all enum members, including aliases. Note that this
         is a read-only view of the internal mapping.
-
         """
         return MappingProxyType(cls._member_map_)
 
@@ -374,15 +430,18 @@ class EnumMeta(type):
         return "<enum %r>" % cls.__name__
 
     def __reversed__(cls):
+        """
+        Returns members in reverse definition order.
+        """
         return (cls._member_map_[name] for name in reversed(cls._member_names_))
 
     def __setattr__(cls, name, value):
-        """Block attempts to reassign Enum members.
+        """
+        Block attempts to reassign Enum members.
 
         A simple assignment to the class namespace only changes one of the
         several possible ways to get an Enum member from the Enum class,
         resulting in an inconsistent Enumeration.
-
         """
         member_map = cls.__dict__.get('_member_map_', {})
         if name in member_map:
@@ -390,7 +449,8 @@ class EnumMeta(type):
         super().__setattr__(name, value)
 
     def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, start=1):
-        """Convenience method to create a new Enum class.
+        """
+        Convenience method to create a new Enum class.
 
         `names` can be:
 
@@ -399,7 +459,6 @@ class EnumMeta(type):
         * An iterable of member names.  Values are incremented by 1 from `start`.
         * An iterable of (member name, value) pairs.
         * A mapping of member name -> value pairs.
-
         """
         metacls = cls.__class__
         bases = (cls, ) if type is None else (type, cls)
@@ -480,15 +539,18 @@ class EnumMeta(type):
         for chain in bases:
             for base in chain.__mro__:
                 if issubclass(base, Enum) and base._member_names_:
-                    raise TypeError("%s: cannot extend enumeration %r" % (class_name, base.__name__))
+                    raise TypeError(
+                            "%s: cannot extend enumeration %r"
+                            % (class_name, base.__name__)
+                            )
 
     @staticmethod
     def _get_mixins_(class_name, bases):
-        """Returns the type for creating enum members, and the first inherited
+        """
+        Returns the type for creating enum members, and the first inherited
         enum class.
 
         bases: the tuple of bases that was given to __new__
-
         """
         if not bases:
             return object, Enum
@@ -500,12 +562,16 @@ class EnumMeta(type):
                 for base in chain.__mro__:
                     if base is object:
                         continue
+                    elif issubclass(base, Enum):
+                        if base._member_type_ is not object:
+                            data_types.append(base._member_type_)
+                            break
                     elif '__new__' in base.__dict__:
                         if issubclass(base, Enum):
                             continue
                         data_types.append(candidate or base)
                         break
-                    elif not issubclass(base, Enum):
+                    else:
                         candidate = base
             if len(data_types) > 1:
                 raise TypeError('%r: too many data types: %r' % (class_name, data_types))
@@ -527,12 +593,12 @@ class EnumMeta(type):
 
     @staticmethod
     def _find_new_(classdict, member_type, first_enum):
-        """Returns the __new__ to be used for creating the enum members.
+        """
+        Returns the __new__ to be used for creating the enum members.
 
         classdict: the class dictionary given to __new__
         member_type: the data type whose __new__ will be used by default
         first_enum: enumeration to check for an overriding __new__
-
         """
         # now find the correct __new__, checking to see of one was defined
         # by the user; also check earlier enum classes in case a __new__ was
@@ -572,10 +638,10 @@ class EnumMeta(type):
 
 
 class Enum(metaclass=EnumMeta):
-    """Generic enumeration.
+    """
+    Generic enumeration.
 
     Derive from this class to define new enumerations.
-
     """
     def __new__(cls, value):
         # all enum instances are actually created during class construction
@@ -618,6 +684,14 @@ class Enum(metaclass=EnumMeta):
             raise exc
 
     def _generate_next_value_(name, start, count, last_values):
+        """
+        Generate the next value when not given.
+
+        name: the name of the member
+        start: the initial start value or None
+        count: the number of existing members
+        last_value: the last value assigned or None
+        """
         for last_value in reversed(last_values):
             try:
                 return last_value + 1
@@ -638,21 +712,27 @@ class Enum(metaclass=EnumMeta):
         return "%s.%s" % (self.__class__.__name__, self._name_)
 
     def __dir__(self):
+        """
+        Returns all members and all public methods
+        """
         added_behavior = [
                 m
                 for cls in self.__class__.mro()
                 for m in cls.__dict__
                 if m[0] != '_' and m not in self._member_map_
-                ]
+                ] + [m for m in self.__dict__ if m[0] != '_']
         return (['__class__', '__doc__', '__module__'] + added_behavior)
 
     def __format__(self, format_spec):
+        """
+        Returns format using actual value type unless __str__ has been overridden.
+        """
         # mixed-in Enums should use the mixed-in type's __format__, otherwise
         # we can get strange results with the Enum name showing up instead of
         # the value
 
         # pure Enum branch, or branch with __str__ explicitly overridden
-        str_overridden = type(self).__str__ != Enum.__str__
+        str_overridden = type(self).__str__ not in (Enum.__str__, Flag.__str__)
         if self._member_type_ is object or str_overridden:
             cls = str
             val = str(self)
@@ -694,7 +774,9 @@ def _reduce_ex_by_name(self, proto):
     return self.name
 
 class Flag(Enum):
-    """Support for flags"""
+    """
+    Support for flags
+    """
 
     def _generate_next_value_(name, start, count, last_values):
         """
@@ -717,6 +799,9 @@ class Flag(Enum):
 
     @classmethod
     def _missing_(cls, value):
+        """
+        Returns member (possibly creating it) if one can be found for value.
+        """
         original_value = value
         if value < 0:
             value = ~value
@@ -746,6 +831,9 @@ class Flag(Enum):
         return pseudo_member
 
     def __contains__(self, other):
+        """
+        Returns True if self has at least the same flags set as other.
+        """
         if not isinstance(other, self.__class__):
             raise TypeError(
                 "unsupported operand type(s) for 'in': '%s' and '%s'" % (
@@ -804,10 +892,15 @@ class Flag(Enum):
 
 
 class IntFlag(int, Flag):
-    """Support for integer-based Flags"""
+    """
+    Support for integer-based Flags
+    """
 
     @classmethod
     def _missing_(cls, value):
+        """
+        Returns member (possibly creating it) if one can be found for value.
+        """
         if not isinstance(value, int):
             raise ValueError("%r is not a valid %s" % (value, cls.__qualname__))
         new_member = cls._create_pseudo_member_(value)
@@ -815,6 +908,9 @@ class IntFlag(int, Flag):
 
     @classmethod
     def _create_pseudo_member_(cls, value):
+        """
+        Create a composite member iff value contains only members.
+        """
         pseudo_member = cls._value2member_map_.get(value, None)
         if pseudo_member is None:
             need_to_create = [value]
@@ -869,11 +965,15 @@ class IntFlag(int, Flag):
 
 
 def _high_bit(value):
-    """returns index of highest bit, or -1 if value is zero or negative"""
+    """
+    returns index of highest bit, or -1 if value is zero or negative
+    """
     return value.bit_length() - 1
 
 def unique(enumeration):
-    """Class decorator for enumerations ensuring unique member values."""
+    """
+    Class decorator for enumerations ensuring unique member values.
+    """
     duplicates = []
     for name, member in enumeration.__members__.items():
         if name != member.name:
@@ -886,7 +986,9 @@ def unique(enumeration):
     return enumeration
 
 def _decompose(flag, value):
-    """Extract all members from the value."""
+    """
+    Extract all members from the value.
+    """
     # _decompose is only called if the value is not named
     not_covered = value
     negative = value < 0
index 0eb1802bdb53c5d8594e06a08cfe4d0e5f8f6a94..7c52c23067d40f3e808b160647ff3537823325ec 100644 (file)
@@ -52,7 +52,7 @@ def _compile_pattern(pat):
     return re.compile(res).match
 
 def filter(names, pat):
-    """Return the subset of the list NAMES that match PAT."""
+    """Construct a list from those elements of the iterable NAMES that match PAT."""
     result = []
     pat = os.path.normcase(pat)
     match = _compile_pattern(pat)
index 60830779816a03e61e128801db514b0609fdfa9b..9e49effca1fcc5ae7378253883073b5d804675a5 100644 (file)
@@ -46,7 +46,7 @@ locatestarttagend_tolerant = re.compile(r"""
           |"[^"]*"                   # LIT-enclosed value
           |(?!['"])[^>\s]*           # bare value
          )
-         (?:\s*,)*                   # possibly followed by a comma
+        \s*                          # possibly followed by a space
        )?(?:\s|/(?!>))*
      )*
    )?
index c2ad0471bfee50ec85ce239dd8fe7584782716d2..16afc871ea6d7a9dfcabfd6eec03cf69a84f7244 100644 (file)
@@ -846,7 +846,7 @@ class HTTPConnection:
         the endpoint passed to `set_tunnel`. This done by sending an HTTP
         CONNECT request to the proxy server when the connection is established.
 
-        This method must be called before the HTML connection has been
+        This method must be called before the HTTP connection has been
         established.
 
         The headers argument should be a mapping of extra HTTP headers to send
index 869be0a62b7dbae492b5ea1654a1d62a93a458af..4bc4aefd1ac352e15d2b310787f9f77a7be18957 100644 (file)
@@ -1,8 +1,24 @@
-What's New in IDLE 3.9.1
-Released on 2020-12-07?
+What's New in IDLE 3.9.2
+Released on 2021-02-15?
 ======================================
 
 
+bpo-23544: Disable Debug=>Stack Viewer when user code is running or
+Debugger is active, to prevent hang or crash.  Patch by Zackery Spytz.
+
+bpo-43008: Make IDLE invoke :func:`sys.excepthook` in normal,
+2-process mode.  Patch by Ken Hilton.
+
+bpo-33065: Fix problem debugging user classes with __repr__ method.
+
+bpo-32631: Finish zzdummy example extension module: make menu entries
+work; add docstrings and tests with 100% coverage.
+
+
+What's New in IDLE 3.9.1
+Released on 2020-12-07
+======================================
+
 bpo-42508: Keep IDLE running on macOS.  Remove obsolete workaround
 that prevented running files with shortcuts when using new universal2
 installers built on macOS 11.
index 989b30e5994650c745eccb302c0e24ef636a4522..f2f44f5f8d4e6112c75a4845e89ba005245abd9b 100644 (file)
@@ -7,11 +7,14 @@ the lines which contain the block opening keywords, e.g. 'if', for the
 enclosing block.  The number of hint lines is determined by the maxlines
 variable in the codecontext section of config-extensions.def. Lines which do
 not open blocks are not shown in the context hints pane.
+
+For EditorWindows, <<toggle-code-context>> is bound to CodeContext(self).
+toggle_code_context_event.
 """
 import re
 from sys import maxsize as INFINITY
 
-import tkinter
+from tkinter import Frame, Text, TclError
 from tkinter.constants import NSEW, SUNKEN
 
 from idlelib.config import idleConf
@@ -83,7 +86,7 @@ class CodeContext:
         if self.t1 is not None:
             try:
                 self.text.after_cancel(self.t1)
-            except tkinter.TclError:  # pragma: no cover
+            except TclError:  # pragma: no cover
                 pass
             self.t1 = None
 
@@ -111,7 +114,7 @@ class CodeContext:
                 padx += widget.tk.getint(info['padx'])
                 padx += widget.tk.getint(widget.cget('padx'))
                 border += widget.tk.getint(widget.cget('border'))
-            context = self.context = tkinter.Text(
+            context = self.context = Text(
                 self.editwin.text_frame,
                 height=1,
                 width=1,  # Don't request more than we get.
@@ -127,7 +130,7 @@ class CodeContext:
 
             line_number_colors = idleConf.GetHighlight(idleConf.CurrentTheme(),
                                                        'linenumber')
-            self.cell00 = tkinter.Frame(self.editwin.text_frame,
+            self.cell00 = Frame(self.editwin.text_frame,
                                         bg=line_number_colors['background'])
             self.cell00.grid(row=0, column=0, sticky=NSEW)
             menu_status = 'Hide'
@@ -139,7 +142,7 @@ class CodeContext:
             self.text.after_cancel(self.t1)
             self._reset()
             menu_status = 'Show'
-        self.editwin.update_menu_label(menu='options', index='* Code Context',
+        self.editwin.update_menu_label(menu='options', index='*ode*ontext',
                                        label=f'{menu_status} Code Context')
         return "break"
 
@@ -221,7 +224,7 @@ class CodeContext:
         """
         try:
             self.context.index("sel.first")
-        except tkinter.TclError:
+        except TclError:
             lines = len(self.info)
             if lines == 1:  # No context lines are showing.
                 newtop = 1
index a84e1c5668f99fee634c7fb06b2e275eede4e299..c52a04b503adb4a1b4d827326ddf25b2d4dd4ea9 100644 (file)
@@ -18,8 +18,8 @@ from tkinter import (Toplevel, Listbox, Scale, Canvas,
                      HORIZONTAL, VERTICAL, ANCHOR, ACTIVE, END)
 from tkinter.ttk import (Frame, LabelFrame, Button, Checkbutton, Entry, Label,
                          OptionMenu, Notebook, Radiobutton, Scrollbar, Style)
-import tkinter.colorchooser as tkColorChooser
-import tkinter.font as tkFont
+from tkinter import colorchooser
+import tkinter.font as tkfont
 from tkinter import messagebox
 
 from idlelib.config import idleConf, ConfigChanges
@@ -609,7 +609,7 @@ class FontPage(Frame):
         font_bold  = configured_font[2]=='bold'
 
         # Set sorted no-duplicate editor font selection list and font_name.
-        fonts = sorted(set(tkFont.families(self)))
+        fonts = sorted(set(tkfont.families(self)))
         for font in fonts:
             self.fontlist.insert(END, font)
         self.font_name.set(font_name)
@@ -663,7 +663,7 @@ class FontPage(Frame):
         Updates font_sample and highlight page highlight_sample.
         """
         font_name = self.font_name.get()
-        font_weight = tkFont.BOLD if self.font_bold.get() else tkFont.NORMAL
+        font_weight = tkfont.BOLD if self.font_bold.get() else tkfont.NORMAL
         new_font = (font_name, self.font_size.get(), font_weight)
         self.font_sample['font'] = new_font
         self.highlight_sample['font'] = new_font
@@ -1100,7 +1100,7 @@ class HighPage(Frame):
         target = self.highlight_target.get()
         prev_color = self.style.lookup(self.frame_color_set['style'],
                                        'background')
-        rgbTuplet, color_string = tkColorChooser.askcolor(
+        rgbTuplet, color_string = colorchooser.askcolor(
                 parent=self, title='Pick new color for : '+target,
                 initialcolor=prev_color)
         if color_string and (color_string != prev_color):
@@ -2316,7 +2316,15 @@ display when Code Context is turned on for an editor window.
 
 Shell Preferences: Auto-Squeeze Min. Lines is the minimum number of lines
 of output to automatically "squeeze".
-'''
+''',
+    'Extensions': '''
+ZzDummy: This extension is provided as an example for how to create and
+use an extension.  Enable indicates whether the extension is active or
+not; likewise enable_editor and enable_shell indicate which windows it
+will be active on.  For this extension, z-text is the text that will be
+inserted at or removed from the beginning of the lines of selected text,
+or the current line if no selection.
+''',
 }
 
 
index 9dcfc56414c05059c3d89b68d634d23dcbb16fee..26204438858d8a4b8e3850c5e8276b7208448b2f 100644 (file)
@@ -19,7 +19,7 @@ arguments and return values that cannot be transported through the RPC
 barrier, in particular frame and traceback objects.
 
 """
-
+import reprlib
 import types
 from idlelib import debugger
 
@@ -170,7 +170,7 @@ class IdbAdapter:
     def dict_item(self, did, key):
         dict = dicttable[did]
         value = dict[key]
-        value = repr(value) ### can't pickle module 'builtins'
+        value = reprlib.repr(value) ### can't pickle module 'builtins'
         return value
 
 #----------end class IdbAdapter----------
@@ -390,4 +390,4 @@ def restart_subprocess_debugger(rpcclt):
 
 if __name__ == "__main__":
     from unittest import main
-    main('idlelib.idle_test.test_debugger', verbosity=2, exit=False)
+    main('idlelib.idle_test.test_debugger_r', verbosity=2, exit=False)
index a178eaf93c013ab6bfdc24ff3579335842960fb5..b9cb50264ff06f22a36cf6cf405ba27aa1f4305d 100644 (file)
@@ -12,8 +12,8 @@ import webbrowser
 from tkinter import *
 from tkinter.font import Font
 from tkinter.ttk import Scrollbar
-import tkinter.simpledialog as tkSimpleDialog
-import tkinter.messagebox as tkMessageBox
+from tkinter import simpledialog
+from tkinter import messagebox
 
 from idlelib.config import idleConf
 from idlelib import configdialog
@@ -46,7 +46,7 @@ def _sphinx_version():
     return release
 
 
-class EditorWindow(object):
+class EditorWindow:
     from idlelib.percolator import Percolator
     from idlelib.colorizer import ColorDelegator, color_config
     from idlelib.undo import UndoDelegator
@@ -295,9 +295,9 @@ class EditorWindow(object):
             window.register_callback(self.postwindowsmenu)
 
         # Some abstractions so IDLE extensions are cross-IDE
-        self.askyesno = tkMessageBox.askyesno
-        self.askinteger = tkSimpleDialog.askinteger
-        self.showerror = tkMessageBox.showerror
+        self.askinteger = simpledialog.askinteger
+        self.askyesno = messagebox.askyesno
+        self.showerror = messagebox.showerror
 
         # Add pseudoevents for former extension fixed keys.
         # (This probably needs to be done once in the process.)
@@ -339,7 +339,7 @@ class EditorWindow(object):
             text.bind("<<toggle-code-context>>",
                       self.code_context.toggle_code_context_event)
         else:
-            self.update_menu_state('options', '*Code Context', 'disabled')
+            self.update_menu_state('options', '*ode*ontext', 'disabled')
         if self.allow_line_numbers:
             self.line_numbers = self.LineNumbers(self)
             if idleConf.GetOption('main', 'EditorWindow',
@@ -347,7 +347,7 @@ class EditorWindow(object):
                 self.toggle_line_numbers_event()
             text.bind("<<toggle-line-numbers>>", self.toggle_line_numbers_event)
         else:
-            self.update_menu_state('options', '*Line Numbers', 'disabled')
+            self.update_menu_state('options', '*ine*umbers', 'disabled')
 
     def handle_winconfig(self, event=None):
         self.set_width()
@@ -450,7 +450,9 @@ class EditorWindow(object):
         self.menudict = menudict = {}
         for name, label in self.menu_specs:
             underline, label = prepstr(label)
-            menudict[name] = menu = Menu(mbar, name=name, tearoff=0)
+            postcommand = getattr(self, f'{name}_menu_postcommand', None)
+            menudict[name] = menu = Menu(mbar, name=name, tearoff=0,
+                                         postcommand=postcommand)
             mbar.add_cascade(label=label, menu=menu, underline=underline)
         if macosx.isCarbonTk():
             # Insert the application menu
@@ -596,7 +598,7 @@ class EditorWindow(object):
             try:
                 os.startfile(self.help_url)
             except OSError as why:
-                tkMessageBox.showerror(title='Document Start Failure',
+                messagebox.showerror(title='Document Start Failure',
                     message=str(why), parent=self.text)
         else:
             webbrowser.open(self.help_url)
@@ -927,7 +929,7 @@ class EditorWindow(object):
                 try:
                     os.startfile(helpfile)
                 except OSError as why:
-                    tkMessageBox.showerror(title='Document Start Failure',
+                    messagebox.showerror(title='Document Start Failure',
                         message=str(why), parent=self.text)
             else:
                 webbrowser.open(helpfile)
@@ -963,7 +965,7 @@ class EditorWindow(object):
             except OSError as err:
                 if not getattr(self.root, "recentfiles_message", False):
                     self.root.recentfiles_message = True
-                    tkMessageBox.showwarning(title='IDLE Warning',
+                    messagebox.showwarning(title='IDLE Warning',
                         message="Cannot save Recent Files list to disk.\n"
                                 f"  {err}\n"
                                 "Select OK to continue.",
@@ -1527,7 +1529,7 @@ class EditorWindow(object):
         else:
             self.line_numbers.show_sidebar()
             menu_label = "Hide"
-        self.update_menu_label(menu='options', index='*Line Numbers',
+        self.update_menu_label(menu='options', index='*ine*umbers',
                                label=f'{menu_label} Line Numbers')
 
 # "line.col" -> line, as an int
@@ -1546,7 +1548,7 @@ def get_line_indent(line, tabwidth):
     return m.end(), len(m.group().expandtabs(tabwidth))
 
 
-class IndentSearcher(object):
+class IndentSearcher:
 
     # .run() chews over the Text widget, looking for a block opener
     # and the stmt following it.  Returns a pair,
index c9cb2e8297eb352586fdc09c47d3d71efb174d82..b482f76c4fb0f752e8f761f854fda0fbb1e10f82 100644 (file)
@@ -28,8 +28,8 @@ variables:
 (There are a few more, but they are rarely useful.)
 
 The extension class must not directly bind Window Manager (e.g. X) events.
-Rather, it must define one or more virtual events, e.g. <<zoom-height>>, and
-corresponding methods, e.g. zoom_height_event().  The virtual events will be
+Rather, it must define one or more virtual events, e.g. <<z-in>>, and
+corresponding methods, e.g. z_in_event().  The virtual events will be
 bound to the corresponding methods, and Window Manager events can then be bound
 to the virtual events. (This indirection is done so that the key bindings can
 easily be changed, and so that other sources of virtual events can exist, such
@@ -54,21 +54,21 @@ Extensions are not required to define menu entries for all the events they
 implement.  (They are also not required to create keybindings, but in that
 case there must be empty bindings in cofig-extensions.def)
 
-Here is a complete example:
+Here is a partial example from zzdummy.py:
 
-class ZoomHeight:
+class ZzDummy:
 
     menudefs = [
-        ('edit', [
-            None, # Separator
-            ('_Zoom Height', '<<zoom-height>>'),
-         ])
+        ('format', [
+            ('Z in', '<<z-in>>'),
+            ('Z out', '<<z-out>>'),
+        )
     ]
 
     def __init__(self, editwin):
         self.editwin = editwin
 
-    def zoom_height_event(self, event):
+    def z_in_event(self, event=None):
         "...Do what you want here..."
 
 The final piece of the puzzle is the file "config-extensions.def", which is
index 0d200854ef0007a4b11f4e19b83d2e3a304828dd..254f5caf6b81b05aa7b34c8c59ce3b7bbbdf418f 100644 (file)
@@ -1,7 +1,7 @@
 "idlelib.filelist"
 
 import os
-from tkinter import messagebox as tkMessageBox
+from tkinter import messagebox
 
 
 class FileList:
@@ -20,7 +20,7 @@ class FileList:
         filename = self.canonize(filename)
         if os.path.isdir(filename):
             # This can happen when bad filename is passed on command line:
-            tkMessageBox.showerror(
+            messagebox.showerror(
                 "File Error",
                 "%r is a directory." % (filename,),
                 master=self.root)
@@ -88,7 +88,7 @@ class FileList:
         if newkey in self.dict:
             conflict = self.dict[newkey]
             self.inversedict[conflict] = None
-            tkMessageBox.showerror(
+            messagebox.showerror(
                 "Name Conflict",
                 "You now have multiple edit windows open for %r" % (filename,),
                 master=self.root)
index b736bd001da87f53e4d7d3290f247ff11b0eee1b..db583553838fb3344c7a09f43500eea6736f6a36 100644 (file)
@@ -59,27 +59,26 @@ class Mbox_func:
 class Mbox:
     """Mock for tkinter.messagebox with an Mbox_func for each function.
 
-    This module was 'tkMessageBox' in 2.x; hence the 'import as' in  3.x.
     Example usage in test_module.py for testing functions in module.py:
     ---
 from idlelib.idle_test.mock_tk import Mbox
 import module
 
-orig_mbox = module.tkMessageBox
+orig_mbox = module.messagebox
 showerror = Mbox.showerror  # example, for attribute access in test methods
 
 class Test(unittest.TestCase):
 
     @classmethod
     def setUpClass(cls):
-        module.tkMessageBox = Mbox
+        module.messagebox = Mbox
 
     @classmethod
     def tearDownClass(cls):
-        module.tkMessageBox = orig_mbox
+        module.messagebox = orig_mbox
     ---
     For 'ask' functions, set func.result return value before calling the method
-    that uses the message function. When tkMessageBox functions are the
+    that uses the message function. When messagebox functions are the
     only gui alls in a method, this replacement makes the method gui-free,
     """
     askokcancel = Mbox_func()     # True or False
index 9c113bd893f137861d6303ca5906cd3280d10f10..642bb5db64dc341d238dd5f097c3985c782ea235 100644 (file)
@@ -195,7 +195,7 @@ class AutoCompleteTest(unittest.TestCase):
         self.assertFalse(acp.open_completions(ac.TAB))
         self.text.delete('1.0', 'end')
 
-    class dummy_acw():
+    class dummy_acw:
         __init__ = Func()
         show_window = Func(result=False)
         hide_window = Func()
index a76829f3656c80a285d574b83864954107d26064..b23915c5ab7849d5ccd8d23524fe8670f6f86649 100644 (file)
@@ -10,7 +10,7 @@ from idlelib.idle_test.mock_tk import Text
 
 
 # Test Class TC is used in multiple get_argspec test methods
-class TC():
+class TC:
     'doc'
     tip = "(ai=None, *b)"
     def __init__(self, ai=None, *b): 'doc'
@@ -268,7 +268,7 @@ class Get_entityTest(unittest.TestCase):
 # open_calltip is about half the code; the others are fairly trivial.
 # The default mocks are what are needed for open_calltip.
 
-class mock_Shell():
+class mock_Shell:
     "Return mock sufficient to pass to hyperparser."
     def __init__(self, text):
         text.tag_prevrange = Mock(return_value=None)
index 9578cc731a6f93aee4777e53c41e842818c04057..6969ad73b01a81a7ec896a2c1991905e26e7a564 100644 (file)
@@ -20,7 +20,7 @@ testcfg = {
 }
 code_sample = """\
 
-class C1():
+class C1:
     # Class comment.
     def __init__(self, a, b):
         self.a = a
@@ -178,29 +178,29 @@ class CodeContextTest(unittest.TestCase):
         with self.assertRaises(AssertionError):
             gc(1, stopline=0)
 
-        eq(gc(3), ([(2, 0, 'class C1():', 'class')], 0))
+        eq(gc(3), ([(2, 0, 'class C1:', 'class')], 0))
 
         # Don't return comment.
-        eq(gc(4), ([(2, 0, 'class C1():', 'class')], 0))
+        eq(gc(4), ([(2, 0, 'class C1:', 'class')], 0))
 
         # Two indentation levels and no comment.
-        eq(gc(5), ([(2, 0, 'class C1():', 'class'),
+        eq(gc(5), ([(2, 0, 'class C1:', 'class'),
                     (4, 4, '    def __init__(self, a, b):', 'def')], 0))
 
         # Only one 'def' is returned, not both at the same indent level.
-        eq(gc(10), ([(2, 0, 'class C1():', 'class'),
+        eq(gc(10), ([(2, 0, 'class C1:', 'class'),
                      (7, 4, '    def compare(self):', 'def'),
                      (8, 8, '        if a > b:', 'if')], 0))
 
         # With 'elif', also show the 'if' even though it's at the same level.
-        eq(gc(11), ([(2, 0, 'class C1():', 'class'),
+        eq(gc(11), ([(2, 0, 'class C1:', 'class'),
                      (7, 4, '    def compare(self):', 'def'),
                      (8, 8, '        if a > b:', 'if'),
                      (10, 8, '        elif a < b:', 'elif')], 0))
 
         # Set stop_line to not go back to first line in source code.
         # Return includes stop_line.
-        eq(gc(11, stopline=2), ([(2, 0, 'class C1():', 'class'),
+        eq(gc(11, stopline=2), ([(2, 0, 'class C1:', 'class'),
                                  (7, 4, '    def compare(self):', 'def'),
                                  (8, 8, '        if a > b:', 'if'),
                                  (10, 8, '        elif a < b:', 'elif')], 0))
@@ -240,37 +240,37 @@ class CodeContextTest(unittest.TestCase):
         # Scroll down to line 2.
         cc.text.yview(2)
         cc.update_code_context()
-        eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1():', 'class')])
+        eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1:', 'class')])
         eq(cc.topvisible, 3)
-        eq(cc.context.get('1.0', 'end-1c'), 'class C1():')
+        eq(cc.context.get('1.0', 'end-1c'), 'class C1:')
 
         # Scroll down to line 3.  Since it's a comment, nothing changes.
         cc.text.yview(3)
         cc.update_code_context()
-        eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1():', 'class')])
+        eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1:', 'class')])
         eq(cc.topvisible, 4)
-        eq(cc.context.get('1.0', 'end-1c'), 'class C1():')
+        eq(cc.context.get('1.0', 'end-1c'), 'class C1:')
 
         # Scroll down to line 4.
         cc.text.yview(4)
         cc.update_code_context()
         eq(cc.info, [(0, -1, '', False),
-                     (2, 0, 'class C1():', 'class'),
+                     (2, 0, 'class C1:', 'class'),
                      (4, 4, '    def __init__(self, a, b):', 'def')])
         eq(cc.topvisible, 5)
-        eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n'
+        eq(cc.context.get('1.0', 'end-1c'), 'class C1:\n'
                                             '    def __init__(self, a, b):')
 
         # Scroll down to line 11.  Last 'def' is removed.
         cc.text.yview(11)
         cc.update_code_context()
         eq(cc.info, [(0, -1, '', False),
-                     (2, 0, 'class C1():', 'class'),
+                     (2, 0, 'class C1:', 'class'),
                      (7, 4, '    def compare(self):', 'def'),
                      (8, 8, '        if a > b:', 'if'),
                      (10, 8, '        elif a < b:', 'elif')])
         eq(cc.topvisible, 12)
-        eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n'
+        eq(cc.context.get('1.0', 'end-1c'), 'class C1:\n'
                                             '    def compare(self):\n'
                                             '        if a > b:\n'
                                             '        elif a < b:')
@@ -279,12 +279,12 @@ class CodeContextTest(unittest.TestCase):
         cc.update_code_context()
         cc.context_depth = 1
         eq(cc.info, [(0, -1, '', False),
-                     (2, 0, 'class C1():', 'class'),
+                     (2, 0, 'class C1:', 'class'),
                      (7, 4, '    def compare(self):', 'def'),
                      (8, 8, '        if a > b:', 'if'),
                      (10, 8, '        elif a < b:', 'elif')])
         eq(cc.topvisible, 12)
-        eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n'
+        eq(cc.context.get('1.0', 'end-1c'), 'class C1:\n'
                                             '    def compare(self):\n'
                                             '        if a > b:\n'
                                             '        elif a < b:')
@@ -293,7 +293,7 @@ class CodeContextTest(unittest.TestCase):
         cc.text.yview(5)
         cc.update_code_context()
         eq(cc.info, [(0, -1, '', False),
-                     (2, 0, 'class C1():', 'class'),
+                     (2, 0, 'class C1:', 'class'),
                      (4, 4, '    def __init__(self, a, b):', 'def')])
         eq(cc.topvisible, 6)
         # context_depth is 1.
@@ -440,7 +440,7 @@ class HelperFunctionText(unittest.TestCase):
         # Line 1 is not a BLOCKOPENER.
         eq(gli(lines[0]), (codecontext.INFINITY, '', False))
         # Line 2 is a BLOCKOPENER without an indent.
-        eq(gli(lines[1]), (0, 'class C1():', 'class'))
+        eq(gli(lines[1]), (0, 'class C1:', 'class'))
         # Line 3 is not a BLOCKOPENER and does not return the indent level.
         eq(gli(lines[2]), (codecontext.INFINITY, '    # Class comment.', False))
         # Line 4 is a BLOCKOPENER and is indented.
index 1fea6d41df811cc19e9c1e98dcae364a9f09035d..98ddc67afdcc0834c8a5dedc2ec83634b8a80926 100644 (file)
@@ -423,7 +423,7 @@ class HighPageTest(unittest.TestCase):
     def test_color(self):
         d = self.page
         d.on_new_color_set = Func()
-        # self.color is only set in get_color through ColorChooser.
+        # self.color is only set in get_color through colorchooser.
         d.color.set('green')
         self.assertEqual(d.on_new_color_set.called, 1)
         del d.on_new_color_set
@@ -540,8 +540,8 @@ class HighPageTest(unittest.TestCase):
     def test_get_color(self):
         eq = self.assertEqual
         d = self.page
-        orig_chooser = configdialog.tkColorChooser.askcolor
-        chooser = configdialog.tkColorChooser.askcolor = Func()
+        orig_chooser = configdialog.colorchooser.askcolor
+        chooser = configdialog.colorchooser.askcolor = Func()
         gntn = d.get_new_theme_name = Func()
 
         d.highlight_target.set('Editor Breakpoint')
@@ -582,7 +582,7 @@ class HighPageTest(unittest.TestCase):
         eq(d.color.get(), '#de0000')
 
         del d.get_new_theme_name
-        configdialog.tkColorChooser.askcolor = orig_chooser
+        configdialog.colorchooser.askcolor = orig_chooser
 
     def test_on_new_color_set(self):
         d = self.page
index 199f63447ce6cac9135c31a80e3b39e650a713b7..638ebd36a7405d273105dcc36d474b8746cede4c 100644 (file)
@@ -25,5 +25,19 @@ class Test(unittest.TestCase):
 # Classes GUIProxy, IdbAdapter, FrameProxy, CodeProxy, DictProxy,
 # GUIAdapter, IdbProxy plus 7 module functions.
 
+class IdbAdapterTest(unittest.TestCase):
+
+    def test_dict_item_noattr(self):  # Issue 33065.
+
+        class BinData:
+            def __repr__(self):
+                return self.length
+
+        debugger_r.dicttable[0] = {'BinData': BinData()}
+        idb = debugger_r.IdbAdapter(None)
+        self.assertTrue(idb.dict_item(0, 'BinData'))
+        debugger_r.dicttable.clear()
+
+
 if __name__ == '__main__':
     unittest.main(verbosity=2)
index a79bb515089e7bc101ac200755bce7c2585ad41d..e5e903688597aa770452f15102f9ee7850ace49e 100644 (file)
@@ -418,7 +418,7 @@ class FormatRegionTest(unittest.TestCase):
 
     code_sample = """\
 # WS line needed for test.
-class C1():
+class C1:
     # Class comment.
     def __init__(self, a, b):
         self.a = a
index 7c148d23a135b64e143d7e8587b84b62ec71d7c5..b915535acac0cc448c63cff87bfb212523f36c10 100644 (file)
@@ -134,7 +134,7 @@ class CloseTest(unittest.TestCase):
             self.dialog.winfo_class()
 
 
-class Dummy_about_dialog():
+class Dummy_about_dialog:
     # Dummy class for testing file display functions.
     idle_credits = About.show_idle_credits
     idle_readme = About.show_readme
index 7ec0368371c7dfd783f3430b453403add433a399..51d2accfe48a1c738b73509563d21bc59e5d3a12 100644 (file)
@@ -2,6 +2,7 @@
 # Reported as 88%; mocking turtledemo absence would have no point.
 
 from idlelib import mainmenu
+import re
 import unittest
 
 
@@ -16,6 +17,26 @@ class MainMenuTest(unittest.TestCase):
     def test_default_keydefs(self):
         self.assertGreaterEqual(len(mainmenu.default_keydefs), 50)
 
+    def test_tcl_indexes(self):
+        # Test tcl patterns used to find menuitem to alter.
+        # On failure, change pattern here and in function(s).
+        # Patterns here have '.*' for re instead of '*' for tcl.
+        for menu, pattern in (
+            ('debug', '.*tack.*iewer'),  # PyShell.debug_menu_postcommand
+            ('options', '.*ode.*ontext'),  # EW.__init__, CodeContext.toggle...
+            ('options', '.*ine.*umbers'),  # EW.__init__, EW.toggle...event.
+            ):
+            with self.subTest(menu=menu, pattern=pattern):
+                for menutup in mainmenu.menudefs:
+                    if menutup[0] == menu:
+                        break
+                else:
+                    self.assertTrue(0, f"{menu} not in menudefs")
+                self.assertTrue(any(re.search(pattern, menuitem[0])
+                                    for menuitem in menutup[1]
+                                    if menuitem is not None),  # Separator.
+                                f"{pattern} not in {menu}")
+
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)
index f21baf7534420a9d014c9dde3920339e1ff14066..fb5726db1d821ebd4a94db7a83682f250d28b453 100644 (file)
@@ -73,11 +73,12 @@ class PyParseTest(unittest.TestCase):
 
         # Split def across lines.
         setcode('"""This is a module docstring"""\n'
-                'class C():\n'
+                'class C:\n'
                 '    def __init__(self, a,\n'
                 '                 b=True):\n'
                 '        pass\n'
                 )
+        pos0, pos = 33, 42  # Start of 'class...', '    def' lines.
 
         # Passing no value or non-callable should fail (issue 32989).
         with self.assertRaises(TypeError):
@@ -91,40 +92,41 @@ class PyParseTest(unittest.TestCase):
 
         # Make all text look like it's not in a string.  This means that it
         # found a good start position.
-        eq(start(char_in_string_false), 44)
+        eq(start(char_in_string_false), pos)
 
         # If the beginning of the def line is not in a string, then it
         # returns that as the index.
-        eq(start(is_char_in_string=lambda index: index > 44), 44)
+        eq(start(is_char_in_string=lambda index: index > pos), pos)
         # If the beginning of the def line is in a string, then it
         # looks for a previous index.
-        eq(start(is_char_in_string=lambda index: index >= 44), 33)
+        eq(start(is_char_in_string=lambda index: index >= pos), pos0)
         # If everything before the 'def' is in a string, then returns None.
         # The non-continuation def line returns 44 (see below).
-        eq(start(is_char_in_string=lambda index: index < 44), None)
+        eq(start(is_char_in_string=lambda index: index < pos), None)
 
         # Code without extra line break in def line - mostly returns the same
         # values.
         setcode('"""This is a module docstring"""\n'
-                'class C():\n'
+                'class C:\n'
                 '    def __init__(self, a, b=True):\n'
                 '        pass\n'
-                )
-        eq(start(char_in_string_false), 44)
-        eq(start(is_char_in_string=lambda index: index > 44), 44)
-        eq(start(is_char_in_string=lambda index: index >= 44), 33)
+                )  # Does not affect class, def positions.
+        eq(start(char_in_string_false), pos)
+        eq(start(is_char_in_string=lambda index: index > pos), pos)
+        eq(start(is_char_in_string=lambda index: index >= pos), pos0)
         # When the def line isn't split, this returns which doesn't match the
         # split line test.
-        eq(start(is_char_in_string=lambda index: index < 44), 44)
+        eq(start(is_char_in_string=lambda index: index < pos), pos)
 
     def test_set_lo(self):
         code = (
                 '"""This is a module docstring"""\n'
-                'class C():\n'
+                'class C:\n'
                 '    def __init__(self, a,\n'
                 '                 b=True):\n'
                 '        pass\n'
                 )
+        pos = 42
         p = self.parser
         p.set_code(code)
 
@@ -137,8 +139,8 @@ class PyParseTest(unittest.TestCase):
         self.assertEqual(p.code, code)
 
         # An index that is preceded by a newline.
-        p.set_lo(44)
-        self.assertEqual(p.code, code[44:])
+        p.set_lo(pos)
+        self.assertEqual(p.code, code[pos:])
 
     def test_study1(self):
         eq = self.assertEqual
index c3c5d2eeb94998bdfb643eaabdf8e8eec213ce98..6c07389b29ad4558077353dd65eccb32c722dcba 100644 (file)
@@ -10,7 +10,7 @@ from unittest.mock import Mock
 from idlelib.idle_test.mock_tk import Mbox
 import idlelib.searchengine as se
 
-orig_mbox = se.tkMessageBox
+orig_mbox = se.messagebox
 showerror = Mbox.showerror
 
 
@@ -20,7 +20,7 @@ class ReplaceDialogTest(unittest.TestCase):
     def setUpClass(cls):
         cls.root = Tk()
         cls.root.withdraw()
-        se.tkMessageBox = Mbox
+        se.messagebox = Mbox
         cls.engine = se.SearchEngine(cls.root)
         cls.dialog = ReplaceDialog(cls.root, cls.engine)
         cls.dialog.bell = lambda: None
@@ -32,7 +32,7 @@ class ReplaceDialogTest(unittest.TestCase):
 
     @classmethod
     def tearDownClass(cls):
-        se.tkMessageBox = orig_mbox
+        se.messagebox = orig_mbox
         del cls.text, cls.dialog, cls.engine
         cls.root.destroy()
         del cls.root
index 37c0d4525e56cd99566e4cbf4fe499a39b7b080b..a31671ee0485fa4e04c305426c0643502bc2cac9 100644 (file)
@@ -1,16 +1,18 @@
 "Test run, coverage 49%."
 
 from idlelib import run
+import io
+import sys
+from test.support import captured_output, captured_stderr
 import unittest
 from unittest import mock
+import idlelib
 from idlelib.idle_test.mock_idle import Func
-from test.support import captured_output, captured_stderr
 
-import io
-import sys
+idlelib.testing = True  # Use {} for executing test user code.
 
 
-class RunTest(unittest.TestCase):
+class PrintExceptionTest(unittest.TestCase):
 
     def test_print_exception_unhashable(self):
         class UnhashableException(Exception):
@@ -351,5 +353,38 @@ class HandleErrorTest(unittest.TestCase):
             self.assertIn('IndexError', msg)
             eq(func.called, 2)
 
+
+class ExecRuncodeTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.addClassCleanup(setattr,run,'print_exception',run.print_exception)
+        cls.prt = Func()  # Need reference.
+        run.print_exception = cls.prt
+        mockrpc = mock.Mock()
+        mockrpc.console.getvar = Func(result=False)
+        cls.ex = run.Executive(mockrpc)
+
+    @classmethod
+    def tearDownClass(cls):
+        assert sys.excepthook == sys.__excepthook__
+
+    def test_exceptions(self):
+        ex = self.ex
+        ex.runcode('1/0')
+        self.assertIs(ex.user_exc_info[0], ZeroDivisionError)
+
+        self.addCleanup(setattr, sys, 'excepthook', sys.__excepthook__)
+        sys.excepthook = lambda t, e, tb: run.print_exception(t)
+        ex.runcode('1/0')
+        self.assertIs(self.prt.args[0], ZeroDivisionError)
+
+        sys.excepthook = lambda: None
+        ex.runcode('1/0')
+        t, e, tb = ex.user_exc_info
+        self.assertIs(t, TypeError)
+        self.assertTrue(isinstance(e.__context__, ZeroDivisionError))
+
+
 if __name__ == '__main__':
     unittest.main(verbosity=2)
index f8401ce9380f25aed12f135e7d554d1650864622..9d97983941958606af154d8a4f8bb70bf9695d00 100644 (file)
@@ -4,7 +4,7 @@ from idlelib import searchengine as se
 import unittest
 # from test.support import requires
 from tkinter import  BooleanVar, StringVar, TclError  # ,Tk, Text
-import tkinter.messagebox as tkMessageBox
+from tkinter import messagebox
 from idlelib.idle_test.mock_tk import Var, Mbox
 from idlelib.idle_test.mock_tk import Text as mockText
 import re
@@ -19,13 +19,13 @@ def setUpModule():
     # Replace s-e module tkinter imports other than non-gui TclError.
     se.BooleanVar = Var
     se.StringVar = Var
-    se.tkMessageBox = Mbox
+    se.messagebox = Mbox
 
 def tearDownModule():
     # Restore 'just in case', though other tests should also replace.
     se.BooleanVar = BooleanVar
     se.StringVar = StringVar
-    se.tkMessageBox = tkMessageBox
+    se.messagebox = messagebox
 
 
 class Mock:
index e3912f4bbbec892cc6ee257440292f9192af9584..ee1bbd76b50562d8a16fc80ad4808a038d2e6b6e 100644 (file)
@@ -396,7 +396,7 @@ class ExpandingButtonTest(unittest.TestCase):
         expandingbutton.base_text = expandingbutton.text
 
         # Patch the message box module to always return False.
-        with patch('idlelib.squeezer.tkMessageBox') as mock_msgbox:
+        with patch('idlelib.squeezer.messagebox') as mock_msgbox:
             mock_msgbox.askokcancel.return_value = False
             mock_msgbox.askyesno.return_value = False
             # Trigger the expand event.
@@ -407,7 +407,7 @@ class ExpandingButtonTest(unittest.TestCase):
         self.assertEqual(expandingbutton.text.get('1.0', 'end-1c'), '')
 
         # Patch the message box module to always return True.
-        with patch('idlelib.squeezer.tkMessageBox') as mock_msgbox:
+        with patch('idlelib.squeezer.messagebox') as mock_msgbox:
             mock_msgbox.askokcancel.return_value = True
             mock_msgbox.askyesno.return_value = True
             # Trigger the expand event.
diff --git a/Lib/idlelib/idle_test/test_zzdummy.py b/Lib/idlelib/idle_test/test_zzdummy.py
new file mode 100644 (file)
index 0000000..1013cdc
--- /dev/null
@@ -0,0 +1,152 @@
+"Test zzdummy, coverage 100%."
+
+from idlelib import zzdummy
+import unittest
+from test.support import requires
+from tkinter import Tk, Text
+from unittest import mock
+from idlelib import config
+from idlelib import editor
+from idlelib import format
+
+
+usercfg = zzdummy.idleConf.userCfg
+testcfg = {
+    'main': config.IdleUserConfParser(''),
+    'highlight': config.IdleUserConfParser(''),
+    'keys': config.IdleUserConfParser(''),
+    'extensions': config.IdleUserConfParser(''),
+}
+code_sample = """\
+
+class C1():
+    # Class comment.
+    def __init__(self, a, b):
+        self.a = a
+        self.b = b
+"""
+
+
+class DummyEditwin:
+    get_selection_indices = editor.EditorWindow.get_selection_indices
+    def __init__(self, root, text):
+        self.root = root
+        self.top = root
+        self.text = text
+        self.fregion = format.FormatRegion(self)
+        self.text.undo_block_start = mock.Mock()
+        self.text.undo_block_stop = mock.Mock()
+
+
+class ZZDummyTest(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        requires('gui')
+        root = cls.root = Tk()
+        root.withdraw()
+        text = cls.text = Text(cls.root)
+        cls.editor = DummyEditwin(root, text)
+        zzdummy.idleConf.userCfg = testcfg
+
+    @classmethod
+    def tearDownClass(cls):
+        zzdummy.idleConf.userCfg = usercfg
+        del cls.editor, cls.text
+        cls.root.update_idletasks()
+        for id in cls.root.tk.call('after', 'info'):
+            cls.root.after_cancel(id)  # Need for EditorWindow.
+        cls.root.destroy()
+        del cls.root
+
+    def setUp(self):
+        text = self.text
+        text.insert('1.0', code_sample)
+        text.undo_block_start.reset_mock()
+        text.undo_block_stop.reset_mock()
+        zz = self.zz = zzdummy.ZzDummy(self.editor)
+        zzdummy.ZzDummy.ztext = '# ignore #'
+
+    def tearDown(self):
+        self.text.delete('1.0', 'end')
+        del self.zz
+
+    def checklines(self, text, value):
+        # Verify that there are lines being checked.
+        end_line = int(float(text.index('end')))
+
+        # Check each line for the starting text.
+        actual = []
+        for line in range(1, end_line):
+            txt = text.get(f'{line}.0', f'{line}.end')
+            actual.append(txt.startswith(value))
+        return actual
+
+    def test_init(self):
+        zz = self.zz
+        self.assertEqual(zz.editwin, self.editor)
+        self.assertEqual(zz.text, self.editor.text)
+
+    def test_reload(self):
+        self.assertEqual(self.zz.ztext, '# ignore #')
+        testcfg['extensions'].SetOption('ZzDummy', 'z-text', 'spam')
+        zzdummy.ZzDummy.reload()
+        self.assertEqual(self.zz.ztext, 'spam')
+
+    def test_z_in_event(self):
+        eq = self.assertEqual
+        zz = self.zz
+        text = zz.text
+        eq(self.zz.ztext, '# ignore #')
+
+        # No lines have the leading text.
+        expected = [False, False, False, False, False, False, False]
+        actual = self.checklines(text, zz.ztext)
+        eq(expected, actual)
+
+        text.tag_add('sel', '2.0', '4.end')
+        eq(zz.z_in_event(), 'break')
+        expected = [False, True, True, True, False, False, False]
+        actual = self.checklines(text, zz.ztext)
+        eq(expected, actual)
+
+        text.undo_block_start.assert_called_once()
+        text.undo_block_stop.assert_called_once()
+
+    def test_z_out_event(self):
+        eq = self.assertEqual
+        zz = self.zz
+        text = zz.text
+        eq(self.zz.ztext, '# ignore #')
+
+        # Prepend text.
+        text.tag_add('sel', '2.0', '5.end')
+        zz.z_in_event()
+        text.undo_block_start.reset_mock()
+        text.undo_block_stop.reset_mock()
+
+        # Select a few lines to remove text.
+        text.tag_remove('sel', '1.0', 'end')
+        text.tag_add('sel', '3.0', '4.end')
+        eq(zz.z_out_event(), 'break')
+        expected = [False, True, False, False, True, False, False]
+        actual = self.checklines(text, zz.ztext)
+        eq(expected, actual)
+
+        text.undo_block_start.assert_called_once()
+        text.undo_block_stop.assert_called_once()
+
+    def test_roundtrip(self):
+        # Insert and remove to all code should give back original text.
+        zz = self.zz
+        text = zz.text
+
+        text.tag_add('sel', '1.0', 'end-1c')
+        zz.z_in_event()
+        zz.z_out_event()
+
+        self.assertEqual(text.get('1.0', 'end-1c'), code_sample)
+
+
+if __name__ == '__main__':
+    unittest.main(verbosity=2)
index 8bb2fa6a6e79393ce9b82ab0a556c5268da852ac..5ebf7089fb9abede84b41c504f4d95cac0923de0 100644 (file)
@@ -5,8 +5,8 @@ import sys
 import tempfile
 import tokenize
 
-import tkinter.filedialog as tkFileDialog
-import tkinter.messagebox as tkMessageBox
+from tkinter import filedialog
+from tkinter import messagebox
 from tkinter.simpledialog import askstring
 
 import idlelib
@@ -147,10 +147,10 @@ class IOBinding:
                     eol_convention = f.newlines
                     converted = True
         except OSError as err:
-            tkMessageBox.showerror("I/O Error", str(err), parent=self.text)
+            messagebox.showerror("I/O Error", str(err), parent=self.text)
             return False
         except UnicodeDecodeError:
-            tkMessageBox.showerror("Decoding Error",
+            messagebox.showerror("Decoding Error",
                                    "File %s\nFailed to Decode" % filename,
                                    parent=self.text)
             return False
@@ -159,7 +159,7 @@ class IOBinding:
             # If the file does not contain line separators, it is None.
             # If the file contains mixed line separators, it is a tuple.
             if eol_convention is not None:
-                tkMessageBox.showwarning("Mixed Newlines",
+                messagebox.showwarning("Mixed Newlines",
                                          "Mixed newlines detected.\n"
                                          "The file will be changed on save.",
                                          parent=self.text)
@@ -187,10 +187,10 @@ class IOBinding:
             return "yes"
         message = "Do you want to save %s before closing?" % (
             self.filename or "this untitled document")
-        confirm = tkMessageBox.askyesnocancel(
+        confirm = messagebox.askyesnocancel(
                   title="Save On Close",
                   message=message,
-                  default=tkMessageBox.YES,
+                  default=messagebox.YES,
                   parent=self.text)
         if confirm:
             reply = "yes"
@@ -249,7 +249,7 @@ class IOBinding:
                 os.fsync(f.fileno())
             return True
         except OSError as msg:
-            tkMessageBox.showerror("I/O Error", str(msg),
+            messagebox.showerror("I/O Error", str(msg),
                                    parent=self.text)
             return False
 
@@ -286,7 +286,7 @@ class IOBinding:
             failed = str(err)
         except UnicodeEncodeError:
             failed = "Invalid encoding '%s'" % enc
-        tkMessageBox.showerror(
+        messagebox.showerror(
             "I/O Error",
             "%s.\nSaving as UTF-8" % failed,
             parent=self.text)
@@ -295,10 +295,10 @@ class IOBinding:
         return chars.encode('utf-8-sig')
 
     def print_window(self, event):
-        confirm = tkMessageBox.askokcancel(
+        confirm = messagebox.askokcancel(
                   title="Print",
                   message="Print to Default Printer",
-                  default=tkMessageBox.OK,
+                  default=messagebox.OK,
                   parent=self.text)
         if not confirm:
             self.text.focus_set()
@@ -336,10 +336,10 @@ class IOBinding:
                          status + output
             if output:
                 output = "Printing command: %s\n" % repr(command) + output
-                tkMessageBox.showerror("Print status", output, parent=self.text)
+                messagebox.showerror("Print status", output, parent=self.text)
         else:  #no printing for this platform
             message = "Printing is not enabled for this platform: %s" % platform
-            tkMessageBox.showinfo("Print status", message, parent=self.text)
+            messagebox.showinfo("Print status", message, parent=self.text)
         if tempfilename:
             os.unlink(tempfilename)
         return "break"
@@ -358,7 +358,7 @@ class IOBinding:
     def askopenfile(self):
         dir, base = self.defaultfilename("open")
         if not self.opendialog:
-            self.opendialog = tkFileDialog.Open(parent=self.text,
+            self.opendialog = filedialog.Open(parent=self.text,
                                                 filetypes=self.filetypes)
         filename = self.opendialog.show(initialdir=dir, initialfile=base)
         return filename
@@ -378,7 +378,7 @@ class IOBinding:
     def asksavefile(self):
         dir, base = self.defaultfilename("save")
         if not self.savedialog:
-            self.savedialog = tkFileDialog.SaveAs(
+            self.savedialog = filedialog.SaveAs(
                     parent=self.text,
                     filetypes=self.filetypes,
                     defaultextension=self.defaultextension)
index adc302883ae66931fe40cb6e4259a86f11e8df3c..fea3762461e99eabde888c3054dad4750b038480 100755 (executable)
@@ -21,13 +21,13 @@ if sys.platform == 'win32':
     except (ImportError, AttributeError, OSError):
         pass
 
-import tkinter.messagebox as tkMessageBox
+from tkinter import messagebox
 if TkVersion < 8.5:
     root = Tk()  # otherwise create root in main
     root.withdraw()
     from idlelib.run import fix_scaling
     fix_scaling(root)
-    tkMessageBox.showerror("Idle Cannot Start",
+    messagebox.showerror("Idle Cannot Start",
             "Idle requires tcl/tk 8.5+, not %s." % TkVersion,
             parent=root)
     raise SystemExit(1)
@@ -261,7 +261,7 @@ class PyShellEditorWindow(EditorWindow):
         except OSError as err:
             if not getattr(self.root, "breakpoint_error_displayed", False):
                 self.root.breakpoint_error_displayed = True
-                tkMessageBox.showerror(title='IDLE Error',
+                messagebox.showerror(title='IDLE Error',
                     message='Unable to update breakpoint list:\n%s'
                         % str(err),
                     parent=self.text)
@@ -771,7 +771,7 @@ class ModifiedInterpreter(InteractiveInterpreter):
                 exec(code, self.locals)
         except SystemExit:
             if not self.tkconsole.closing:
-                if tkMessageBox.askyesno(
+                if messagebox.askyesno(
                     "Exit?",
                     "Do you want to exit altogether?",
                     default="yes",
@@ -805,7 +805,7 @@ class ModifiedInterpreter(InteractiveInterpreter):
         return self.tkconsole.stderr.write(s)
 
     def display_port_binding_error(self):
-        tkMessageBox.showerror(
+        messagebox.showerror(
             "Port Binding Error",
             "IDLE can't bind to a TCP/IP port, which is necessary to "
             "communicate with its Python execution server.  This might be "
@@ -816,7 +816,7 @@ class ModifiedInterpreter(InteractiveInterpreter):
             parent=self.tkconsole.text)
 
     def display_no_subprocess_error(self):
-        tkMessageBox.showerror(
+        messagebox.showerror(
             "Subprocess Connection Error",
             "IDLE's subprocess didn't make connection.\n"
             "See the 'Startup failure' section of the IDLE doc, online at\n"
@@ -824,7 +824,7 @@ class ModifiedInterpreter(InteractiveInterpreter):
             parent=self.tkconsole.text)
 
     def display_executing_dialog(self):
-        tkMessageBox.showerror(
+        messagebox.showerror(
             "Already executing",
             "The Python Shell window is already executing a command; "
             "please wait until it is finished.",
@@ -945,7 +945,7 @@ class PyShell(OutputWindow):
 
     def toggle_debugger(self, event=None):
         if self.executing:
-            tkMessageBox.showerror("Don't debug now",
+            messagebox.showerror("Don't debug now",
                 "You can only toggle the debugger when idle",
                 parent=self.text)
             self.set_debugger_indicator()
@@ -989,6 +989,10 @@ class PyShell(OutputWindow):
         self.showprompt()
         self.set_debugger_indicator()
 
+    def debug_menu_postcommand(self):
+        state = 'disabled' if self.executing else 'normal'
+        self.update_menu_state('debug', '*tack*iewer', state)
+
     def beginexecuting(self):
         "Helper for ModifiedInterpreter"
         self.resetoutput()
@@ -1003,7 +1007,7 @@ class PyShell(OutputWindow):
     def close(self):
         "Extend EditorWindow.close()"
         if self.executing:
-            response = tkMessageBox.askokcancel(
+            response = messagebox.askokcancel(
                 "Kill?",
                 "Your program is still running!\n Do you want to kill it?",
                 default="ok",
@@ -1061,8 +1065,10 @@ class PyShell(OutputWindow):
                    (sys.version, sys.platform, self.COPYRIGHT, nosub))
         self.text.focus_force()
         self.showprompt()
+        # User code should use separate default Tk root window
         import tkinter
-        tkinter._default_root = None # 03Jan04 KBK What's this?
+        tkinter._support_default_root = True
+        tkinter._default_root = None
         return True
 
     def stop_readline(self):
@@ -1252,7 +1258,7 @@ class PyShell(OutputWindow):
         try:
             sys.last_traceback
         except:
-            tkMessageBox.showerror("No stack trace",
+            messagebox.showerror("No stack trace",
                 "There is no stack trace yet.\n"
                 "(sys.last_traceback is not defined)",
                 parent=self.text)
index aa8cbd36c47926daeab57a0ecce2a3204504e9f6..8efcf048fa3aa20d60efa1ff7973778f642922dd 100644 (file)
@@ -125,7 +125,7 @@ request_queue = queue.Queue(0)
 response_queue = queue.Queue(0)
 
 
-class SocketIO(object):
+class SocketIO:
 
     nextseq = 0
 
@@ -486,7 +486,7 @@ class SocketIO(object):
 
 #----------------- end class SocketIO --------------------
 
-class RemoteObject(object):
+class RemoteObject:
     # Token mix-in class
     pass
 
@@ -497,7 +497,7 @@ def remoteref(obj):
     return RemoteProxy(oid)
 
 
-class RemoteProxy(object):
+class RemoteProxy:
 
     def __init__(self, oid):
         self.oid = oid
@@ -547,7 +547,7 @@ class RPCClient(SocketIO):
         return RPCProxy(self, oid)
 
 
-class RPCProxy(object):
+class RPCProxy:
 
     __methods = None
     __attributes = None
@@ -596,7 +596,7 @@ def _getattributes(obj, attributes):
             attributes[name] = 1
 
 
-class MethodProxy(object):
+class MethodProxy:
 
     def __init__(self, sockio, oid, name):
         self.sockio = sockio
index 1e84ecc6584ef1c77ecee138a81cef23fd353743..07e9a2bf9ceeae1d356e404c58c2247cd43a688f 100644 (file)
@@ -16,6 +16,7 @@ import _thread as thread
 import threading
 import warnings
 
+import idlelib  # testing
 from idlelib import autocomplete  # AutoComplete, fetch_encodings
 from idlelib import calltip  # Calltip
 from idlelib import debugger_r  # start_debugger
@@ -538,18 +539,21 @@ class MyHandler(rpc.RPCHandler):
         thread.interrupt_main()
 
 
-class Executive(object):
+class Executive:
 
     def __init__(self, rpchandler):
         self.rpchandler = rpchandler
-        self.locals = __main__.__dict__
-        self.calltip = calltip.Calltip()
-        self.autocomplete = autocomplete.AutoComplete()
+        if idlelib.testing is False:
+            self.locals = __main__.__dict__
+            self.calltip = calltip.Calltip()
+            self.autocomplete = autocomplete.AutoComplete()
+        else:
+            self.locals = {}
 
     def runcode(self, code):
         global interruptable
         try:
-            self.usr_exc_info = None
+            self.user_exc_info = None
             interruptable = True
             try:
                 exec(code, self.locals)
@@ -562,10 +566,17 @@ class Executive(object):
                     print('SystemExit: ' + str(ob), file=sys.stderr)
             # Return to the interactive prompt.
         except:
-            self.usr_exc_info = sys.exc_info()
+            self.user_exc_info = sys.exc_info()  # For testing, hook, viewer.
             if quitting:
                 exit()
-            print_exception()
+            if sys.excepthook is sys.__excepthook__:
+                print_exception()
+            else:
+                try:
+                    sys.excepthook(*self.user_exc_info)
+                except:
+                    self.user_exc_info = sys.exc_info()  # For testing.
+                    print_exception()
             jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
             if jit:
                 self.rpchandler.interp.open_remote_stack_viewer()
@@ -590,8 +601,8 @@ class Executive(object):
         return self.autocomplete.fetch_completions(what, mode)
 
     def stackviewer(self, flist_oid=None):
-        if self.usr_exc_info:
-            typ, val, tb = self.usr_exc_info
+        if self.user_exc_info:
+            typ, val, tb = self.user_exc_info
         else:
             return None
         flist = None
index 028b0dbd21dfe63c0e8b465dffbd8380102a5fac..55712e904603f867df186ff076e855ceffe248d9 100644 (file)
@@ -14,7 +14,7 @@ import tabnanny
 import time
 import tokenize
 
-import tkinter.messagebox as tkMessageBox
+from tkinter import messagebox
 
 from idlelib.config import idleConf
 from idlelib import macosx
@@ -195,15 +195,15 @@ class ScriptBinding:
 
     def ask_save_dialog(self):
         msg = "Source Must Be Saved\n" + 5*' ' + "OK to Save?"
-        confirm = tkMessageBox.askokcancel(title="Save Before Run or Check",
+        confirm = messagebox.askokcancel(title="Save Before Run or Check",
                                            message=msg,
-                                           default=tkMessageBox.OK,
+                                           default=messagebox.OK,
                                            parent=self.editwin.text)
         return confirm
 
     def errorbox(self, title, message):
         # XXX This should really be a function of EditorWindow...
-        tkMessageBox.showerror(title, message, parent=self.editwin.text)
+        messagebox.showerror(title, message, parent=self.editwin.text)
         self.editwin.text.focus_set()
         self.perf = time.perf_counter()
 
index a50038e282ba6c1966a44275276c1cd9781dce37..eddef581ab40a752b287ee43b052d2e65731d12d 100644 (file)
@@ -2,7 +2,7 @@
 import re
 
 from tkinter import StringVar, BooleanVar, TclError
-import tkinter.messagebox as tkMessageBox
+from tkinter import messagebox
 
 def get(root):
     '''Return the singleton SearchEngine instance for the process.
@@ -96,7 +96,7 @@ class SearchEngine:
             msg = msg + "\nPattern: " + str(pat)
         if col is not None:
             msg = msg + "\nOffset: " + str(col)
-        tkMessageBox.showerror("Regular expression error",
+        messagebox.showerror("Regular expression error",
                                msg, master=self.root)
 
     def search_text(self, text, prog=None, ok=0):
index be1538a25fdedfc53281985398606dc427c67713..3046d803b74a4e3441785d118971f60356e07c1f 100644 (file)
@@ -17,7 +17,7 @@ messages and their tracebacks.
 import re
 
 import tkinter as tk
-import tkinter.messagebox as tkMessageBox
+from tkinter import messagebox
 
 from idlelib.config import idleConf
 from idlelib.textview import view_text
@@ -147,7 +147,7 @@ class ExpandingButton(tk.Button):
         if self.is_dangerous is None:
             self.set_is_dangerous()
         if self.is_dangerous:
-            confirm = tkMessageBox.askokcancel(
+            confirm = messagebox.askokcancel(
                 title="Expand huge output?",
                 message="\n\n".join([
                     "The squeezed output is very long: %d lines, %d chars.",
@@ -155,7 +155,7 @@ class ExpandingButton(tk.Button):
                     "It is recommended to view or copy the output instead.",
                     "Really expand?"
                 ]) % (self.numoflines, len(self.s)),
-                default=tkMessageBox.CANCEL,
+                default=messagebox.CANCEL,
                 parent=self.text)
             if not confirm:
                 return "break"
index 69658264dbd4a485051d25cf7762e50098b01b3f..d714318dae8ef190d08df210fc9ef98e1d840c00 100644 (file)
@@ -7,7 +7,7 @@ This includes:
 from tkinter import *
 
 
-class TooltipBase(object):
+class TooltipBase:
     """abstract base class for tooltips"""
 
     def __init__(self, anchor_widget):
index 3c4b1d23b0d3791cae22cc851ecbecc8cfb65207..1247e8f1cc052860b173e9959deaf134d4b6906a 100644 (file)
@@ -1,42 +1,73 @@
-"Example extension, also used for testing."
+"""Example extension, also used for testing.
+
+See extend.txt for more details on creating an extension.
+See config-extension.def for configuring an extension.
+"""
 
 from idlelib.config import idleConf
+from functools import wraps
+
+
+def format_selection(format_line):
+    "Apply a formatting function to all of the selected lines."
+
+    @wraps(format_line)
+    def apply(self, event=None):
+        head, tail, chars, lines = self.formatter.get_region()
+        for pos in range(len(lines) - 1):
+            line = lines[pos]
+            lines[pos] = format_line(self, line)
+        self.formatter.set_region(head, tail, chars, lines)
+        return 'break'
 
-ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text')
+    return apply
 
 
 class ZzDummy:
+    """Prepend or remove initial text from selected lines."""
 
-##    menudefs = [
-##        ('format', [
-##            ('Z in', '<<z-in>>'),
-##            ('Z out', '<<z-out>>'),
-##        ] )
-##    ]
+    # Extend the format menu.
+    menudefs = [
+        ('format', [
+            ('Z in', '<<z-in>>'),
+            ('Z out', '<<z-out>>'),
+        ] )
+    ]
 
     def __init__(self, editwin):
+        "Initialize the settings for this extension."
+        self.editwin = editwin
         self.text = editwin.text
-        z_in = False
+        self.formatter = editwin.fregion
 
     @classmethod
     def reload(cls):
+        "Load class variables from config."
         cls.ztext = idleConf.GetOption('extensions', 'ZzDummy', 'z-text')
 
-    def z_in_event(self, event):
+    @format_selection
+    def z_in_event(self, line):
+        """Insert text at the beginning of each selected line.
+
+        This is bound to the <<z-in>> virtual event when the extensions
+        are loaded.
         """
+        return f'{self.ztext}{line}'
+
+    @format_selection
+    def z_out_event(self, line):
+        """Remove specific text from the beginning of each selected line.
+
+        This is bound to the <<z-out>> virtual event when the extensions
+        are loaded.
         """
-        text = self.text
-        text.undo_block_start()
-        for line in range(1, text.index('end')):
-            text.insert('%d.0', ztext)
-        text.undo_block_stop()
-        return "break"
+        zlength = 0 if not line.startswith(self.ztext) else len(self.ztext)
+        return line[zlength:]
 
-    def z_out_event(self, event): pass
 
 ZzDummy.reload()
 
-##if __name__ == "__main__":
-##    import unittest
-##    unittest.main('idlelib.idle_test.test_zzdummy',
-##            verbosity=2, exit=False)
+
+if __name__ == "__main__":
+    import unittest
+    unittest.main('idlelib.idle_test.test_zzdummy', verbosity=2, exit=False)
index e007dc188af503685975d7a3820e3c4f1a7ef72a..fa7b15061d941c4d952c8d6446fe33c40890a264 100644 (file)
@@ -18,15 +18,55 @@ decorated: decorators (classdef | funcdef | async_funcdef)
 async_funcdef: ASYNC funcdef
 funcdef: 'def' NAME parameters ['->' test] ':' suite
 parameters: '(' [typedargslist] ')'
-typedargslist: ((tfpdef ['=' test] ',')*
-                ('*' [tname] (',' tname ['=' test])* [',' ['**' tname [',']]] | '**' tname [','])
-                | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
+
+# The following definition for typedarglist is equivalent to this set of rules:
+#
+#     arguments = argument (',' argument)*
+#     argument = tfpdef ['=' test]
+#     kwargs = '**' tname [',']
+#     args = '*' [tname]
+#     kwonly_kwargs = (',' argument)* [',' [kwargs]]
+#     args_kwonly_kwargs = args kwonly_kwargs | kwargs
+#     poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]]
+#     typedargslist_no_posonly  = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs
+#     typedarglist = arguments ',' '/' [',' [typedargslist_no_posonly]])|(typedargslist_no_posonly)"
+#
+# It needs to be fully expanded to allow our LL(1) parser to work on it.
+
+typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* ',' '/' [
+                     ',' [((tfpdef ['=' test] ',')* ('*' [tname] (',' tname ['=' test])*
+                            [',' ['**' tname [',']]] | '**' tname [','])
+                     | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])]
+                ] | ((tfpdef ['=' test] ',')* ('*' [tname] (',' tname ['=' test])*
+                     [',' ['**' tname [',']]] | '**' tname [','])
+                     | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
+
 tname: NAME [':' test]
 tfpdef: tname | '(' tfplist ')'
 tfplist: tfpdef (',' tfpdef)* [',']
-varargslist: ((vfpdef ['=' test] ',')*
-              ('*' [vname] (',' vname ['=' test])*  [',' ['**' vname [',']]] | '**' vname [','])
-              | vfpdef ['=' test] (',' vfpdef ['=' test])* [','])
+
+# The following definition for varargslist is equivalent to this set of rules:
+#
+#     arguments = argument (',' argument )*
+#     argument = vfpdef ['=' test]
+#     kwargs = '**' vname [',']
+#     args = '*' [vname]
+#     kwonly_kwargs = (',' argument )* [',' [kwargs]]
+#     args_kwonly_kwargs = args kwonly_kwargs | kwargs
+#     poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]]
+#     vararglist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs
+#     varargslist = arguments ',' '/' [','[(vararglist_no_posonly)]] | (vararglist_no_posonly)
+#
+# It needs to be fully expanded to allow our LL(1) parser to work on it.
+
+varargslist: vfpdef ['=' test ](',' vfpdef ['=' test])* ',' '/' [',' [
+                     ((vfpdef ['=' test] ',')* ('*' [vname] (',' vname ['=' test])*
+                            [',' ['**' vname [',']]] | '**' vname [','])
+                            | vfpdef ['=' test] (',' vfpdef ['=' test])* [','])
+                     ]] | ((vfpdef ['=' test] ',')*
+                     ('*' [vname] (',' vname ['=' test])*  [',' ['**' vname [',']]]| '**' vname [','])
+                     | vfpdef ['=' test] (',' vfpdef ['=' test])* [','])
+
 vname: NAME
 vfpdef: vname | '(' vfplist ')'
 vfplist: vfpdef (',' vfpdef)* [',']
index ba2bb787332edda24b3993820fb6556c4dc74789..d5db66b9b1e7b9a5c0961befe82bfc043dec78e1 100644 (file)
@@ -272,6 +272,12 @@ class TestUnpackingGeneralizations(GrammarTest):
     def test_dict_display_2(self):
         self.validate("""{**{}, 3:4, **{5:6, 7:8}}""")
 
+    def test_complex_star_expression(self):
+        self.validate("func(* [] or [1])")
+
+    def test_complex_double_star_expression(self):
+        self.validate("func(**{1: 3} if False else {x: x for x in range(3)})")
+
     def test_argument_unpacking_1(self):
         self.validate("""f(a, *b, *c, d)""")
 
@@ -630,6 +636,7 @@ class TestLiterals(GrammarTest):
 
 
 class TestNamedAssignments(GrammarTest):
+    """Also known as the walrus operator."""
 
     def test_named_assignment_if(self):
         driver.parse_string("if f := x(): pass\n")
@@ -644,6 +651,30 @@ class TestNamedAssignments(GrammarTest):
         driver.parse_string("[(lastNum := num) == 1 for num in [1, 2, 3]]\n")
 
 
+class TestPositionalOnlyArgs(GrammarTest):
+
+    def test_one_pos_only_arg(self):
+        driver.parse_string("def one_pos_only_arg(a, /): pass\n")
+
+    def test_all_markers(self):
+        driver.parse_string(
+                "def all_markers(a, b=2, /, c, d=4, *, e=5, f): pass\n")
+
+    def test_all_with_args_and_kwargs(self):
+        driver.parse_string(
+                """def all_markers_with_args_and_kwargs(
+                           aa, b, /, _cc, d, *args, e, f_f, **kwargs,
+                   ):
+                       pass\n""")
+
+    def test_lambda_soup(self):
+        driver.parse_string(
+                "lambda a, b, /, c, d, *args, e, f, **kw: kw\n")
+
+    def test_only_positional_or_keyword(self):
+        driver.parse_string("def func(a,b,/,*,g,e=3): pass\n")
+
+
 class TestPickleableException(unittest.TestCase):
     def test_ParseError(self):
         err = ParseError('msg', 2, None, (1, 'context'))
index 7b169a16fbb70f7bb53287360bcf31413a0aad45..6920a7b654a5989fadc4633e2380192001d2924a 100644 (file)
@@ -1269,6 +1269,14 @@ class Manager(object):
         self.loggerClass = None
         self.logRecordFactory = None
 
+    @property
+    def disable(self):
+        return self._disable
+
+    @disable.setter
+    def disable(self, value):
+        self._disable = _checkLevel(value)
+
     def getLogger(self, name):
         """
         Get a logger with the specified name (channel name), creating it
index d7d957159458be0e0c0f1882beec348fddec6238..7a5192cbadc3adda0876f30fffae63965cca8d1a 100755 (executable)
@@ -1686,8 +1686,9 @@ def main():
 
     sys.argv[:] = args      # Hide "pdb.py" and pdb options from argument list
 
-    # Replace pdb's dir with script's dir in front of module search path.
     if not run_as_module:
+        mainpyfile = os.path.realpath(mainpyfile)
+        # Replace pdb's dir with script's dir in front of module search path.
         sys.path[0] = os.path.dirname(mainpyfile)
 
     # Note on saving/restoring sys.argv: it's a good idea when sys.argv was
index e9f50ab622d3169d1c46e04d4c27f1ae275f4c33..6258827d0e41f80cd7096f65598734a0b7dd1574 100755 (executable)
@@ -782,7 +782,7 @@ class uname_result(
         ):
     """
     A uname_result that's largely compatible with a
-    simple namedtuple except that 'platform' is
+    simple namedtuple except that 'processor' is
     resolved late and cached to avoid calling "uname"
     except when needed.
     """
@@ -797,12 +797,25 @@ class uname_result(
             (self.processor,)
         )
 
+    @classmethod
+    def _make(cls, iterable):
+        # override factory to affect length check
+        num_fields = len(cls._fields)
+        result = cls.__new__(cls, *iterable)
+        if len(result) != num_fields + 1:
+            msg = f'Expected {num_fields} arguments, got {len(result)}'
+            raise TypeError(msg)
+        return result
+
     def __getitem__(self, key):
-        return tuple(iter(self))[key]
+        return tuple(self)[key]
 
     def __len__(self):
         return len(tuple(iter(self)))
 
+    def __reduce__(self):
+        return uname_result, tuple(self)[:len(self._fields)]
+
 
 _uname_cache = None
 
index 5cb017ed8300993ad9767db967e105926e2f0159..d8599fb4eebd66f2e15020b7b0a637b5140dc5f8 100755 (executable)
@@ -595,7 +595,12 @@ def main():
                 '__package__': None,
                 '__cached__': None,
             }
-        runctx(code, globs, None, options.outfile, options.sort)
+        try:
+            runctx(code, globs, None, options.outfile, options.sort)
+        except BrokenPipeError as exc:
+            # Prevent "Exception ignored" during interpreter shutdown.
+            sys.stdout = None
+            sys.exit(exc.errno)
     else:
         parser.print_usage()
     return parser
index d8dd8c536aa708b72aab5e9651e5477800d186b1..ae896c2e5afd6e2d71eda1580310825a7cab06c3 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Autogenerated by Sphinx on Mon Dec  7 15:00:07 2020
+# Autogenerated by Sphinx on Fri Feb 19 13:29:38 2021
 topics = {'assert': 'The "assert" statement\n'
            '**********************\n'
            '\n'
@@ -459,13 +459,12 @@ topics = {'assert': 'The "assert" statement\n'
           '\n'
           '   async_for_stmt ::= "async" for_stmt\n'
           '\n'
-          'An *asynchronous iterable* is able to call asynchronous code in '
-          'its\n'
-          '*iter* implementation, and *asynchronous iterator* can call\n'
-          'asynchronous code in its *next* method.\n'
+          'An *asynchronous iterable* provides an "__aiter__" method that\n'
+          'directly returns an *asynchronous iterator*, which can call\n'
+          'asynchronous code in its "__anext__" method.\n'
           '\n'
           'The "async for" statement allows convenient iteration over\n'
-          'asynchronous iterators.\n'
+          'asynchronous iterables.\n'
           '\n'
           'The following code:\n'
           '\n'
@@ -2381,8 +2380,9 @@ topics = {'assert': 'The "assert" statement\n'
              'compatible\n'
              'with an exception if it is the class or a base class of the '
              'exception\n'
-             'object or a tuple containing an item compatible with the '
-             'exception.\n'
+             'object, or a tuple containing an item that is the class or a '
+             'base\n'
+             'class of the exception object.\n'
              '\n'
              'If no except clause matches the exception, the search for an '
              'exception\n'
@@ -2991,13 +2991,12 @@ topics = {'assert': 'The "assert" statement\n'
              '\n'
              '   async_for_stmt ::= "async" for_stmt\n'
              '\n'
-             'An *asynchronous iterable* is able to call asynchronous code in '
-             'its\n'
-             '*iter* implementation, and *asynchronous iterator* can call\n'
-             'asynchronous code in its *next* method.\n'
+             'An *asynchronous iterable* provides an "__aiter__" method that\n'
+             'directly returns an *asynchronous iterator*, which can call\n'
+             'asynchronous code in its "__anext__" method.\n'
              '\n'
              'The "async for" statement allows convenient iteration over\n'
-             'asynchronous iterators.\n'
+             'asynchronous iterables.\n'
              '\n'
              'The following code:\n'
              '\n'
@@ -5530,44 +5529,51 @@ topics = {'assert': 'The "assert" statement\n'
                   '   |           | formats the result in either fixed-point '
                   'format or in      |\n'
                   '   |           | scientific notation, depending on its '
-                  'magnitude.  The      |\n'
-                  '   |           | precise rules are as follows: suppose that '
-                  'the result      |\n'
+                  'magnitude. A         |\n'
+                  '   |           | precision of "0" is treated as equivalent '
+                  'to a precision   |\n'
+                  '   |           | of "1".  The precise rules are as follows: '
+                  'suppose that    |\n'
+                  '   |           | the result formatted with presentation '
+                  'type "\'e\'" and      |\n'
+                  '   |           | precision "p-1" would have exponent '
+                  '"exp".  Then, if "m <= |\n'
+                  '   |           | exp < p", where "m" is -4 for floats and '
+                  '-6 for            |\n'
+                  '   |           | "Decimals", the number is formatted with '
+                  'presentation type |\n'
+                  '   |           | "\'f\'" and precision "p-1-exp".  '
+                  'Otherwise, the number is   |\n'
                   '   |           | formatted with presentation type "\'e\'" '
-                  'and precision "p-1" |\n'
-                  '   |           | would have exponent "exp".  Then, if "m <= '
-                  'exp < p", where |\n'
-                  '   |           | "m" is -4 for floats and -6 for '
-                  '"Decimals", the number is  |\n'
-                  '   |           | formatted with presentation type "\'f\'" '
                   'and precision       |\n'
-                  '   |           | "p-1-exp".  Otherwise, the number is '
-                  'formatted with        |\n'
-                  '   |           | presentation type "\'e\'" and precision '
-                  '"p-1". In both cases |\n'
-                  '   |           | insignificant trailing zeros are removed '
-                  'from the          |\n'
-                  '   |           | significand, and the decimal point is also '
-                  'removed if      |\n'
-                  '   |           | there are no remaining digits following '
-                  'it, unless the     |\n'
-                  '   |           | "\'#\'" option is used.  Positive and '
-                  'negative infinity,     |\n'
-                  '   |           | positive and negative zero, and nans, are '
-                  'formatted as     |\n'
-                  '   |           | "inf", "-inf", "0", "-0" and "nan" '
-                  'respectively,           |\n'
-                  '   |           | regardless of the precision.  A precision '
-                  'of "0" is        |\n'
-                  '   |           | treated as equivalent to a precision of '
-                  '"1". With no       |\n'
-                  '   |           | precision given, uses a precision of "6" '
-                  'significant       |\n'
-                  '   |           | digits for "float", and shows all '
-                  'coefficient digits for   |\n'
-                  '   |           | '
-                  '"Decimal".                                                 '
-                  '|\n'
+                  '   |           | "p-1". In both cases insignificant '
+                  'trailing zeros are      |\n'
+                  '   |           | removed from the significand, and the '
+                  'decimal point is     |\n'
+                  '   |           | also removed if there are no remaining '
+                  'digits following    |\n'
+                  '   |           | it, unless the "\'#\'" option is used.  '
+                  'With no precision    |\n'
+                  '   |           | given, uses a precision of "6" significant '
+                  'digits for      |\n'
+                  '   |           | "float". For "Decimal", the coefficient of '
+                  'the result is   |\n'
+                  '   |           | formed from the coefficient digits of the '
+                  'value;           |\n'
+                  '   |           | scientific notation is used for values '
+                  'smaller than "1e-6" |\n'
+                  '   |           | in absolute value and values where the '
+                  'place value of the  |\n'
+                  '   |           | least significant digit is larger than 1, '
+                  'and fixed-point  |\n'
+                  '   |           | notation is used otherwise.  Positive and '
+                  'negative         |\n'
+                  '   |           | infinity, positive and negative zero, and '
+                  'nans, are        |\n'
+                  '   |           | formatted as "inf", "-inf", "0", "-0" and '
+                  '"nan"            |\n'
+                  '   |           | respectively, regardless of the '
+                  'precision.                 |\n'
                   '   '
                   '+-----------+------------------------------------------------------------+\n'
                   '   | "\'G\'"     | General format. Same as "\'g\'" except '
@@ -5592,19 +5598,24 @@ topics = {'assert': 'The "assert" statement\n'
                   'percent sign.          |\n'
                   '   '
                   '+-----------+------------------------------------------------------------+\n'
-                  '   | None      | Similar to "\'g\'", except that '
-                  'fixed-point notation, when   |\n'
-                  '   |           | used, has at least one digit past the '
-                  'decimal point. The   |\n'
-                  '   |           | default precision is as high as needed to '
-                  'represent the    |\n'
-                  '   |           | particular value. The overall effect is to '
-                  'match the       |\n'
-                  '   |           | output of "str()" as altered by the other '
-                  'format           |\n'
-                  '   |           | '
-                  'modifiers.                                                 '
-                  '|\n'
+                  '   | None      | For "float" this is the same as "\'g\'", '
+                  'except that when    |\n'
+                  '   |           | fixed-point notation is used to format the '
+                  'result, it      |\n'
+                  '   |           | always includes at least one digit past '
+                  'the decimal point. |\n'
+                  '   |           | The precision used is as large as needed '
+                  'to represent the  |\n'
+                  '   |           | given value faithfully.  For "Decimal", '
+                  'this is the same   |\n'
+                  '   |           | as either "\'g\'" or "\'G\'" depending on '
+                  'the value of         |\n'
+                  '   |           | "context.capitals" for the current decimal '
+                  'context.  The   |\n'
+                  '   |           | overall effect is to match the output of '
+                  '"str()" as        |\n'
+                  '   |           | altered by the other format '
+                  'modifiers.                     |\n'
                   '   '
                   '+-----------+------------------------------------------------------------+\n'
                   '\n'
@@ -7950,7 +7961,7 @@ topics = {'assert': 'The "assert" statement\n'
                  'immediate\n'
                  '   subclasses.  This method returns a list of all those '
                  'references\n'
-                 '   still alive. Example:\n'
+                 '   still alive.  The list is in definition order.  Example:\n'
                  '\n'
                  '      >>> int.__subclasses__()\n'
                  "      [<class 'bool'>]\n"
@@ -11259,7 +11270,8 @@ topics = {'assert': 'The "assert" statement\n'
         'object is “compatible” with the exception.  An object is compatible\n'
         'with an exception if it is the class or a base class of the '
         'exception\n'
-        'object or a tuple containing an item compatible with the exception.\n'
+        'object, or a tuple containing an item that is the class or a base\n'
+        'class of the exception object.\n'
         '\n'
         'If no except clause matches the exception, the search for an '
         'exception\n'
@@ -11480,7 +11492,6 @@ topics = {'assert': 'The "assert" statement\n'
           '      There are two types of integers:\n'
           '\n'
           '      Integers ("int")\n'
-          '\n'
           '         These represent numbers in an unlimited range, subject to\n'
           '         available (virtual) memory only.  For the purpose of '
           'shift\n'
index a6454f520df0a321495b5da6f8dade6e4c44036f..36e16a9063b5346dede2fedbb30db2bdbbbbcf17 100644 (file)
@@ -77,6 +77,7 @@ __all__ = [
     "lognormvariate",
     "normalvariate",
     "paretovariate",
+    "randbytes",
     "randint",
     "random",
     "randrange",
@@ -441,7 +442,7 @@ class Random(_random.Random):
                 raise TypeError('Counts must be integers')
             if total <= 0:
                 raise ValueError('Total of counts must be greater than zero')
-            selections = sample(range(total), k=k)
+            selections = self.sample(range(total), k=k)
             bisect = _bisect
             return [population[bisect(cum_counts, s)] for s in selections]
         randbelow = self._randbelow
index 7808ba01cba887f6359a8af488376d8abd41a046..f0472317de9190b50476b2564a6da16933c77f0a 100755 (executable)
@@ -1082,7 +1082,8 @@ class LMTP(SMTP):
         # Handle Unix-domain sockets.
         try:
             self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-            self.sock.settimeout(self.timeout)
+            if self.timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
+                self.sock.settimeout(self.timeout)
             self.file = None
             self.sock.connect(host)
         except OSError:
index d74e74bf2722754256cf82b55d9a90f174115072..214205c1167a411acc058c5b246168148bcd2fc4 100644 (file)
@@ -265,6 +265,14 @@ class TraceCallbackTests(unittest.TestCase):
         cur.execute(queries[0])
         con2.execute("create table bar(x)")
         cur.execute(queries[1])
+
+        # Extract from SQLite 3.7.15 changelog:
+        # Avoid invoking the sqlite3_trace() callback multiple times when a
+        # statement is automatically reprepared due to SQLITE_SCHEMA errors.
+        #
+        # See bpo-40810
+        if sqlite.sqlite_version_info < (3, 7, 15):
+            queries.append(queries[-1])
         self.assertEqual(traced_statements, queries)
 
 
index f1d829a6f1724ef0eafd8240f2e57bca9992261c..ddf1128fdd1c78ec32690e78502d3afc405fb378 100644 (file)
@@ -415,7 +415,11 @@ def check_output(*popenargs, timeout=None, **kwargs):
     if 'input' in kwargs and kwargs['input'] is None:
         # Explicitly passing input=None was previously equivalent to passing an
         # empty string. That is maintained here for backwards compatibility.
-        kwargs['input'] = '' if kwargs.get('universal_newlines', False) else b''
+        if kwargs.get('universal_newlines') or kwargs.get('text'):
+            empty = ''
+        else:
+            empty = b''
+        kwargs['input'] = empty
 
     return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
                **kwargs).stdout
index bf04ac541e6b027f3be0a96f874088c3ea6626f7..e3f79bfde52948d4b49d11e732a90e2a06c0f1cf 100644 (file)
@@ -18,6 +18,11 @@ __all__ = [
     'parse_config_h',
 ]
 
+# Keys for get_config_var() that are never converted to Python integers.
+_ALWAYS_STR = {
+    'MACOSX_DEPLOYMENT_TARGET',
+}
+
 _INSTALL_SCHEMES = {
     'posix_prefix': {
         'stdlib': '{installed_base}/{platlibdir}/python{py_version_short}',
@@ -240,6 +245,9 @@ def _parse_makefile(filename, vars=None):
                 notdone[n] = v
             else:
                 try:
+                    if n in _ALWAYS_STR:
+                        raise ValueError
+
                     v = int(v)
                 except ValueError:
                     # insert literal `$'
@@ -298,6 +306,8 @@ def _parse_makefile(filename, vars=None):
                         notdone[name] = value
                     else:
                         try:
+                            if name in _ALWAYS_STR:
+                                raise ValueError
                             value = int(value)
                         except ValueError:
                             done[name] = value.strip()
@@ -424,10 +434,11 @@ def _init_posix(vars):
 def _init_non_posix(vars):
     """Initialize the module as appropriate for NT"""
     # set basic install directories
+    import _imp
     vars['LIBDEST'] = get_path('stdlib')
     vars['BINLIBDEST'] = get_path('platstdlib')
     vars['INCLUDEPY'] = get_path('include')
-    vars['EXT_SUFFIX'] = '.pyd'
+    vars['EXT_SUFFIX'] = _imp.extension_suffixes()[0]
     vars['EXE'] = '.exe'
     vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
     vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
@@ -458,6 +469,8 @@ def parse_config_h(fp, vars=None):
         if m:
             n, v = m.group(1, 2)
             try:
+                if n in _ALWAYS_STR:
+                    raise ValueError
                 v = int(v)
             except ValueError:
                 pass
index 198d229491b143548a5b244bac80ac9ba59b21ad..e71b3582cf2d7611801945efd7f9b8bbaa25dda4 100644 (file)
@@ -14,6 +14,6 @@ the user build or load random bytecodes anyway.  Otherwise, this is a
 
 import types
 
-co = types.CodeType(0, 0, 0, 0, 0, b'\x04\x71\x00\x00',
+co = types.CodeType(0, 0, 0, 0, 0, 0, b'\x04\x00\x71\x00',
                     (), (), (), '', '', 1, b'')
 exec(co)
index cda4db25cba59446aa315e78c3f6e0b92134fbb5..c7abddcf5fafd34c209e35ea692192fe5a93d002 100644 (file)
@@ -107,6 +107,9 @@ class MockSocket:
     def close(self):
         pass
 
+    def connect(self, host):
+        pass
+
 
 def socket(family=None, type=None, proto=None):
     return MockSocket(family)
@@ -152,8 +155,12 @@ error = socket_module.error
 
 
 # Constants
+_GLOBAL_DEFAULT_TIMEOUT = socket_module._GLOBAL_DEFAULT_TIMEOUT
 AF_INET = socket_module.AF_INET
 AF_INET6 = socket_module.AF_INET6
 SOCK_STREAM = socket_module.SOCK_STREAM
 SOL_SOCKET = None
 SO_REUSEADDR = None
+
+if hasattr(socket_module, 'AF_UNIX'):
+    AF_UNIX = socket_module.AF_UNIX
index 3d54617f68ba4a7d1e4f6cac597fe59b39ffcc5f..7e279cc736a23669d88a5aa6a1c739d0c4aaa46a 100644 (file)
@@ -65,6 +65,10 @@ def count_opcode(code, pickle):
     return n
 
 
+def identity(x):
+    return x
+
+
 class UnseekableIO(io.BytesIO):
     def peek(self, *args):
         raise NotImplementedError
@@ -134,11 +138,12 @@ class E(C):
     def __getinitargs__(self):
         return ()
 
-class H(object):
+# Simple mutable object.
+class Object:
     pass
 
-# Hashable mutable key
-class K(object):
+# Hashable immutable key object containing unheshable mutable data.
+class K:
     def __init__(self, value):
         self.value = value
 
@@ -153,10 +158,6 @@ __main__.D = D
 D.__module__ = "__main__"
 __main__.E = E
 E.__module__ = "__main__"
-__main__.H = H
-H.__module__ = "__main__"
-__main__.K = K
-K.__module__ = "__main__"
 
 class myint(int):
     def __init__(self, x):
@@ -1492,54 +1493,182 @@ class AbstractPickleTests(unittest.TestCase):
             got = filelike.getvalue()
             self.assertEqual(expected, got)
 
-    def test_recursive_list(self):
-        l = []
+    def _test_recursive_list(self, cls, aslist=identity, minprotocol=0):
+        # List containing itself.
+        l = cls()
         l.append(l)
-        for proto in protocols:
+        for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
             s = self.dumps(l, proto)
             x = self.loads(s)
-            self.assertIsInstance(x, list)
-            self.assertEqual(len(x), 1)
-            self.assertIs(x[0], x)
+            self.assertIsInstance(x, cls)
+            y = aslist(x)
+            self.assertEqual(len(y), 1)
+            self.assertIs(y[0], x)
 
-    def test_recursive_tuple_and_list(self):
-        t = ([],)
+    def test_recursive_list(self):
+        self._test_recursive_list(list)
+
+    def test_recursive_list_subclass(self):
+        self._test_recursive_list(MyList, minprotocol=2)
+
+    def test_recursive_list_like(self):
+        self._test_recursive_list(REX_six, aslist=lambda x: x.items)
+
+    def _test_recursive_tuple_and_list(self, cls, aslist=identity, minprotocol=0):
+        # Tuple containing a list containing the original tuple.
+        t = (cls(),)
         t[0].append(t)
-        for proto in protocols:
+        for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
             s = self.dumps(t, proto)
             x = self.loads(s)
             self.assertIsInstance(x, tuple)
             self.assertEqual(len(x), 1)
-            self.assertIsInstance(x[0], list)
-            self.assertEqual(len(x[0]), 1)
-            self.assertIs(x[0][0], x)
+            self.assertIsInstance(x[0], cls)
+            y = aslist(x[0])
+            self.assertEqual(len(y), 1)
+            self.assertIs(y[0], x)
+
+        # List containing a tuple containing the original list.
+        t, = t
+        for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
+            s = self.dumps(t, proto)
+            x = self.loads(s)
+            self.assertIsInstance(x, cls)
+            y = aslist(x)
+            self.assertEqual(len(y), 1)
+            self.assertIsInstance(y[0], tuple)
+            self.assertEqual(len(y[0]), 1)
+            self.assertIs(y[0][0], x)
 
-    def test_recursive_dict(self):
-        d = {}
+    def test_recursive_tuple_and_list(self):
+        self._test_recursive_tuple_and_list(list)
+
+    def test_recursive_tuple_and_list_subclass(self):
+        self._test_recursive_tuple_and_list(MyList, minprotocol=2)
+
+    def test_recursive_tuple_and_list_like(self):
+        self._test_recursive_tuple_and_list(REX_six, aslist=lambda x: x.items)
+
+    def _test_recursive_dict(self, cls, asdict=identity, minprotocol=0):
+        # Dict containing itself.
+        d = cls()
         d[1] = d
-        for proto in protocols:
+        for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
             s = self.dumps(d, proto)
             x = self.loads(s)
-            self.assertIsInstance(x, dict)
-            self.assertEqual(list(x.keys()), [1])
-            self.assertIs(x[1], x)
+            self.assertIsInstance(x, cls)
+            y = asdict(x)
+            self.assertEqual(list(y.keys()), [1])
+            self.assertIs(y[1], x)
 
-    def test_recursive_dict_key(self):
-        d = {}
-        k = K(d)
-        d[k] = 1
-        for proto in protocols:
+    def test_recursive_dict(self):
+        self._test_recursive_dict(dict)
+
+    def test_recursive_dict_subclass(self):
+        self._test_recursive_dict(MyDict, minprotocol=2)
+
+    def test_recursive_dict_like(self):
+        self._test_recursive_dict(REX_seven, asdict=lambda x: x.table)
+
+    def _test_recursive_tuple_and_dict(self, cls, asdict=identity, minprotocol=0):
+        # Tuple containing a dict containing the original tuple.
+        t = (cls(),)
+        t[0][1] = t
+        for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
+            s = self.dumps(t, proto)
+            x = self.loads(s)
+            self.assertIsInstance(x, tuple)
+            self.assertEqual(len(x), 1)
+            self.assertIsInstance(x[0], cls)
+            y = asdict(x[0])
+            self.assertEqual(list(y), [1])
+            self.assertIs(y[1], x)
+
+        # Dict containing a tuple containing the original dict.
+        t, = t
+        for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
+            s = self.dumps(t, proto)
+            x = self.loads(s)
+            self.assertIsInstance(x, cls)
+            y = asdict(x)
+            self.assertEqual(list(y), [1])
+            self.assertIsInstance(y[1], tuple)
+            self.assertEqual(len(y[1]), 1)
+            self.assertIs(y[1][0], x)
+
+    def test_recursive_tuple_and_dict(self):
+        self._test_recursive_tuple_and_dict(dict)
+
+    def test_recursive_tuple_and_dict_subclass(self):
+        self._test_recursive_tuple_and_dict(MyDict, minprotocol=2)
+
+    def test_recursive_tuple_and_dict_like(self):
+        self._test_recursive_tuple_and_dict(REX_seven, asdict=lambda x: x.table)
+
+    def _test_recursive_dict_key(self, cls, asdict=identity, minprotocol=0):
+        # Dict containing an immutable object (as key) containing the original
+        # dict.
+        d = cls()
+        d[K(d)] = 1
+        for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
             s = self.dumps(d, proto)
             x = self.loads(s)
-            self.assertIsInstance(x, dict)
-            self.assertEqual(len(x.keys()), 1)
-            self.assertIsInstance(list(x.keys())[0], K)
-            self.assertIs(list(x.keys())[0].value, x)
+            self.assertIsInstance(x, cls)
+            y = asdict(x)
+            self.assertEqual(len(y.keys()), 1)
+            self.assertIsInstance(list(y.keys())[0], K)
+            self.assertIs(list(y.keys())[0].value, x)
+
+    def test_recursive_dict_key(self):
+        self._test_recursive_dict_key(dict)
+
+    def test_recursive_dict_subclass_key(self):
+        self._test_recursive_dict_key(MyDict, minprotocol=2)
+
+    def test_recursive_dict_like_key(self):
+        self._test_recursive_dict_key(REX_seven, asdict=lambda x: x.table)
+
+    def _test_recursive_tuple_and_dict_key(self, cls, asdict=identity, minprotocol=0):
+        # Tuple containing a dict containing an immutable object (as key)
+        # containing the original tuple.
+        t = (cls(),)
+        t[0][K(t)] = 1
+        for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
+            s = self.dumps(t, proto)
+            x = self.loads(s)
+            self.assertIsInstance(x, tuple)
+            self.assertEqual(len(x), 1)
+            self.assertIsInstance(x[0], cls)
+            y = asdict(x[0])
+            self.assertEqual(len(y), 1)
+            self.assertIsInstance(list(y.keys())[0], K)
+            self.assertIs(list(y.keys())[0].value, x)
+
+        # Dict containing an immutable object (as key) containing a tuple
+        # containing the original dict.
+        t, = t
+        for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
+            s = self.dumps(t, proto)
+            x = self.loads(s)
+            self.assertIsInstance(x, cls)
+            y = asdict(x)
+            self.assertEqual(len(y), 1)
+            self.assertIsInstance(list(y.keys())[0], K)
+            self.assertIs(list(y.keys())[0].value[0], x)
+
+    def test_recursive_tuple_and_dict_key(self):
+        self._test_recursive_tuple_and_dict_key(dict)
+
+    def test_recursive_tuple_and_dict_subclass_key(self):
+        self._test_recursive_tuple_and_dict_key(MyDict, minprotocol=2)
+
+    def test_recursive_tuple_and_dict_like_key(self):
+        self._test_recursive_tuple_and_dict_key(REX_seven, asdict=lambda x: x.table)
 
     def test_recursive_set(self):
+        # Set containing an immutable object containing the original set.
         y = set()
-        k = K(y)
-        y.add(k)
+        y.add(K(y))
         for proto in range(4, pickle.HIGHEST_PROTOCOL + 1):
             s = self.dumps(y, proto)
             x = self.loads(s)
@@ -1548,52 +1677,31 @@ class AbstractPickleTests(unittest.TestCase):
             self.assertIsInstance(list(x)[0], K)
             self.assertIs(list(x)[0].value, x)
 
-    def test_recursive_list_subclass(self):
-        y = MyList()
-        y.append(y)
-        for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
+        # Immutable object containing a set containing the original object.
+        y, = y
+        for proto in range(4, pickle.HIGHEST_PROTOCOL + 1):
             s = self.dumps(y, proto)
             x = self.loads(s)
-            self.assertIsInstance(x, MyList)
-            self.assertEqual(len(x), 1)
-            self.assertIs(x[0], x)
-
-    def test_recursive_dict_subclass(self):
-        d = MyDict()
-        d[1] = d
-        for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
-            s = self.dumps(d, proto)
-            x = self.loads(s)
-            self.assertIsInstance(x, MyDict)
-            self.assertEqual(list(x.keys()), [1])
-            self.assertIs(x[1], x)
-
-    def test_recursive_dict_subclass_key(self):
-        d = MyDict()
-        k = K(d)
-        d[k] = 1
-        for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
-            s = self.dumps(d, proto)
-            x = self.loads(s)
-            self.assertIsInstance(x, MyDict)
-            self.assertEqual(len(list(x.keys())), 1)
-            self.assertIsInstance(list(x.keys())[0], K)
-            self.assertIs(list(x.keys())[0].value, x)
+            self.assertIsInstance(x, K)
+            self.assertIsInstance(x.value, set)
+            self.assertEqual(len(x.value), 1)
+            self.assertIs(list(x.value)[0], x)
 
     def test_recursive_inst(self):
-        i = C()
+        # Mutable object containing itself.
+        i = Object()
         i.attr = i
         for proto in protocols:
             s = self.dumps(i, proto)
             x = self.loads(s)
-            self.assertIsInstance(x, C)
+            self.assertIsInstance(x, Object)
             self.assertEqual(dir(x), dir(i))
             self.assertIs(x.attr, x)
 
     def test_recursive_multi(self):
         l = []
         d = {1:l}
-        i = C()
+        i = Object()
         i.attr = d
         l.append(i)
         for proto in protocols:
@@ -1603,49 +1711,94 @@ class AbstractPickleTests(unittest.TestCase):
             self.assertEqual(len(x), 1)
             self.assertEqual(dir(x[0]), dir(i))
             self.assertEqual(list(x[0].attr.keys()), [1])
-            self.assertTrue(x[0].attr[1] is x)
-
-    def check_recursive_collection_and_inst(self, factory):
-        h = H()
-        y = factory([h])
-        h.attr = y
+            self.assertIs(x[0].attr[1], x)
+
+    def _test_recursive_collection_and_inst(self, factory):
+        # Mutable object containing a collection containing the original
+        # object.
+        o = Object()
+        o.attr = factory([o])
+        t = type(o.attr)
         for proto in protocols:
-            s = self.dumps(y, proto)
+            s = self.dumps(o, proto)
             x = self.loads(s)
-            self.assertIsInstance(x, type(y))
+            self.assertIsInstance(x.attr, t)
+            self.assertEqual(len(x.attr), 1)
+            self.assertIsInstance(list(x.attr)[0], Object)
+            self.assertIs(list(x.attr)[0], x)
+
+        # Collection containing a mutable object containing the original
+        # collection.
+        o = o.attr
+        for proto in protocols:
+            s = self.dumps(o, proto)
+            x = self.loads(s)
+            self.assertIsInstance(x, t)
             self.assertEqual(len(x), 1)
-            self.assertIsInstance(list(x)[0], H)
+            self.assertIsInstance(list(x)[0], Object)
             self.assertIs(list(x)[0].attr, x)
 
     def test_recursive_list_and_inst(self):
-        self.check_recursive_collection_and_inst(list)
+        self._test_recursive_collection_and_inst(list)
 
     def test_recursive_tuple_and_inst(self):
-        self.check_recursive_collection_and_inst(tuple)
+        self._test_recursive_collection_and_inst(tuple)
 
     def test_recursive_dict_and_inst(self):
-        self.check_recursive_collection_and_inst(dict.fromkeys)
+        self._test_recursive_collection_and_inst(dict.fromkeys)
 
     def test_recursive_set_and_inst(self):
-        self.check_recursive_collection_and_inst(set)
+        self._test_recursive_collection_and_inst(set)
 
     def test_recursive_frozenset_and_inst(self):
-        self.check_recursive_collection_and_inst(frozenset)
+        self._test_recursive_collection_and_inst(frozenset)
 
     def test_recursive_list_subclass_and_inst(self):
-        self.check_recursive_collection_and_inst(MyList)
+        self._test_recursive_collection_and_inst(MyList)
 
     def test_recursive_tuple_subclass_and_inst(self):
-        self.check_recursive_collection_and_inst(MyTuple)
+        self._test_recursive_collection_and_inst(MyTuple)
 
     def test_recursive_dict_subclass_and_inst(self):
-        self.check_recursive_collection_and_inst(MyDict.fromkeys)
+        self._test_recursive_collection_and_inst(MyDict.fromkeys)
 
     def test_recursive_set_subclass_and_inst(self):
-        self.check_recursive_collection_and_inst(MySet)
+        self._test_recursive_collection_and_inst(MySet)
 
     def test_recursive_frozenset_subclass_and_inst(self):
-        self.check_recursive_collection_and_inst(MyFrozenSet)
+        self._test_recursive_collection_and_inst(MyFrozenSet)
+
+    def test_recursive_inst_state(self):
+        # Mutable object containing itself.
+        y = REX_state()
+        y.state = y
+        for proto in protocols:
+            s = self.dumps(y, proto)
+            x = self.loads(s)
+            self.assertIsInstance(x, REX_state)
+            self.assertIs(x.state, x)
+
+    def test_recursive_tuple_and_inst_state(self):
+        # Tuple containing a mutable object containing the original tuple.
+        t = (REX_state(),)
+        t[0].state = t
+        for proto in protocols:
+            s = self.dumps(t, proto)
+            x = self.loads(s)
+            self.assertIsInstance(x, tuple)
+            self.assertEqual(len(x), 1)
+            self.assertIsInstance(x[0], REX_state)
+            self.assertIs(x[0].state, x)
+
+        # Mutable object containing a tuple containing the object.
+        t, = t
+        for proto in protocols:
+            s = self.dumps(t, proto)
+            x = self.loads(s)
+            self.assertIsInstance(x, REX_state)
+            self.assertIsInstance(x.state, tuple)
+            self.assertEqual(len(x.state), 1)
+            self.assertIs(x.state[0], x)
 
     def test_unicode(self):
         endcases = ['', '<\\u>', '<\\\u1234>', '<\n>',
@@ -3058,6 +3211,19 @@ class REX_seven(object):
     def __reduce__(self):
         return type(self), (), None, None, iter(self.table.items())
 
+class REX_state(object):
+    """This class is used to check the 3th argument (state) of
+    the reduce protocol.
+    """
+    def __init__(self, state=None):
+        self.state = state
+    def __eq__(self, other):
+        return type(self) is type(other) and self.state == other.state
+    def __setstate__(self, state):
+        self.state = state
+    def __reduce__(self):
+        return type(self), (), self.state
+
 
 # Test classes for newobj
 
diff --git a/Lib/test/test_asyncio/test_asyncio_waitfor.py b/Lib/test/test_asyncio/test_asyncio_waitfor.py
new file mode 100644 (file)
index 0000000..2ca64ab
--- /dev/null
@@ -0,0 +1,61 @@
+import asyncio
+import unittest
+import time
+
+def tearDownModule():
+    asyncio.set_event_loop_policy(None)
+
+
+class SlowTask:
+    """ Task will run for this defined time, ignoring cancel requests """
+    TASK_TIMEOUT = 0.2
+
+    def __init__(self):
+        self.exited = False
+
+    async def run(self):
+        exitat = time.monotonic() + self.TASK_TIMEOUT
+
+        while True:
+            tosleep = exitat - time.monotonic()
+            if tosleep <= 0:
+                break
+
+            try:
+                await asyncio.sleep(tosleep)
+            except asyncio.CancelledError:
+                pass
+
+        self.exited = True
+
+class AsyncioWaitForTest(unittest.TestCase):
+
+    async def atest_asyncio_wait_for_cancelled(self):
+        t  = SlowTask()
+
+        waitfortask = asyncio.create_task(asyncio.wait_for(t.run(), t.TASK_TIMEOUT * 2))
+        await asyncio.sleep(0)
+        waitfortask.cancel()
+        await asyncio.wait({waitfortask})
+
+        self.assertTrue(t.exited)
+
+    def test_asyncio_wait_for_cancelled(self):
+        asyncio.run(self.atest_asyncio_wait_for_cancelled())
+
+    async def atest_asyncio_wait_for_timeout(self):
+        t  = SlowTask()
+
+        try:
+            await asyncio.wait_for(t.run(), t.TASK_TIMEOUT / 2)
+        except asyncio.TimeoutError:
+            pass
+
+        self.assertTrue(t.exited)
+
+    def test_asyncio_wait_for_timeout(self):
+        asyncio.run(self.atest_asyncio_wait_for_timeout())
+
+
+if __name__ == '__main__':
+    unittest.main()
index 4df1b95bca79afbaa527d23a7a5c88bc3f277812..d009f57e47e05a36f05800f66d09672d8292fb91 100644 (file)
@@ -6,6 +6,7 @@ import builtins
 import collections
 import decimal
 import fractions
+import gc
 import io
 import locale
 import os
@@ -1606,6 +1607,18 @@ class BuiltinTest(unittest.TestCase):
 
         self.assertIs(cm.exception, exception)
 
+    @support.cpython_only
+    def test_zip_result_gc(self):
+        # bpo-42536: zip's tuple-reuse speed trick breaks the GC's assumptions
+        # about what can be untracked. Make sure we re-track result tuples
+        # whenever we reuse them.
+        it = zip([[]])
+        gc.collect()
+        # That GC collection probably untracked the recycled internal result
+        # tuple, which is initialized to (None,). Make sure it's re-tracked when
+        # it's mutated and returned from __next__:
+        self.assertTrue(gc.is_tracked(next(it)))
+
     def test_format(self):
         # Test the basic machinery of the format() builtin.  Don't test
         #  the specifics of the various formatters
index 101942de947fb461220cce6376828f43d3d19cdc..4e1506a6468b931fcb937c16f7e20451037ac354 100644 (file)
@@ -53,12 +53,9 @@ parse_strict_test_cases = [
     ("", ValueError("bad query field: ''")),
     ("&", ValueError("bad query field: ''")),
     ("&&", ValueError("bad query field: ''")),
-    (";", ValueError("bad query field: ''")),
-    (";&;", ValueError("bad query field: ''")),
     # Should the next few really be valid?
     ("=", {}),
     ("=&=", {}),
-    ("=;=", {}),
     # This rest seem to make sense
     ("=a", {'': ['a']}),
     ("&=a", ValueError("bad query field: ''")),
@@ -73,8 +70,6 @@ parse_strict_test_cases = [
     ("a=a+b&b=b+c", {'a': ['a b'], 'b': ['b c']}),
     ("a=a+b&a=b+a", {'a': ['a b', 'b a']}),
     ("x=1&y=2.0&z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}),
-    ("x=1;y=2.0&z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}),
-    ("x=1;y=2.0;z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}),
     ("Hbc5161168c542333633315dee1182227:key_store_seqid=400006&cuyer=r&view=bustomer&order_id=0bb2e248638833d48cb7fed300000f1b&expire=964546263&lobale=en-US&kid=130003.300038&ss=env",
      {'Hbc5161168c542333633315dee1182227:key_store_seqid': ['400006'],
       'cuyer': ['r'],
@@ -201,6 +196,30 @@ Content-Length: 3
                     else:
                         self.assertEqual(fs.getvalue(key), expect_val[0])
 
+    def test_separator(self):
+        parse_semicolon = [
+            ("x=1;y=2.0", {'x': ['1'], 'y': ['2.0']}),
+            ("x=1;y=2.0;z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}),
+            (";", ValueError("bad query field: ''")),
+            (";;", ValueError("bad query field: ''")),
+            ("=;a", ValueError("bad query field: 'a'")),
+            (";b=a", ValueError("bad query field: ''")),
+            ("b;=a", ValueError("bad query field: 'b'")),
+            ("a=a+b;b=b+c", {'a': ['a b'], 'b': ['b c']}),
+            ("a=a+b;a=b+a", {'a': ['a b', 'b a']}),
+        ]
+        for orig, expect in parse_semicolon:
+            env = {'QUERY_STRING': orig}
+            fs = cgi.FieldStorage(separator=';', environ=env)
+            if isinstance(expect, dict):
+                for key in expect.keys():
+                    expect_val = expect[key]
+                    self.assertIn(key, fs)
+                    if len(expect_val) > 1:
+                        self.assertEqual(fs.getvalue(key), expect_val)
+                    else:
+                        self.assertEqual(fs.getvalue(key), expect_val[0])
+
     def test_log(self):
         cgi.log("Testing")
 
index 057ec92015cf4f4ef72507bd75c53b52475cc9c2..3ff660cf7a37be31c19790a47f9311de7cab6827 100644 (file)
@@ -680,6 +680,11 @@ class TestNamedTuple(unittest.TestCase):
         self.assertEqual(np.x, 1)
         self.assertEqual(np.y, 2)
 
+    def test_new_builtins_issue_43102(self):
+        self.assertEqual(
+            namedtuple('C', ()).__new__.__globals__['__builtins__'],
+            {})
+
 
 ################################################################################
 ### Abstract Base Classes
index 5e619d13836d2608d467bd56e78a3076183b591c..c1ad23b456e2068793fa675cbfed3b1114d479b3 100644 (file)
@@ -1,14 +1,5 @@
-#
-# Test script for the curses module
-#
-# This script doesn't actually display anything very coherent. but it
-# does call (nearly) every method and function.
-#
-# Functions not tested: {def,reset}_{shell,prog}_mode, getch(), getstr(),
-# init_color()
-# Only called, not tested: getmouse(), ungetmouse()
-#
-
+import functools
+import inspect
 import os
 import string
 import sys
@@ -20,7 +11,6 @@ from test.support import requires, import_module, verbose, SaveSignals
 # Optionally test curses module.  This currently requires that the
 # 'curses' resource be given on the regrtest command line using the -u
 # option.  If not available, nothing after this line will be executed.
-import inspect
 requires('curses')
 
 # If either of these don't exist, skip the tests.
@@ -36,7 +26,28 @@ def requires_curses_func(name):
     return unittest.skipUnless(hasattr(curses, name),
                                'requires curses.%s' % name)
 
+def requires_curses_window_meth(name):
+    def deco(test):
+        @functools.wraps(test)
+        def wrapped(self, *args, **kwargs):
+            if not hasattr(self.stdscr, name):
+                raise unittest.SkipTest('requires curses.window.%s' % name)
+            test(self, *args, **kwargs)
+        return wrapped
+    return deco
+
+
+def requires_colors(test):
+    @functools.wraps(test)
+    def wrapped(self, *args, **kwargs):
+        if not curses.has_colors():
+            self.skipTest('requires colors support')
+        curses.start_color()
+        test(self, *args, **kwargs)
+    return wrapped
+
 term = os.environ.get('TERM')
+SHORT_MAX = 0x7fff
 
 # If newterm was supported we could use it instead of initscr and not exit
 @unittest.skipIf(not term or term == 'unknown',
@@ -47,254 +58,941 @@ class TestCurses(unittest.TestCase):
 
     @classmethod
     def setUpClass(cls):
-        if not sys.__stdout__.isatty():
-            # Temporary skip tests on non-tty
-            raise unittest.SkipTest('sys.__stdout__ is not a tty')
-            cls.tmp = tempfile.TemporaryFile()
-            fd = cls.tmp.fileno()
-        else:
-            cls.tmp = None
-            fd = sys.__stdout__.fileno()
+        if verbose:
+            print(f'TERM={term}', file=sys.stderr, flush=True)
         # testing setupterm() inside initscr/endwin
         # causes terminal breakage
-        curses.setupterm(fd=fd)
-
-    @classmethod
-    def tearDownClass(cls):
-        if cls.tmp:
-            cls.tmp.close()
-            del cls.tmp
+        stdout_fd = sys.__stdout__.fileno()
+        curses.setupterm(fd=stdout_fd)
 
     def setUp(self):
+        self.isatty = True
+        self.output = sys.__stdout__
+        stdout_fd = sys.__stdout__.fileno()
+        if not sys.__stdout__.isatty():
+            # initstr() unconditionally uses C stdout.
+            # If it is redirected to file or pipe, try to attach it
+            # to terminal.
+            # First, save a copy of the file descriptor of stdout, so it
+            # can be restored after finishing the test.
+            dup_fd = os.dup(stdout_fd)
+            self.addCleanup(os.close, dup_fd)
+            self.addCleanup(os.dup2, dup_fd, stdout_fd)
+
+            if sys.__stderr__.isatty():
+                # If stderr is connected to terminal, use it.
+                tmp = sys.__stderr__
+                self.output = sys.__stderr__
+            else:
+                try:
+                    # Try to open the terminal device.
+                    tmp = open('/dev/tty', 'wb', buffering=0)
+                except OSError:
+                    # As a fallback, use regular file to write control codes.
+                    # Some functions (like savetty) will not work, but at
+                    # least the garbage control sequences will not be mixed
+                    # with the testing report.
+                    tmp = tempfile.TemporaryFile(mode='wb', buffering=0)
+                    self.isatty = False
+                self.addCleanup(tmp.close)
+                self.output = None
+            os.dup2(tmp.fileno(), stdout_fd)
+
         self.save_signals = SaveSignals()
         self.save_signals.save()
-        if verbose:
+        self.addCleanup(self.save_signals.restore)
+        if verbose and self.output is not None:
             # just to make the test output a little more readable
-            print()
+            sys.stderr.flush()
+            sys.stdout.flush()
+            print(file=self.output, flush=True)
         self.stdscr = curses.initscr()
-        curses.savetty()
+        if self.isatty:
+            curses.savetty()
+            self.addCleanup(curses.endwin)
+            self.addCleanup(curses.resetty)
+        self.stdscr.erase()
+
+    @requires_curses_func('filter')
+    def test_filter(self):
+        # TODO: Should be called before initscr() or newterm() are called.
+        # TODO: nofilter()
+        curses.filter()
+
+    @requires_curses_func('use_env')
+    def test_use_env(self):
+        # TODO: Should be called before initscr() or newterm() are called.
+        # TODO: use_tioctl()
+        curses.use_env(False)
+        curses.use_env(True)
+
+    def test_create_windows(self):
+        win = curses.newwin(5, 10)
+        self.assertEqual(win.getbegyx(), (0, 0))
+        self.assertEqual(win.getparyx(), (-1, -1))
+        self.assertEqual(win.getmaxyx(), (5, 10))
+
+        win = curses.newwin(10, 15, 2, 5)
+        self.assertEqual(win.getbegyx(), (2, 5))
+        self.assertEqual(win.getparyx(), (-1, -1))
+        self.assertEqual(win.getmaxyx(), (10, 15))
+
+        win2 = win.subwin(3, 7)
+        self.assertEqual(win2.getbegyx(), (3, 7))
+        self.assertEqual(win2.getparyx(), (1, 2))
+        self.assertEqual(win2.getmaxyx(), (9, 13))
+
+        win2 = win.subwin(5, 10, 3, 7)
+        self.assertEqual(win2.getbegyx(), (3, 7))
+        self.assertEqual(win2.getparyx(), (1, 2))
+        self.assertEqual(win2.getmaxyx(), (5, 10))
+
+        win3 = win.derwin(2, 3)
+        self.assertEqual(win3.getbegyx(), (4, 8))
+        self.assertEqual(win3.getparyx(), (2, 3))
+        self.assertEqual(win3.getmaxyx(), (8, 12))
+
+        win3 = win.derwin(6, 11, 2, 3)
+        self.assertEqual(win3.getbegyx(), (4, 8))
+        self.assertEqual(win3.getparyx(), (2, 3))
+        self.assertEqual(win3.getmaxyx(), (6, 11))
+
+        win.mvwin(0, 1)
+        self.assertEqual(win.getbegyx(), (0, 1))
+        self.assertEqual(win.getparyx(), (-1, -1))
+        self.assertEqual(win.getmaxyx(), (10, 15))
+        self.assertEqual(win2.getbegyx(), (3, 7))
+        self.assertEqual(win2.getparyx(), (1, 2))
+        self.assertEqual(win2.getmaxyx(), (5, 10))
+        self.assertEqual(win3.getbegyx(), (4, 8))
+        self.assertEqual(win3.getparyx(), (2, 3))
+        self.assertEqual(win3.getmaxyx(), (6, 11))
+
+        win2.mvderwin(2, 1)
+        self.assertEqual(win2.getbegyx(), (3, 7))
+        self.assertEqual(win2.getparyx(), (2, 1))
+        self.assertEqual(win2.getmaxyx(), (5, 10))
+
+        win3.mvderwin(2, 1)
+        self.assertEqual(win3.getbegyx(), (4, 8))
+        self.assertEqual(win3.getparyx(), (2, 1))
+        self.assertEqual(win3.getmaxyx(), (6, 11))
+
+    def test_move_cursor(self):
+        stdscr = self.stdscr
+        win = stdscr.subwin(10, 15, 2, 5)
+        stdscr.move(1, 2)
+        win.move(2, 4)
+        self.assertEqual(stdscr.getyx(), (1, 2))
+        self.assertEqual(win.getyx(), (2, 4))
 
-    def tearDown(self):
-        curses.resetty()
-        curses.endwin()
-        self.save_signals.restore()
+        win.cursyncup()
+        self.assertEqual(stdscr.getyx(), (4, 9))
+
+    def test_refresh_control(self):
+        stdscr = self.stdscr
+        # touchwin()/untouchwin()/is_wintouched()
+        stdscr.refresh()
+        self.assertIs(stdscr.is_wintouched(), False)
+        stdscr.touchwin()
+        self.assertIs(stdscr.is_wintouched(), True)
+        stdscr.refresh()
+        self.assertIs(stdscr.is_wintouched(), False)
+        stdscr.touchwin()
+        self.assertIs(stdscr.is_wintouched(), True)
+        stdscr.untouchwin()
+        self.assertIs(stdscr.is_wintouched(), False)
+
+        # touchline()/untouchline()/is_linetouched()
+        stdscr.touchline(5, 2)
+        self.assertIs(stdscr.is_linetouched(5), True)
+        self.assertIs(stdscr.is_linetouched(6), True)
+        self.assertIs(stdscr.is_wintouched(), True)
+        stdscr.touchline(5, 1, False)
+        self.assertIs(stdscr.is_linetouched(5), False)
+
+        # syncup()
+        win = stdscr.subwin(10, 15, 2, 5)
+        win2 = win.subwin(5, 10, 3, 7)
+        win2.touchwin()
+        stdscr.untouchwin()
+        win2.syncup()
+        self.assertIs(win.is_wintouched(), True)
+        self.assertIs(stdscr.is_wintouched(), True)
+
+        # syncdown()
+        stdscr.touchwin()
+        win.untouchwin()
+        win2.untouchwin()
+        win2.syncdown()
+        self.assertIs(win2.is_wintouched(), True)
+
+        # syncok()
+        if hasattr(stdscr, 'syncok') and not sys.platform.startswith("sunos"):
+            win.untouchwin()
+            stdscr.untouchwin()
+            for syncok in [False, True]:
+                win2.syncok(syncok)
+                win2.addch('a')
+                self.assertIs(win.is_wintouched(), syncok)
+                self.assertIs(stdscr.is_wintouched(), syncok)
+
+    def test_output_character(self):
+        stdscr = self.stdscr
+        encoding = stdscr.encoding
+        # addch()
+        stdscr.refresh()
+        stdscr.move(0, 0)
+        stdscr.addch('A')
+        stdscr.addch(b'A')
+        stdscr.addch(65)
+        c = '\u20ac'
+        try:
+            stdscr.addch(c)
+        except UnicodeEncodeError:
+            self.assertRaises(UnicodeEncodeError, c.encode, encoding)
+        except OverflowError:
+            encoded = c.encode(encoding)
+            self.assertNotEqual(len(encoded), 1, repr(encoded))
+        stdscr.addch('A', curses.A_BOLD)
+        stdscr.addch(1, 2, 'A')
+        stdscr.addch(2, 3, 'A', curses.A_BOLD)
+        self.assertIs(stdscr.is_wintouched(), True)
+
+        # echochar()
+        stdscr.refresh()
+        stdscr.move(0, 0)
+        stdscr.echochar('A')
+        stdscr.echochar(b'A')
+        stdscr.echochar(65)
+        with self.assertRaises((UnicodeEncodeError, OverflowError)):
+            stdscr.echochar('\u20ac')
+        stdscr.echochar('A', curses.A_BOLD)
+        self.assertIs(stdscr.is_wintouched(), False)
+
+    def test_output_string(self):
+        stdscr = self.stdscr
+        encoding = stdscr.encoding
+        # addstr()/insstr()
+        for func in [stdscr.addstr, stdscr.insstr]:
+            with self.subTest(func.__qualname__):
+                stdscr.move(0, 0)
+                func('abcd')
+                func(b'abcd')
+                s = 'àßçđ'
+                try:
+                    func(s)
+                except UnicodeEncodeError:
+                    self.assertRaises(UnicodeEncodeError, s.encode, encoding)
+                func('abcd', curses.A_BOLD)
+                func(1, 2, 'abcd')
+                func(2, 3, 'abcd', curses.A_BOLD)
+
+        # addnstr()/insnstr()
+        for func in [stdscr.addnstr, stdscr.insnstr]:
+            with self.subTest(func.__qualname__):
+                stdscr.move(0, 0)
+                func('1234', 3)
+                func(b'1234', 3)
+                s = '\u0661\u0662\u0663\u0664'
+                try:
+                    func(s, 3)
+                except UnicodeEncodeError:
+                    self.assertRaises(UnicodeEncodeError, s.encode, encoding)
+                func('1234', 5)
+                func('1234', 3, curses.A_BOLD)
+                func(1, 2, '1234', 3)
+                func(2, 3, '1234', 3, curses.A_BOLD)
+
+    def test_output_string_embedded_null_chars(self):
+        # reject embedded null bytes and characters
+        stdscr = self.stdscr
+        for arg in ['a\0', b'a\0']:
+            with self.subTest(arg=arg):
+                self.assertRaises(ValueError, stdscr.addstr, arg)
+                self.assertRaises(ValueError, stdscr.addnstr, arg, 1)
+                self.assertRaises(ValueError, stdscr.insstr, arg)
+                self.assertRaises(ValueError, stdscr.insnstr, arg, 1)
 
-    def test_window_funcs(self):
-        "Test the methods of windows"
+    def test_read_from_window(self):
         stdscr = self.stdscr
-        win = curses.newwin(10,10)
-        win = curses.newwin(5,5, 5,5)
-        win2 = curses.newwin(15,15, 5,5)
-
-        for meth in [stdscr.addch, stdscr.addstr]:
-            for args in [('a',), ('a', curses.A_BOLD),
-                         (4,4, 'a'), (5,5, 'a', curses.A_BOLD)]:
-                with self.subTest(meth=meth.__qualname__, args=args):
-                    meth(*args)
-
-        for meth in [stdscr.clear, stdscr.clrtobot,
-                     stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch,
-                     stdscr.deleteln, stdscr.erase, stdscr.getbegyx,
-                     stdscr.getbkgd, stdscr.getkey, stdscr.getmaxyx,
-                     stdscr.getparyx, stdscr.getyx, stdscr.inch,
-                     stdscr.insertln, stdscr.instr, stdscr.is_wintouched,
-                     win.noutrefresh, stdscr.redrawwin, stdscr.refresh,
-                     stdscr.standout, stdscr.standend, stdscr.syncdown,
-                     stdscr.syncup, stdscr.touchwin, stdscr.untouchwin]:
-            with self.subTest(meth=meth.__qualname__):
-                meth()
-
-        stdscr.addnstr('1234', 3)
-        stdscr.addnstr('1234', 3, curses.A_BOLD)
-        stdscr.addnstr(4,4, '1234', 3)
-        stdscr.addnstr(5,5, '1234', 3, curses.A_BOLD)
-
-        stdscr.attron(curses.A_BOLD)
-        stdscr.attroff(curses.A_BOLD)
-        stdscr.attrset(curses.A_BOLD)
-        stdscr.bkgd(' ')
-        stdscr.bkgd(' ', curses.A_REVERSE)
-        stdscr.bkgdset(' ')
-        stdscr.bkgdset(' ', curses.A_REVERSE)
+        stdscr.addstr(0, 1, 'ABCD', curses.A_BOLD)
+        # inch()
+        stdscr.move(0, 1)
+        self.assertEqual(stdscr.inch(), 65 | curses.A_BOLD)
+        self.assertEqual(stdscr.inch(0, 3), 67 | curses.A_BOLD)
+        stdscr.move(0, 0)
+        # instr()
+        self.assertEqual(stdscr.instr()[:6], b' ABCD ')
+        self.assertEqual(stdscr.instr(3)[:6], b' AB')
+        self.assertEqual(stdscr.instr(0, 2)[:4], b'BCD ')
+        self.assertEqual(stdscr.instr(0, 2, 4), b'BCD ')
+        self.assertRaises(ValueError, stdscr.instr, -2)
+        self.assertRaises(ValueError, stdscr.instr, 0, 2, -2)
+
+    def test_getch(self):
+        win = curses.newwin(5, 12, 5, 2)
+
+        # TODO: Test with real input by writing to master fd.
+        for c in 'spam\n'[::-1]:
+            curses.ungetch(c)
+        self.assertEqual(win.getch(3, 1), b's'[0])
+        self.assertEqual(win.getyx(), (3, 1))
+        self.assertEqual(win.getch(3, 4), b'p'[0])
+        self.assertEqual(win.getyx(), (3, 4))
+        self.assertEqual(win.getch(), b'a'[0])
+        self.assertEqual(win.getyx(), (3, 4))
+        self.assertEqual(win.getch(), b'm'[0])
+        self.assertEqual(win.getch(), b'\n'[0])
+
+    def test_getstr(self):
+        win = curses.newwin(5, 12, 5, 2)
+        curses.echo()
+        self.addCleanup(curses.noecho)
+
+        self.assertRaises(ValueError, win.getstr, -400)
+        self.assertRaises(ValueError, win.getstr, 2, 3, -400)
+
+        # TODO: Test with real input by writing to master fd.
+        for c in 'Lorem\nipsum\ndolor\nsit\namet\n'[::-1]:
+            curses.ungetch(c)
+        self.assertEqual(win.getstr(3, 1, 2), b'Lo')
+        self.assertEqual(win.instr(3, 0), b' Lo         ')
+        self.assertEqual(win.getstr(3, 5, 10), b'ipsum')
+        self.assertEqual(win.instr(3, 0), b' Lo  ipsum  ')
+        self.assertEqual(win.getstr(1, 5), b'dolor')
+        self.assertEqual(win.instr(1, 0), b'     dolor  ')
+        self.assertEqual(win.getstr(2), b'si')
+        self.assertEqual(win.instr(1, 0), b'si   dolor  ')
+        self.assertEqual(win.getstr(), b'amet')
+        self.assertEqual(win.instr(1, 0), b'amet dolor  ')
+
+    def test_clear(self):
+        win = curses.newwin(5, 15, 5, 2)
+        lorem_ipsum(win)
+
+        win.move(0, 8)
+        win.clrtoeol()
+        self.assertEqual(win.instr(0, 0).rstrip(), b'Lorem ip')
+        self.assertEqual(win.instr(1, 0).rstrip(), b'dolor sit amet,')
+
+        win.move(0, 3)
+        win.clrtobot()
+        self.assertEqual(win.instr(0, 0).rstrip(), b'Lor')
+        self.assertEqual(win.instr(1, 0).rstrip(), b'')
+
+        for func in [win.erase, win.clear]:
+            lorem_ipsum(win)
+            func()
+            self.assertEqual(win.instr(0, 0).rstrip(), b'')
+            self.assertEqual(win.instr(1, 0).rstrip(), b'')
+
+    def test_insert_delete(self):
+        win = curses.newwin(5, 15, 5, 2)
+        lorem_ipsum(win)
+
+        win.move(0, 2)
+        win.delch()
+        self.assertEqual(win.instr(0, 0), b'Loem ipsum     ')
+        win.delch(0, 7)
+        self.assertEqual(win.instr(0, 0), b'Loem ipum      ')
+
+        win.move(1, 5)
+        win.deleteln()
+        self.assertEqual(win.instr(0, 0), b'Loem ipum      ')
+        self.assertEqual(win.instr(1, 0), b'consectetur    ')
+        self.assertEqual(win.instr(2, 0), b'adipiscing elit')
+        self.assertEqual(win.instr(3, 0), b'sed do eiusmod ')
+        self.assertEqual(win.instr(4, 0), b'               ')
+
+        win.move(1, 5)
+        win.insertln()
+        self.assertEqual(win.instr(0, 0), b'Loem ipum      ')
+        self.assertEqual(win.instr(1, 0), b'               ')
+        self.assertEqual(win.instr(2, 0), b'consectetur    ')
+
+        win.clear()
+        lorem_ipsum(win)
+        win.move(1, 5)
+        win.insdelln(2)
+        self.assertEqual(win.instr(0, 0), b'Lorem ipsum    ')
+        self.assertEqual(win.instr(1, 0), b'               ')
+        self.assertEqual(win.instr(2, 0), b'               ')
+        self.assertEqual(win.instr(3, 0), b'dolor sit amet,')
+
+        win.clear()
+        lorem_ipsum(win)
+        win.move(1, 5)
+        win.insdelln(-2)
+        self.assertEqual(win.instr(0, 0), b'Lorem ipsum    ')
+        self.assertEqual(win.instr(1, 0), b'adipiscing elit')
+        self.assertEqual(win.instr(2, 0), b'sed do eiusmod ')
+        self.assertEqual(win.instr(3, 0), b'               ')
+
+    def test_scroll(self):
+        win = curses.newwin(5, 15, 5, 2)
+        lorem_ipsum(win)
+        win.scrollok(True)
+        win.scroll()
+        self.assertEqual(win.instr(0, 0), b'dolor sit amet,')
+        win.scroll(2)
+        self.assertEqual(win.instr(0, 0), b'adipiscing elit')
+        win.scroll(-3)
+        self.assertEqual(win.instr(0, 0), b'               ')
+        self.assertEqual(win.instr(2, 0), b'               ')
+        self.assertEqual(win.instr(3, 0), b'adipiscing elit')
+        win.scrollok(False)
+
+    def test_attributes(self):
+        # TODO: attr_get(), attr_set(), ...
+        win = curses.newwin(5, 15, 5, 2)
+        win.attron(curses.A_BOLD)
+        win.attroff(curses.A_BOLD)
+        win.attrset(curses.A_BOLD)
+
+        win.standout()
+        win.standend()
+
+    @requires_curses_window_meth('chgat')
+    def test_chgat(self):
+        win = curses.newwin(5, 15, 5, 2)
+        win.addstr(2, 0, 'Lorem ipsum')
+        win.addstr(3, 0, 'dolor sit amet')
+
+        win.move(2, 8)
+        win.chgat(curses.A_BLINK)
+        self.assertEqual(win.inch(2, 7), b'p'[0])
+        self.assertEqual(win.inch(2, 8), b's'[0] | curses.A_BLINK)
+        self.assertEqual(win.inch(2, 14), b' '[0] | curses.A_BLINK)
+
+        win.move(2, 1)
+        win.chgat(3, curses.A_BOLD)
+        self.assertEqual(win.inch(2, 0), b'L'[0])
+        self.assertEqual(win.inch(2, 1), b'o'[0] | curses.A_BOLD)
+        self.assertEqual(win.inch(2, 3), b'e'[0] | curses.A_BOLD)
+        self.assertEqual(win.inch(2, 4), b'm'[0])
+
+        win.chgat(3, 2, curses.A_UNDERLINE)
+        self.assertEqual(win.inch(3, 1), b'o'[0])
+        self.assertEqual(win.inch(3, 2), b'l'[0] | curses.A_UNDERLINE)
+        self.assertEqual(win.inch(3, 14), b' '[0] | curses.A_UNDERLINE)
+
+        win.chgat(3, 4, 7, curses.A_BLINK)
+        self.assertEqual(win.inch(3, 3), b'o'[0] | curses.A_UNDERLINE)
+        self.assertEqual(win.inch(3, 4), b'r'[0] | curses.A_BLINK)
+        self.assertEqual(win.inch(3, 10), b'a'[0] | curses.A_BLINK)
+        self.assertEqual(win.inch(3, 11), b'm'[0] | curses.A_UNDERLINE)
+        self.assertEqual(win.inch(3, 14), b' '[0] | curses.A_UNDERLINE)
+
+    def test_background(self):
+        win = curses.newwin(5, 15, 5, 2)
+        win.addstr(0, 0, 'Lorem ipsum')
+
+        self.assertIn(win.getbkgd(), (0, 32))
+
+        # bkgdset()
+        win.bkgdset('_')
+        self.assertEqual(win.getbkgd(), b'_'[0])
+        win.bkgdset(b'#')
+        self.assertEqual(win.getbkgd(), b'#'[0])
+        win.bkgdset(65)
+        self.assertEqual(win.getbkgd(), 65)
+        win.bkgdset(0)
+        self.assertEqual(win.getbkgd(), 32)
+
+        win.bkgdset('#', curses.A_REVERSE)
+        self.assertEqual(win.getbkgd(), b'#'[0] | curses.A_REVERSE)
+        self.assertEqual(win.inch(0, 0), b'L'[0])
+        self.assertEqual(win.inch(0, 5), b' '[0])
+        win.bkgdset(0)
+
+        # bkgd()
+        win.bkgd('_')
+        self.assertEqual(win.getbkgd(), b'_'[0])
+        self.assertEqual(win.inch(0, 0), b'L'[0])
+        self.assertEqual(win.inch(0, 5), b'_'[0])
+
+        win.bkgd('#', curses.A_REVERSE)
+        self.assertEqual(win.getbkgd(), b'#'[0] | curses.A_REVERSE)
+        self.assertEqual(win.inch(0, 0), b'L'[0] | curses.A_REVERSE)
+        self.assertEqual(win.inch(0, 5), b'#'[0] | curses.A_REVERSE)
+
+    def test_overlay(self):
+        srcwin = curses.newwin(5, 18, 3, 4)
+        lorem_ipsum(srcwin)
+        dstwin = curses.newwin(7, 17, 5, 7)
+        for i in range(6):
+            dstwin.addstr(i, 0, '_'*17)
+
+        srcwin.overlay(dstwin)
+        self.assertEqual(dstwin.instr(0, 0), b'sectetur_________')
+        self.assertEqual(dstwin.instr(1, 0), b'piscing_elit,____')
+        self.assertEqual(dstwin.instr(2, 0), b'_do_eiusmod______')
+        self.assertEqual(dstwin.instr(3, 0), b'_________________')
+
+        srcwin.overwrite(dstwin)
+        self.assertEqual(dstwin.instr(0, 0), b'sectetur       __')
+        self.assertEqual(dstwin.instr(1, 0), b'piscing elit,  __')
+        self.assertEqual(dstwin.instr(2, 0), b' do eiusmod    __')
+        self.assertEqual(dstwin.instr(3, 0), b'_________________')
+
+        srcwin.overlay(dstwin, 1, 4, 3, 2, 4, 11)
+        self.assertEqual(dstwin.instr(3, 0), b'__r_sit_amet_____')
+        self.assertEqual(dstwin.instr(4, 0), b'__ectetur________')
+        self.assertEqual(dstwin.instr(5, 0), b'_________________')
+
+        srcwin.overwrite(dstwin, 1, 4, 3, 2, 4, 11)
+        self.assertEqual(dstwin.instr(3, 0), b'__r sit amet_____')
+        self.assertEqual(dstwin.instr(4, 0), b'__ectetur   _____')
+        self.assertEqual(dstwin.instr(5, 0), b'_________________')
+
+    def test_refresh(self):
+        win = curses.newwin(5, 15, 2, 5)
+        win.noutrefresh()
+        win.redrawln(1, 2)
+        win.redrawwin()
+        win.refresh()
+        curses.doupdate()
+
+    @requires_curses_window_meth('resize')
+    def test_resize(self):
+        win = curses.newwin(5, 15, 2, 5)
+        win.resize(4, 20)
+        self.assertEqual(win.getmaxyx(), (4, 20))
+        win.resize(5, 15)
+        self.assertEqual(win.getmaxyx(), (5, 15))
+
+    @requires_curses_window_meth('enclose')
+    def test_enclose(self):
+        win = curses.newwin(5, 15, 2, 5)
+        # TODO: Return bool instead of 1/0
+        self.assertTrue(win.enclose(2, 5))
+        self.assertFalse(win.enclose(1, 5))
+        self.assertFalse(win.enclose(2, 4))
+        self.assertTrue(win.enclose(6, 19))
+        self.assertFalse(win.enclose(7, 19))
+        self.assertFalse(win.enclose(6, 20))
+
+    def test_putwin(self):
+        win = curses.newwin(5, 12, 1, 2)
+        win.addstr(2, 1, 'Lorem ipsum')
+        with tempfile.TemporaryFile() as f:
+            win.putwin(f)
+            del win
+            f.seek(0)
+            win = curses.getwin(f)
+            self.assertEqual(win.getbegyx(), (1, 2))
+            self.assertEqual(win.getmaxyx(), (5, 12))
+            self.assertEqual(win.instr(2, 0), b' Lorem ipsum')
 
-        win.border(65, 66, 67, 68,
-                   69, 70, 71, 72)
+    def test_borders_and_lines(self):
+        win = curses.newwin(5, 10, 5, 2)
         win.border('|', '!', '-', '_',
                    '+', '\\', '#', '/')
-        with self.assertRaises(TypeError,
-                               msg="Expected win.border() to raise TypeError"):
-            win.border(65, 66, 67, 68,
-                       69, [], 71, 72)
-
-        win.box(65, 67)
-        win.box('!', '_')
+        self.assertEqual(win.instr(0, 0), b'+--------\\')
+        self.assertEqual(win.instr(1, 0), b'|        !')
+        self.assertEqual(win.instr(4, 0), b'#________/')
+        win.border(b'|', b'!', b'-', b'_',
+                   b'+', b'\\', b'#', b'/')
+        win.border(65, 66, 67, 68,
+                   69, 70, 71, 72)
+        self.assertRaises(TypeError, win.border,
+                          65, 66, 67, 68, 69, [], 71, 72)
+        self.assertRaises(TypeError, win.border,
+                          65, 66, 67, 68, 69, 70, 71, 72, 73)
+        self.assertRaises(TypeError, win.border,
+                          65, 66, 67, 68, 69, 70, 71, 72, 73)
+        win.border(65, 66, 67, 68, 69, 70, 71)
+        win.border(65, 66, 67, 68, 69, 70)
+        win.border(65, 66, 67, 68, 69)
+        win.border(65, 66, 67, 68)
+        win.border(65, 66, 67)
+        win.border(65, 66)
+        win.border(65)
+        win.border()
+
+        win.box(':', '~')
+        self.assertEqual(win.instr(0, 1, 8), b'~~~~~~~~')
+        self.assertEqual(win.instr(1, 0),   b':        :')
+        self.assertEqual(win.instr(4, 1, 8), b'~~~~~~~~')
         win.box(b':', b'~')
+        win.box(65, 67)
         self.assertRaises(TypeError, win.box, 65, 66, 67)
         self.assertRaises(TypeError, win.box, 65)
         win.box()
 
-        stdscr.clearok(1)
+        win.move(1, 2)
+        win.hline('-', 5)
+        self.assertEqual(win.instr(1, 1, 7), b' ----- ')
+        win.hline(b'-', 5)
+        win.hline(45, 5)
+        win.hline('-', 5, curses.A_BOLD)
+        win.hline(1, 1, '-', 5)
+        win.hline(1, 1, '-', 5, curses.A_BOLD)
+
+        win.move(1, 2)
+        win.vline('a', 3)
+        win.vline(b'a', 3)
+        win.vline(97, 3)
+        win.vline('a', 3, curses.A_STANDOUT)
+        win.vline(1, 1, 'a', 3)
+        win.vline(1, 1, ';', 2, curses.A_STANDOUT)
+        self.assertEqual(win.inch(1, 1), b';'[0] | curses.A_STANDOUT)
+        self.assertEqual(win.inch(2, 1), b';'[0] | curses.A_STANDOUT)
+        self.assertEqual(win.inch(3, 1), b'a'[0])
+
+    def test_unctrl(self):
+        # TODO: wunctrl()
+        self.assertEqual(curses.unctrl(b'A'), b'A')
+        self.assertEqual(curses.unctrl('A'), b'A')
+        self.assertEqual(curses.unctrl(65), b'A')
+        self.assertEqual(curses.unctrl(b'\n'), b'^J')
+        self.assertEqual(curses.unctrl('\n'), b'^J')
+        self.assertEqual(curses.unctrl(10), b'^J')
+        self.assertRaises(TypeError, curses.unctrl, b'')
+        self.assertRaises(TypeError, curses.unctrl, b'AB')
+        self.assertRaises(TypeError, curses.unctrl, '')
+        self.assertRaises(TypeError, curses.unctrl, 'AB')
+        self.assertRaises(OverflowError, curses.unctrl, 2**64)
+
+    def test_endwin(self):
+        if not self.isatty:
+            self.skipTest('requires terminal')
+        self.assertIs(curses.isendwin(), False)
+        curses.endwin()
+        self.assertIs(curses.isendwin(), True)
+        curses.doupdate()
+        self.assertIs(curses.isendwin(), False)
+
+    def test_terminfo(self):
+        self.assertIsInstance(curses.tigetflag('hc'), int)
+        self.assertEqual(curses.tigetflag('cols'), -1)
+        self.assertEqual(curses.tigetflag('cr'), -1)
+
+        self.assertIsInstance(curses.tigetnum('cols'), int)
+        self.assertEqual(curses.tigetnum('hc'), -2)
+        self.assertEqual(curses.tigetnum('cr'), -2)
+
+        self.assertIsInstance(curses.tigetstr('cr'), (bytes, type(None)))
+        self.assertIsNone(curses.tigetstr('hc'))
+        self.assertIsNone(curses.tigetstr('cols'))
+
+        cud = curses.tigetstr('cud')
+        if cud is not None:
+            # See issue10570.
+            self.assertIsInstance(cud, bytes)
+            curses.tparm(cud, 2)
+            cud_2 = curses.tparm(cud, 2)
+            self.assertIsInstance(cud_2, bytes)
+            curses.putp(cud_2)
+
+        curses.putp(b'abc\n')
+
+    def test_misc_module_funcs(self):
+        curses.delay_output(1)
+        curses.flushinp()
+
+        curses.doupdate()
+        self.assertIs(curses.isendwin(), False)
 
-        win4 = stdscr.derwin(2,2)
-        win4 = stdscr.derwin(1,1, 5,5)
-        win4.mvderwin(9,9)
+        curses.napms(100)
+
+        curses.newpad(50, 50)
+
+    def test_env_queries(self):
+        # TODO: term_attrs(), erasewchar(), killwchar()
+        self.assertIsInstance(curses.termname(), bytes)
+        self.assertIsInstance(curses.longname(), bytes)
+        self.assertIsInstance(curses.baudrate(), int)
+        self.assertIsInstance(curses.has_ic(), bool)
+        self.assertIsInstance(curses.has_il(), bool)
+        self.assertIsInstance(curses.termattrs(), int)
+
+        c = curses.killchar()
+        self.assertIsInstance(c, bytes)
+        self.assertEqual(len(c), 1)
+        c = curses.erasechar()
+        self.assertIsInstance(c, bytes)
+        self.assertEqual(len(c), 1)
+
+    def test_output_options(self):
+        stdscr = self.stdscr
+
+        stdscr.clearok(True)
+        stdscr.clearok(False)
 
-        stdscr.echochar('a')
-        stdscr.echochar('a', curses.A_BOLD)
-        stdscr.hline('-', 5)
-        stdscr.hline('-', 5, curses.A_BOLD)
-        stdscr.hline(1,1,'-', 5)
-        stdscr.hline(1,1,'-', 5, curses.A_BOLD)
+        stdscr.idcok(True)
+        stdscr.idcok(False)
+
+        stdscr.idlok(False)
+        stdscr.idlok(True)
 
-        stdscr.idcok(1)
-        stdscr.idlok(1)
         if hasattr(stdscr, 'immedok'):
-            stdscr.immedok(1)
-            stdscr.immedok(0)
-        stdscr.insch('c')
-        stdscr.insdelln(1)
-        stdscr.insnstr('abc', 3)
-        stdscr.insnstr('abc', 3, curses.A_BOLD)
-        stdscr.insnstr(5, 5, 'abc', 3)
-        stdscr.insnstr(5, 5, 'abc', 3, curses.A_BOLD)
-
-        stdscr.insstr('def')
-        stdscr.insstr('def', curses.A_BOLD)
-        stdscr.insstr(5, 5, 'def')
-        stdscr.insstr(5, 5, 'def', curses.A_BOLD)
-        stdscr.is_linetouched(0)
-        stdscr.keypad(1)
-        stdscr.leaveok(1)
-        stdscr.move(3,3)
-        win.mvwin(2,2)
-        stdscr.nodelay(1)
-        stdscr.notimeout(1)
-        win2.overlay(win)
-        win2.overwrite(win)
-        win2.overlay(win, 1, 2, 2, 1, 3, 3)
-        win2.overwrite(win, 1, 2, 2, 1, 3, 3)
-        stdscr.redrawln(1,2)
-
-        stdscr.scrollok(1)
-        stdscr.scroll()
-        stdscr.scroll(2)
-        stdscr.scroll(-3)
-
-        stdscr.move(12, 2)
-        stdscr.setscrreg(10,15)
-        win3 = stdscr.subwin(10,10)
-        win3 = stdscr.subwin(10,10, 5,5)
-        if hasattr(stdscr, 'syncok') and not sys.platform.startswith("sunos"):
-            stdscr.syncok(1)
-        stdscr.timeout(5)
-        stdscr.touchline(5,5)
-        stdscr.touchline(5,5,0)
-        stdscr.vline('a', 3)
-        stdscr.vline('a', 3, curses.A_STANDOUT)
-        if hasattr(stdscr, 'chgat'):
-            stdscr.chgat(5, 2, 3, curses.A_BLINK)
-            stdscr.chgat(3, curses.A_BOLD)
-            stdscr.chgat(5, 8, curses.A_UNDERLINE)
-            stdscr.chgat(curses.A_BLINK)
-        stdscr.refresh()
+            stdscr.immedok(True)
+            stdscr.immedok(False)
 
-        stdscr.vline(1,1, 'a', 3)
-        stdscr.vline(1,1, 'a', 3, curses.A_STANDOUT)
+        stdscr.leaveok(True)
+        stdscr.leaveok(False)
 
-        if hasattr(stdscr, 'resize'):
-            stdscr.resize(25, 80)
-        if hasattr(stdscr, 'enclose'):
-            stdscr.enclose(10, 10)
+        stdscr.scrollok(True)
+        stdscr.scrollok(False)
 
-        self.assertRaises(ValueError, stdscr.getstr, -400)
-        self.assertRaises(ValueError, stdscr.getstr, 2, 3, -400)
-        self.assertRaises(ValueError, stdscr.instr, -2)
-        self.assertRaises(ValueError, stdscr.instr, 2, 3, -2)
+        stdscr.setscrreg(5, 10)
 
-    def test_embedded_null_chars(self):
-        # reject embedded null bytes and characters
+        curses.nonl()
+        curses.nl(True)
+        curses.nl(False)
+        curses.nl()
+
+
+    def test_input_options(self):
         stdscr = self.stdscr
-        for arg in ['a', b'a']:
-            with self.subTest(arg=arg):
-                self.assertRaises(ValueError, stdscr.addstr, 'a\0')
-                self.assertRaises(ValueError, stdscr.addnstr, 'a\0', 1)
-                self.assertRaises(ValueError, stdscr.insstr, 'a\0')
-                self.assertRaises(ValueError, stdscr.insnstr, 'a\0', 1)
-
-    def test_module_funcs(self):
-        "Test module-level functions"
-        for func in [curses.baudrate, curses.beep, curses.can_change_color,
-                     curses.cbreak, curses.def_prog_mode, curses.doupdate,
-                     curses.flash, curses.flushinp,
-                     curses.has_colors, curses.has_ic, curses.has_il,
-                     curses.isendwin, curses.killchar, curses.longname,
-                     curses.nocbreak, curses.noecho, curses.nonl,
-                     curses.noqiflush, curses.noraw,
-                     curses.reset_prog_mode, curses.termattrs,
-                     curses.termname, curses.erasechar]:
-            with self.subTest(func=func.__qualname__):
-                func()
-        if hasattr(curses, 'filter'):
-            curses.filter()
-        if hasattr(curses, 'getsyx'):
-            curses.getsyx()
-
-        # Functions that actually need arguments
-        if curses.tigetstr("cnorm"):
-            curses.curs_set(1)
-        curses.delay_output(1)
-        curses.echo() ; curses.echo(1)
 
-        with tempfile.TemporaryFile() as f:
-            self.stdscr.putwin(f)
-            f.seek(0)
-            curses.getwin(f)
+        if self.isatty:
+            curses.nocbreak()
+            curses.cbreak()
+            curses.cbreak(False)
+            curses.cbreak(True)
+
+            curses.intrflush(True)
+            curses.intrflush(False)
+
+            curses.raw()
+            curses.raw(False)
+            curses.raw(True)
+            curses.noraw()
 
+        curses.noecho()
+        curses.echo()
+        curses.echo(False)
+        curses.echo(True)
+
+        curses.halfdelay(255)
         curses.halfdelay(1)
-        curses.intrflush(1)
-        curses.meta(1)
-        curses.napms(100)
-        curses.newpad(50,50)
-        win = curses.newwin(5,5)
-        win = curses.newwin(5,5, 1,1)
-        curses.nl() ; curses.nl(1)
-        curses.putp(b'abc')
+
+        stdscr.keypad(True)
+        stdscr.keypad(False)
+
+        curses.meta(True)
+        curses.meta(False)
+
+        stdscr.nodelay(True)
+        stdscr.nodelay(False)
+
+        curses.noqiflush()
+        curses.qiflush(True)
+        curses.qiflush(False)
         curses.qiflush()
-        curses.raw() ; curses.raw(1)
+
+        stdscr.notimeout(True)
+        stdscr.notimeout(False)
+
+        stdscr.timeout(-1)
+        stdscr.timeout(0)
+        stdscr.timeout(5)
+
+    @requires_curses_func('typeahead')
+    def test_typeahead(self):
+        curses.typeahead(sys.__stdin__.fileno())
+        curses.typeahead(-1)
+
+    def test_prog_mode(self):
+        if not self.isatty:
+            self.skipTest('requires terminal')
+        curses.def_prog_mode()
+        curses.reset_prog_mode()
+
+    def test_beep(self):
+        if (curses.tigetstr("bel") is not None
+            or curses.tigetstr("flash") is not None):
+            curses.beep()
+        else:
+            try:
+                curses.beep()
+            except curses.error:
+                self.skipTest('beep() failed')
+
+    def test_flash(self):
+        if (curses.tigetstr("bel") is not None
+            or curses.tigetstr("flash") is not None):
+            curses.flash()
+        else:
+            try:
+                curses.flash()
+            except curses.error:
+                self.skipTest('flash() failed')
+
+    def test_curs_set(self):
+        for vis, cap in [(0, 'civis'), (2, 'cvvis'), (1, 'cnorm')]:
+            if curses.tigetstr(cap) is not None:
+                curses.curs_set(vis)
+            else:
+                try:
+                    curses.curs_set(vis)
+                except curses.error:
+                    pass
+
+    @requires_curses_func('get_escdelay')
+    def test_escdelay(self):
+        escdelay = curses.get_escdelay()
+        self.assertIsInstance(escdelay, int)
         curses.set_escdelay(25)
         self.assertEqual(curses.get_escdelay(), 25)
+        curses.set_escdelay(escdelay)
+
+    @requires_curses_func('get_tabsize')
+    def test_tabsize(self):
+        tabsize = curses.get_tabsize()
+        self.assertIsInstance(tabsize, int)
         curses.set_tabsize(4)
         self.assertEqual(curses.get_tabsize(), 4)
-        if hasattr(curses, 'setsyx'):
-            curses.setsyx(5,5)
-        curses.tigetflag('hc')
-        curses.tigetnum('co')
-        curses.tigetstr('cr')
-        curses.tparm(b'cr')
-        if hasattr(curses, 'typeahead'):
-            curses.typeahead(sys.__stdin__.fileno())
-        curses.unctrl('a')
-        curses.ungetch('a')
-        if hasattr(curses, 'use_env'):
-            curses.use_env(1)
-
-    # Functions only available on a few platforms
-    def test_colors_funcs(self):
+        curses.set_tabsize(tabsize)
+
+    @requires_curses_func('getsyx')
+    def test_getsyx(self):
+        y, x = curses.getsyx()
+        self.assertIsInstance(y, int)
+        self.assertIsInstance(x, int)
+        curses.setsyx(4, 5)
+        self.assertEqual(curses.getsyx(), (4, 5))
+
+    def bad_colors(self):
+        return (-2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64)
+
+    def bad_pairs(self):
+        return (-2**31 - 1, 2**31, -2**63 - 1, 2**63, 2**64)
+
+    def test_has_colors(self):
+        self.assertIsInstance(curses.has_colors(), bool)
+        self.assertIsInstance(curses.can_change_color(), bool)
+
+    def test_start_color(self):
         if not curses.has_colors():
             self.skipTest('requires colors support')
         curses.start_color()
-        curses.init_pair(2, 1,1)
-        curses.color_content(1)
-        curses.color_pair(2)
-        curses.pair_content(curses.COLOR_PAIRS - 1)
-        curses.pair_number(0)
-
-        if hasattr(curses, 'use_default_colors'):
+        if verbose:
+            print(f'COLORS = {curses.COLORS}', file=sys.stderr)
+            print(f'COLOR_PAIRS = {curses.COLOR_PAIRS}', file=sys.stderr)
+
+    @requires_colors
+    def test_color_content(self):
+        self.assertEqual(curses.color_content(curses.COLOR_BLACK), (0, 0, 0))
+        curses.color_content(0)
+        maxcolor = min(curses.COLORS - 1, SHORT_MAX)
+        curses.color_content(maxcolor)
+
+        for color in self.bad_colors():
+            self.assertRaises(OverflowError, curses.color_content, color)
+        if curses.COLORS <= SHORT_MAX:
+            self.assertRaises(curses.error, curses.color_content, curses.COLORS)
+        self.assertRaises(curses.error, curses.color_content, -1)
+
+    @requires_colors
+    def test_init_color(self):
+        if not curses.can_change_color():
+            self.skipTest('cannot change color')
+
+        old = curses.color_content(0)
+        try:
+            curses.init_color(0, *old)
+        except curses.error:
+            self.skipTest('cannot change color (init_color() failed)')
+        self.addCleanup(curses.init_color, 0, *old)
+        curses.init_color(0, 0, 0, 0)
+        self.assertEqual(curses.color_content(0), (0, 0, 0))
+        curses.init_color(0, 1000, 1000, 1000)
+        self.assertEqual(curses.color_content(0), (1000, 1000, 1000))
+
+        maxcolor = min(curses.COLORS - 1, SHORT_MAX)
+        old = curses.color_content(maxcolor)
+        curses.init_color(maxcolor, *old)
+        self.addCleanup(curses.init_color, maxcolor, *old)
+        curses.init_color(maxcolor, 0, 500, 1000)
+        self.assertEqual(curses.color_content(maxcolor), (0, 500, 1000))
+
+        for color in self.bad_colors():
+            self.assertRaises(OverflowError, curses.init_color, color, 0, 0, 0)
+        if curses.COLORS <= SHORT_MAX:
+            self.assertRaises(curses.error, curses.init_color, curses.COLORS, 0, 0, 0)
+        self.assertRaises(curses.error, curses.init_color, -1, 0, 0, 0)
+        for comp in (-1, 1001):
+            self.assertRaises(curses.error, curses.init_color, 0, comp, 0, 0)
+            self.assertRaises(curses.error, curses.init_color, 0, 0, comp, 0)
+            self.assertRaises(curses.error, curses.init_color, 0, 0, 0, comp)
+
+    def get_pair_limit(self):
+        return min(curses.COLOR_PAIRS, SHORT_MAX)
+
+    @requires_colors
+    def test_pair_content(self):
+        if not hasattr(curses, 'use_default_colors'):
+            self.assertEqual(curses.pair_content(0),
+                             (curses.COLOR_WHITE, curses.COLOR_BLACK))
+        curses.pair_content(0)
+        maxpair = self.get_pair_limit() - 1
+        if maxpair > 0:
+            curses.pair_content(maxpair)
+
+        for pair in self.bad_pairs():
+            self.assertRaises(OverflowError, curses.pair_content, pair)
+        self.assertRaises(curses.error, curses.pair_content, -1)
+
+    @requires_colors
+    def test_init_pair(self):
+        old = curses.pair_content(1)
+        curses.init_pair(1, *old)
+        self.addCleanup(curses.init_pair, 1, *old)
+
+        curses.init_pair(1, 0, 0)
+        self.assertEqual(curses.pair_content(1), (0, 0))
+        maxcolor = min(curses.COLORS - 1, SHORT_MAX)
+        curses.init_pair(1, maxcolor, 0)
+        self.assertEqual(curses.pair_content(1), (maxcolor, 0))
+        curses.init_pair(1, 0, maxcolor)
+        self.assertEqual(curses.pair_content(1), (0, maxcolor))
+        maxpair = self.get_pair_limit() - 1
+        if maxpair > 1:
+            curses.init_pair(maxpair, 0, 0)
+            self.assertEqual(curses.pair_content(maxpair), (0, 0))
+
+        for pair in self.bad_pairs():
+            self.assertRaises(OverflowError, curses.init_pair, pair, 0, 0)
+        self.assertRaises(curses.error, curses.init_pair, -1, 0, 0)
+        for color in self.bad_colors():
+            self.assertRaises(OverflowError, curses.init_pair, 1, color, 0)
+            self.assertRaises(OverflowError, curses.init_pair, 1, 0, color)
+        if curses.COLORS <= SHORT_MAX:
+            self.assertRaises(curses.error, curses.init_pair, 1, curses.COLORS, 0)
+            self.assertRaises(curses.error, curses.init_pair, 1, 0, curses.COLORS)
+
+    @requires_colors
+    def test_color_attrs(self):
+        for pair in 0, 1, 255:
+            attr = curses.color_pair(pair)
+            self.assertEqual(curses.pair_number(attr), pair, attr)
+            self.assertEqual(curses.pair_number(attr | curses.A_BOLD), pair)
+        self.assertEqual(curses.color_pair(0), 0)
+        self.assertEqual(curses.pair_number(0), 0)
+
+    @requires_curses_func('use_default_colors')
+    @requires_colors
+    def test_use_default_colors(self):
+        old = curses.pair_content(0)
+        try:
             curses.use_default_colors()
+        except curses.error:
+            self.skipTest('cannot change color (use_default_colors() failed)')
+        self.assertEqual(curses.pair_content(0), (-1, -1))
+        self.assertIn(old, [(curses.COLOR_WHITE, curses.COLOR_BLACK), (-1, -1), (0, 0)])
 
-    @requires_curses_func('keyname')
     def test_keyname(self):
-        curses.keyname(13)
+        # TODO: key_name()
+        self.assertEqual(curses.keyname(65), b'A')
+        self.assertEqual(curses.keyname(13), b'^M')
+        self.assertEqual(curses.keyname(127), b'^?')
+        self.assertEqual(curses.keyname(0), b'^@')
+        self.assertRaises(ValueError, curses.keyname, -1)
+        self.assertIsInstance(curses.keyname(256), bytes)
 
     @requires_curses_func('has_key')
     def test_has_key(self):
@@ -350,23 +1048,46 @@ class TestCurses(unittest.TestCase):
 
     @requires_curses_func('is_term_resized')
     def test_is_term_resized(self):
-        curses.is_term_resized(*self.stdscr.getmaxyx())
+        lines, cols = curses.LINES, curses.COLS
+        self.assertIs(curses.is_term_resized(lines, cols), False)
+        self.assertIs(curses.is_term_resized(lines-1, cols-1), True)
 
     @requires_curses_func('resize_term')
     def test_resize_term(self):
-        curses.resize_term(*self.stdscr.getmaxyx())
+        curses.update_lines_cols()
+        lines, cols = curses.LINES, curses.COLS
+        new_lines = lines - 1
+        new_cols = cols + 1
+        curses.resize_term(new_lines, new_cols)
+        self.assertEqual(curses.LINES, new_lines)
+        self.assertEqual(curses.COLS, new_cols)
+
+        curses.resize_term(lines, cols)
+        self.assertEqual(curses.LINES, lines)
+        self.assertEqual(curses.COLS, cols)
 
     @requires_curses_func('resizeterm')
     def test_resizeterm(self):
-        stdscr = self.stdscr
+        curses.update_lines_cols()
         lines, cols = curses.LINES, curses.COLS
         new_lines = lines - 1
         new_cols = cols + 1
         curses.resizeterm(new_lines, new_cols)
-
         self.assertEqual(curses.LINES, new_lines)
         self.assertEqual(curses.COLS, new_cols)
 
+        curses.resizeterm(lines, cols)
+        self.assertEqual(curses.LINES, lines)
+        self.assertEqual(curses.COLS, cols)
+
+    def test_ungetch(self):
+        curses.ungetch(b'A')
+        self.assertEqual(self.stdscr.getkey(), 'A')
+        curses.ungetch('B')
+        self.assertEqual(self.stdscr.getkey(), 'B')
+        curses.ungetch(67)
+        self.assertEqual(self.stdscr.getkey(), 'C')
+
     def test_issue6243(self):
         curses.ungetch(1025)
         self.stdscr.getkey()
@@ -395,10 +1116,6 @@ class TestCurses(unittest.TestCase):
             read = stdscr.get_wch()
             self.assertEqual(read, ch)
 
-    def test_issue10570(self):
-        b = curses.tparm(curses.tigetstr("cup"), 5, 3)
-        self.assertIs(type(b), bytes)
-
     def test_encoding(self):
         stdscr = self.stdscr
         import codecs
@@ -438,30 +1155,31 @@ class TestCurses(unittest.TestCase):
         human_readable_signature = stdscr.addch.__doc__.split("\n")[0]
         self.assertIn("[y, x,]", human_readable_signature)
 
+    @requires_curses_window_meth('resize')
     def test_issue13051(self):
-        stdscr = self.stdscr
-        if not hasattr(stdscr, 'resize'):
-            raise unittest.SkipTest('requires curses.window.resize')
-        box = curses.textpad.Textbox(stdscr, insert_mode=True)
-        lines, cols = stdscr.getmaxyx()
-        stdscr.resize(lines-2, cols-2)
+        win = curses.newwin(5, 15, 2, 5)
+        box = curses.textpad.Textbox(win, insert_mode=True)
+        lines, cols = win.getmaxyx()
+        win.resize(lines-2, cols-2)
         # this may cause infinite recursion, leading to a RuntimeError
         box._insert_printable_char('a')
 
 
 class MiscTests(unittest.TestCase):
 
-    @requires_curses_func('update_lines_cols')
     def test_update_lines_cols(self):
-        # this doesn't actually test that LINES and COLS are updated,
-        # because we can't automate changing them. See Issue #4254 for
-        # a manual test script. We can only test that the function
-        # can be called.
         curses.update_lines_cols()
+        lines, cols = curses.LINES, curses.COLS
+        curses.LINES = curses.COLS = 0
+        curses.update_lines_cols()
+        self.assertEqual(curses.LINES, lines)
+        self.assertEqual(curses.COLS, cols)
 
     @requires_curses_func('ncurses_version')
     def test_ncurses_version(self):
         v = curses.ncurses_version
+        if verbose:
+            print(f'ncurses_version = {curses.ncurses_version}', flush=True)
         self.assertIsInstance(v[:], tuple)
         self.assertEqual(len(v), 3)
         self.assertIsInstance(v[0], int)
@@ -477,6 +1195,7 @@ class MiscTests(unittest.TestCase):
         self.assertGreaterEqual(v.minor, 0)
         self.assertGreaterEqual(v.patch, 0)
 
+
 class TestAscii(unittest.TestCase):
 
     def test_controlnames(self):
@@ -565,5 +1284,21 @@ class TestAscii(unittest.TestCase):
         self.assertEqual(unctrl(ord('\xc1')), '!A')
 
 
+def lorem_ipsum(win):
+    text = [
+        'Lorem ipsum',
+        'dolor sit amet,',
+        'consectetur',
+        'adipiscing elit,',
+        'sed do eiusmod',
+        'tempor incididunt',
+        'ut labore et',
+        'dolore magna',
+        'aliqua.',
+    ]
+    maxy, maxx = win.getmaxyx()
+    for y, line in enumerate(text[:maxy]):
+        win.addstr(y, 0, line[:maxx - (y == maxy - 1)])
+
 if __name__ == '__main__':
     unittest.main()
index 9e875da37508382ace354031f718be38e76c0d0b..c7a191bccd69c40256dd88dfd3681bd5a4cda979 100644 (file)
@@ -4,6 +4,8 @@ import gc
 import itertools
 import math
 import pickle
+import random
+import string
 import sys
 import types
 import unittest
@@ -845,6 +847,14 @@ class ClassPropertiesAndMethods(unittest.TestCase):
             self.fail("inheriting from ModuleType and str at the same time "
                       "should fail")
 
+        # Issue 34805: Verify that definition order is retained
+        def random_name():
+            return ''.join(random.choices(string.ascii_letters, k=10))
+        class A:
+            pass
+        subclasses = [type(random_name(), (A,), {}) for i in range(100)]
+        self.assertEqual(A.__subclasses__(), subclasses)
+
     def test_multiple_inheritance(self):
         # Testing multiple inheritance...
         class C(object):
index 6b8596fff6a9f7f1cb4ae378812632b894d4b4a0..b10c07534ddb21a6a803536030a699aeaf979df8 100644 (file)
@@ -1422,6 +1422,25 @@ class DictTest(unittest.TestCase):
         d = CustomReversedDict(pairs)
         self.assertEqual(pairs[::-1], list(dict(d).items()))
 
+    @support.cpython_only
+    def test_dict_items_result_gc(self):
+        # bpo-42536: dict.items's tuple-reuse speed trick breaks the GC's
+        # assumptions about what can be untracked. Make sure we re-track result
+        # tuples whenever we reuse them.
+        it = iter({None: []}.items())
+        gc.collect()
+        # That GC collection probably untracked the recycled internal result
+        # tuple, which is initialized to (None, None). Make sure it's re-tracked
+        # when it's mutated and returned from __next__:
+        self.assertTrue(gc.is_tracked(next(it)))
+
+    @support.cpython_only
+    def test_dict_items_result_gc(self):
+        # Same as test_dict_items_result_gc above, but reversed.
+        it = reversed({None: []}.items())
+        gc.collect()
+        self.assertTrue(gc.is_tracked(next(it)))
+
 
 class CAPITest(unittest.TestCase):
 
index 0e6b1b16ca323827900d79c64d513924c834fb6e..4e22986325521173d2cf18dee585f2bed9390352 100644 (file)
@@ -215,6 +215,18 @@ class TestEnum(unittest.TestCase):
                 set(['__class__', '__doc__', '__module__', 'name', 'value', 'invisible']),
                 )
 
+    def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
+        # see issue40084
+        class SuperEnum(IntEnum):
+            def __new__(cls, value, description=""):
+                obj = int.__new__(cls, value)
+                obj._value_ = value
+                obj.description = description
+                return obj
+        class SubEnum(SuperEnum):
+            sample = 5
+        self.assertTrue({'description'} <= set(dir(SubEnum.sample)))
+
     def test_enum_in_enum_out(self):
         Season = self.Season
         self.assertIs(Season(Season.WINTER), Season.WINTER)
@@ -570,12 +582,15 @@ class TestEnum(unittest.TestCase):
         class Test1Enum(MyMethodEnum, int, MyStrEnum):
             One = 1
             Two = 2
+        self.assertTrue(Test1Enum._member_type_ is int)
         self.assertEqual(str(Test1Enum.One), 'MyStr')
+        self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
         #
         class Test2Enum(MyStrEnum, MyMethodEnum):
             One = 1
             Two = 2
         self.assertEqual(str(Test2Enum.One), 'MyStr')
+        self.assertEqual(format(Test1Enum.One, ''), 'MyStr')
 
     def test_inherited_data_type(self):
         class HexInt(int):
@@ -1132,6 +1147,7 @@ class TestEnum(unittest.TestCase):
         class auto_enum(type(Enum)):
             def __new__(metacls, cls, bases, classdict):
                 temp = type(classdict)()
+                temp._cls_name = cls
                 names = set(classdict._member_names)
                 i = 0
                 for k in classdict._member_names:
@@ -1998,6 +2014,32 @@ class TestEnum(unittest.TestCase):
             REVERT_ALL = "REVERT_ALL"
             RETRY = "RETRY"
 
+    def test_multiple_mixin_inherited(self):
+        class MyInt(int):
+            def __new__(cls, value):
+                return super().__new__(cls, value)
+
+        class HexMixin:
+            def __repr__(self):
+                return hex(self)
+
+        class MyIntEnum(HexMixin, MyInt, enum.Enum):
+            pass
+
+        class Foo(MyIntEnum):
+            TEST = 1
+        self.assertTrue(isinstance(Foo.TEST, MyInt))
+        self.assertEqual(repr(Foo.TEST), "0x1")
+
+        class Fee(MyIntEnum):
+            TEST = 1
+            def __new__(cls, value):
+                value += 1
+                member = int.__new__(cls, value)
+                member._value_ = value
+                return member
+        self.assertEqual(Fee.TEST, 2)
+
     def test_empty_globals(self):
         # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
         # when using compile and exec because f_globals is empty
@@ -2007,6 +2049,22 @@ class TestEnum(unittest.TestCase):
         local_ls = {}
         exec(code, global_ns, local_ls)
 
+    @unittest.skipUnless(
+            sys.version_info[:2] == (3, 9),
+            'private variables are now normal attributes',
+            )
+    def test_warning_for_private_variables(self):
+        with self.assertWarns(DeprecationWarning):
+            class Private(Enum):
+                __corporal = 'Radar'
+        self.assertEqual(Private._Private__corporal.value, 'Radar')
+        try:
+            with self.assertWarns(DeprecationWarning):
+                class Private(Enum):
+                    __major_ = 'Hoolihan'
+        except ValueError:
+            pass
+
 
 class TestOrder(unittest.TestCase):
 
@@ -2144,6 +2202,11 @@ class TestFlag(unittest.TestCase):
         self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
         self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
 
+    def test_format(self):
+        Perm = self.Perm
+        self.assertEqual(format(Perm.R, ''), 'Perm.R')
+        self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
+
     def test_or(self):
         Perm = self.Perm
         for i in Perm:
@@ -2452,6 +2515,42 @@ class TestFlag(unittest.TestCase):
                 'at least one thread failed while creating composite members')
         self.assertEqual(256, len(seen), 'too many composite members created')
 
+    def test_init_subclass(self):
+        class MyEnum(Flag):
+            def __init_subclass__(cls, **kwds):
+                super().__init_subclass__(**kwds)
+                self.assertFalse(cls.__dict__.get('_test', False))
+                cls._test1 = 'MyEnum'
+        #
+        class TheirEnum(MyEnum):
+            def __init_subclass__(cls, **kwds):
+                super(TheirEnum, cls).__init_subclass__(**kwds)
+                cls._test2 = 'TheirEnum'
+        class WhoseEnum(TheirEnum):
+            def __init_subclass__(cls, **kwds):
+                pass
+        class NoEnum(WhoseEnum):
+            ONE = 1
+        self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
+        self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
+        self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
+        self.assertFalse(NoEnum.__dict__.get('_test1', False))
+        self.assertFalse(NoEnum.__dict__.get('_test2', False))
+        #
+        class OurEnum(MyEnum):
+            def __init_subclass__(cls, **kwds):
+                cls._test2 = 'OurEnum'
+        class WhereEnum(OurEnum):
+            def __init_subclass__(cls, **kwds):
+                pass
+        class NeverEnum(WhereEnum):
+            ONE = 1
+        self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
+        self.assertFalse(WhereEnum.__dict__.get('_test1', False))
+        self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
+        self.assertFalse(NeverEnum.__dict__.get('_test1', False))
+        self.assertFalse(NeverEnum.__dict__.get('_test2', False))
+
 
 class TestIntFlag(unittest.TestCase):
     """Tests of the IntFlags."""
@@ -2477,6 +2576,7 @@ class TestIntFlag(unittest.TestCase):
 
     def test_type(self):
         Perm = self.Perm
+        self.assertTrue(Perm._member_type_ is int)
         Open = self.Open
         for f in Perm:
             self.assertTrue(isinstance(f, Perm))
@@ -2556,6 +2656,11 @@ class TestIntFlag(unittest.TestCase):
         self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: -524290>')
         self.assertEqual(repr(Open(~4)), '<Open.CE|AC|RW|WO: -5>')
 
+    def test_format(self):
+        Perm = self.Perm
+        self.assertEqual(format(Perm.R, ''), '4')
+        self.assertEqual(format(Perm.R | Perm.X, ''), '5')
+
     def test_or(self):
         Perm = self.Perm
         for i in Perm:
index 5785cb46492ef7c65a7281f24065ccae0454ae6e..906bfc21a26aede0a6a9d9014e95c385b43c53b2 100644 (file)
@@ -2,6 +2,7 @@ import unittest
 import operator
 import sys
 import pickle
+import gc
 
 from test import support
 
@@ -134,6 +135,18 @@ class EnumerateTestCase(unittest.TestCase, PickleTest):
         self.assertEqual(len(set(map(id, list(enumerate(self.seq))))), len(self.seq))
         self.assertEqual(len(set(map(id, enumerate(self.seq)))), min(1,len(self.seq)))
 
+    @support.cpython_only
+    def test_enumerate_result_gc(self):
+        # bpo-42536: enumerate's tuple-reuse speed trick breaks the GC's
+        # assumptions about what can be untracked. Make sure we re-track result
+        # tuples whenever we reuse them.
+        it = self.enum([[]])
+        gc.collect()
+        # That GC collection probably untracked the recycled internal result
+        # tuple, which is initialized to (None, None). Make sure it's re-tracked
+        # when it's mutated and returned from __next__:
+        self.assertTrue(gc.is_tracked(next(it)))
+
 class MyEnum(enumerate):
     pass
 
index 10f148fe5cdb41e06714ddaafc64659036a44c47..b623852f9eb4ee6adb3d8bbc0ccd0e609443f56d 100644 (file)
@@ -160,44 +160,42 @@ class TestEPoll(unittest.TestCase):
             self.fail("epoll on closed fd didn't raise EBADF")
 
     def test_control_and_wait(self):
+        # create the epoll object
         client, server = self._connected_pair()
-
         ep = select.epoll(16)
         ep.register(server.fileno(),
                     select.EPOLLIN | select.EPOLLOUT | select.EPOLLET)
         ep.register(client.fileno(),
                     select.EPOLLIN | select.EPOLLOUT | select.EPOLLET)
 
+        # EPOLLOUT
         now = time.monotonic()
         events = ep.poll(1, 4)
         then = time.monotonic()
         self.assertFalse(then - now > 0.1, then - now)
 
-        events.sort()
         expected = [(client.fileno(), select.EPOLLOUT),
                     (server.fileno(), select.EPOLLOUT)]
-        expected.sort()
-
-        self.assertEqual(events, expected)
+        self.assertEqual(sorted(events), sorted(expected))
 
-        events = ep.poll(timeout=2.1, maxevents=4)
+        # no event
+        events = ep.poll(timeout=0.1, maxevents=4)
         self.assertFalse(events)
 
-        client.send(b"Hello!")
-        server.send(b"world!!!")
+        # send: EPOLLIN and EPOLLOUT
+        client.sendall(b"Hello!")
+        server.sendall(b"world!!!")
 
         now = time.monotonic()
-        events = ep.poll(1, 4)
+        events = ep.poll(1.0, 4)
         then = time.monotonic()
         self.assertFalse(then - now > 0.01)
 
-        events.sort()
         expected = [(client.fileno(), select.EPOLLIN | select.EPOLLOUT),
                     (server.fileno(), select.EPOLLIN | select.EPOLLOUT)]
-        expected.sort()
-
-        self.assertEqual(events, expected)
+        self.assertEqual(sorted(events), sorted(expected))
 
+        # unregister, modify
         ep.unregister(client.fileno())
         ep.modify(server.fileno(), select.EPOLLOUT)
         now = time.monotonic()
index 2ae815aab18f6dcd5c5730c8901427250bf62f2c..2f08d35f26dc3bb6cd9fb0440479b7dceb41d99f 100644 (file)
@@ -332,6 +332,59 @@ non-important content
         self.assertEqual(binop.left.col_offset, 4)
         self.assertEqual(binop.right.col_offset, 7)
 
+    def test_ast_line_numbers_with_parentheses(self):
+        expr = """
+x = (
+    f" {test(t)}"
+)"""
+        t = ast.parse(expr)
+        self.assertEqual(type(t), ast.Module)
+        self.assertEqual(len(t.body), 1)
+        # check the test(t) location
+        call = t.body[0].value.values[1].value
+        self.assertEqual(type(call), ast.Call)
+        self.assertEqual(call.lineno, 3)
+        self.assertEqual(call.end_lineno, 3)
+        self.assertEqual(call.col_offset, 8)
+        self.assertEqual(call.end_col_offset, 15)
+
+        expr = """
+x = (
+        'PERL_MM_OPT', (
+            f'wat'
+            f'some_string={f(x)} '
+            f'wat'
+        ),
+)
+"""
+        t = ast.parse(expr)
+        self.assertEqual(type(t), ast.Module)
+        self.assertEqual(len(t.body), 1)
+        # check the fstring
+        fstring = t.body[0].value.elts[1]
+        self.assertEqual(type(fstring), ast.JoinedStr)
+        self.assertEqual(len(fstring.values), 3)
+        wat1, middle, wat2 = fstring.values
+        # check the first wat
+        self.assertEqual(type(wat1), ast.Constant)
+        self.assertEqual(wat1.lineno, 4)
+        self.assertEqual(wat1.end_lineno, 6)
+        self.assertEqual(wat1.col_offset, 12)
+        self.assertEqual(wat1.end_col_offset, 18)
+        # check the call
+        call = middle.value
+        self.assertEqual(type(call), ast.Call)
+        self.assertEqual(call.lineno, 5)
+        self.assertEqual(call.end_lineno, 5)
+        self.assertEqual(call.col_offset, 27)
+        self.assertEqual(call.end_col_offset, 31)
+        # check the second wat
+        self.assertEqual(type(wat2), ast.Constant)
+        self.assertEqual(wat2.lineno, 4)
+        self.assertEqual(wat2.end_lineno, 6)
+        self.assertEqual(wat2.col_offset, 12)
+        self.assertEqual(wat2.end_col_offset, 18)
+
     def test_docstring(self):
         def f():
             f'''Not a docstring'''
index c113e538248e9c1e988881009e6917933062fb44..ccf40b13d3a94c00eaf4c87cf5cbcce94646d7a0 100644 (file)
@@ -62,7 +62,6 @@ class BaseTest(unittest.TestCase):
                      Iterable, Iterator,
                      Reversible,
                      Container, Collection,
-                     Callable,
                      Mailbox, _PartialFile,
                      ContextVar, Token,
                      Field,
@@ -307,6 +306,69 @@ class BaseTest(unittest.TestCase):
         with self.assertRaises(TypeError):
             GenericAlias(bad=float)
 
+    def test_subclassing_types_genericalias(self):
+        class SubClass(GenericAlias): ...
+        alias = SubClass(list, int)
+        class Bad(GenericAlias):
+            def __new__(cls, *args, **kwargs):
+                super().__new__(cls, *args, **kwargs)
+
+        self.assertEqual(alias, list[int])
+        with self.assertRaises(TypeError):
+            Bad(list, int, bad=int)
+
+    def test_abc_callable(self):
+        # A separate test is needed for Callable since it uses a subclass of
+        # GenericAlias.
+        alias = Callable[[int, str], float]
+        with self.subTest("Testing subscription"):
+            self.assertIs(alias.__origin__, Callable)
+            self.assertEqual(alias.__args__, (int, str, float))
+            self.assertEqual(alias.__parameters__, ())
+
+        with self.subTest("Testing instance checks"):
+            self.assertIsInstance(alias, GenericAlias)
+
+        with self.subTest("Testing weakref"):
+            self.assertEqual(ref(alias)(), alias)
+
+        with self.subTest("Testing pickling"):
+            s = pickle.dumps(alias)
+            loaded = pickle.loads(s)
+            self.assertEqual(alias.__origin__, loaded.__origin__)
+            self.assertEqual(alias.__args__, loaded.__args__)
+            self.assertEqual(alias.__parameters__, loaded.__parameters__)
+
+        with self.subTest("Testing TypeVar substitution"):
+            C1 = Callable[[int, T], T]
+            C2 = Callable[[K, T], V]
+            C3 = Callable[..., T]
+            self.assertEqual(C1[str], Callable[[int, str], str])
+            self.assertEqual(C2[int, float, str], Callable[[int, float], str])
+            self.assertEqual(C3[int], Callable[..., int])
+
+            # multi chaining
+            C4 = C2[int, V, str]
+            self.assertEqual(repr(C4).split(".")[-1], "Callable[[int, ~V], str]")
+            self.assertEqual(repr(C4[dict]).split(".")[-1], "Callable[[int, dict], str]")
+            self.assertEqual(C4[dict], Callable[[int, dict], str])
+
+        with self.subTest("Testing type erasure"):
+            class C1(Callable):
+                def __call__(self):
+                    return None
+            a = C1[[int], T]
+            self.assertIs(a().__class__, C1)
+            self.assertEqual(a().__orig_class__, C1[[int], T])
+
+        # bpo-42195
+        with self.subTest("Testing collections.abc.Callable's consistency "
+                          "with typing.Callable"):
+            c1 = typing.Callable[[int, str], dict]
+            c2 = Callable[[int, str], dict]
+            self.assertEqual(c1.__args__, c2.__args__)
+            self.assertEqual(hash(c1.__args__), hash(c2.__args__))
+
 
 if __name__ == "__main__":
     unittest.main()
index a2bfb39d16a57194772e7d9542d9b4d93775e300..12917755a56017e31e6a5ba2c241bd01673e823a 100644 (file)
@@ -452,42 +452,6 @@ text
         self._run_check('<!spacer type="block" height="25">',
                         [('comment', 'spacer type="block" height="25"')])
 
-    def test_with_unquoted_attributes(self):
-        # see #12008
-        html = ("<html><body bgcolor=d0ca90 text='181008'>"
-                "<table cellspacing=0 cellpadding=1 width=100% ><tr>"
-                "<td align=left><font size=-1>"
-                "- <a href=/rabota/><span class=en> software-and-i</span></a>"
-                "- <a href='/1/'><span class=en> library</span></a></table>")
-        expected = [
-            ('starttag', 'html', []),
-            ('starttag', 'body', [('bgcolor', 'd0ca90'), ('text', '181008')]),
-            ('starttag', 'table',
-                [('cellspacing', '0'), ('cellpadding', '1'), ('width', '100%')]),
-            ('starttag', 'tr', []),
-            ('starttag', 'td', [('align', 'left')]),
-            ('starttag', 'font', [('size', '-1')]),
-            ('data', '- '), ('starttag', 'a', [('href', '/rabota/')]),
-            ('starttag', 'span', [('class', 'en')]), ('data', ' software-and-i'),
-            ('endtag', 'span'), ('endtag', 'a'),
-            ('data', '- '), ('starttag', 'a', [('href', '/1/')]),
-            ('starttag', 'span', [('class', 'en')]), ('data', ' library'),
-            ('endtag', 'span'), ('endtag', 'a'), ('endtag', 'table')
-        ]
-        self._run_check(html, expected)
-
-    def test_comma_between_attributes(self):
-        self._run_check('<form action="/xxx.php?a=1&amp;b=2&amp", '
-                        'method="post">', [
-                            ('starttag', 'form',
-                                [('action', '/xxx.php?a=1&b=2&'),
-                                 (',', None), ('method', 'post')])])
-
-    def test_weird_chars_in_unquoted_attribute_values(self):
-        self._run_check('<form action=bogus|&#()value>', [
-                            ('starttag', 'form',
-                                [('action', 'bogus|&#()value')])])
-
     def test_invalid_end_tags(self):
         # A collection of broken end tags. <br> is used as separator.
         # see http://www.w3.org/TR/html5/tokenization.html#end-tag-open-state
@@ -766,6 +730,62 @@ class AttributesTestCase(TestCaseBase):
                           [("href", "http://www.example.org/\">;")]),
                          ("data", "spam"), ("endtag", "a")])
 
+    def test_with_unquoted_attributes(self):
+        # see #12008
+        html = ("<html><body bgcolor=d0ca90 text='181008'>"
+                "<table cellspacing=0 cellpadding=1 width=100% ><tr>"
+                "<td align=left><font size=-1>"
+                "- <a href=/rabota/><span class=en> software-and-i</span></a>"
+                "- <a href='/1/'><span class=en> library</span></a></table>")
+        expected = [
+            ('starttag', 'html', []),
+            ('starttag', 'body', [('bgcolor', 'd0ca90'), ('text', '181008')]),
+            ('starttag', 'table',
+                [('cellspacing', '0'), ('cellpadding', '1'), ('width', '100%')]),
+            ('starttag', 'tr', []),
+            ('starttag', 'td', [('align', 'left')]),
+            ('starttag', 'font', [('size', '-1')]),
+            ('data', '- '), ('starttag', 'a', [('href', '/rabota/')]),
+            ('starttag', 'span', [('class', 'en')]), ('data', ' software-and-i'),
+            ('endtag', 'span'), ('endtag', 'a'),
+            ('data', '- '), ('starttag', 'a', [('href', '/1/')]),
+            ('starttag', 'span', [('class', 'en')]), ('data', ' library'),
+            ('endtag', 'span'), ('endtag', 'a'), ('endtag', 'table')
+        ]
+        self._run_check(html, expected)
+
+    def test_comma_between_attributes(self):
+        # see bpo 41478
+        # HTMLParser preserves duplicate attributes, leaving the task of
+        # removing duplicate attributes to a conformant html tree builder
+        html = ('<div class=bar,baz=asd>'        # between attrs (unquoted)
+                '<div class="bar",baz="asd">'    # between attrs (quoted)
+                '<div class=bar, baz=asd,>'      # after values (unquoted)
+                '<div class="bar", baz="asd",>'  # after values (quoted)
+                '<div class="bar",>'             # one comma values (quoted)
+                '<div class=,bar baz=,asd>'      # before values (unquoted)
+                '<div class=,"bar" baz=,"asd">'  # before values (quoted)
+                '<div ,class=bar ,baz=asd>'      # before names
+                '<div class,="bar" baz,="asd">'  # after names
+        )
+        expected = [
+            ('starttag', 'div', [('class', 'bar,baz=asd'),]),
+            ('starttag', 'div', [('class', 'bar'), (',baz', 'asd')]),
+            ('starttag', 'div', [('class', 'bar,'), ('baz', 'asd,')]),
+            ('starttag', 'div', [('class', 'bar'), (',', None),
+                                 ('baz', 'asd'), (',', None)]),
+            ('starttag', 'div', [('class', 'bar'), (',', None)]),
+            ('starttag', 'div', [('class', ',bar'), ('baz', ',asd')]),
+            ('starttag', 'div', [('class', ',"bar"'), ('baz', ',"asd"')]),
+            ('starttag', 'div', [(',class', 'bar'), (',baz', 'asd')]),
+            ('starttag', 'div', [('class,', 'bar'), ('baz,', 'asd')]),
+        ]
+        self._run_check(html, expected)
+
+    def test_weird_chars_in_unquoted_attribute_values(self):
+        self._run_check('<form action=bogus|&#()value>', [
+                            ('starttag', 'form',
+                                [('action', 'bogus|&#()value')])])
 
 if __name__ == "__main__":
     unittest.main()
index ed125893d6d07292e8244d11e7baae2d19170bce..28943f02564fb0e66b3df4d55b656ab9fdcbde2c 100644 (file)
@@ -1,5 +1,5 @@
 import errno
-from http import client
+from http import client, HTTPStatus
 import io
 import itertools
 import os
@@ -516,6 +516,10 @@ class TransferEncodingTest(TestCase):
 
 
 class BasicTest(TestCase):
+    def test_dir_with_added_behavior_on_status(self):
+        # see issue40084
+        self.assertTrue({'description', 'name', 'phrase', 'value'} <= set(dir(HTTPStatus(404))))
+
     def test_status_lines(self):
         # Test HTTP status lines
 
index 8bc01deaa33841322d7edc651bc35a2b07af3912..310b72c1d72e74cda637ac9fea6216e0e71781c8 100644 (file)
@@ -20,5 +20,5 @@ from idlelib.idle_test import load_tests
 if __name__ == '__main__':
     tk.NoDefaultRoot()
     unittest.main(exit=False)
-    tk._support_default_root = 1
+    tk._support_default_root = True
     tk._default_root = None
index 702cf0820316b19216dac418d1af345ead84bc31..71012642849198542133f6238487dff06c4a3034 100644 (file)
@@ -12,6 +12,8 @@ from functools import reduce
 import sys
 import struct
 import threading
+import gc
+
 maxsize = support.MAX_Py_ssize_t
 minsize = -maxsize-1
 
@@ -1554,6 +1556,51 @@ class TestBasicOps(unittest.TestCase):
             self.assertRaises(StopIteration, next, f(lambda x:x, []))
             self.assertRaises(StopIteration, next, f(lambda x:x, StopNow()))
 
+    @support.cpython_only
+    def test_combinations_result_gc(self):
+        # bpo-42536: combinations's tuple-reuse speed trick breaks the GC's
+        # assumptions about what can be untracked. Make sure we re-track result
+        # tuples whenever we reuse them.
+        it = combinations([None, []], 1)
+        next(it)
+        gc.collect()
+        # That GC collection probably untracked the recycled internal result
+        # tuple, which has the value (None,). Make sure it's re-tracked when
+        # it's mutated and returned from __next__:
+        self.assertTrue(gc.is_tracked(next(it)))
+
+    @support.cpython_only
+    def test_combinations_with_replacement_result_gc(self):
+        # Ditto for combinations_with_replacement.
+        it = combinations_with_replacement([None, []], 1)
+        next(it)
+        gc.collect()
+        self.assertTrue(gc.is_tracked(next(it)))
+
+    @support.cpython_only
+    def test_permutations_result_gc(self):
+        # Ditto for permutations.
+        it = permutations([None, []], 1)
+        next(it)
+        gc.collect()
+        self.assertTrue(gc.is_tracked(next(it)))
+
+    @support.cpython_only
+    def test_product_result_gc(self):
+        # Ditto for product.
+        it = product([None, []])
+        next(it)
+        gc.collect()
+        self.assertTrue(gc.is_tracked(next(it)))
+
+    @support.cpython_only
+    def test_zip_longest_result_gc(self):
+        # Ditto for zip_longest.
+        it = zip_longest([[]])
+        gc.collect()
+        self.assertTrue(gc.is_tracked(next(it)))
+
+
 class TestExamples(unittest.TestCase):
 
     def test_accumulate(self):
index 410eae2208688435aaa7251b81314850c0161471..a6cd291c9a553647b2175416884130d48e596c7f 100644 (file)
@@ -4191,6 +4191,15 @@ class ModuleLevelMiscTest(BaseTest):
         logging.disable(83)
         self.assertEqual(logging.root.manager.disable, 83)
 
+        self.assertRaises(ValueError, logging.disable, "doesnotexists")
+
+        class _NotAnIntOrString:
+            pass
+
+        self.assertRaises(TypeError, logging.disable, _NotAnIntOrString())
+
+        logging.disable("WARN")
+
         # test the default value introduced in 3.7
         # (Issue #28524)
         logging.disable()
index 1df64fa7c6b00b2272be8032fce3cd7335ae4379..99386ddbaedfa9e88728e3d42cc34a0d46bf8d7f 100644 (file)
@@ -82,7 +82,7 @@ class NetworkedNNTPTestsMixin:
         desc = self.server.description(self.GROUP_NAME)
         _check_desc(desc)
         # Another sanity check
-        self.assertIn("Python", desc)
+        self.assertIn(self.DESC, desc)
         # With a pattern
         desc = self.server.description(self.GROUP_PAT)
         _check_desc(desc)
@@ -309,6 +309,7 @@ class NetworkedNNTPTests(NetworkedNNTPTestsMixin, unittest.TestCase):
     NNTP_HOST = 'news.trigofacile.com'
     GROUP_NAME = 'fr.comp.lang.python'
     GROUP_PAT = 'fr.comp.lang.*'
+    DESC = 'Python'
 
     NNTP_CLASS = NNTP
 
@@ -343,8 +344,11 @@ class NetworkedNNTP_SSLTests(NetworkedNNTPTests):
     # 400 connections per day are accepted from each IP address."
 
     NNTP_HOST = 'nntp.aioe.org'
-    GROUP_NAME = 'comp.lang.python'
-    GROUP_PAT = 'comp.lang.*'
+    # bpo-42794: aioe.test is one of the official groups on this server
+    # used for testing: https://news.aioe.org/manual/aioe-hierarchy/
+    GROUP_NAME = 'aioe.test'
+    GROUP_PAT = 'aioe.*'
+    DESC = 'test'
 
     NNTP_CLASS = getattr(nntplib, 'NNTP_SSL', None)
 
index fdea44e4d85965135c15cf249fff8e585113901a..9df4efbfffa22dce27f2a451fb64fc9bb8a68f9d 100644 (file)
@@ -697,6 +697,17 @@ class OrderedDictTests:
         with self.assertRaises(ValueError):
             a |= "BAD"
 
+    @support.cpython_only
+    def test_ordered_dict_items_result_gc(self):
+        # bpo-42536: OrderedDict.items's tuple-reuse speed trick breaks the GC's
+        # assumptions about what can be untracked. Make sure we re-track result
+        # tuples whenever we reuse them.
+        it = iter(self.OrderedDict({None: []}).items())
+        gc.collect()
+        # That GC collection probably untracked the recycled internal result
+        # tuple, which is initialized to (None, None). Make sure it's re-tracked
+        # when it's mutated and returned from __next__:
+        self.assertTrue(gc.is_tracked(next(it)))
 
 class PurePythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
 
index bf1cb5f5112557b8ec02b5ef9101c26d4fa7292e..35933e9c8c3a971f7ef2a23497331ffb09a8c1b9 100644 (file)
@@ -3659,6 +3659,33 @@ class FDInheritanceTests(unittest.TestCase):
         self.assertEqual(fcntl.fcntl(fd, fcntl.F_GETFD) & fcntl.FD_CLOEXEC,
                          0)
 
+    @unittest.skipUnless(hasattr(os, 'O_PATH'), "need os.O_PATH")
+    def test_get_set_inheritable_o_path(self):
+        fd = os.open(__file__, os.O_PATH)
+        self.addCleanup(os.close, fd)
+        self.assertEqual(os.get_inheritable(fd), False)
+
+        os.set_inheritable(fd, True)
+        self.assertEqual(os.get_inheritable(fd), True)
+
+        os.set_inheritable(fd, False)
+        self.assertEqual(os.get_inheritable(fd), False)
+
+    def test_get_set_inheritable_badf(self):
+        fd = support.make_bad_fd()
+
+        with self.assertRaises(OSError) as ctx:
+            os.get_inheritable(fd)
+        self.assertEqual(ctx.exception.errno, errno.EBADF)
+
+        with self.assertRaises(OSError) as ctx:
+            os.set_inheritable(fd, True)
+        self.assertEqual(ctx.exception.errno, errno.EBADF)
+
+        with self.assertRaises(OSError) as ctx:
+            os.set_inheritable(fd, False)
+        self.assertEqual(ctx.exception.errno, errno.EBADF)
+
     def test_open(self):
         fd = os.open(__file__, os.O_RDONLY)
         self.addCleanup(os.close, fd)
index 8016f81e5ac51b934ae23268d8a678ba8daebcbc..6c4eaf318e448005e7c65c173e9dfb56f29f9e1f 100644 (file)
@@ -1661,6 +1661,71 @@ def bœr():
             '(Pdb) ',
         ])
 
+
+    def test_issue42384(self):
+        '''When running `python foo.py` sys.path[0] is an absolute path. `python -m pdb foo.py` should behave the same'''
+        script = textwrap.dedent("""
+            import sys
+            print('sys.path[0] is', sys.path[0])
+        """)
+        commands = 'c\nq'
+
+        with support.temp_cwd() as cwd:
+            expected = f'(Pdb) sys.path[0] is {os.path.realpath(cwd)}'
+
+            stdout, stderr = self.run_pdb_script(script, commands)
+
+            self.assertEqual(stdout.split('\n')[2].rstrip('\r'), expected)
+
+    @support.skip_unless_symlink
+    def test_issue42384_symlink(self):
+        '''When running `python foo.py` sys.path[0] resolves symlinks. `python -m pdb foo.py` should behave the same'''
+        script = textwrap.dedent("""
+            import sys
+            print('sys.path[0] is', sys.path[0])
+        """)
+        commands = 'c\nq'
+
+        with support.temp_cwd() as cwd:
+            cwd = os.path.realpath(cwd)
+            dir_one = os.path.join(cwd, 'dir_one')
+            dir_two = os.path.join(cwd, 'dir_two')
+            expected = f'(Pdb) sys.path[0] is {dir_one}'
+
+            os.mkdir(dir_one)
+            with open(os.path.join(dir_one, 'foo.py'), 'w') as f:
+                f.write(script)
+            os.mkdir(dir_two)
+            os.symlink(os.path.join(dir_one, 'foo.py'), os.path.join(dir_two, 'foo.py'))
+
+            stdout, stderr = self._run_pdb([os.path.join('dir_two', 'foo.py')], commands)
+
+            self.assertEqual(stdout.split('\n')[2].rstrip('\r'), expected)
+
+    def test_issue42383(self):
+        with support.temp_cwd() as cwd:
+            with open('foo.py', 'w') as f:
+                s = textwrap.dedent("""
+                    print('The correct file was executed')
+
+                    import os
+                    os.chdir("subdir")
+                """)
+                f.write(s)
+
+            subdir = os.path.join(cwd, 'subdir')
+            os.mkdir(subdir)
+            os.mkdir(os.path.join(subdir, 'subdir'))
+            wrong_file = os.path.join(subdir, 'foo.py')
+
+            with open(wrong_file, 'w') as f:
+                f.write('print("The wrong file was executed")')
+
+            stdout, stderr = self._run_pdb(['foo.py'], 'c\nc\nq')
+            expected = '(Pdb) The correct file was executed'
+            self.assertEqual(stdout.split('\n')[6].rstrip('\r'), expected)
+
+
 def load_tests(*args):
     from test import test_pdb
     suites = [
index a3b06feb6552ec6b87804dafb6b6236b88ce18d6..9f04c79e09ba462fc36136470f4819f501bfb2bc 100644 (file)
@@ -1,4 +1,6 @@
 import os
+import copy
+import pickle
 import platform
 import subprocess
 import sys
@@ -175,6 +177,38 @@ class PlatformTest(unittest.TestCase):
         )
         self.assertEqual(tuple(res), expected)
 
+    def test_uname_replace(self):
+        res = platform.uname()
+        new = res._replace(
+            system='system', node='node', release='release',
+            version='version', machine='machine')
+        self.assertEqual(new.system, 'system')
+        self.assertEqual(new.node, 'node')
+        self.assertEqual(new.release, 'release')
+        self.assertEqual(new.version, 'version')
+        self.assertEqual(new.machine, 'machine')
+        # processor cannot be replaced
+        self.assertEqual(new.processor, res.processor)
+
+    def test_uname_copy(self):
+        uname = platform.uname()
+        self.assertEqual(copy.copy(uname), uname)
+        self.assertEqual(copy.deepcopy(uname), uname)
+
+    def test_uname_pickle(self):
+        orig = platform.uname()
+        for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+            with self.subTest(protocol=proto):
+                pickled = pickle.dumps(orig, proto)
+                restored = pickle.loads(pickled)
+                self.assertEqual(restored, orig)
+
+    def test_uname_slices(self):
+        res = platform.uname()
+        expected = tuple(res)
+        self.assertEqual(res[:], expected)
+        self.assertEqual(res[:5], expected[:5])
+
     @unittest.skipIf(sys.platform in ['win32', 'OpenVMS'], "uname -p not used")
     def test_uname_processor(self):
         """
index bfbcbab3b62f96c2ae2966972c00ded829c66094..f4edb8bd9575f4d7c96cef9f1ebb9a8664a05793 100644 (file)
@@ -1045,7 +1045,7 @@ class PosixTester(unittest.TestCase):
         if sys.platform == 'darwin':
             import sysconfig
             dt = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') or '10.0'
-            if tuple(int(n) for n in str(dt).split('.')[0:2]) < (10, 6):
+            if tuple(int(n) for n in dt.split('.')[0:2]) < (10, 6):
                 raise unittest.SkipTest("getgroups(2) is broken prior to 10.6")
 
         # 'id -G' and 'os.getgroups()' should return the same
index a80e71e67e4c6ce037f6f1ed38f109198e8aa0e7..15a68418bdd86a3aadead7ec4f696161d307518e 100644 (file)
@@ -207,33 +207,6 @@ class TestBasicOps:
         with self.assertRaises(ValueError):
             sample(['red', 'green', 'blue'], counts=[1, 2, 3, 4], k=2)      # too many counts
 
-    def test_sample_counts_equivalence(self):
-        # Test the documented strong equivalence to a sample with repeated elements.
-        # We run this test on random.Random() which makes deterministic selections
-        # for a given seed value.
-        sample = random.sample
-        seed = random.seed
-
-        colors =  ['red', 'green', 'blue', 'orange', 'black', 'amber']
-        counts = [500,      200,     20,       10,       5,       1 ]
-        k = 700
-        seed(8675309)
-        s1 = sample(colors, counts=counts, k=k)
-        seed(8675309)
-        expanded = [color for (color, count) in zip(colors, counts) for i in range(count)]
-        self.assertEqual(len(expanded), sum(counts))
-        s2 = sample(expanded, k=k)
-        self.assertEqual(s1, s2)
-
-        pop = 'abcdefghi'
-        counts = [10, 9, 8, 7, 6, 5, 4, 3, 2]
-        seed(8675309)
-        s1 = ''.join(sample(pop, counts=counts, k=30))
-        expanded = ''.join([letter for (letter, count) in zip(pop, counts) for i in range(count)])
-        seed(8675309)
-        s2 = ''.join(sample(expanded, k=30))
-        self.assertEqual(s1, s2)
-
     def test_choices(self):
         choices = self.gen.choices
         data = ['red', 'green', 'blue', 'yellow']
@@ -888,6 +861,33 @@ class MersenneTwister_TestBasicOps(TestBasicOps, unittest.TestCase):
             self.assertEqual(self.gen.randbytes(n),
                              gen2.getrandbits(n * 8).to_bytes(n, 'little'))
 
+    def test_sample_counts_equivalence(self):
+        # Test the documented strong equivalence to a sample with repeated elements.
+        # We run this test on random.Random() which makes deterministic selections
+        # for a given seed value.
+        sample = self.gen.sample
+        seed = self.gen.seed
+
+        colors =  ['red', 'green', 'blue', 'orange', 'black', 'amber']
+        counts = [500,      200,     20,       10,       5,       1 ]
+        k = 700
+        seed(8675309)
+        s1 = sample(colors, counts=counts, k=k)
+        seed(8675309)
+        expanded = [color for (color, count) in zip(colors, counts) for i in range(count)]
+        self.assertEqual(len(expanded), sum(counts))
+        s2 = sample(expanded, k=k)
+        self.assertEqual(s1, s2)
+
+        pop = 'abcdefghi'
+        counts = [10, 9, 8, 7, 6, 5, 4, 3, 2]
+        seed(8675309)
+        s1 = ''.join(sample(pop, counts=counts, k=30))
+        expanded = ''.join([letter for (letter, count) in zip(pop, counts) for i in range(count)])
+        seed(8675309)
+        s2 = ''.join(sample(expanded, k=30))
+        self.assertEqual(s1, s2)
+
 
 def gamma(z, sqrt2pi=(2.0*pi)**0.5):
     # Reflection to right half of complex plane
index 576299900318d5b175e7c4db83a0aa6d2a7e1a3b..3451f3a411e9a5d9c80d66b53116fdd31ded5747 100644 (file)
@@ -165,6 +165,17 @@ class LMTPGeneralTests(GeneralTests, unittest.TestCase):
 
     client = smtplib.LMTP
 
+    @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), "test requires Unix domain socket")
+    def testUnixDomainSocketTimeoutDefault(self):
+        local_host = '/some/local/lmtp/delivery/program'
+        mock_socket.reply_with(b"220 Hello world")
+        try:
+            client = self.client(local_host, self.port)
+        finally:
+            mock_socket.setdefaulttimeout(None)
+        self.assertIsNone(client.sock.gettimeout())
+        client.close()
+
     def testTimeoutZero(self):
         super().testTimeoutZero()
         local_host = '/some/local/lmtp/delivery/program'
index 7373fe29c47d810be3dbc9d8eb6c34ca5ddd9df3..e8f9699ef763504703f1e40c86bb94e27c2345ca 100644 (file)
@@ -196,6 +196,28 @@ class ProcessTestCase(BaseTestCase):
                 input=b'pear')
         self.assertIn(b'PEAR', output)
 
+    def test_check_output_input_none(self):
+        """input=None has a legacy meaning of input='' on check_output."""
+        output = subprocess.check_output(
+                [sys.executable, "-c",
+                 "import sys; print('XX' if sys.stdin.read() else '')"],
+                input=None)
+        self.assertNotIn(b'XX', output)
+
+    def test_check_output_input_none_text(self):
+        output = subprocess.check_output(
+                [sys.executable, "-c",
+                 "import sys; print('XX' if sys.stdin.read() else '')"],
+                input=None, text=True)
+        self.assertNotIn('XX', output)
+
+    def test_check_output_input_none_universal_newlines(self):
+        output = subprocess.check_output(
+                [sys.executable, "-c",
+                 "import sys; print('XX' if sys.stdin.read() else '')"],
+                input=None, universal_newlines=True)
+        self.assertNotIn('XX', output)
+
     def test_check_output_stdout_arg(self):
         # check_output() refuses to accept 'stdout' argument
         with self.assertRaises(ValueError) as c:
index 44e44bf5ea995f0c601e21a96a3780cd44ee08c6..0ca5c9390dbb9a1aec47dce9ee5bbd5992e23d29 100644 (file)
@@ -358,10 +358,12 @@ class TestSysConfig(unittest.TestCase):
 
     @unittest.skipIf(sysconfig.get_config_var('EXT_SUFFIX') is None,
                      'EXT_SUFFIX required for this test')
-    def test_SO_in_vars(self):
+    def test_EXT_SUFFIX_in_vars(self):
+        import _imp
         vars = sysconfig.get_config_vars()
         self.assertIsNotNone(vars['SO'])
         self.assertEqual(vars['SO'], vars['EXT_SUFFIX'])
+        self.assertEqual(vars['EXT_SUFFIX'], _imp.extension_suffixes()[0])
 
     @unittest.skipUnless(sys.platform == 'linux' and
                          hasattr(sys.implementation, '_multiarch'),
index 1c5b9cf2bd2a8367d24e134f234a5c0691120944..0bbb39b147ea1e543afec9cb29dbd2bab97a0dd9 100644 (file)
@@ -1,4 +1,5 @@
 import unittest
+import locale
 import re
 import subprocess
 import sys
@@ -59,6 +60,10 @@ class TclTest(unittest.TestCase):
         tcl = self.interp
         self.assertEqual(tcl.eval('set a "a\\0b"'), 'a\x00b')
 
+    def test_eval_surrogates_in_result(self):
+        tcl = self.interp
+        self.assertIn(tcl.eval(r'set a "<\ud83d\udcbb>"'), '<\U0001f4bb>')
+
     def testEvalException(self):
         tcl = self.interp
         self.assertRaises(TclError,tcl.eval,'set a')
@@ -131,10 +136,14 @@ class TclTest(unittest.TestCase):
 
     def get_integers(self):
         integers = (0, 1, -1, 2**31-1, -2**31, 2**31, -2**31-1, 2**63-1, -2**63)
-        # bignum was added in Tcl 8.5, but its support is able only since 8.5.8
-        if (get_tk_patchlevel() >= (8, 6, 0, 'final') or
-            (8, 5, 8) <= get_tk_patchlevel() < (8, 6)):
-            integers += (2**63, -2**63-1, 2**1000, -2**1000)
+        # bignum was added in Tcl 8.5, but its support is able only since 8.5.8.
+        # Actually it is determined at compile time, so using get_tk_patchlevel()
+        # is not reliable.
+        # TODO: expose full static version.
+        if tcl_version >= (8, 5):
+            v = get_tk_patchlevel()
+            if v >= (8, 6, 0, 'final') or (8, 5, 8) <= v < (8, 6):
+                integers += (2**63, -2**63-1, 2**1000, -2**1000)
         return integers
 
     def test_getint(self):
@@ -191,29 +200,48 @@ class TclTest(unittest.TestCase):
 
     def testEvalFile(self):
         tcl = self.interp
-        with open(support.TESTFN, 'w') as f:
-            self.addCleanup(support.unlink, support.TESTFN)
+        filename = support.TESTFN_ASCII
+        self.addCleanup(support.unlink, filename)
+        with open(filename, 'w') as f:
             f.write("""set a 1
             set b 2
             set c [ expr $a + $b ]
             """)
-        tcl.evalfile(support.TESTFN)
+        tcl.evalfile(filename)
         self.assertEqual(tcl.eval('set a'),'1')
         self.assertEqual(tcl.eval('set b'),'2')
         self.assertEqual(tcl.eval('set c'),'3')
 
     def test_evalfile_null_in_result(self):
         tcl = self.interp
-        with open(support.TESTFN, 'w') as f:
-            self.addCleanup(support.unlink, support.TESTFN)
+        filename = support.TESTFN_ASCII
+        self.addCleanup(support.unlink, filename)
+        with open(filename, 'w') as f:
             f.write("""
             set a "a\0b"
             set b "a\\0b"
             """)
-        tcl.evalfile(support.TESTFN)
+        tcl.evalfile(filename)
         self.assertEqual(tcl.eval('set a'), 'a\x00b')
         self.assertEqual(tcl.eval('set b'), 'a\x00b')
 
+    def test_evalfile_surrogates_in_result(self):
+        tcl = self.interp
+        encoding = tcl.call('encoding', 'system')
+        self.addCleanup(tcl.call, 'encoding', 'system', encoding)
+        tcl.call('encoding', 'system', 'utf-8')
+
+        filename = support.TESTFN_ASCII
+        self.addCleanup(support.unlink, filename)
+        with open(filename, 'wb') as f:
+            f.write(b"""
+            set a "<\xed\xa0\xbd\xed\xb2\xbb>"
+            set b "<\\ud83d\\udcbb>"
+            """)
+        tcl.evalfile(filename)
+        self.assertEqual(tcl.eval('set a'), '<\U0001f4bb>')
+        self.assertEqual(tcl.eval('set b'), '<\U0001f4bb>')
+
     def testEvalFileException(self):
         tcl = self.interp
         filename = "doesnotexists"
@@ -419,7 +447,7 @@ class TclTest(unittest.TestCase):
             else:
                 self.assertEqual(result, str(i))
                 self.assertIsInstance(result, str)
-        if tcl_version < (8, 5):  # bignum was added in Tcl 8.5
+        if get_tk_patchlevel() < (8, 5):  # bignum was added in Tcl 8.5
             self.assertRaises(TclError, tcl.call, 'expr', str(2**1000))
 
     def test_passing_values(self):
@@ -436,6 +464,11 @@ class TclTest(unittest.TestCase):
         self.assertEqual(passValue('str\x00ing\u20ac'), 'str\x00ing\u20ac')
         self.assertEqual(passValue('str\x00ing\U0001f4bb'),
                          'str\x00ing\U0001f4bb')
+        if sys.platform != 'win32':
+            self.assertEqual(passValue('<\udce2\udc82\udcac>'),
+                             '<\u20ac>')
+            self.assertEqual(passValue('<\udced\udca0\udcbd\udced\udcb2\udcbb>'),
+                             '<\U0001f4bb>')
         self.assertEqual(passValue(b'str\x00ing'),
                          b'str\x00ing' if self.wantobjects else 'str\x00ing')
         self.assertEqual(passValue(b'str\xc0\x80ing'),
@@ -495,6 +528,9 @@ class TclTest(unittest.TestCase):
         check('string\xbd')
         check('string\u20ac')
         check('string\U0001f4bb')
+        if sys.platform != 'win32':
+            check('<\udce2\udc82\udcac>', '<\u20ac>')
+            check('<\udced\udca0\udcbd\udced\udcb2\udcbb>', '<\U0001f4bb>')
         check('')
         check(b'string', 'string')
         check(b'string\xe2\x82\xac', 'string\xe2\x82\xac')
@@ -538,6 +574,8 @@ class TclTest(unittest.TestCase):
             ('a \u20ac', ('a', '\u20ac')),
             ('a \U0001f4bb', ('a', '\U0001f4bb')),
             (b'a \xe2\x82\xac', ('a', '\u20ac')),
+            (b'a \xf0\x9f\x92\xbb', ('a', '\U0001f4bb')),
+            (b'a \xed\xa0\xbd\xed\xb2\xbb', ('a', '\U0001f4bb')),
             (b'a\xc0\x80b c\xc0\x80d', ('a\x00b', 'c\x00d')),
             ('a {b c}', ('a', 'b c')),
             (r'a b\ c', ('a', 'b c')),
index 8549ba2b75ad08755c148b40cf809753f11b0ca2..5bb3a58b2a103bec529c72440ed69de099ea3fa4 100644 (file)
@@ -667,6 +667,31 @@ class BaseExceptionReportingTests:
         msg = self.get_report(e).splitlines()
         self.assertEqual(msg[-2], '               ^')
 
+    def test_syntax_error_no_lineno(self):
+        # See #34463.
+
+        # Without filename
+        e = SyntaxError('bad syntax')
+        msg = self.get_report(e).splitlines()
+        self.assertEqual(msg,
+            ['SyntaxError: bad syntax'])
+        e.lineno = 100
+        msg = self.get_report(e).splitlines()
+        self.assertEqual(msg,
+            ['  File "<string>", line 100', 'SyntaxError: bad syntax'])
+
+        # With filename
+        e = SyntaxError('bad syntax')
+        e.filename = 'myfile.py'
+
+        msg = self.get_report(e).splitlines()
+        self.assertEqual(msg,
+            ['SyntaxError: bad syntax (myfile.py)'])
+        e.lineno = 100
+        msg = self.get_report(e).splitlines()
+        self.assertEqual(msg,
+            ['  File "myfile.py", line 100', 'SyntaxError: bad syntax'])
+
     def test_message_none(self):
         # A message that looks like "None" should not be treated specially
         err = self.get_report(Exception(None))
index c5ae4e6d653bf74793ff86563dbb657bfd442894..b10d1798c29777ce284c5bea44c7e637a7d8f4d2 100644 (file)
@@ -84,6 +84,25 @@ def traceback_filename(filename):
     return traceback_lineno(filename, 0)
 
 
+class TestTraceback(unittest.TestCase):
+    def test_repr(self):
+        def get_repr(*args) -> str:
+            return repr(tracemalloc.Traceback(*args))
+
+        self.assertEqual(get_repr(()), "<Traceback ()>")
+        self.assertEqual(get_repr((), 0), "<Traceback () total_nframe=0>")
+
+        frames = (("f1", 1), ("f2", 2))
+        exp_repr_frames = (
+            "(<Frame filename='f2' lineno=2>,"
+            " <Frame filename='f1' lineno=1>)"
+        )
+        self.assertEqual(get_repr(frames),
+                         f"<Traceback {exp_repr_frames}>")
+        self.assertEqual(get_repr(frames, 2),
+                         f"<Traceback {exp_repr_frames} total_nframe=2>")
+
+
 class TestTracemallocEnabled(unittest.TestCase):
     def setUp(self):
         if tracemalloc.is_tracing():
@@ -1064,6 +1083,7 @@ class TestCAPI(unittest.TestCase):
 
 def test_main():
     support.run_unittest(
+        TestTraceback,
         TestTracemallocEnabled,
         TestSnapshot,
         TestFilters,
index 13cf20eee09ab1a7b8dd732cbee4609a76b453f2..4bdb2a0fad6c762199f43b2434338c216cd1dece 100644 (file)
@@ -450,14 +450,6 @@ class CallableTests(BaseTestCase):
             type(c)()
 
     def test_callable_wrong_forms(self):
-        with self.assertRaises(TypeError):
-            Callable[[...], int]
-        with self.assertRaises(TypeError):
-            Callable[(), int]
-        with self.assertRaises(TypeError):
-            Callable[[()], int]
-        with self.assertRaises(TypeError):
-            Callable[[int, 1], 2]
         with self.assertRaises(TypeError):
             Callable[int]
 
@@ -3079,6 +3071,11 @@ class GetUtilitiesTestCase(TestCase):
         self.assertEqual(get_args(Callable), ())
         self.assertEqual(get_args(list[int]), (int,))
         self.assertEqual(get_args(list), ())
+        self.assertEqual(get_args(collections.abc.Callable[[int], str]), ([int], str))
+        self.assertEqual(get_args(collections.abc.Callable[..., str]), (..., str))
+        self.assertEqual(get_args(collections.abc.Callable[[], str]), ([], str))
+        self.assertEqual(get_args(collections.abc.Callable[[int], str]),
+                         get_args(Callable[[int], str]))
 
 
 class CollectionsAbcTests(BaseTestCase):
@@ -3899,10 +3896,14 @@ class TypedDictTests(BaseTestCase):
         self.assertEqual(D(), {})
         self.assertEqual(D(x=1), {'x': 1})
         self.assertEqual(D.__total__, False)
+        self.assertEqual(D.__required_keys__, frozenset())
+        self.assertEqual(D.__optional_keys__, {'x'})
 
         self.assertEqual(Options(), {})
         self.assertEqual(Options(log_level=2), {'log_level': 2})
         self.assertEqual(Options.__total__, False)
+        self.assertEqual(Options.__required_keys__, frozenset())
+        self.assertEqual(Options.__optional_keys__, {'log_level', 'log_path'})
 
     def test_optional_keys(self):
         class Point2Dor3D(Point2D, total=False):
index fcc93829cc3b848fa57b82dc62eb07d53ccd8238..049e48b13fa1f90d9d14ec2439c272f0eea801b5 100644 (file)
@@ -346,6 +346,31 @@ Now some general starred expressions (all fail).
       ...
     SyntaxError: can't use starred expression here
 
+    >>> (*x),y = 1, 2 # doctest:+ELLIPSIS
+    Traceback (most recent call last):
+      ...
+    SyntaxError: can't use starred expression here
+
+    >>> (((*x))),y = 1, 2 # doctest:+ELLIPSIS
+    Traceback (most recent call last):
+      ...
+    SyntaxError: can't use starred expression here
+
+    >>> z,(*x),y = 1, 2, 4 # doctest:+ELLIPSIS
+    Traceback (most recent call last):
+      ...
+    SyntaxError: can't use starred expression here
+
+    >>> z,(*x) = 1, 2 # doctest:+ELLIPSIS
+    Traceback (most recent call last):
+      ...
+    SyntaxError: can't use starred expression here
+
+    >>> ((*x),y) = 1, 2 # doctest:+ELLIPSIS
+    Traceback (most recent call last):
+      ...
+    SyntaxError: can't use starred expression here
+
 Some size constraints (all fail.)
 
     >>> s = ", ".join("a%d" % i for i in range(1<<8)) + ", *rest = range(1<<8 + 1)"
index b71be549d28b5aa9f46a96aa2babf418dd3e3148..12c3f4dbd5bf087764e211523ff88f00ba46704c 100644 (file)
@@ -1849,9 +1849,17 @@ class MiscTests(unittest.TestCase):
              ('ftp', 'joe', 'password', 'proxy.example.com')),
             # Test for no trailing '/' case
             ('http://joe:password@proxy.example.com',
-             ('http', 'joe', 'password', 'proxy.example.com'))
+             ('http', 'joe', 'password', 'proxy.example.com')),
+            # Testcases with '/' character in username, password
+            ('http://user/name:password@localhost:22',
+             ('http', 'user/name', 'password', 'localhost:22')),
+            ('http://username:pass/word@localhost:22',
+             ('http', 'username', 'pass/word', 'localhost:22')),
+            ('http://user/name:pass/word@localhost:22',
+             ('http', 'user/name', 'pass/word', 'localhost:22')),
         ]
 
+
         for tc, expected in parse_proxy_test_cases:
             self.assertEqual(_parse_proxy(tc), expected)
 
index 762500789f73acfd4ee38d77ce82188f08e894fc..3b1c360625b5a63218d75f6bd2cbffaa546d517d 100644 (file)
@@ -32,16 +32,10 @@ parse_qsl_test_cases = [
     (b"&a=b", [(b'a', b'b')]),
     (b"a=a+b&b=b+c", [(b'a', b'a b'), (b'b', b'b c')]),
     (b"a=1&a=2", [(b'a', b'1'), (b'a', b'2')]),
-    (";", []),
-    (";;", []),
-    (";a=b", [('a', 'b')]),
-    ("a=a+b;b=b+c", [('a', 'a b'), ('b', 'b c')]),
-    ("a=1;a=2", [('a', '1'), ('a', '2')]),
-    (b";", []),
-    (b";;", []),
-    (b";a=b", [(b'a', b'b')]),
-    (b"a=a+b;b=b+c", [(b'a', b'a b'), (b'b', b'b c')]),
-    (b"a=1;a=2", [(b'a', b'1'), (b'a', b'2')]),
+    (";a=b", [(';a', 'b')]),
+    ("a=a+b;b=b+c", [('a', 'a b;b=b c')]),
+    (b";a=b", [(b';a', b'b')]),
+    (b"a=a+b;b=b+c", [(b'a', b'a b;b=b c')]),
 ]
 
 # Each parse_qs testcase is a two-tuple that contains
@@ -68,16 +62,10 @@ parse_qs_test_cases = [
     (b"&a=b", {b'a': [b'b']}),
     (b"a=a+b&b=b+c", {b'a': [b'a b'], b'b': [b'b c']}),
     (b"a=1&a=2", {b'a': [b'1', b'2']}),
-    (";", {}),
-    (";;", {}),
-    (";a=b", {'a': ['b']}),
-    ("a=a+b;b=b+c", {'a': ['a b'], 'b': ['b c']}),
-    ("a=1;a=2", {'a': ['1', '2']}),
-    (b";", {}),
-    (b";;", {}),
-    (b";a=b", {b'a': [b'b']}),
-    (b"a=a+b;b=b+c", {b'a': [b'a b'], b'b': [b'b c']}),
-    (b"a=1;a=2", {b'a': [b'1', b'2']}),
+    (";a=b", {';a': ['b']}),
+    ("a=a+b;b=b+c", {'a': ['a b;b=b c']}),
+    (b";a=b", {b';a': [b'b']}),
+    (b"a=a+b;b=b+c", {b'a':[ b'a b;b=b c']}),
 ]
 
 class UrlParseTestCase(unittest.TestCase):
@@ -886,10 +874,46 @@ class UrlParseTestCase(unittest.TestCase):
     def test_parse_qsl_max_num_fields(self):
         with self.assertRaises(ValueError):
             urllib.parse.parse_qs('&'.join(['a=a']*11), max_num_fields=10)
-        with self.assertRaises(ValueError):
-            urllib.parse.parse_qs(';'.join(['a=a']*11), max_num_fields=10)
         urllib.parse.parse_qs('&'.join(['a=a']*10), max_num_fields=10)
 
+    def test_parse_qs_separator(self):
+        parse_qs_semicolon_cases = [
+            (";", {}),
+            (";;", {}),
+            (";a=b", {'a': ['b']}),
+            ("a=a+b;b=b+c", {'a': ['a b'], 'b': ['b c']}),
+            ("a=1;a=2", {'a': ['1', '2']}),
+            (b";", {}),
+            (b";;", {}),
+            (b";a=b", {b'a': [b'b']}),
+            (b"a=a+b;b=b+c", {b'a': [b'a b'], b'b': [b'b c']}),
+            (b"a=1;a=2", {b'a': [b'1', b'2']}),
+        ]
+        for orig, expect in parse_qs_semicolon_cases:
+            with self.subTest(f"Original: {orig!r}, Expected: {expect!r}"):
+                result = urllib.parse.parse_qs(orig, separator=';')
+                self.assertEqual(result, expect, "Error parsing %r" % orig)
+
+
+    def test_parse_qsl_separator(self):
+        parse_qsl_semicolon_cases = [
+            (";", []),
+            (";;", []),
+            (";a=b", [('a', 'b')]),
+            ("a=a+b;b=b+c", [('a', 'a b'), ('b', 'b c')]),
+            ("a=1;a=2", [('a', '1'), ('a', '2')]),
+            (b";", []),
+            (b";;", []),
+            (b";a=b", [(b'a', b'b')]),
+            (b"a=a+b;b=b+c", [(b'a', b'a b'), (b'b', b'b c')]),
+            (b"a=1;a=2", [(b'a', b'1'), (b'a', b'2')]),
+        ]
+        for orig, expect in parse_qsl_semicolon_cases:
+            with self.subTest(f"Original: {orig!r}, Expected: {expect!r}"):
+                result = urllib.parse.parse_qsl(orig, separator=';')
+                self.assertEqual(result, expect, "Error parsing %r" % orig)
+
+
     def test_urlencode_sequences(self):
         # Other tests incidentally urlencode things; test non-covered cases:
         # Sequence and object values.
index 2175afcffa435ad4f85375eb593a2a29fc5a136f..f15f6c5e57a501ec6b1edaa3a055ba74ecfa822e 100644 (file)
@@ -270,7 +270,7 @@ class Event:
         )
 
 
-_support_default_root = 1
+_support_default_root = True
 _default_root = None
 
 
@@ -280,13 +280,26 @@ def NoDefaultRoot():
     Call this function to inhibit that the first instance of
     Tk is used for windows without an explicit parent window.
     """
-    global _support_default_root
-    _support_default_root = 0
-    global _default_root
+    global _support_default_root, _default_root
+    _support_default_root = False
+    # Delete, so any use of _default_root will immediately raise an exception.
+    # Rebind before deletion, so repeated calls will not fail.
     _default_root = None
     del _default_root
 
 
+def _get_default_root(what=None):
+    if not _support_default_root:
+        raise RuntimeError("No master specified and tkinter is "
+                           "configured to not support default root")
+    if not _default_root:
+        if what:
+            raise RuntimeError(f"Too early to {what}: no default root window")
+        root = Tk()
+        assert _default_root is root
+    return _default_root
+
+
 def _tkerror(err):
     """Internal function."""
     pass
@@ -330,7 +343,7 @@ class Variable:
             raise TypeError("name must be a string")
         global _varnum
         if not master:
-            master = _default_root
+            master = _get_default_root('create variable')
         self._root = master._root()
         self._tk = master.tk
         if name:
@@ -478,15 +491,11 @@ class Variable:
             self._tk.call("trace", "vinfo", self._name))]
 
     def __eq__(self, other):
-        """Comparison for equality (==).
-
-        Note: if the Variable's master matters to behavior
-        also compare self._master == other._master
-        """
         if not isinstance(other, Variable):
             return NotImplemented
-        return self.__class__.__name__ == other.__class__.__name__ \
-            and self._name == other._name
+        return (self._name == other._name
+                and self.__class__.__name__ == other.__class__.__name__
+                and self._tk == other._tk)
 
 
 class StringVar(Variable):
@@ -591,7 +600,7 @@ class BooleanVar(Variable):
 
 def mainloop(n=0):
     """Run the main loop of Tcl."""
-    _default_root.tk.mainloop(n)
+    _get_default_root('run the main loop').tk.mainloop(n)
 
 
 getint = int
@@ -600,9 +609,9 @@ getdouble = float
 
 
 def getboolean(s):
-    """Convert true and false to integer values 1 and 0."""
+    """Convert Tcl object to True or False."""
     try:
-        return _default_root.tk.getboolean(s)
+        return _get_default_root('use getboolean()').tk.getboolean(s)
     except TclError:
         raise ValueError("invalid literal for getboolean()")
 
@@ -1151,8 +1160,7 @@ class Misc:
             self.tk.call('winfo', 'reqwidth', self._w))
 
     def winfo_rgb(self, color):
-        """Return tuple of decimal values for red, green, blue for
-        COLOR in this widget."""
+        """Return a tuple of integer RGB values in range(65536) for color in this widget."""
         return self._getints(
             self.tk.call('winfo', 'rgb', self._w, color))
 
@@ -2248,7 +2256,7 @@ class Tk(Misc, Wm):
         is the name of the widget class."""
         self.master = None
         self.children = {}
-        self._tkloaded = 0
+        self._tkloaded = False
         # to avoid recursions in the getattr code in case of failure, we
         # ensure that self.tk is always _something_.
         self.tk = None
@@ -2272,7 +2280,7 @@ class Tk(Misc, Wm):
             self._loadtk()
 
     def _loadtk(self):
-        self._tkloaded = 1
+        self._tkloaded = True
         global _default_root
         # Version sanity checks
         tk_version = self.tk.getvar('tk_version')
@@ -2521,12 +2529,8 @@ class BaseWidget(Misc):
 
     def _setup(self, master, cnf):
         """Internal function. Sets up information about children."""
-        if _support_default_root:
-            global _default_root
-            if not master:
-                if not _default_root:
-                    _default_root = Tk()
-                master = _default_root
+        if not master:
+            master = _get_default_root()
         self.master = master
         self.tk = master.tk
         name = None
@@ -3990,9 +3994,7 @@ class Image:
     def __init__(self, imgtype, name=None, cnf={}, master=None, **kw):
         self.name = None
         if not master:
-            master = _default_root
-            if not master:
-                raise RuntimeError('Too early to create image')
+            master = _get_default_root('create image')
         self.tk = getattr(master, 'tk', master)
         if not name:
             Image._last_id += 1
@@ -4146,11 +4148,13 @@ class BitmapImage(Image):
 
 
 def image_names():
-    return _default_root.tk.splitlist(_default_root.tk.call('image', 'names'))
+    tk = _get_default_root('use image_names()').tk
+    return tk.splitlist(tk.call('image', 'names'))
 
 
 def image_types():
-    return _default_root.tk.splitlist(_default_root.tk.call('image', 'types'))
+    tk = _get_default_root('use image_types()').tk
+    return tk.splitlist(tk.call('image', 'types'))
 
 
 class Spinbox(Widget, XView):
index 3cfc06f6f1fae60e89e6027fad4dce5d15f22305..e2fb69dba927633e614d9438a20ecee6de6b7260 100644 (file)
@@ -8,57 +8,69 @@
 # fixed initialcolor handling in August 1998
 #
 
-#
-# options (all have default values):
-#
-# - initialcolor: color to mark as selected when dialog is displayed
-#   (given as an RGB triplet or a Tk color string)
-#
-# - parent: which window to place the dialog on top of
-#
-# - title: dialog title
-#
 
 from tkinter.commondialog import Dialog
 
 __all__ = ["Chooser", "askcolor"]
 
 
-#
-# color chooser class
-
 class Chooser(Dialog):
-    "Ask for a color"
+    """Create a dialog for the tk_chooseColor command.
+
+    Args:
+        master: The master widget for this dialog.  If not provided,
+            defaults to options['parent'] (if defined).
+        options: Dictionary of options for the tk_chooseColor call.
+            initialcolor: Specifies the selected color when the
+                dialog is first displayed.  This can be a tk color
+                string or a 3-tuple of ints in the range (0, 255)
+                for an RGB triplet.
+            parent: The parent window of the color dialog.  The
+                color dialog is displayed on top of this.
+            title: A string for the title of the dialog box.
+    """
 
     command = "tk_chooseColor"
 
     def _fixoptions(self):
+        """Ensure initialcolor is a tk color string.
+
+        Convert initialcolor from a RGB triplet to a color string.
+        """
         try:
-            # make sure initialcolor is a tk color string
             color = self.options["initialcolor"]
             if isinstance(color, tuple):
-                # assume an RGB triplet
+                # Assume an RGB triplet.
                 self.options["initialcolor"] = "#%02x%02x%02x" % color
         except KeyError:
             pass
 
     def _fixresult(self, widget, result):
-        # result can be somethings: an empty tuple, an empty string or
-        # a Tcl_Obj, so this somewhat weird check handles that
+        """Adjust result returned from call to tk_chooseColor.
+
+        Return both an RGB tuple of ints in the range (0, 255) and the
+        tk color string in the form #rrggbb.
+        """
+        # Result can be many things: an empty tuple, an empty string, or
+        # a _tkinter.Tcl_Obj, so this somewhat weird check handles that.
         if not result or not str(result):
-            return None, None # canceled
+            return None, None  # canceled
 
-        # to simplify application code, the color chooser returns
-        # an RGB tuple together with the Tk color string
+        # To simplify application code, the color chooser returns
+        # an RGB tuple together with the Tk color string.
         r, g, b = widget.winfo_rgb(result)
-        return (r/256, g/256, b/256), str(result)
+        return (r//256, g//256, b//256), str(result)
 
 
 #
 # convenience stuff
 
-def askcolor(color = None, **options):
-    "Ask for a color"
+def askcolor(color=None, **options):
+    """Display dialog window for selection of a color.
+
+    Convenience wrapper for the Chooser class.  Displays the color
+    chooser dialog with color as the initial value.
+    """
 
     if color:
         options = options.copy()
index e56b5baf7d1e12b40865a84c8027eb618cb20988..cc3069842c3e46a0c39e5e837d7ee1a957559585 100644 (file)
@@ -18,10 +18,10 @@ class Dialog:
     command = None
 
     def __init__(self, master=None, **options):
+        if not master:
+            master = options.get('parent')
         self.master = master
         self.options = options
-        if not master and options.get('parent'):
-            self.master = options['parent']
 
     def _fixoptions(self):
         pass # hook
index 15ad7ab4b63a81509590b2135ad867aa295054cc..78b660c54be314cded4f22e38c58e70a894eafe6 100644 (file)
@@ -69,7 +69,7 @@ class Font:
     def __init__(self, root=None, font=None, name=None, exists=False,
                  **options):
         if not root:
-            root = tkinter._default_root
+            root = tkinter._get_default_root('use font')
         tk = getattr(root, 'tk', root)
         if font:
             # get actual settings corresponding to the given font
@@ -103,7 +103,7 @@ class Font:
     def __eq__(self, other):
         if not isinstance(other, Font):
             return NotImplemented
-        return self.name == other.name
+        return self.name == other.name and self._tk == other._tk
 
     def __getitem__(self, key):
         return self.cget(key)
@@ -180,7 +180,7 @@ class Font:
 def families(root=None, displayof=None):
     "Get font families (as a tuple)"
     if not root:
-        root = tkinter._default_root
+        root = tkinter._get_default_root('use font.families()')
     args = ()
     if displayof:
         args = ('-displayof', displayof)
@@ -190,7 +190,7 @@ def families(root=None, displayof=None):
 def names(root=None):
     "Get names of defined fonts (as a tuple)"
     if not root:
-        root = tkinter._default_root
+        root = tkinter._get_default_root('use font.names()')
     return root.tk.splitlist(root.tk.call("font", "names"))
 
 
index 85244171117b61e8a7ef4412064b63ba45782bef..b882d47c961bdbf889d67273e12b5969a86a639c 100644 (file)
@@ -24,9 +24,7 @@ askstring -- get a string from the user
 """
 
 from tkinter import *
-from tkinter import messagebox
-
-import tkinter # used at _QueryDialog for tkinter._default_root
+from tkinter import messagebox, _get_default_root
 
 
 class SimpleDialog:
@@ -128,13 +126,17 @@ class Dialog(Toplevel):
 
             title -- the dialog title
         '''
-        Toplevel.__init__(self, parent)
+        master = parent
+        if not master:
+            master = _get_default_root('create dialog window')
+
+        Toplevel.__init__(self, master)
 
         self.withdraw() # remain invisible for now
-        # If the master is not viewable, don't
+        # If the parent is not viewable, don't
         # make the child transient, or else it
         # would be opened withdrawn
-        if parent.winfo_viewable():
+        if parent is not None and parent.winfo_viewable():
             self.transient(parent)
 
         if title:
@@ -155,7 +157,7 @@ class Dialog(Toplevel):
 
         self.protocol("WM_DELETE_WINDOW", self.cancel)
 
-        if self.parent is not None:
+        if parent is not None:
             self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
                                       parent.winfo_rooty()+50))
 
@@ -259,9 +261,6 @@ class _QueryDialog(Dialog):
                  minvalue = None, maxvalue = None,
                  parent = None):
 
-        if not parent:
-            parent = tkinter._default_root
-
         self.prompt   = prompt
         self.minvalue = minvalue
         self.maxvalue = maxvalue
index 467a0b66c265c05f5631f544633151cd19e9b261..dbc47a81e6515730e2fb0947668e18fab2e0dbda 100644 (file)
@@ -36,6 +36,33 @@ class AbstractTkTest:
             w.destroy()
         self.root.withdraw()
 
+
+class AbstractDefaultRootTest:
+
+    def setUp(self):
+        self._old_support_default_root = tkinter._support_default_root
+        destroy_default_root()
+        tkinter._support_default_root = True
+        self.wantobjects = tkinter.wantobjects
+
+    def tearDown(self):
+        destroy_default_root()
+        tkinter._default_root = None
+        tkinter._support_default_root = self._old_support_default_root
+
+    def _test_widget(self, constructor):
+        # no master passing
+        x = constructor()
+        self.assertIsNotNone(tkinter._default_root)
+        self.assertIs(x.master, tkinter._default_root)
+        self.assertIs(x.tk, tkinter._default_root.tk)
+        x.destroy()
+        destroy_default_root()
+        tkinter.NoDefaultRoot()
+        self.assertRaises(RuntimeError, constructor)
+        self.assertFalse(hasattr(tkinter, '_default_root'))
+
+
 def destroy_default_root():
     if getattr(tkinter, '_default_root', None):
         tkinter._default_root.update_idletasks()
diff --git a/Lib/tkinter/test/test_tkinter/test_colorchooser.py b/Lib/tkinter/test/test_tkinter/test_colorchooser.py
new file mode 100644 (file)
index 0000000..4798bc9
--- /dev/null
@@ -0,0 +1,43 @@
+import unittest
+import tkinter
+from test.support import requires, run_unittest, swap_attr
+from tkinter.test.support import AbstractTkTest
+from tkinter import colorchooser
+
+requires('gui')
+
+
+class ChooserTest(AbstractTkTest, unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        AbstractTkTest.setUpClass.__func__(cls)
+        cls.cc = colorchooser.Chooser(initialcolor='dark blue slate')
+
+    def test_fixoptions(self):
+        cc = self.cc
+        cc._fixoptions()
+        self.assertEqual(cc.options['initialcolor'], 'dark blue slate')
+
+        cc.options['initialcolor'] = '#D2D269691E1E'
+        cc._fixoptions()
+        self.assertEqual(cc.options['initialcolor'], '#D2D269691E1E')
+
+        cc.options['initialcolor'] = (210, 105, 30)
+        cc._fixoptions()
+        self.assertEqual(cc.options['initialcolor'], '#d2691e')
+
+    def test_fixresult(self):
+        cc = self.cc
+        self.assertEqual(cc._fixresult(self.root, ()), (None, None))
+        self.assertEqual(cc._fixresult(self.root, ''), (None, None))
+        self.assertEqual(cc._fixresult(self.root, 'chocolate'),
+                         ((210, 105, 30), 'chocolate'))
+        self.assertEqual(cc._fixresult(self.root, '#4a3c8c'),
+                         ((74, 60, 140), '#4a3c8c'))
+
+
+tests_gui = (ChooserTest,)
+
+if __name__ == "__main__":
+    run_unittest(*tests_gui)
index a021ea336807bb8e95571ee12755d7dcb6526f54..0ea7924f5d5c9ece9ffcbaed6707e5937b529e24 100644 (file)
@@ -2,7 +2,7 @@ import unittest
 import tkinter
 from tkinter import font
 from test.support import requires, run_unittest, gc_collect, ALWAYS_EQ
-from tkinter.test.support import AbstractTkTest
+from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest
 
 requires('gui')
 
@@ -63,15 +63,22 @@ class FontTest(AbstractTkTest, unittest.TestCase):
         self.assertEqual(self.font.name, fontname)
         self.assertEqual(str(self.font), fontname)
 
-    def test_eq(self):
+    def test_equality(self):
         font1 = font.Font(root=self.root, name=fontname, exists=True)
         font2 = font.Font(root=self.root, name=fontname, exists=True)
         self.assertIsNot(font1, font2)
         self.assertEqual(font1, font2)
         self.assertNotEqual(font1, font1.copy())
+
         self.assertNotEqual(font1, 0)
         self.assertEqual(font1, ALWAYS_EQ)
 
+        root2 = tkinter.Tk()
+        self.addCleanup(root2.destroy)
+        font3 = font.Font(root=root2, name=fontname, exists=True)
+        self.assertEqual(str(font1), str(font3))
+        self.assertNotEqual(font1, font3)
+
     def test_measure(self):
         self.assertIsInstance(self.font.measure('abc'), int)
 
@@ -101,7 +108,38 @@ class FontTest(AbstractTkTest, unittest.TestCase):
             self.assertTrue(name)
         self.assertIn(fontname, names)
 
-tests_gui = (FontTest, )
+
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+    def test_families(self):
+        self.assertRaises(RuntimeError, font.families)
+        root = tkinter.Tk()
+        families = font.families()
+        self.assertIsInstance(families, tuple)
+        self.assertTrue(families)
+        for family in families:
+            self.assertIsInstance(family, str)
+            self.assertTrue(family)
+        root.destroy()
+        tkinter.NoDefaultRoot()
+        self.assertRaises(RuntimeError, font.families)
+
+    def test_names(self):
+        self.assertRaises(RuntimeError, font.names)
+        root = tkinter.Tk()
+        names = font.names()
+        self.assertIsInstance(names, tuple)
+        self.assertTrue(names)
+        for name in names:
+            self.assertIsInstance(name, str)
+            self.assertTrue(name)
+        self.assertIn(fontname, names)
+        root.destroy()
+        tkinter.NoDefaultRoot()
+        self.assertRaises(RuntimeError, font.names)
+
+
+tests_gui = (FontTest, DefaultRootTest)
 
 if __name__ == "__main__":
     run_unittest(*tests_gui)
index 2805d35a1f5b1bffde880cd179572c043827e05b..94bba8518fdaa6d9bbd7592867eb5fa25a327c7e 100644 (file)
@@ -1,7 +1,7 @@
 import unittest
 import tkinter
 from test import support
-from tkinter.test.support import AbstractTkTest, requires_tcl
+from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest, requires_tcl
 
 support.requires('gui')
 
@@ -19,6 +19,47 @@ class MiscTest(AbstractTkTest, unittest.TestCase):
         self.assertIsInstance(image_names, tuple)
 
 
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+    def test_image_types(self):
+        self.assertRaises(RuntimeError, tkinter.image_types)
+        root = tkinter.Tk()
+        image_types = tkinter.image_types()
+        self.assertIsInstance(image_types, tuple)
+        self.assertIn('photo', image_types)
+        self.assertIn('bitmap', image_types)
+        root.destroy()
+        tkinter.NoDefaultRoot()
+        self.assertRaises(RuntimeError, tkinter.image_types)
+
+    def test_image_names(self):
+        self.assertRaises(RuntimeError, tkinter.image_names)
+        root = tkinter.Tk()
+        image_names = tkinter.image_names()
+        self.assertIsInstance(image_names, tuple)
+        root.destroy()
+        tkinter.NoDefaultRoot()
+        self.assertRaises(RuntimeError, tkinter.image_names)
+
+    def test_image_create_bitmap(self):
+        self.assertRaises(RuntimeError, tkinter.BitmapImage)
+        root = tkinter.Tk()
+        image = tkinter.BitmapImage()
+        self.assertIn(image.name, tkinter.image_names())
+        root.destroy()
+        tkinter.NoDefaultRoot()
+        self.assertRaises(RuntimeError, tkinter.BitmapImage)
+
+    def test_image_create_photo(self):
+        self.assertRaises(RuntimeError, tkinter.PhotoImage)
+        root = tkinter.Tk()
+        image = tkinter.PhotoImage()
+        self.assertIn(image.name, tkinter.image_names())
+        root.destroy()
+        tkinter.NoDefaultRoot()
+        self.assertRaises(RuntimeError, tkinter.PhotoImage)
+
+
 class BitmapImageTest(AbstractTkTest, unittest.TestCase):
 
     @classmethod
@@ -330,7 +371,7 @@ class PhotoImageTest(AbstractTkTest, unittest.TestCase):
         self.assertEqual(image.transparency_get(4, 6), False)
 
 
-tests_gui = (MiscTest, BitmapImageTest, PhotoImageTest,)
+tests_gui = (MiscTest, DefaultRootTest, BitmapImageTest, PhotoImageTest,)
 
 if __name__ == "__main__":
     support.run_unittest(*tests_gui)
index b8eea2544f5228e2b45225929c8d5d4826526952..f6e5b4db1ae1fbb006d76b75f6919e83e51b9e3a 100644 (file)
@@ -1,7 +1,7 @@
 import unittest
 import tkinter
 from test import support
-from tkinter.test.support import AbstractTkTest
+from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest
 
 support.requires('gui')
 
@@ -192,6 +192,26 @@ class MiscTest(AbstractTkTest, unittest.TestCase):
         with self.assertRaises(tkinter.TclError):
             root.clipboard_get()
 
+    def test_winfo_rgb(self):
+        root = self.root
+        rgb = root.winfo_rgb
+
+        # Color name.
+        self.assertEqual(rgb('red'), (65535, 0, 0))
+        self.assertEqual(rgb('dark slate blue'), (18504, 15677, 35723))
+        # #RGB - extends each 4-bit hex value to be 16-bit.
+        self.assertEqual(rgb('#F0F'), (0xFFFF, 0x0000, 0xFFFF))
+        # #RRGGBB - extends each 8-bit hex value to be 16-bit.
+        self.assertEqual(rgb('#4a3c8c'), (0x4a4a, 0x3c3c, 0x8c8c))
+        # #RRRRGGGGBBBB
+        self.assertEqual(rgb('#dede14143939'), (0xdede, 0x1414, 0x3939))
+        # Invalid string.
+        with self.assertRaises(tkinter.TclError):
+            rgb('#123456789a')
+        # RGB triplet is invalid input.
+        with self.assertRaises(tkinter.TclError):
+            rgb((111, 78, 55))
+
     def test_event_repr_defaults(self):
         e = tkinter.Event()
         e.serial = 12345
@@ -241,7 +261,85 @@ class MiscTest(AbstractTkTest, unittest.TestCase):
                          " num=3 delta=-1 focus=True"
                          " x=10 y=20 width=300 height=200>")
 
-tests_gui = (MiscTest, )
+    def test_getboolean(self):
+        for v in 'true', 'yes', 'on', '1', 't', 'y', 1, True:
+            self.assertIs(self.root.getboolean(v), True)
+        for v in 'false', 'no', 'off', '0', 'f', 'n', 0, False:
+            self.assertIs(self.root.getboolean(v), False)
+        self.assertRaises(ValueError, self.root.getboolean, 'yea')
+        self.assertRaises(ValueError, self.root.getboolean, '')
+        self.assertRaises(TypeError, self.root.getboolean, None)
+        self.assertRaises(TypeError, self.root.getboolean, ())
+
+    def test_mainloop(self):
+        log = []
+        def callback():
+            log.append(1)
+            self.root.after(100, self.root.quit)
+        self.root.after(100, callback)
+        self.root.mainloop(1)
+        self.assertEqual(log, [])
+        self.root.mainloop(0)
+        self.assertEqual(log, [1])
+        self.assertTrue(self.root.winfo_exists())
+
+
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+    def test_default_root(self):
+        self.assertIs(tkinter._support_default_root, True)
+        self.assertIsNone(tkinter._default_root)
+        root = tkinter.Tk()
+        root2 = tkinter.Tk()
+        root3 = tkinter.Tk()
+        self.assertIs(tkinter._default_root, root)
+        root2.destroy()
+        self.assertIs(tkinter._default_root, root)
+        root.destroy()
+        self.assertIsNone(tkinter._default_root)
+        root3.destroy()
+        self.assertIsNone(tkinter._default_root)
+
+    def test_no_default_root(self):
+        self.assertIs(tkinter._support_default_root, True)
+        self.assertIsNone(tkinter._default_root)
+        root = tkinter.Tk()
+        self.assertIs(tkinter._default_root, root)
+        tkinter.NoDefaultRoot()
+        self.assertIs(tkinter._support_default_root, False)
+        self.assertFalse(hasattr(tkinter, '_default_root'))
+        # repeated call is no-op
+        tkinter.NoDefaultRoot()
+        self.assertIs(tkinter._support_default_root, False)
+        self.assertFalse(hasattr(tkinter, '_default_root'))
+        root.destroy()
+        self.assertIs(tkinter._support_default_root, False)
+        self.assertFalse(hasattr(tkinter, '_default_root'))
+        root = tkinter.Tk()
+        self.assertIs(tkinter._support_default_root, False)
+        self.assertFalse(hasattr(tkinter, '_default_root'))
+        root.destroy()
+
+    def test_getboolean(self):
+        self.assertRaises(RuntimeError, tkinter.getboolean, '1')
+        root = tkinter.Tk()
+        self.assertIs(tkinter.getboolean('1'), True)
+        self.assertRaises(ValueError, tkinter.getboolean, 'yea')
+        root.destroy()
+        tkinter.NoDefaultRoot()
+        self.assertRaises(RuntimeError, tkinter.getboolean, '1')
+
+    def test_mainloop(self):
+        self.assertRaises(RuntimeError, tkinter.mainloop)
+        root = tkinter.Tk()
+        root.after_idle(root.quit)
+        tkinter.mainloop()
+        root.destroy()
+        tkinter.NoDefaultRoot()
+        self.assertRaises(RuntimeError, tkinter.mainloop)
+
+
+tests_gui = (MiscTest, DefaultRootTest)
 
 if __name__ == "__main__":
     support.run_unittest(*tests_gui)
diff --git a/Lib/tkinter/test/test_tkinter/test_simpledialog.py b/Lib/tkinter/test/test_tkinter/test_simpledialog.py
new file mode 100644 (file)
index 0000000..9119172
--- /dev/null
@@ -0,0 +1,25 @@
+import unittest
+import tkinter
+from test.support import requires, run_unittest, swap_attr
+from tkinter.test.support import AbstractDefaultRootTest
+from tkinter.simpledialog import Dialog, askinteger
+
+requires('gui')
+
+
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+    def test_askinteger(self):
+        self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
+        root = tkinter.Tk()
+        with swap_attr(Dialog, 'wait_window', lambda self, w: w.destroy()):
+            askinteger("Go To Line", "Line number")
+        root.destroy()
+        tkinter.NoDefaultRoot()
+        self.assertRaises(RuntimeError, askinteger, "Go To Line", "Line number")
+
+
+tests_gui = (DefaultRootTest,)
+
+if __name__ == "__main__":
+    run_unittest(*tests_gui)
index 08b7dedcaf933b67e7574674074e46f622b5297d..6aebe8d16d556b66ca243ddf3e9464572a46c742 100644 (file)
@@ -1,8 +1,10 @@
 import unittest
 import gc
+import tkinter
 from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl,
                      TclError)
 from test.support import ALWAYS_EQ
+from tkinter.test.support import AbstractDefaultRootTest
 
 
 class Var(Variable):
@@ -56,22 +58,32 @@ class TestVariable(TestBase):
         del v2
         self.assertFalse(self.info_exists("name"))
 
-    def test___eq__(self):
+    def test_equality(self):
         # values doesn't matter, only class and name are checked
         v1 = Variable(self.root, name="abc")
         v2 = Variable(self.root, name="abc")
         self.assertIsNot(v1, v2)
         self.assertEqual(v1, v2)
 
-        v3 = StringVar(self.root, name="abc")
+        v3 = Variable(self.root, name="cba")
         self.assertNotEqual(v1, v3)
 
+        v4 = StringVar(self.root, name="abc")
+        self.assertEqual(str(v1), str(v4))
+        self.assertNotEqual(v1, v4)
+
         V = type('Variable', (), {})
         self.assertNotEqual(v1, V())
 
         self.assertNotEqual(v1, object())
         self.assertEqual(v1, ALWAYS_EQ)
 
+        root2 = tkinter.Tk()
+        self.addCleanup(root2.destroy)
+        v5 = Variable(root2, name="abc")
+        self.assertEqual(str(v1), str(v5))
+        self.assertNotEqual(v1, v5)
+
     def test_invalid_name(self):
         with self.assertRaises(TypeError):
             Variable(self.root, name=123)
@@ -308,8 +320,21 @@ class TestBooleanVar(TestBase):
             v.get()
 
 
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+    def test_variable(self):
+        self.assertRaises(RuntimeError, Variable)
+        root = tkinter.Tk()
+        v = Variable()
+        v.set("value")
+        self.assertEqual(v.get(), "value")
+        root.destroy()
+        tkinter.NoDefaultRoot()
+        self.assertRaises(RuntimeError, Variable)
+
+
 tests_gui = (TestVariable, TestStringVar, TestIntVar,
-             TestDoubleVar, TestBooleanVar)
+             TestDoubleVar, TestBooleanVar, DefaultRootTest)
 
 
 if __name__ == "__main__":
index b6f792d6c2cf8566085c244d990aeec13dbd1a4e..39334de8cf41c3caba0f1f0e0ba4267aeeb31e1d 100644 (file)
@@ -2,11 +2,11 @@ import unittest
 import tkinter
 from tkinter import TclError
 import os
-import sys
 from test.support import requires
 
 from tkinter.test.support import (tcl_version, requires_tcl,
-                                  get_tk_patchlevel, widget_eq)
+                                  get_tk_patchlevel, widget_eq,
+                                  AbstractDefaultRootTest)
 from tkinter.test.widget_tests import (
     add_standard_options, noconv, pixels_round,
     AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests,
@@ -22,7 +22,7 @@ def float_round(x):
 class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
     _conv_pad_pixels = noconv
 
-    def test_class(self):
+    def test_configure_class(self):
         widget = self.create()
         self.assertEqual(widget['class'],
                          widget.__class__.__name__.title())
@@ -31,7 +31,7 @@ class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
         widget2 = self.create(class_='Foo')
         self.assertEqual(widget2['class'], 'Foo')
 
-    def test_colormap(self):
+    def test_configure_colormap(self):
         widget = self.create()
         self.assertEqual(widget['colormap'], '')
         self.checkInvalidParam(widget, 'colormap', 'new',
@@ -39,7 +39,7 @@ class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
         widget2 = self.create(colormap='new')
         self.assertEqual(widget2['colormap'], 'new')
 
-    def test_container(self):
+    def test_configure_container(self):
         widget = self.create()
         self.assertEqual(widget['container'], 0 if self.wantobjects else '0')
         self.checkInvalidParam(widget, 'container', 1,
@@ -47,7 +47,7 @@ class AbstractToplevelTest(AbstractWidgetTest, PixelSizeTests):
         widget2 = self.create(container=True)
         self.assertEqual(widget2['container'], 1 if self.wantobjects else '1')
 
-    def test_visual(self):
+    def test_configure_visual(self):
         widget = self.create()
         self.assertEqual(widget['visual'], '')
         self.checkInvalidParam(widget, 'visual', 'default',
@@ -69,13 +69,13 @@ class ToplevelTest(AbstractToplevelTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Toplevel(self.root, **kwargs)
 
-    def test_menu(self):
+    def test_configure_menu(self):
         widget = self.create()
         menu = tkinter.Menu(self.root)
         self.checkParam(widget, 'menu', menu, eq=widget_eq)
         self.checkParam(widget, 'menu', '')
 
-    def test_screen(self):
+    def test_configure_screen(self):
         widget = self.create()
         self.assertEqual(widget['screen'], '')
         try:
@@ -87,7 +87,7 @@ class ToplevelTest(AbstractToplevelTest, unittest.TestCase):
         widget2 = self.create(screen=display)
         self.assertEqual(widget2['screen'], display)
 
-    def test_use(self):
+    def test_configure_use(self):
         widget = self.create()
         self.assertEqual(widget['use'], '')
         parent = self.create(container=True)
@@ -124,14 +124,14 @@ class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.LabelFrame(self.root, **kwargs)
 
-    def test_labelanchor(self):
+    def test_configure_labelanchor(self):
         widget = self.create()
         self.checkEnumParam(widget, 'labelanchor',
                             'e', 'en', 'es', 'n', 'ne', 'nw',
                             's', 'se', 'sw', 'w', 'wn', 'ws')
         self.checkInvalidParam(widget, 'labelanchor', 'center')
 
-    def test_labelwidget(self):
+    def test_configure_labelwidget(self):
         widget = self.create()
         label = tkinter.Label(self.root, text='Mupp', name='foo')
         self.checkParam(widget, 'labelwidget', label, expected='.foo')
@@ -141,7 +141,7 @@ class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):
 class AbstractLabelTest(AbstractWidgetTest, IntegerSizeTests):
     _conv_pixels = noconv
 
-    def test_highlightthickness(self):
+    def test_configure_highlightthickness(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'highlightthickness',
                               0, 1.3, 2.6, 6, -2, '10p')
@@ -179,7 +179,7 @@ class ButtonTest(AbstractLabelTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Button(self.root, **kwargs)
 
-    def test_default(self):
+    def test_configure_default(self):
         widget = self.create()
         self.checkEnumParam(widget, 'default', 'active', 'disabled', 'normal')
 
@@ -204,11 +204,11 @@ class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):
         return tkinter.Checkbutton(self.root, **kwargs)
 
 
-    def test_offvalue(self):
+    def test_configure_offvalue(self):
         widget = self.create()
         self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string')
 
-    def test_onvalue(self):
+    def test_configure_onvalue(self):
         widget = self.create()
         self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string')
 
@@ -231,7 +231,7 @@ class RadiobuttonTest(AbstractLabelTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Radiobutton(self.root, **kwargs)
 
-    def test_value(self):
+    def test_configure_value(self):
         widget = self.create()
         self.checkParams(widget, 'value', 1, 2.3, '', 'any string')
 
@@ -254,20 +254,19 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Menubutton(self.root, **kwargs)
 
-    def test_direction(self):
+    def test_configure_direction(self):
         widget = self.create()
         self.checkEnumParam(widget, 'direction',
                 'above', 'below', 'flush', 'left', 'right')
 
-    def test_height(self):
+    def test_configure_height(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'height', 100, -100, 0, conv=str)
 
-    test_highlightthickness = StandardOptionsTests.test_highlightthickness
+    test_configure_highlightthickness = \
+        StandardOptionsTests.test_configure_highlightthickness
 
-    @unittest.skipIf(sys.platform == 'darwin',
-                     'crashes with Cocoa Tk (issue19733)')
-    def test_image(self):
+    def test_configure_image(self):
         widget = self.create()
         image = tkinter.PhotoImage(master=self.root, name='image1')
         self.checkParam(widget, 'image', image, conv=str)
@@ -281,23 +280,23 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
         if errmsg is not None:
             self.assertEqual(str(cm.exception), errmsg)
 
-    def test_menu(self):
+    def test_configure_menu(self):
         widget = self.create()
         menu = tkinter.Menu(widget, name='menu')
         self.checkParam(widget, 'menu', menu, eq=widget_eq)
         menu.destroy()
 
-    def test_padx(self):
+    def test_configure_padx(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, '12m')
         self.checkParam(widget, 'padx', -2, expected=0)
 
-    def test_pady(self):
+    def test_configure_pady(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, '12m')
         self.checkParam(widget, 'pady', -2, expected=0)
 
-    def test_width(self):
+    def test_configure_width(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'width', 402, -402, 0, conv=str)
 
@@ -330,18 +329,18 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Entry(self.root, **kwargs)
 
-    def test_disabledbackground(self):
+    def test_configure_disabledbackground(self):
         widget = self.create()
         self.checkColorParam(widget, 'disabledbackground')
 
-    def test_insertborderwidth(self):
+    def test_configure_insertborderwidth(self):
         widget = self.create(insertwidth=100)
         self.checkPixelsParam(widget, 'insertborderwidth',
                               0, 1.3, 2.6, 6, -2, '10p')
         # insertborderwidth is bounded above by a half of insertwidth.
         self.checkParam(widget, 'insertborderwidth', 60, expected=100//2)
 
-    def test_insertwidth(self):
+    def test_configure_insertwidth(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'insertwidth', 1.3, 3.6, '10p')
         self.checkParam(widget, 'insertwidth', 0.1, expected=2)
@@ -351,32 +350,32 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
         else:
             self.checkParam(widget, 'insertwidth', 0.9, expected=1)
 
-    def test_invalidcommand(self):
+    def test_configure_invalidcommand(self):
         widget = self.create()
         self.checkCommandParam(widget, 'invalidcommand')
         self.checkCommandParam(widget, 'invcmd')
 
-    def test_readonlybackground(self):
+    def test_configure_readonlybackground(self):
         widget = self.create()
         self.checkColorParam(widget, 'readonlybackground')
 
-    def test_show(self):
+    def test_configure_show(self):
         widget = self.create()
         self.checkParam(widget, 'show', '*')
         self.checkParam(widget, 'show', '')
         self.checkParam(widget, 'show', ' ')
 
-    def test_state(self):
+    def test_configure_state(self):
         widget = self.create()
         self.checkEnumParam(widget, 'state',
                             'disabled', 'normal', 'readonly')
 
-    def test_validate(self):
+    def test_configure_validate(self):
         widget = self.create()
         self.checkEnumParam(widget, 'validate',
                 'all', 'key', 'focus', 'focusin', 'focusout', 'none')
 
-    def test_validatecommand(self):
+    def test_configure_validatecommand(self):
         widget = self.create()
         self.checkCommandParam(widget, 'validatecommand')
         self.checkCommandParam(widget, 'vcmd')
@@ -429,25 +428,25 @@ class SpinboxTest(EntryTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Spinbox(self.root, **kwargs)
 
-    test_show = None
+    test_configure_show = None
 
-    def test_buttonbackground(self):
+    def test_configure_buttonbackground(self):
         widget = self.create()
         self.checkColorParam(widget, 'buttonbackground')
 
-    def test_buttoncursor(self):
+    def test_configure_buttoncursor(self):
         widget = self.create()
         self.checkCursorParam(widget, 'buttoncursor')
 
-    def test_buttondownrelief(self):
+    def test_configure_buttondownrelief(self):
         widget = self.create()
         self.checkReliefParam(widget, 'buttondownrelief')
 
-    def test_buttonuprelief(self):
+    def test_configure_buttonuprelief(self):
         widget = self.create()
         self.checkReliefParam(widget, 'buttonuprelief')
 
-    def test_format(self):
+    def test_configure_format(self):
         widget = self.create()
         self.checkParam(widget, 'format', '%2f')
         self.checkParam(widget, 'format', '%2.2f')
@@ -462,25 +461,25 @@ class SpinboxTest(EntryTest, unittest.TestCase):
         self.checkParam(widget, 'format', '%09.200f')
         self.checkInvalidParam(widget, 'format', '%d')
 
-    def test_from(self):
+    def test_configure_from(self):
         widget = self.create()
         self.checkParam(widget, 'to', 100.0)
         self.checkFloatParam(widget, 'from', -10, 10.2, 11.7)
         self.checkInvalidParam(widget, 'from', 200,
                 errmsg='-to value must be greater than -from value')
 
-    def test_increment(self):
+    def test_configure_increment(self):
         widget = self.create()
         self.checkFloatParam(widget, 'increment', -1, 1, 10.2, 12.8, 0)
 
-    def test_to(self):
+    def test_configure_to(self):
         widget = self.create()
         self.checkParam(widget, 'from', -100.0)
         self.checkFloatParam(widget, 'to', -10, 10.2, 11.7)
         self.checkInvalidParam(widget, 'to', -200,
                 errmsg='-to value must be greater than -from value')
 
-    def test_values(self):
+    def test_configure_values(self):
         # XXX
         widget = self.create()
         self.assertEqual(widget['values'], '')
@@ -491,7 +490,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
                         expected='42 3.14 {} {any string}')
         self.checkParam(widget, 'values', '')
 
-    def test_wrap(self):
+    def test_configure_wrap(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'wrap')
 
@@ -557,17 +556,17 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Text(self.root, **kwargs)
 
-    def test_autoseparators(self):
+    def test_configure_autoseparators(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'autoseparators')
 
     @requires_tcl(8, 5)
-    def test_blockcursor(self):
+    def test_configure_blockcursor(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'blockcursor')
 
     @requires_tcl(8, 5)
-    def test_endline(self):
+    def test_configure_endline(self):
         widget = self.create()
         text = '\n'.join('Line %d' for i in range(100))
         widget.insert('end', text)
@@ -580,50 +579,50 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
         self.checkInvalidParam(widget, 'endline', 10,
                 errmsg='-startline must be less than or equal to -endline')
 
-    def test_height(self):
+    def test_configure_height(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, '3c')
         self.checkParam(widget, 'height', -100, expected=1)
         self.checkParam(widget, 'height', 0, expected=1)
 
-    def test_maxundo(self):
+    def test_configure_maxundo(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'maxundo', 0, 5, -1)
 
     @requires_tcl(8, 5)
-    def test_inactiveselectbackground(self):
+    def test_configure_inactiveselectbackground(self):
         widget = self.create()
         self.checkColorParam(widget, 'inactiveselectbackground')
 
     @requires_tcl(8, 6)
-    def test_insertunfocussed(self):
+    def test_configure_insertunfocussed(self):
         widget = self.create()
         self.checkEnumParam(widget, 'insertunfocussed',
                             'hollow', 'none', 'solid')
 
-    def test_selectborderwidth(self):
+    def test_configure_selectborderwidth(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'selectborderwidth',
                               1.3, 2.6, -2, '10p', conv=noconv,
                               keep_orig=tcl_version >= (8, 5))
 
-    def test_spacing1(self):
+    def test_configure_spacing1(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'spacing1', 20, 21.4, 22.6, '0.5c')
         self.checkParam(widget, 'spacing1', -5, expected=0)
 
-    def test_spacing2(self):
+    def test_configure_spacing2(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'spacing2', 5, 6.4, 7.6, '0.1c')
         self.checkParam(widget, 'spacing2', -1, expected=0)
 
-    def test_spacing3(self):
+    def test_configure_spacing3(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'spacing3', 20, 21.4, 22.6, '0.5c')
         self.checkParam(widget, 'spacing3', -10, expected=0)
 
     @requires_tcl(8, 5)
-    def test_startline(self):
+    def test_configure_startline(self):
         widget = self.create()
         text = '\n'.join('Line %d' for i in range(100))
         widget.insert('end', text)
@@ -636,14 +635,14 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
         self.checkInvalidParam(widget, 'startline', 70,
                 errmsg='-startline must be less than or equal to -endline')
 
-    def test_state(self):
+    def test_configure_state(self):
         widget = self.create()
         if tcl_version < (8, 5):
             self.checkParams(widget, 'state', 'disabled', 'normal')
         else:
             self.checkEnumParam(widget, 'state', 'disabled', 'normal')
 
-    def test_tabs(self):
+    def test_configure_tabs(self):
         widget = self.create()
         if get_tk_patchlevel() < (8, 5, 11):
             self.checkParam(widget, 'tabs', (10.2, 20.7, '1i', '2i'),
@@ -659,21 +658,21 @@ class TextTest(AbstractWidgetTest, unittest.TestCase):
                                keep_orig=tcl_version >= (8, 5))
 
     @requires_tcl(8, 5)
-    def test_tabstyle(self):
+    def test_configure_tabstyle(self):
         widget = self.create()
         self.checkEnumParam(widget, 'tabstyle', 'tabular', 'wordprocessor')
 
-    def test_undo(self):
+    def test_configure_undo(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'undo')
 
-    def test_width(self):
+    def test_configure_width(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'width', 402)
         self.checkParam(widget, 'width', -402, expected=1)
         self.checkParam(widget, 'width', 0, expected=1)
 
-    def test_wrap(self):
+    def test_configure_wrap(self):
         widget = self.create()
         if tcl_version < (8, 5):
             self.checkParams(widget, 'wrap', 'char', 'none', 'word')
@@ -711,16 +710,16 @@ class CanvasTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Canvas(self.root, **kwargs)
 
-    def test_closeenough(self):
+    def test_configure_closeenough(self):
         widget = self.create()
         self.checkFloatParam(widget, 'closeenough', 24, 2.4, 3.6, -3,
                              conv=float)
 
-    def test_confine(self):
+    def test_configure_confine(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'confine')
 
-    def test_offset(self):
+    def test_configure_offset(self):
         widget = self.create()
         self.assertEqual(widget['offset'], '0,0')
         self.checkParams(widget, 'offset',
@@ -729,7 +728,7 @@ class CanvasTest(AbstractWidgetTest, unittest.TestCase):
         self.checkParam(widget, 'offset', '#5,6')
         self.checkInvalidParam(widget, 'offset', 'spam')
 
-    def test_scrollregion(self):
+    def test_configure_scrollregion(self):
         widget = self.create()
         self.checkParam(widget, 'scrollregion', '0 0 200 150')
         self.checkParam(widget, 'scrollregion', (0, 0, 200, 150),
@@ -741,17 +740,17 @@ class CanvasTest(AbstractWidgetTest, unittest.TestCase):
         self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200))
         self.checkInvalidParam(widget, 'scrollregion', (0, 0, 200, 150, 0))
 
-    def test_state(self):
+    def test_configure_state(self):
         widget = self.create()
         self.checkEnumParam(widget, 'state', 'disabled', 'normal',
                 errmsg='bad state value "{}": must be normal or disabled')
 
-    def test_xscrollincrement(self):
+    def test_configure_xscrollincrement(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'xscrollincrement',
                               40, 0, 41.2, 43.6, -40, '0.5i')
 
-    def test_yscrollincrement(self):
+    def test_configure_yscrollincrement(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'yscrollincrement',
                               10, 0, 11.2, 13.6, -10, '0.1i')
@@ -796,26 +795,26 @@ class ListboxTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Listbox(self.root, **kwargs)
 
-    def test_activestyle(self):
+    def test_configure_activestyle(self):
         widget = self.create()
         self.checkEnumParam(widget, 'activestyle',
                             'dotbox', 'none', 'underline')
 
-    test_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_justify)
+    test_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_configure_justify)
 
-    def test_listvariable(self):
+    def test_configure_listvariable(self):
         widget = self.create()
         var = tkinter.DoubleVar(self.root)
         self.checkVariableParam(widget, 'listvariable', var)
 
-    def test_selectmode(self):
+    def test_configure_selectmode(self):
         widget = self.create()
         self.checkParam(widget, 'selectmode', 'single')
         self.checkParam(widget, 'selectmode', 'browse')
         self.checkParam(widget, 'selectmode', 'multiple')
         self.checkParam(widget, 'selectmode', 'extended')
 
-    def test_state(self):
+    def test_configure_state(self):
         widget = self.create()
         self.checkEnumParam(widget, 'state', 'disabled', 'normal')
 
@@ -930,53 +929,53 @@ class ScaleTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Scale(self.root, **kwargs)
 
-    def test_bigincrement(self):
+    def test_configure_bigincrement(self):
         widget = self.create()
         self.checkFloatParam(widget, 'bigincrement', 12.4, 23.6, -5)
 
-    def test_digits(self):
+    def test_configure_digits(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'digits', 5, 0)
 
-    def test_from(self):
+    def test_configure_from(self):
         widget = self.create()
         conv = False if get_tk_patchlevel() >= (8, 6, 10) else float_round
         self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv)
 
-    def test_label(self):
+    def test_configure_label(self):
         widget = self.create()
         self.checkParam(widget, 'label', 'any string')
         self.checkParam(widget, 'label', '')
 
-    def test_length(self):
+    def test_configure_length(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i')
 
-    def test_resolution(self):
+    def test_configure_resolution(self):
         widget = self.create()
         self.checkFloatParam(widget, 'resolution', 4.2, 0, 6.7, -2)
 
-    def test_showvalue(self):
+    def test_configure_showvalue(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'showvalue')
 
-    def test_sliderlength(self):
+    def test_configure_sliderlength(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'sliderlength',
                               10, 11.2, 15.6, -3, '3m')
 
-    def test_sliderrelief(self):
+    def test_configure_sliderrelief(self):
         widget = self.create()
         self.checkReliefParam(widget, 'sliderrelief')
 
-    def test_tickinterval(self):
+    def test_configure_tickinterval(self):
         widget = self.create()
         self.checkFloatParam(widget, 'tickinterval', 1, 4.3, 7.6, 0,
                              conv=float_round)
         self.checkParam(widget, 'tickinterval', -2, expected=2,
                         conv=float_round)
 
-    def test_to(self):
+    def test_configure_to(self):
         widget = self.create()
         self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10,
                              conv=float_round)
@@ -1000,15 +999,15 @@ class ScrollbarTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Scrollbar(self.root, **kwargs)
 
-    def test_activerelief(self):
+    def test_configure_activerelief(self):
         widget = self.create()
         self.checkReliefParam(widget, 'activerelief')
 
-    def test_elementborderwidth(self):
+    def test_configure_elementborderwidth(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'elementborderwidth', 4.3, 5.6, -2, '1m')
 
-    def test_orient(self):
+    def test_configure_orient(self):
         widget = self.create()
         self.checkEnumParam(widget, 'orient', 'vertical', 'horizontal',
                 errmsg='bad orientation "{}": must be vertical or horizontal')
@@ -1049,63 +1048,63 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.PanedWindow(self.root, **kwargs)
 
-    def test_handlepad(self):
+    def test_configure_handlepad(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'handlepad', 5, 6.4, 7.6, -3, '1m')
 
-    def test_handlesize(self):
+    def test_configure_handlesize(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'handlesize', 8, 9.4, 10.6, -3, '2m',
                               conv=noconv)
 
-    def test_height(self):
+    def test_configure_height(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i',
                               conv=noconv)
 
-    def test_opaqueresize(self):
+    def test_configure_opaqueresize(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'opaqueresize')
 
     @requires_tcl(8, 6, 5)
-    def test_proxybackground(self):
+    def test_configure_proxybackground(self):
         widget = self.create()
         self.checkColorParam(widget, 'proxybackground')
 
     @requires_tcl(8, 6, 5)
-    def test_proxyborderwidth(self):
+    def test_configure_proxyborderwidth(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'proxyborderwidth',
                               0, 1.3, 2.9, 6, -2, '10p',
                               conv=noconv)
 
     @requires_tcl(8, 6, 5)
-    def test_proxyrelief(self):
+    def test_configure_proxyrelief(self):
         widget = self.create()
         self.checkReliefParam(widget, 'proxyrelief')
 
-    def test_sashcursor(self):
+    def test_configure_sashcursor(self):
         widget = self.create()
         self.checkCursorParam(widget, 'sashcursor')
 
-    def test_sashpad(self):
+    def test_configure_sashpad(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'sashpad', 8, 1.3, 2.6, -2, '2m')
 
-    def test_sashrelief(self):
+    def test_configure_sashrelief(self):
         widget = self.create()
         self.checkReliefParam(widget, 'sashrelief')
 
-    def test_sashwidth(self):
+    def test_configure_sashwidth(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'sashwidth', 10, 11.1, 15.6, -3, '1m',
                               conv=noconv)
 
-    def test_showhandle(self):
+    def test_configure_showhandle(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'showhandle')
 
-    def test_width(self):
+    def test_configure_width(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i',
                               conv=noconv)
@@ -1224,23 +1223,23 @@ class MenuTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Menu(self.root, **kwargs)
 
-    def test_postcommand(self):
+    def test_configure_postcommand(self):
         widget = self.create()
         self.checkCommandParam(widget, 'postcommand')
 
-    def test_tearoff(self):
+    def test_configure_tearoff(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'tearoff')
 
-    def test_tearoffcommand(self):
+    def test_configure_tearoffcommand(self):
         widget = self.create()
         self.checkCommandParam(widget, 'tearoffcommand')
 
-    def test_title(self):
+    def test_configure_title(self):
         widget = self.create()
         self.checkParam(widget, 'title', 'any string')
 
-    def test_type(self):
+    def test_configure_type(self):
         widget = self.create()
         self.checkEnumParam(widget, 'type',
                 'normal', 'tearoff', 'menubar')
@@ -1293,17 +1292,26 @@ class MessageTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return tkinter.Message(self.root, **kwargs)
 
-    def test_aspect(self):
+    def test_configure_aspect(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'aspect', 250, 0, -300)
 
 
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+    def test_frame(self):
+        self._test_widget(tkinter.Frame)
+
+    def test_label(self):
+        self._test_widget(tkinter.Label)
+
+
 tests_gui = (
         ButtonTest, CanvasTest, CheckbuttonTest, EntryTest,
         FrameTest, LabelFrameTest,LabelTest, ListboxTest,
         MenubuttonTest, MenuTest, MessageTest, OptionMenuTest,
         PanedWindowTest, RadiobuttonTest, ScaleTest, ScrollbarTest,
-        SpinboxTest, TextTest, ToplevelTest,
+        SpinboxTest, TextTest, ToplevelTest, DefaultRootTest,
 )
 
 if __name__ == '__main__':
index 6937ba1ca9be41e19e02da4a3fc8509fe150031d..1a70e0befe6234b519989849b18620dbec19df6e 100644 (file)
@@ -2,8 +2,8 @@ import sys
 import unittest
 import tkinter
 from tkinter import ttk
-from test.support import requires, run_unittest, swap_attr
-from tkinter.test.support import AbstractTkTest, destroy_default_root
+from test.support import requires, run_unittest
+from tkinter.test.support import AbstractTkTest, AbstractDefaultRootTest
 
 requires('gui')
 
@@ -46,20 +46,6 @@ class LabeledScaleTest(AbstractTkTest, unittest.TestCase):
         if hasattr(sys, 'last_type'):
             self.assertNotEqual(sys.last_type, tkinter.TclError)
 
-
-    def test_initialization_no_master(self):
-        # no master passing
-        with swap_attr(tkinter, '_default_root', None), \
-             swap_attr(tkinter, '_support_default_root', True):
-            try:
-                x = ttk.LabeledScale()
-                self.assertIsNotNone(tkinter._default_root)
-                self.assertEqual(x.master, tkinter._default_root)
-                self.assertEqual(x.tk, tkinter._default_root.tk)
-                x.destroy()
-            finally:
-                destroy_default_root()
-
     def test_initialization(self):
         # master passing
         master = tkinter.Frame(self.root)
@@ -311,7 +297,13 @@ class OptionMenuTest(AbstractTkTest, unittest.TestCase):
         optmenu2.destroy()
 
 
-tests_gui = (LabeledScaleTest, OptionMenuTest)
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+    def test_labeledscale(self):
+        self._test_widget(ttk.LabeledScale)
+
+
+tests_gui = (LabeledScaleTest, OptionMenuTest, DefaultRootTest)
 
 if __name__ == "__main__":
     run_unittest(*tests_gui)
index 157ef0e8f87bb5c32a19c38f65ff08f46b829726..1fac83a004a6d0e441c289dcec070120237bb5dd 100644 (file)
@@ -6,7 +6,7 @@ import sys
 
 from tkinter.test.test_ttk.test_functions import MockTclObj
 from tkinter.test.support import (AbstractTkTest, tcl_version, get_tk_patchlevel,
-                                  simulate_mouse_click)
+                                  simulate_mouse_click, AbstractDefaultRootTest)
 from tkinter.test.widget_tests import (add_standard_options, noconv,
     AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests,
     setUpModule)
@@ -16,7 +16,7 @@ requires('gui')
 
 class StandardTtkOptionsTests(StandardOptionsTests):
 
-    def test_class(self):
+    def test_configure_class(self):
         widget = self.create()
         self.assertEqual(widget['class'], '')
         errmsg='attempt to change read-only option'
@@ -26,7 +26,7 @@ class StandardTtkOptionsTests(StandardOptionsTests):
         widget2 = self.create(class_='Foo')
         self.assertEqual(widget2['class'], 'Foo')
 
-    def test_padding(self):
+    def test_configure_padding(self):
         widget = self.create()
         self.checkParam(widget, 'padding', 0, expected=('0',))
         self.checkParam(widget, 'padding', 5, expected=('5',))
@@ -38,7 +38,7 @@ class StandardTtkOptionsTests(StandardOptionsTests):
         self.checkParam(widget, 'padding', ('5p', '6p', '7p', '8p'))
         self.checkParam(widget, 'padding', (), expected='')
 
-    def test_style(self):
+    def test_configure_style(self):
         widget = self.create()
         self.assertEqual(widget['style'], '')
         errmsg = 'Layout Foo not found'
@@ -139,14 +139,14 @@ class LabelFrameTest(AbstractToplevelTest, unittest.TestCase):
     def create(self, **kwargs):
         return ttk.LabelFrame(self.root, **kwargs)
 
-    def test_labelanchor(self):
+    def test_configure_labelanchor(self):
         widget = self.create()
         self.checkEnumParam(widget, 'labelanchor',
                 'e', 'en', 'es', 'n', 'ne', 'nw', 's', 'se', 'sw', 'w', 'wn', 'ws',
                 errmsg='Bad label anchor specification {}')
         self.checkInvalidParam(widget, 'labelanchor', 'center')
 
-    def test_labelwidget(self):
+    def test_configure_labelwidget(self):
         widget = self.create()
         label = ttk.Label(self.root, text='Mupp', name='foo')
         self.checkParam(widget, 'labelwidget', label, expected='.foo')
@@ -168,17 +168,17 @@ class AbstractLabelTest(AbstractWidgetTest):
         self.checkInvalidParam(widget, name, 'spam',
                 errmsg='image "spam" doesn\'t exist')
 
-    def test_compound(self):
+    def test_configure_compound(self):
         widget = self.create()
         self.checkEnumParam(widget, 'compound',
                 'none', 'text', 'image', 'center',
                 'top', 'bottom', 'left', 'right')
 
-    def test_state(self):
+    def test_configure_state(self):
         widget = self.create()
         self.checkParams(widget, 'state', 'active', 'disabled', 'normal')
 
-    def test_width(self):
+    def test_configure_width(self):
         widget = self.create()
         self.checkParams(widget, 'width', 402, -402, 0)
 
@@ -197,7 +197,7 @@ class LabelTest(AbstractLabelTest, unittest.TestCase):
     def create(self, **kwargs):
         return ttk.Label(self.root, **kwargs)
 
-    def test_font(self):
+    def test_configure_font(self):
         widget = self.create()
         self.checkParam(widget, 'font',
                         '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*')
@@ -215,7 +215,7 @@ class ButtonTest(AbstractLabelTest, unittest.TestCase):
     def create(self, **kwargs):
         return ttk.Button(self.root, **kwargs)
 
-    def test_default(self):
+    def test_configure_default(self):
         widget = self.create()
         self.checkEnumParam(widget, 'default', 'normal', 'active', 'disabled')
 
@@ -240,11 +240,11 @@ class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):
     def create(self, **kwargs):
         return ttk.Checkbutton(self.root, **kwargs)
 
-    def test_offvalue(self):
+    def test_configure_offvalue(self):
         widget = self.create()
         self.checkParams(widget, 'offvalue', 1, 2.3, '', 'any string')
 
-    def test_onvalue(self):
+    def test_configure_onvalue(self):
         widget = self.create()
         self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string')
 
@@ -292,27 +292,27 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return ttk.Entry(self.root, **kwargs)
 
-    def test_invalidcommand(self):
+    def test_configure_invalidcommand(self):
         widget = self.create()
         self.checkCommandParam(widget, 'invalidcommand')
 
-    def test_show(self):
+    def test_configure_show(self):
         widget = self.create()
         self.checkParam(widget, 'show', '*')
         self.checkParam(widget, 'show', '')
         self.checkParam(widget, 'show', ' ')
 
-    def test_state(self):
+    def test_configure_state(self):
         widget = self.create()
         self.checkParams(widget, 'state',
                          'disabled', 'normal', 'readonly')
 
-    def test_validate(self):
+    def test_configure_validate(self):
         widget = self.create()
         self.checkEnumParam(widget, 'validate',
                 'all', 'key', 'focus', 'focusin', 'focusout', 'none')
 
-    def test_validatecommand(self):
+    def test_configure_validatecommand(self):
         widget = self.create()
         self.checkCommandParam(widget, 'validatecommand')
 
@@ -429,7 +429,7 @@ class ComboboxTest(EntryTest, unittest.TestCase):
     def create(self, **kwargs):
         return ttk.Combobox(self.root, **kwargs)
 
-    def test_height(self):
+    def test_configure_height(self):
         widget = self.create()
         self.checkParams(widget, 'height', 100, 101.2, 102.6, -100, 0, '1i')
 
@@ -459,7 +459,7 @@ class ComboboxTest(EntryTest, unittest.TestCase):
         self.assertTrue(success)
 
 
-    def test_postcommand(self):
+    def test_configure_postcommand(self):
         success = []
 
         self.combo['postcommand'] = lambda: success.append(True)
@@ -475,7 +475,7 @@ class ComboboxTest(EntryTest, unittest.TestCase):
         self.assertEqual(len(success), 1)
 
 
-    def test_values(self):
+    def test_configure_values(self):
         def check_get_current(getval, currval):
             self.assertEqual(self.combo.get(), getval)
             self.assertEqual(self.combo.current(), currval)
@@ -551,7 +551,7 @@ class PanedWindowTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return ttk.PanedWindow(self.root, **kwargs)
 
-    def test_orient(self):
+    def test_configure_orient(self):
         widget = self.create()
         self.assertEqual(str(widget['orient']), 'vertical')
         errmsg='attempt to change read-only option'
@@ -684,11 +684,11 @@ class RadiobuttonTest(AbstractLabelTest, unittest.TestCase):
     def create(self, **kwargs):
         return ttk.Radiobutton(self.root, **kwargs)
 
-    def test_value(self):
+    def test_configure_value(self):
         widget = self.create()
         self.checkParams(widget, 'value', 1, 2.3, '', 'any string')
 
-    def test_invoke(self):
+    def test_configure_invoke(self):
         success = []
         def cb_test():
             success.append(1)
@@ -739,7 +739,7 @@ class MenubuttonTest(AbstractLabelTest, unittest.TestCase):
         self.checkEnumParam(widget, 'direction',
                 'above', 'below', 'left', 'right', 'flush')
 
-    def test_menu(self):
+    def test_configure_menu(self):
         widget = self.create()
         menu = tkinter.Menu(widget, name='menu')
         self.checkParam(widget, 'menu', menu, conv=str)
@@ -764,19 +764,19 @@ class ScaleTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return ttk.Scale(self.root, **kwargs)
 
-    def test_from(self):
+    def test_configure_from(self):
         widget = self.create()
         self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=False)
 
-    def test_length(self):
+    def test_configure_length(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'length', 130, 131.2, 135.6, '5i')
 
-    def test_to(self):
+    def test_configure_to(self):
         widget = self.create()
         self.checkFloatParam(widget, 'to', 300, 14.9, 15.1, -10, conv=False)
 
-    def test_value(self):
+    def test_configure_value(self):
         widget = self.create()
         self.checkFloatParam(widget, 'value', 300, 14.9, 15.1, -10, conv=False)
 
@@ -866,23 +866,23 @@ class ProgressbarTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return ttk.Progressbar(self.root, **kwargs)
 
-    def test_length(self):
+    def test_configure_length(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'length', 100.1, 56.7, '2i')
 
-    def test_maximum(self):
+    def test_configure_maximum(self):
         widget = self.create()
         self.checkFloatParam(widget, 'maximum', 150.2, 77.7, 0, -10, conv=False)
 
-    def test_mode(self):
+    def test_configure_mode(self):
         widget = self.create()
         self.checkEnumParam(widget, 'mode', 'determinate', 'indeterminate')
 
-    def test_phase(self):
+    def test_configure_phase(self):
         # XXX
         pass
 
-    def test_value(self):
+    def test_configure_value(self):
         widget = self.create()
         self.checkFloatParam(widget, 'value', 150.2, 77.7, 0, -10,
                              conv=False)
@@ -1071,7 +1071,7 @@ class NotebookTest(AbstractWidgetTest, unittest.TestCase):
         self.assertEqual(self.nb.tab(self.child1, 'text'), 'abc')
 
 
-    def test_tabs(self):
+    def test_configure_tabs(self):
         self.assertEqual(len(self.nb.tabs()), 2)
 
         self.nb.forget(self.child1)
@@ -1147,7 +1147,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
         self.spin.event_generate('<ButtonRelease-1>', x=x, y=y)
         self.spin.update_idletasks()
 
-    def test_command(self):
+    def test_configure_command(self):
         success = []
 
         self.spin['command'] = lambda: success.append(True)
@@ -1167,7 +1167,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
         self.spin.update()
         self.assertEqual(len(success), 2)
 
-    def test_to(self):
+    def test_configure_to(self):
         self.spin['from'] = 0
         self.spin['to'] = 5
         self.spin.set(4)
@@ -1179,7 +1179,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
         self._click_increment_arrow()  # 5
         self.assertEqual(self.spin.get(), '5')
 
-    def test_from(self):
+    def test_configure_from(self):
         self.spin['from'] = 1
         self.spin['to'] = 10
         self.spin.set(2)
@@ -1189,7 +1189,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
         self._click_decrement_arrow()  # 1
         self.assertEqual(self.spin.get(), '1')
 
-    def test_increment(self):
+    def test_configure_increment(self):
         self.spin['from'] = 0
         self.spin['to'] = 10
         self.spin['increment'] = 4
@@ -1203,7 +1203,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
         self._click_decrement_arrow()  # 3
         self.assertEqual(self.spin.get(), '3')
 
-    def test_format(self):
+    def test_configure_format(self):
         self.spin.set(1)
         self.spin['format'] = '%10.3f'
         self.spin.update()
@@ -1220,7 +1220,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
         self.assertTrue('.' not in value)
         self.assertEqual(len(value), 1)
 
-    def test_wrap(self):
+    def test_configure_wrap(self):
         self.spin['to'] = 10
         self.spin['from'] = 1
         self.spin.set(1)
@@ -1239,7 +1239,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
         self._click_decrement_arrow()
         self.assertEqual(self.spin.get(), '1')
 
-    def test_values(self):
+    def test_configure_values(self):
         self.assertEqual(self.spin['values'],
                          () if tcl_version < (8, 5) else '')
         self.checkParam(self.spin, 'values', 'mon tue wed thur',
@@ -1299,14 +1299,14 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return ttk.Treeview(self.root, **kwargs)
 
-    def test_columns(self):
+    def test_configure_columns(self):
         widget = self.create()
         self.checkParam(widget, 'columns', 'a b c',
                         expected=('a', 'b', 'c'))
         self.checkParam(widget, 'columns', ('a', 'b', 'c'))
         self.checkParam(widget, 'columns', '')
 
-    def test_displaycolumns(self):
+    def test_configure_displaycolumns(self):
         widget = self.create()
         widget['columns'] = ('a', 'b', 'c')
         self.checkParam(widget, 'displaycolumns', 'b a c',
@@ -1322,17 +1322,17 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
         self.checkInvalidParam(widget, 'displaycolumns', (1, -2),
                                errmsg='Column index -2 out of bounds')
 
-    def test_height(self):
+    def test_configure_height(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'height', 100, -100, 0, '3c', conv=False)
         self.checkPixelsParam(widget, 'height', 101.2, 102.6, conv=noconv)
 
-    def test_selectmode(self):
+    def test_configure_selectmode(self):
         widget = self.create()
         self.checkEnumParam(widget, 'selectmode',
                             'none', 'browse', 'extended')
 
-    def test_show(self):
+    def test_configure_show(self):
         widget = self.create()
         self.checkParam(widget, 'show', 'tree headings',
                         expected=('tree', 'headings'))
@@ -1860,12 +1860,22 @@ class SizegripTest(AbstractWidgetTest, unittest.TestCase):
     def create(self, **kwargs):
         return ttk.Sizegrip(self.root, **kwargs)
 
+
+class DefaultRootTest(AbstractDefaultRootTest, unittest.TestCase):
+
+    def test_frame(self):
+        self._test_widget(ttk.Frame)
+
+    def test_label(self):
+        self._test_widget(ttk.Label)
+
+
 tests_gui = (
         ButtonTest, CheckbuttonTest, ComboboxTest, EntryTest,
         FrameTest, LabelFrameTest, LabelTest, MenubuttonTest,
         NotebookTest, PanedWindowTest, ProgressbarTest,
         RadiobuttonTest, ScaleTest, ScrollbarTest, SeparatorTest,
-        SizegripTest, SpinboxTest, TreeviewTest, WidgetTest,
+        SizegripTest, SpinboxTest, TreeviewTest, WidgetTest, DefaultRootTest,
         )
 
 if __name__ == "__main__":
index b42ff52178f29e7c585febcb916871dcc1b7574d..9702ff453002e9dcfecdc4308e8e44b06970602b 100644 (file)
@@ -1,7 +1,6 @@
 # Common tests for test_tkinter/test_widgets.py and test_ttk/test_widgets.py
 
 import unittest
-import sys
 import tkinter
 from tkinter.test.support import (AbstractTkTest, tcl_version, requires_tcl,
                                   get_tk_patchlevel, pixels_conv, tcl_obj_eq)
@@ -243,31 +242,31 @@ class StandardOptionsTests:
         'underline', 'wraplength', 'xscrollcommand', 'yscrollcommand',
     )
 
-    def test_activebackground(self):
+    def test_configure_activebackground(self):
         widget = self.create()
         self.checkColorParam(widget, 'activebackground')
 
-    def test_activeborderwidth(self):
+    def test_configure_activeborderwidth(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'activeborderwidth',
                               0, 1.3, 2.9, 6, -2, '10p')
 
-    def test_activeforeground(self):
+    def test_configure_activeforeground(self):
         widget = self.create()
         self.checkColorParam(widget, 'activeforeground')
 
-    def test_anchor(self):
+    def test_configure_anchor(self):
         widget = self.create()
         self.checkEnumParam(widget, 'anchor',
                 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'center')
 
-    def test_background(self):
+    def test_configure_background(self):
         widget = self.create()
         self.checkColorParam(widget, 'background')
         if 'bg' in self.OPTIONS:
             self.checkColorParam(widget, 'bg')
 
-    def test_bitmap(self):
+    def test_configure_bitmap(self):
         widget = self.create()
         self.checkParam(widget, 'bitmap', 'questhead')
         self.checkParam(widget, 'bitmap', 'gray50')
@@ -280,90 +279,88 @@ class StandardOptionsTests:
             self.checkInvalidParam(widget, 'bitmap', 'spam',
                     errmsg='bitmap "spam" not defined')
 
-    def test_borderwidth(self):
+    def test_configure_borderwidth(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'borderwidth',
                               0, 1.3, 2.6, 6, -2, '10p')
         if 'bd' in self.OPTIONS:
             self.checkPixelsParam(widget, 'bd', 0, 1.3, 2.6, 6, -2, '10p')
 
-    def test_compound(self):
+    def test_configure_compound(self):
         widget = self.create()
         self.checkEnumParam(widget, 'compound',
                 'bottom', 'center', 'left', 'none', 'right', 'top')
 
-    def test_cursor(self):
+    def test_configure_cursor(self):
         widget = self.create()
         self.checkCursorParam(widget, 'cursor')
 
-    def test_disabledforeground(self):
+    def test_configure_disabledforeground(self):
         widget = self.create()
         self.checkColorParam(widget, 'disabledforeground')
 
-    def test_exportselection(self):
+    def test_configure_exportselection(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'exportselection')
 
-    def test_font(self):
+    def test_configure_font(self):
         widget = self.create()
         self.checkParam(widget, 'font',
                         '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*')
         self.checkInvalidParam(widget, 'font', '',
                                errmsg='font "" doesn\'t exist')
 
-    def test_foreground(self):
+    def test_configure_foreground(self):
         widget = self.create()
         self.checkColorParam(widget, 'foreground')
         if 'fg' in self.OPTIONS:
             self.checkColorParam(widget, 'fg')
 
-    def test_highlightbackground(self):
+    def test_configure_highlightbackground(self):
         widget = self.create()
         self.checkColorParam(widget, 'highlightbackground')
 
-    def test_highlightcolor(self):
+    def test_configure_highlightcolor(self):
         widget = self.create()
         self.checkColorParam(widget, 'highlightcolor')
 
-    def test_highlightthickness(self):
+    def test_configure_highlightthickness(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'highlightthickness',
                               0, 1.3, 2.6, 6, '10p')
         self.checkParam(widget, 'highlightthickness', -2, expected=0,
                         conv=self._conv_pixels)
 
-    @unittest.skipIf(sys.platform == 'darwin',
-                     'crashes with Cocoa Tk (issue19733)')
-    def test_image(self):
+    def test_configure_image(self):
         widget = self.create()
         self.checkImageParam(widget, 'image')
 
-    def test_insertbackground(self):
+    def test_configure_insertbackground(self):
         widget = self.create()
         self.checkColorParam(widget, 'insertbackground')
 
-    def test_insertborderwidth(self):
+    def test_configure_insertborderwidth(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'insertborderwidth',
                               0, 1.3, 2.6, 6, -2, '10p')
 
-    def test_insertofftime(self):
+    def test_configure_insertofftime(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'insertofftime', 100)
 
-    def test_insertontime(self):
+    def test_configure_insertontime(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'insertontime', 100)
 
-    def test_insertwidth(self):
+    def test_configure_insertwidth(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'insertwidth', 1.3, 2.6, -2, '10p')
 
-    def test_jump(self):
+    def test_configure_jump(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'jump')
 
-    def test_justify(self):
+    def test_configure_justify(self):
         widget = self.create()
         self.checkEnumParam(widget, 'justify', 'left', 'right', 'center',
                 errmsg='bad justification "{}": must be '
@@ -372,154 +369,155 @@ class StandardOptionsTests:
                 errmsg='ambiguous justification "": must be '
                        'left, right, or center')
 
-    def test_orient(self):
+    def test_configure_orient(self):
         widget = self.create()
         self.assertEqual(str(widget['orient']), self.default_orient)
         self.checkEnumParam(widget, 'orient', 'horizontal', 'vertical')
 
-    def test_padx(self):
+    def test_configure_padx(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'padx', 3, 4.4, 5.6, -2, '12m',
                               conv=self._conv_pad_pixels)
 
-    def test_pady(self):
+    def test_configure_pady(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'pady', 3, 4.4, 5.6, -2, '12m',
                               conv=self._conv_pad_pixels)
 
-    def test_relief(self):
+    def test_configure_relief(self):
         widget = self.create()
         self.checkReliefParam(widget, 'relief')
 
-    def test_repeatdelay(self):
+    def test_configure_repeatdelay(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'repeatdelay', -500, 500)
 
-    def test_repeatinterval(self):
+    def test_configure_repeatinterval(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'repeatinterval', -500, 500)
 
-    def test_selectbackground(self):
+    def test_configure_selectbackground(self):
         widget = self.create()
         self.checkColorParam(widget, 'selectbackground')
 
-    def test_selectborderwidth(self):
+    def test_configure_selectborderwidth(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'selectborderwidth', 1.3, 2.6, -2, '10p')
 
-    def test_selectforeground(self):
+    def test_configure_selectforeground(self):
         widget = self.create()
         self.checkColorParam(widget, 'selectforeground')
 
-    def test_setgrid(self):
+    def test_configure_setgrid(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'setgrid')
 
-    def test_state(self):
+    def test_configure_state(self):
         widget = self.create()
         self.checkEnumParam(widget, 'state', 'active', 'disabled', 'normal')
 
-    def test_takefocus(self):
+    def test_configure_takefocus(self):
         widget = self.create()
         self.checkParams(widget, 'takefocus', '0', '1', '')
 
-    def test_text(self):
+    def test_configure_text(self):
         widget = self.create()
         self.checkParams(widget, 'text', '', 'any string')
 
-    def test_textvariable(self):
+    def test_configure_textvariable(self):
         widget = self.create()
         var = tkinter.StringVar(self.root)
         self.checkVariableParam(widget, 'textvariable', var)
 
-    def test_troughcolor(self):
+    def test_configure_troughcolor(self):
         widget = self.create()
         self.checkColorParam(widget, 'troughcolor')
 
-    def test_underline(self):
+    def test_configure_underline(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'underline', 0, 1, 10)
 
-    def test_wraplength(self):
+    def test_configure_wraplength(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'wraplength', 100)
 
-    def test_xscrollcommand(self):
+    def test_configure_xscrollcommand(self):
         widget = self.create()
         self.checkCommandParam(widget, 'xscrollcommand')
 
-    def test_yscrollcommand(self):
+    def test_configure_yscrollcommand(self):
         widget = self.create()
         self.checkCommandParam(widget, 'yscrollcommand')
 
     # non-standard but common options
 
-    def test_command(self):
+    def test_configure_command(self):
         widget = self.create()
         self.checkCommandParam(widget, 'command')
 
-    def test_indicatoron(self):
+    def test_configure_indicatoron(self):
         widget = self.create()
         self.checkBooleanParam(widget, 'indicatoron')
 
-    def test_offrelief(self):
+    def test_configure_offrelief(self):
         widget = self.create()
         self.checkReliefParam(widget, 'offrelief')
 
-    def test_overrelief(self):
+    def test_configure_overrelief(self):
         widget = self.create()
         self.checkReliefParam(widget, 'overrelief')
 
-    def test_selectcolor(self):
+    def test_configure_selectcolor(self):
         widget = self.create()
         self.checkColorParam(widget, 'selectcolor')
 
-    def test_selectimage(self):
+    def test_configure_selectimage(self):
         widget = self.create()
         self.checkImageParam(widget, 'selectimage')
 
     @requires_tcl(8, 5)
-    def test_tristateimage(self):
+    def test_configure_tristateimage(self):
         widget = self.create()
         self.checkImageParam(widget, 'tristateimage')
 
     @requires_tcl(8, 5)
-    def test_tristatevalue(self):
+    def test_configure_tristatevalue(self):
         widget = self.create()
         self.checkParam(widget, 'tristatevalue', 'unknowable')
 
-    def test_variable(self):
+    def test_configure_variable(self):
         widget = self.create()
         var = tkinter.DoubleVar(self.root)
         self.checkVariableParam(widget, 'variable', var)
 
 
 class IntegerSizeTests:
-    def test_height(self):
+    def test_configure_height(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'height', 100, -100, 0)
 
-    def test_width(self):
+    def test_configure_width(self):
         widget = self.create()
         self.checkIntegerParam(widget, 'width', 402, -402, 0)
 
 
 class PixelSizeTests:
-    def test_height(self):
+    def test_configure_height(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'height', 100, 101.2, 102.6, -100, 0, '3c')
 
-    def test_width(self):
+    def test_configure_width(self):
         widget = self.create()
         self.checkPixelsParam(widget, 'width', 402, 403.4, 404.6, -402, 0, '5i')
 
 
 def add_standard_options(*source_classes):
-    # This decorator adds test_xxx methods from source classes for every xxx
-    # option in the OPTIONS class attribute if they are not defined explicitly.
+    # This decorator adds test_configure_xxx methods from source classes for
+    # every xxx option in the OPTIONS class attribute if they are not defined
+    # explicitly.
     def decorator(cls):
         for option in cls.OPTIONS:
-            methodname = 'test_' + option
+            methodname = 'test_configure_' + option
             if not hasattr(cls, methodname):
                 for source_class in source_classes:
                     if hasattr(source_class, methodname):
index ac545502e45c30b22395de366f2f18e0f8f614b5..ef1e7406bc1ae0c333c53604dd6d1aeea8360c16 100644 (file)
@@ -387,9 +387,7 @@ class TixWidget(tkinter.Widget):
     # These are missing from Tkinter
     def image_create(self, imgtype, cnf={}, master=None, **kw):
         if not master:
-            master = tkinter._default_root
-            if not master:
-                raise RuntimeError('Too early to create image')
+            master = self
         if kw and cnf: cnf = _cnfmerge((cnf, kw))
         elif kw: cnf = kw
         options = ()
@@ -475,10 +473,7 @@ class DisplayStyle:
             elif 'refwindow' in cnf:
                 master = cnf['refwindow']
             else:
-                master = tkinter._default_root
-                if not master:
-                    raise RuntimeError("Too early to create display style: "
-                                       "no root window")
+                master = tkinter._get_default_root('create display style')
         self.tk = master.tk
         self.stylename = self.tk.call('tixDisplayStyle', itemtype,
                             *self._options(cnf,kw) )
index 968fd54dce1ee0070015aa0ea72bee2614a74110..ab7aeb15e8ff222e3b99bc56badba70ea0f17098 100644 (file)
@@ -349,12 +349,7 @@ def setup_master(master=None):
     If it is not allowed to use the default root and master is None,
     RuntimeError is raised."""
     if master is None:
-        if tkinter._support_default_root:
-            master = tkinter._default_root or tkinter.Tk()
-        else:
-            raise RuntimeError(
-                    "No master specified and tkinter is "
-                    "configured to not support default root")
+        master = tkinter._get_default_root()
     return master
 
 
@@ -1538,7 +1533,10 @@ class LabeledScale(Frame):
         scale_side = 'bottom' if self._label_top else 'top'
         label_side = 'top' if scale_side == 'bottom' else 'bottom'
         self.scale.pack(side=scale_side, fill='x')
-        tmp = Label(self).pack(side=label_side) # place holder
+        # Dummy required to make frame correct height
+        dummy = Label(self)
+        dummy.pack(side=label_side)
+        dummy.lower()
         self.label.place(anchor='n' if label_side == 'top' else 's')
 
         # update the label as scale or variable changes
index fb34de948930076f5ad571298e92e2c622ca4c32..d7fbdae680be6242b7e7b8874d2671bc0f7945c2 100644 (file)
@@ -515,7 +515,8 @@ class TracebackException:
         if exc_type and issubclass(exc_type, SyntaxError):
             # Handle SyntaxError's specially
             self.filename = exc_value.filename
-            self.lineno = str(exc_value.lineno)
+            lno = exc_value.lineno
+            self.lineno = str(lno) if lno is not None else None
             self.text = exc_value.text
             self.offset = exc_value.offset
             self.msg = exc_value.msg
@@ -574,9 +575,12 @@ class TracebackException:
     def _format_syntax_error(self, stype):
         """Format SyntaxError exceptions (internal helper)."""
         # Show exactly where the problem was found.
-        filename = self.filename or "<string>"
-        lineno = str(self.lineno) or '?'
-        yield '  File "{}", line {}\n'.format(filename, lineno)
+        filename_suffix = ''
+        if self.lineno is not None:
+            yield '  File "{}", line {}\n'.format(
+                self.filename or "<string>", self.lineno)
+        elif self.filename is not None:
+            filename_suffix = ' ({})'.format(self.filename)
 
         text = self.text
         if text is not None:
@@ -594,7 +598,7 @@ class TracebackException:
                 caretspace = ((c if c.isspace() else ' ') for c in ltext[:caret])
                 yield '    {}^\n'.format(''.join(caretspace))
         msg = self.msg or "<no detail available>"
-        yield "{}: {}\n".format(stype, msg)
+        yield "{}: {}{}\n".format(stype, msg, filename_suffix)
 
     def format(self, *, chain=True):
         """Format the exception.
index 69b4170ec82462ff6e0289991324e62e3be91708..cec99c59700fe05e457f3668d2b947cc6bfef9c6 100644 (file)
@@ -226,7 +226,7 @@ class Traceback(Sequence):
         return str(self[0])
 
     def __repr__(self):
-        s = "<Traceback %r" % tuple(self)
+        s = f"<Traceback {tuple(self)}"
         if self._total_nframe is None:
             s += ">"
         else:
index f5316ab8a5f5384c44bba476078b2e4f0e335afc..3556b8adb8190566f4bdc4cc2b515ae753ebf76e 100644 (file)
@@ -118,6 +118,15 @@ __all__ = [
 # legitimate imports of those modules.
 
 
+def _type_convert(arg):
+    """For converting None to type(None), and strings to ForwardRef."""
+    if arg is None:
+        return type(None)
+    if isinstance(arg, str):
+        return ForwardRef(arg)
+    return arg
+
+
 def _type_check(arg, msg, is_argument=True):
     """Check that the argument is a type, and return it (internal helper).
 
@@ -134,10 +143,7 @@ def _type_check(arg, msg, is_argument=True):
     if is_argument:
         invalid_generic_forms = invalid_generic_forms + (ClassVar, Final)
 
-    if arg is None:
-        return type(None)
-    if isinstance(arg, str):
-        return ForwardRef(arg)
+    arg = _type_convert(arg)
     if (isinstance(arg, _GenericAlias) and
             arg.__origin__ in invalid_generic_forms):
         raise TypeError(f"{arg} is not valid as type argument")
@@ -859,13 +865,13 @@ class _CallableType(_SpecialGenericAlias, _root=True):
             raise TypeError("Callable must be used as "
                             "Callable[[arg, ...], result].")
         args, result = params
-        if args is Ellipsis:
-            params = (Ellipsis, result)
-        else:
-            if not isinstance(args, list):
-                raise TypeError(f"Callable[args, result]: args must be a list."
-                                f" Got {args}")
+        # This relaxes what args can be on purpose to allow things like
+        # PEP 612 ParamSpec.  Responsibility for whether a user is using
+        # Callable[...] properly is deferred to static type checkers.
+        if isinstance(args, list):
             params = (tuple(args), result)
+        else:
+            params = (args, result)
         return self.__getitem_inner__(params)
 
     @_tp_cache
@@ -875,8 +881,9 @@ class _CallableType(_SpecialGenericAlias, _root=True):
         result = _type_check(result, msg)
         if args is Ellipsis:
             return self.copy_with((_TypingEllipsis, result))
-        msg = "Callable[[arg, ...], result]: each arg must be a type."
-        args = tuple(_type_check(arg, msg) for arg in args)
+        if not isinstance(args, tuple):
+            args = (args,)
+        args = tuple(_type_convert(arg) for arg in args)
         params = args + (result,)
         return self.copy_with(params)
 
@@ -1500,13 +1507,11 @@ def get_args(tp):
     """
     if isinstance(tp, _AnnotatedAlias):
         return (tp.__origin__,) + tp.__metadata__
-    if isinstance(tp, _GenericAlias):
+    if isinstance(tp, (_GenericAlias, GenericAlias)):
         res = tp.__args__
         if tp.__origin__ is collections.abc.Callable and res[0] is not Ellipsis:
             res = (list(res[:-1]), res[-1])
         return res
-    if isinstance(tp, GenericAlias):
-        return tp.__args__
     return ()
 
 
@@ -1980,14 +1985,14 @@ def TypedDict(typename, fields=None, /, *, total=True, **kwargs):
         raise TypeError("TypedDict takes either a dict or keyword arguments,"
                         " but not both")
 
-    ns = {'__annotations__': dict(fields), '__total__': total}
+    ns = {'__annotations__': dict(fields)}
     try:
         # Setting correct module is necessary to make typed dict classes pickleable.
         ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__')
     except (AttributeError, ValueError):
         pass
 
-    return _TypedDictMeta(typename, (), ns)
+    return _TypedDictMeta(typename, (), ns, total=total)
 
 _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {})
 TypedDict.__mro_entries__ = lambda bases: (_TypedDict,)
index 1bc1312c8c2ee9cba2491d66a44b157a37c3ab9e..520213c37275555f29d37bf361202fb72d1af4ec 100644 (file)
@@ -102,9 +102,9 @@ class IsolatedAsyncioTestCase(TestCase):
                 ret = await awaitable
                 if not fut.cancelled():
                     fut.set_result(ret)
-            except asyncio.CancelledError:
+            except (SystemExit, KeyboardInterrupt):
                 raise
-            except Exception as ex:
+            except (BaseException, asyncio.CancelledError) as ex:
                 if not fut.cancelled():
                     fut.set_exception(ex)
 
index b495a5f6ccc017eed3859be17843acbd7c857fca..f03c88baca671baefd01b56c25c62ba1c8dbf83b 100644 (file)
@@ -406,7 +406,7 @@ class NonCallableMock(Base):
             # Check if spec is an async object or function
             bound_args = _MOCK_SIG.bind_partial(cls, *args, **kw).arguments
             spec_arg = bound_args.get('spec_set', bound_args.get('spec'))
-            if spec_arg and _is_async_obj(spec_arg):
+            if spec_arg is not None and _is_async_obj(spec_arg):
                 bases = (AsyncMockMixin, cls)
         new = type(cls.__name__, bases, {'__doc__': cls.__doc__})
         instance = _safe_super(NonCallableMock, cls).__new__(new)
index 2db441da202a0183d91381bb7c15eb9c345c6cad..d01864b6936ca8d2ec5d47e2c2b6bd7fb1ab092f 100644 (file)
@@ -190,6 +190,33 @@ class TestAsyncCase(unittest.TestCase):
                                   'async_cleanup 2',
                                   'sync_cleanup 1'])
 
+    def test_base_exception_from_async_method(self):
+        events = []
+        class Test(unittest.IsolatedAsyncioTestCase):
+            async def test_base(self):
+                events.append("test_base")
+                raise BaseException()
+                events.append("not it")
+
+            async def test_no_err(self):
+                events.append("test_no_err")
+
+            async def test_cancel(self):
+                raise asyncio.CancelledError()
+
+        test = Test("test_base")
+        output = test.run()
+        self.assertFalse(output.wasSuccessful())
+
+        test = Test("test_no_err")
+        test.run()
+        self.assertEqual(events, ['test_base', 'test_no_err'])
+
+        test = Test("test_cancel")
+        output = test.run()
+        self.assertFalse(output.wasSuccessful())
+
+
 
 if __name__ == "__main__":
     unittest.main()
index ce674e713e99cd5a2ab7ae18c7fcf83ae9efd3b7..f9307245307b9b23cf1098db01da6c44ceeca1ba 100644 (file)
@@ -2156,6 +2156,16 @@ class MockTest(unittest.TestCase):
                 obj = mock(spec=Something)
                 self.assertIsInstance(obj, Something)
 
+    def test_bool_not_called_when_passing_spec_arg(self):
+        class Something:
+            def __init__(self):
+                self.obj_with_bool_func = unittest.mock.MagicMock()
+
+        obj = Something()
+        with unittest.mock.patch.object(obj, 'obj_with_bool_func', autospec=True): pass
+
+        self.assertEqual(obj.obj_with_bool_func.__bool__.call_count, 0)
+
 
 if __name__ == '__main__':
     unittest.main()
index ea897c3032257b290724c21c2e4c20542175b42c..335e183498d8bd5ea1c29142b54c60c36c31c09a 100644 (file)
@@ -662,7 +662,7 @@ def unquote(string, encoding='utf-8', errors='replace'):
 
 
 def parse_qs(qs, keep_blank_values=False, strict_parsing=False,
-             encoding='utf-8', errors='replace', max_num_fields=None):
+             encoding='utf-8', errors='replace', max_num_fields=None, separator='&'):
     """Parse a query given as a string argument.
 
         Arguments:
@@ -686,12 +686,15 @@ def parse_qs(qs, keep_blank_values=False, strict_parsing=False,
         max_num_fields: int. If set, then throws a ValueError if there
             are more than n fields read by parse_qsl().
 
+        separator: str. The symbol to use for separating the query arguments.
+            Defaults to &.
+
         Returns a dictionary.
     """
     parsed_result = {}
     pairs = parse_qsl(qs, keep_blank_values, strict_parsing,
                       encoding=encoding, errors=errors,
-                      max_num_fields=max_num_fields)
+                      max_num_fields=max_num_fields, separator=separator)
     for name, value in pairs:
         if name in parsed_result:
             parsed_result[name].append(value)
@@ -701,7 +704,7 @@ def parse_qs(qs, keep_blank_values=False, strict_parsing=False,
 
 
 def parse_qsl(qs, keep_blank_values=False, strict_parsing=False,
-              encoding='utf-8', errors='replace', max_num_fields=None):
+              encoding='utf-8', errors='replace', max_num_fields=None, separator='&'):
     """Parse a query given as a string argument.
 
         Arguments:
@@ -724,19 +727,25 @@ def parse_qsl(qs, keep_blank_values=False, strict_parsing=False,
         max_num_fields: int. If set, then throws a ValueError
             if there are more than n fields read by parse_qsl().
 
+        separator: str. The symbol to use for separating the query arguments.
+            Defaults to &.
+
         Returns a list, as G-d intended.
     """
     qs, _coerce_result = _coerce_args(qs)
 
+    if not separator or (not isinstance(separator, (str, bytes))):
+        raise ValueError("Separator must be of type string or bytes.")
+
     # If max_num_fields is defined then check that the number of fields
     # is less than max_num_fields. This prevents a memory exhaustion DOS
     # attack via post bodies with many fields.
     if max_num_fields is not None:
-        num_fields = 1 + qs.count('&') + qs.count(';')
+        num_fields = 1 + qs.count(separator)
         if max_num_fields < num_fields:
             raise ValueError('Max number of fields exceeded')
 
-    pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
+    pairs = [s1 for s1 in qs.split(separator)]
     r = []
     for name_value in pairs:
         if not name_value and not strict_parsing:
index a8c870b9778eba34b1c5b1d7524252a7ee5e8d8c..57d991465a5b0c128a9e885fac389ea3576e4d67 100644 (file)
@@ -771,7 +771,11 @@ def _parse_proxy(proxy):
             raise ValueError("proxy URL with no authority: %r" % proxy)
         # We have an authority, so for RFC 3986-compliant URLs (by ss 3.
         # and 3.3.), path is empty or starts with '/'
-        end = r_scheme.find("/", 2)
+        if '@' in r_scheme:
+            host_separator = r_scheme.find('@')
+            end = r_scheme.find("/", host_separator)
+        else:
+            end = r_scheme.find("/", 2)
         if end == -1:
             end = None
         authority = r_scheme[2:end]
index 16816d1cf86a44724949d83c1a8059d9a11341f4..ef64502ab780c790cbc34cdfaec40b5d20512921 100755 (executable)
@@ -242,15 +242,12 @@ def library_recipes():
 
     result.extend([
           dict(
-              name="OpenSSL 1.1.1g",
-              url="https://www.openssl.org/source/openssl-1.1.1g.tar.gz",
-              checksum='76766e98997660138cdaf13a187bd234',
+              name="OpenSSL 1.1.1i",
+              url="https://www.openssl.org/source/openssl-1.1.1i.tar.gz",
+              checksum='08987c3cf125202e2b0840035efb392c',
               buildrecipe=build_universal_openssl,
               configure=None,
               install=None,
-              patches=[
-                  "openssl-mac-arm64.patch",
-                   ],
           ),
     ])
 
@@ -263,10 +260,10 @@ def library_recipes():
             tk_patches = ['tk868_on_10_8_10_9.patch']
 
         else:
-            tcl_tk_ver='8.6.10'
-            tcl_checksum='97c55573f8520bcab74e21bfd8d0aadc'
+            tcl_tk_ver='8.6.11'
+            tcl_checksum='8a4c004f48984a03a7747e9ba06e4da4'
 
-            tk_checksum='602a47ad9ecac7bf655ada729d140a94'
+            tk_checksum='c7ee71a2d05bba78dfffd76528dc17c6'
             tk_patches = [ ]
 
 
@@ -357,9 +354,9 @@ def library_recipes():
                   ),
           ),
           dict(
-              name="SQLite 3.33.0",
-              url="https://sqlite.org/2020/sqlite-autoconf-3330000.tar.gz",
-              checksum='842a8a100d7b01b09e543deb2b7951dd',
+              name="SQLite 3.34.0",
+              url="https://sqlite.org/2020/sqlite-autoconf-3340000.tar.gz",
+              checksum='7f33c9db7b713957fcb9271fe9049fef',
               extra_cflags=('-Os '
                             '-DSQLITE_ENABLE_FTS5 '
                             '-DSQLITE_ENABLE_FTS4 '
@@ -1138,7 +1135,6 @@ def buildPythonDocs():
     if not os.path.exists(htmlDir):
         # Create virtual environment for docs builds with blurb and sphinx
         runCommand('make venv')
-        runCommand('venv/bin/python3 -m pip install -U Sphinx==2.3.1')
         runCommand('make html PYTHON=venv/bin/python')
     os.rename(htmlDir, docdir)
     os.chdir(curDir)
@@ -1615,7 +1611,7 @@ def buildDMG():
     if os.path.exists(outdir):
         shutil.rmtree(outdir)
 
-    # We used to use the deployment target as the last characters of the 
+    # We used to use the deployment target as the last characters of the
     # installer file name. With the introduction of weaklinked installer
     # variants, we may have two variants with the same file name, i.e.
     # both ending in '10.9'.  To avoid this, we now use the major/minor
diff --git a/Mac/BuildScript/openssl-mac-arm64.patch b/Mac/BuildScript/openssl-mac-arm64.patch
deleted file mode 100644 (file)
index 11267fb..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-diff -ur openssl-1.1.1g-orig/Configurations/10-main.conf openssl-1.1.1g/Configurations/10-main.conf
---- openssl-1.1.1g-orig/Configurations/10-main.conf    2020-04-21 14:22:39.000000000 +0200
-+++ openssl-1.1.1g/Configurations/10-main.conf 2020-07-26 12:21:32.000000000 +0200
-@@ -1557,6 +1557,14 @@
-         bn_ops           => "SIXTY_FOUR_BIT_LONG",
-         perlasm_scheme   => "macosx",
-     },
-+    "darwin64-arm64-cc" => {
-+        inherit_from     => [ "darwin-common", asm("aarch64_asm") ],
-+        CFLAGS           => add("-Wall"),
-+        cflags           => add("-arch arm64"),
-+        lib_cppflags     => add("-DL_ENDIAN"),
-+        bn_ops           => "SIXTY_FOUR_BIT_LONG",
-+        perlasm_scheme   => "ios64",
-+    },
- ##### GNU Hurd
-     "hurd-x86" => {
-diff -ur openssl-1.1.1g-orig/config openssl-1.1.1g/config
---- openssl-1.1.1g-orig/config 2020-04-21 14:22:39.000000000 +0200
-+++ openssl-1.1.1g/config      2020-07-26 12:21:59.000000000 +0200
-@@ -255,6 +255,9 @@
-               ;;
-           x86_64)
-               echo "x86_64-apple-darwin${VERSION}"
-+                ;;
-+          arm64)
-+              echo "arm64-apple-darwin${VERSION}"
-               ;;
-           *)
-               echo "i686-apple-darwin${VERSION}"
-@@ -497,6 +500,9 @@
-       else
-           OUT="darwin64-x86_64-cc"
-       fi ;;
-+  x86_64-apple-darwin*)
-+      OUT="darwin64-arm64-cc"
-+        ;;
-   armv6+7-*-iphoneos)
-       __CNF_CFLAGS="$__CNF_CFLAGS -arch armv6 -arch armv7"
-       __CNF_CXXFLAGS="$__CNF_CXXFLAGS -arch armv6 -arch armv7"
index 0a62e327f51b389aa0c27fdd96291bbe1fd14f24..68b8e4bb044e1008d53ad067524e0955abdb188b 100755 (executable)
@@ -20,7 +20,7 @@ fi
 # Make sure the directory ${PYTHON_ROOT}/bin is on the users PATH.
 BSH="`basename "${theShell}"`"
 case "${BSH}" in
-bash|ksh|sh|*csh|zsh)
+bash|ksh|sh|*csh|zsh|fish)
        if [ `id -ur` = 0 ]; then
                P=`su - ${USER} -c 'echo A-X-4-X@@$PATH@@X-4-X-A' | grep 'A-X-4-X@@.*@@X-4-X-A' | sed -e 's/^A-X-4-X@@//g' -e 's/@@X-4-X-A$//g'`
        else
@@ -76,6 +76,22 @@ bash)
                PR="${HOME}/.bash_profile"
        fi
        ;;
+fish)
+       CONFIG_DIR="${HOME}/.config/fish"
+       RC="${CONFIG_DIR}/config.fish"
+       mkdir -p "$CONFIG_DIR"
+       if [ -f "${RC}" ]; then
+               cp -fp "${RC}" "${RC}.pysave"
+       fi
+       echo "" >> "${RC}"
+       echo "# Setting PATH for Python ${PYVER}" >> "${RC}"
+       echo "# The original version is saved in ${RC}.pysave" >> "${RC}"
+       echo "set -x PATH \"${PYTHON_ROOT}/bin\" \"\$PATH\"" >> "${RC}"
+       if [ `id -ur` = 0 ]; then
+               chown "${USER}" "${RC}"
+       fi
+       exit 0
+       ;;
 zsh)
         PR="${HOME}/.zprofile"
         ;;
index dcc48abdd2a395aa7605170c0b3cf71c18af8635..f6b5cfe8d5451f7a7e2d60b8ee1706908494dc0c 100644 (file)
@@ -36,7 +36,7 @@
        <key>CFBundleExecutable</key>
        <string>IDLE</string>
        <key>CFBundleGetInfoString</key>
-       <string>%version%, © 2001-2020 Python Software Foundation</string>
+       <string>%version%, © 2001-2021 Python Software Foundation</string>
        <key>CFBundleIconFile</key>
        <string>IDLE.icns</string>
        <key>CFBundleIdentifier</key>
index 21a051535fb92523a37a2cc92ebc52e79f28eb20..3d8bc3e4154ee28a3636d5b77c34c026b3a42476 100644 (file)
@@ -40,7 +40,7 @@
        <key>CFBundleExecutable</key>
        <string>Python Launcher</string>
        <key>CFBundleGetInfoString</key>
-       <string>%VERSION%, © 2001-2020 Python Software Foundation</string>
+       <string>%VERSION%, © 2001-2021 Python Software Foundation</string>
        <key>CFBundleIconFile</key>
        <string>PythonLauncher.icns</string>
        <key>CFBundleIdentifier</key>
index 1d624984a852038c4b40051ef4a7de83d608fe00..2c801332332b30fa2906a0de0cff5f9cb18e55a3 100644 (file)
@@ -37,7 +37,7 @@
        <key>CFBundleInfoDictionaryVersion</key>
        <string>6.0</string>
        <key>CFBundleLongVersionString</key>
-       <string>%version%, (c) 2001-2020 Python Software Foundation.</string>
+       <string>%version%, (c) 2001-2021 Python Software Foundation.</string>
        <key>CFBundleName</key>
        <string>Python</string>
        <key>CFBundlePackageType</key>
index 12a5ac1410a7700252cd32c2c91b9f6908234465..73d35c2d86bdc01d1b110360ae536906ba6aeffe 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -192,6 +192,7 @@ Gawain Bolton
 Carl Friedrich Bolz-Tereick
 Forest Bond
 Gregory Bond
+Angelin Booz
 Médéric Boquien
 Matias Bordese
 Jonas Borgström
@@ -1443,6 +1444,7 @@ Mark Roddy
 Kevin Rodgers
 Sean Rodman
 Giampaolo Rodola
+Dustin Rodrigues
 Mauro S. M. Rodrigues
 Elson Rodriguez
 Adi Roiban
@@ -1640,6 +1642,7 @@ Quentin Stafford-Fraser
 Frank Stajano
 Joel Stanley
 Kyle Stanley
+Brandon Stansbury
 Anthony Starks
 David Steele
 Oliver Steele
@@ -1828,6 +1831,7 @@ Zachary Ware
 Barry Warsaw
 Steve Waterbury
 Bob Watson
+Colin Watson
 David Watson
 Aaron Watters
 Henrik Weber
index 03c84f31c569a682c7b7083ef8c8979dfc0a5f6e..c438e3f8e906702ef4134b28362c545458795c82 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -2,6 +2,318 @@
 Python News
 +++++++++++
 
+What's New in Python 3.9.2 final?
+=================================
+
+*Release date: 2021-02-19*
+
+Windows
+-------
+
+- bpo-43155: :c:func:`PyCMethod_New` is now present in ``python3.lib``.
+
+
+What's New in Python 3.9.2 release candidate 1?
+===============================================
+
+*Release date: 2021-02-16*
+
+Security
+--------
+
+- bpo-42967: Fix web cache poisoning vulnerability by defaulting the query
+  args separator to ``&``, and allowing the user to choose a custom
+  separator.
+
+- bpo-42938: Avoid static buffers when computing the repr of
+  :class:`ctypes.c_double` and :class:`ctypes.c_longdouble` values.
+
+Core and Builtins
+-----------------
+
+- bpo-42819: :mod:`readline`: Explicitly disable bracketed paste in the
+  interactive interpreter, even if it's set in the inputrc, is enabled by
+  default (eg GNU Readline 8.1), or a user calls
+  ``readline.read_init_file()``. The Python REPL has not implemented
+  bracketed paste support. Also, bracketed mode writes the ``"\x1b[?2004h"``
+  escape sequence into stdout which causes test failures in applications
+  that don't support it. It can still be explicitly enabled by calling
+  ``readline.parse_and_bind("set enable-bracketed-paste on")``. Patch by
+  Dustin Rodrigues.
+
+- bpo-42806: Fix the column offsets for f-strings :mod:`ast` nodes
+  surrounded by parentheses and for nodes that spawn multiple lines. Patch
+  by Pablo Galindo.
+
+- bpo-40631: Fix regression where a single parenthesized starred expression
+  was a valid assignment target.
+
+- bpo-32381: Fix encoding name when running a ``.pyc`` file on Windows:
+  :c:func:`PyRun_SimpleFileExFlags()` now uses the correct encoding to
+  decode the filename.
+
+- bpo-42536: Several built-in and standard library types now ensure that
+  their internal result tuples are always tracked by the :term:`garbage
+  collector <garbage collection>`:
+
+  - :meth:`collections.OrderedDict.items() <collections.OrderedDict>`
+
+  - :meth:`dict.items`
+
+  - :func:`enumerate`
+
+  - :func:`functools.reduce`
+
+  - :func:`itertools.combinations`
+
+  - :func:`itertools.combinations_with_replacement`
+
+  - :func:`itertools.permutations`
+
+  - :func:`itertools.product`
+
+  - :func:`itertools.zip_longest`
+
+  - :func:`zip`
+
+  Previously, they could have become untracked by a prior garbage
+  collection. Patch by Brandt Bucher.
+
+- bpo-42195: The ``__args__`` of the parameterized generics for
+  :data:`typing.Callable` and :class:`collections.abc.Callable` are now
+  consistent.  The ``__args__`` for :class:`collections.abc.Callable` are
+  now flattened while :data:`typing.Callable`'s have not changed.  To allow
+  this change, :class:`types.GenericAlias` can now be subclassed and
+  ``collections.abc.Callable``'s ``__class_getitem__`` will now return a
+  subclass of ``types.GenericAlias``.  Tests for typing were also updated to
+  not subclass things like ``Callable[..., T]`` as that is not a valid base
+  class.  Finally, both types no longer validate their ``argtypes``, in
+  ``Callable[[argtypes], resulttype]`` to prepare for :pep:`612`.  Patch by
+  Ken Jin.
+
+Library
+-------
+
+- bpo-43102: The namedtuple __new__ method had its __builtins__ set to None
+  instead of an actual dictionary.  This created problems for introspection
+  tools.
+
+- bpo-43108: Fixed a reference leak in the :mod:`curses` module. Patch by
+  Pablo Galindo
+
+- bpo-42944: Fix ``random.Random.sample`` when ``counts`` argument is not
+  ``None``.
+
+- bpo-42931: Add :func:`randbytes` to ``random.__all__``.
+
+- bpo-42780: Fix os.set_inheritable() for O_PATH file descriptors on Linux.
+
+- bpo-42851: remove __init_subclass__ support for Enum members
+
+- bpo-41748: Fix HTMLParser parsing rules for element attributes containing
+  commas with spaces. Patch by Karl Dubost.
+
+- bpo-42759: Fixed equality comparison of :class:`tkinter.Variable` and
+  :class:`tkinter.font.Font`. Objects which belong to different Tcl
+  interpreters are now always different, even if they have the same name.
+
+- bpo-42756: Configure LMTP Unix-domain socket to use socket global default
+  timeout when a timeout is not explicitly provided.
+
+- bpo-23328: Allow / character in username, password fields on _PROXY
+  envars.
+
+- bpo-42655: :mod:`subprocess` *extra_groups* is now correctly passed into
+  setgroups() system call.
+
+- bpo-42727: ``EnumMeta.__prepare__`` now accepts ``**kwds`` to properly
+  support ``__init_subclass__``
+
+- bpo-42681: Fixed range checks for color and pair numbers in :mod:`curses`.
+
+- bpo-37961: Fix crash in :func:`tracemalloc.Traceback.__repr__` (regressed
+  in Python 3.9).
+
+- bpo-42630: :mod:`tkinter` functions and constructors which need a default
+  root window raise now :exc:`RuntimeError` with descriptive message instead
+  of obscure :exc:`AttributeError` or :exc:`NameError` if it is not created
+  yet or cannot be created automatically.
+
+- bpo-42644: `logging.disable` will now validate the types and value of its
+  parameter. It also now accepts strings representing the levels (as does
+  `loging.setLevel`) instead of only the numerical values.
+
+- bpo-36541: Fixed lib2to3.pgen2 to be able to parse PEP-570 positional only
+  argument syntax.
+
+- bpo-42517: Enum: private names will raise a DeprecationWarning; in 3.10
+  they will become normal attributes
+
+- bpo-42678: `Enum`: call `__init_subclass__` after members have been added
+
+- bpo-42532: Remove unexpected call of ``__bool__`` when passing a
+  ``spec_arg`` argument to a Mock.
+
+- bpo-42388: Fix subprocess.check_output(..., input=None) behavior when
+  text=True to be consistent with that of the documentation and
+  universal_newlines=True.
+
+- bpo-34463: Fixed discrepancy between :mod:`traceback` and the interpreter
+  in formatting of SyntaxError with lineno not set (:mod:`traceback` was
+  changed to match interpreter).
+
+- bpo-42375: subprocess module update for DragonFlyBSD support.
+
+- bpo-42384: Make pdb populate sys.path[0] exactly the same as regular
+  python execution.
+
+- bpo-42383: Fix pdb: previously pdb would fail to restart the debugging
+  target if it was specified using a relative path and the current directory
+  changed.
+
+- bpo-42318: Fixed support of non-BMP characters in :mod:`tkinter` on macOS.
+
+- bpo-42163: Restore compatibility for ``uname_result`` around deepcopy and
+  _replace.
+
+- bpo-39825: Windows: Change ``sysconfig.get_config_var('EXT_SUFFIX')`` to
+  the expected full ``platform_tag.extension`` format. Previously it was
+  hard-coded to ``.pyd``, now it is compatible with ``distutils.sysconfig``
+  and will result in something like ``.cp38-win_amd64.pyd``. This brings
+  windows into conformance with the other platforms.
+
+- bpo-42059: :class:`typing.TypedDict` types created using the alternative
+  call-style syntax now correctly respect the ``total`` keyword argument
+  when setting their ``__required_keys__`` and ``__optional_keys__`` class
+  attributes.
+
+- bpo-39101: Fixed tests using IsolatedAsyncioTestCase from hanging on
+  BaseExceptions.
+
+- bpo-42005: Fix CLI of :mod:`cProfile` and :mod:`profile` to catch
+  :exc:`BrokenPipeError`.
+
+- bpo-41907: fix `format()` behavior for `IntFlag`
+
+- bpo-41889: Enum: fix regression involving inheriting a multiply-inherited
+  enum
+
+- bpo-41891: Ensure asyncio.wait_for waits for task completion
+
+- bpo-41604: Don't decrement the reference count of the previous user_ptr
+  when set_panel_userptr fails.
+
+- bpo-40219: Lowered :class:`tkinter.ttk.LabeledScale` dummy widget to
+  prevent hiding part of the content label.
+
+- bpo-40084: Fix ``Enum.__dir__``: dir(Enum.member) now includes attributes
+  as well as methods.
+
+- bpo-39068: Fix initialization race condition in :func:`a85encode` and
+  :func:`b85encode` in :mod:`base64`. Patch by Brandon Stansbury.
+
+- bpo-33289: Correct call to :mod:`tkinter.colorchooser` to return RGB
+  triplet of ints instead of floats.  Patch by Cheryl Sabella.
+
+Documentation
+-------------
+
+- bpo-40304: Fix doc for type(name, bases, dict).  Patch by Boris
+  Verkhovskiy and Éric Araujo.
+
+- bpo-42811: Updated importlib.utils.resolve_name() doc to use
+  __spec__.parent instead of __package__. (Thanks Yair Frid.)
+
+- bpo-17140: Add documentation for the
+  :class:`multiprocessing.pool.ThreadPool` class.
+
+Tests
+-----
+
+- bpo-42794: Update test_nntplib to use offical group name of news.aioe.org
+  for testing. Patch by Dong-hee Na.
+
+- bpo-40810: In :mod:`sqlite3`, fix ``CheckTraceCallbackContent`` for SQLite
+  pre 3.7.15.
+
+Build
+-----
+
+- bpo-43174: Windows build now uses ``/utf-8`` compiler option.
+
+- bpo-42692: Fix __builtin_available check on older compilers. Patch by
+  Joshua Root.
+
+- bpo-42604: Now all platforms use a value for the "EXT_SUFFIX" build
+  variable derived from SOABI (for instance in freeBSD, "EXT_SUFFIX" is now
+  ".cpython-310d.so" instead of ".so"). Previosuly only Linux, Mac and
+  VxWorks were using a value for "EXT_SUFFIX" that included "SOABI".
+
+- bpo-42598: Fix implicit function declarations in configure which could
+  have resulted in incorrect configuration checks.  Patch contributed by
+  Joshua Root.
+
+- bpo-29076: Add fish shell support to macOS installer.
+
+Windows
+-------
+
+- bpo-41837: Updated Windows installer to include OpenSSL 1.1.1i
+
+- bpo-42584: Upgrade Windows installer to use SQLite 3.34.0.
+
+macOS
+-----
+
+- bpo-42504: Ensure that the value of
+  sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') is always a string,
+  even in when the value is parsable as an integer.
+
+- bpo-42361: Update macOS installer build to use Tcl/Tk 8.6.11 (rc2,
+  expected to be final release).
+
+- bpo-41837: Update macOS installer build to use OpenSSL 1.1.1i.
+
+- bpo-42584: Update macOS installer to use SQLite 3.34.0.
+
+IDLE
+----
+
+- bpo-43008: Make IDLE invoke :func:`sys.excepthook` in normal, 2-process
+  mode. Patch by Ken Hilton.
+
+- bpo-33065: Fix problem debugging user classes with __repr__ method.
+
+- bpo-23544: Disable Debug=>Stack Viewer when user code is running or
+  Debugger is active, to prevent hang or crash.  Patch by Zackery Spytz.
+
+- bpo-32631: Finish zzdummy example extension module: make menu entries
+  work; add docstrings and tests with 100% coverage.
+
+Tools/Demos
+-----------
+
+- bpo-42726: Fixed Python 3 compatibility issue with gdb/libpython.py
+  handling of attribute dictionaries.
+
+- bpo-42613: Fix ``freeze.py`` tool to use the prope config and library
+  directories. Patch by Victor Stinner.
+
+C API
+-----
+
+- bpo-43030: Fixed a compiler warning in :c:func:`Py_UNICODE_ISSPACE()` on
+  platforms with signed ``wchar_t``.
+
+- bpo-42591: Export the :c:func:`Py_FrozenMain` function: fix a Python 3.9.0
+  regression. Python 3.9 uses ``-fvisibility=hidden`` and the function was
+  not exported explicitly and so not exported.
+
+- bpo-40052: Fix an alignment build warning/error in function
+  ``PyVectorcall_Function()``. Patch by Andreas Schneider, Antoine Pitrou
+  and Petr Viktorin.
+
+
 What's New in Python 3.9.1 final?
 =================================
 
@@ -148,8 +460,6 @@ Core and Builtins
   rules that only generate better error messages to gain performance. If
   there's a parse failure, run the parser a second time with those enabled.
 
-- bpo-41910: Document the default implementation of `object.__eq__`.
-
 - bpo-42057: Fix peephole optimizer misoptimize conditional jump +
   JUMP_IF_NOT_EXC_MATCH pair.
 
@@ -265,7 +575,7 @@ Library
 - bpo-41316: Fix the :mod:`tarfile` module to write only basename of TAR
   file to GZIP compression header.
 
-- bpo-16936: Allow ``ctypes.wintypes`` to be imported on non-Windows
+- bpo-16396: Allow ``ctypes.wintypes`` to be imported on non-Windows
   systems.
 
 - bpo-40592: :func:`shutil.which` now ignores empty entries in
@@ -291,6 +601,8 @@ Documentation
 
 - bpo-42061: Document __format__ functionality for IP addresses.
 
+- bpo-41910: Document the default implementation of `object.__eq__`.
+
 - bpo-42010: Clarify that subscription expressions are also valid for
   certain :term:`classes <class>` and :term:`types <type>` in the standard
   library, and for user-defined classes and types if the classmethod
index b0a36a30248f741950da902902934277cb1f2412..f2506de54498e7b38f3e0ed00418ad25751c7a1b 100644 (file)
@@ -489,58 +489,47 @@ is_literal_char(unsigned char c)
 static PyObject *
 PyCArg_repr(PyCArgObject *self)
 {
-    char buffer[256];
     switch(self->tag) {
     case 'b':
     case 'B':
-        sprintf(buffer, "<cparam '%c' (%d)>",
+        return PyUnicode_FromFormat("<cparam '%c' (%d)>",
             self->tag, self->value.b);
-        break;
     case 'h':
     case 'H':
-        sprintf(buffer, "<cparam '%c' (%d)>",
+        return PyUnicode_FromFormat("<cparam '%c' (%d)>",
             self->tag, self->value.h);
-        break;
     case 'i':
     case 'I':
-        sprintf(buffer, "<cparam '%c' (%d)>",
+        return PyUnicode_FromFormat("<cparam '%c' (%d)>",
             self->tag, self->value.i);
-        break;
     case 'l':
     case 'L':
-        sprintf(buffer, "<cparam '%c' (%ld)>",
+        return PyUnicode_FromFormat("<cparam '%c' (%ld)>",
             self->tag, self->value.l);
-        break;
 
     case 'q':
     case 'Q':
-        sprintf(buffer,
-#ifdef MS_WIN32
-            "<cparam '%c' (%I64d)>",
-#else
-            "<cparam '%c' (%lld)>",
-#endif
+        return PyUnicode_FromFormat("<cparam '%c' (%lld)>",
             self->tag, self->value.q);
-        break;
     case 'd':
-        sprintf(buffer, "<cparam '%c' (%f)>",
-            self->tag, self->value.d);
-        break;
-    case 'f':
-        sprintf(buffer, "<cparam '%c' (%f)>",
-            self->tag, self->value.f);
-        break;
-
+    case 'f': {
+        PyObject *f = PyFloat_FromDouble((self->tag == 'f') ? self->value.f : self->value.d);
+        if (f == NULL) {
+            return NULL;
+        }
+        PyObject *result = PyUnicode_FromFormat("<cparam '%c' (%R)>", self->tag, f);
+        Py_DECREF(f);
+        return result;
+    }
     case 'c':
         if (is_literal_char((unsigned char)self->value.c)) {
-            sprintf(buffer, "<cparam '%c' ('%c')>",
+            return PyUnicode_FromFormat("<cparam '%c' ('%c')>",
                 self->tag, self->value.c);
         }
         else {
-            sprintf(buffer, "<cparam '%c' ('\\x%02x')>",
+            return PyUnicode_FromFormat("<cparam '%c' ('\\x%02x')>",
                 self->tag, (unsigned char)self->value.c);
         }
-        break;
 
 /* Hm, are these 'z' and 'Z' codes useful at all?
    Shouldn't they be replaced by the functionality of c_string
@@ -549,22 +538,20 @@ PyCArg_repr(PyCArgObject *self)
     case 'z':
     case 'Z':
     case 'P':
-        sprintf(buffer, "<cparam '%c' (%p)>",
+        return PyUnicode_FromFormat("<cparam '%c' (%p)>",
             self->tag, self->value.p);
         break;
 
     default:
         if (is_literal_char((unsigned char)self->tag)) {
-            sprintf(buffer, "<cparam '%c' at %p>",
+            return PyUnicode_FromFormat("<cparam '%c' at %p>",
                 (unsigned char)self->tag, (void *)self);
         }
         else {
-            sprintf(buffer, "<cparam 0x%02x at %p>",
+            return PyUnicode_FromFormat("<cparam 0x%02x at %p>",
                 (unsigned char)self->tag, (void *)self);
         }
-        break;
     }
-    return PyUnicode_FromString(buffer);
 }
 
 static PyMemberDef PyCArgType_members[] = {
index 4f220e42ff3fccb45f4c5c95acfcd2b0072312b2..788bae6a96c7f4a8558f8ef3f34c01c747e659fd 100644 (file)
@@ -91,11 +91,15 @@ static void more_core(void)
 /* put the item back into the free list */
 void Py_ffi_closure_free(void *p)
 {
-#if USING_APPLE_OS_LIBFFI && HAVE_FFI_CLOSURE_ALLOC
+#if HAVE_FFI_CLOSURE_ALLOC
+#if USING_APPLE_OS_LIBFFI
     if (__builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)) {
+#endif
         ffi_closure_free(p);
         return;
+#if USING_APPLE_OS_LIBFFI
     }
+#endif
 #endif
     ITEM *item = (ITEM *)p;
     item->next = free_list;
@@ -105,10 +109,14 @@ void Py_ffi_closure_free(void *p)
 /* return one item from the free list, allocating more if needed */
 void *Py_ffi_closure_alloc(size_t size, void** codeloc)
 {
-#if USING_APPLE_OS_LIBFFI && HAVE_FFI_CLOSURE_ALLOC
+#if HAVE_FFI_CLOSURE_ALLOC
+#if USING_APPLE_OS_LIBFFI
     if (__builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)) {
+#endif
         return ffi_closure_alloc(size, codeloc);
+#if USING_APPLE_OS_LIBFFI
     }
+#endif
 #endif
     ITEM *item;
     if (!free_list)
index f124803493d88b5eafb46572a199880125b4e903..4f026794e341774b177d5f0cf3bfdf3a233990b3 100644 (file)
@@ -440,7 +440,9 @@ _curses_panel_panel_set_userptr(PyCursesPanelObject *self, PyObject *obj)
         /* In case of an ncurses error, decref the new object again */
         Py_DECREF(obj);
     }
-    Py_XDECREF(oldobj);
+    else {
+        Py_XDECREF(oldobj);
+    }
     return PyCursesCheckERR(rc, "set_panel_userptr");
 }
 
index c70b0e2a19fadc440797a950dd8268fc3446901a..c84f8382274b5e4d12bc6902a2ae9e24f513fafd 100644 (file)
@@ -176,18 +176,6 @@ static char *screen_encoding = NULL;
 
 /* Utility Functions */
 
-static inline int
-color_pair_to_attr(short color_number)
-{
-    return ((int)color_number << 8);
-}
-
-static inline short
-attr_to_color_pair(int attr)
-{
-    return (short)((attr & A_COLOR) >> 8);
-}
-
 /*
  * Check the return code from a curses function and return None
  * or raise an exception as appropriate.  These are exported using the
@@ -377,6 +365,7 @@ PyCurses_ConvertToString(PyCursesWindowObject *win, PyObject *obj,
         *bytes = obj;
         /* check for embedded null bytes */
         if (PyBytes_AsStringAndSize(*bytes, &str, NULL) < 0) {
+            Py_DECREF(obj);
             return 0;
         }
         return 1;
@@ -618,7 +607,7 @@ _curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1,
     if (type == 2) {
         funcname = "add_wch";
         wstr[1] = L'\0';
-        setcchar(&wcval, wstr, attr, attr_to_color_pair(attr), NULL);
+        setcchar(&wcval, wstr, attr, PAIR_NUMBER(attr), NULL);
         if (coordinates_group)
             rtn = mvwadd_wch(self->win,y,x, &wcval);
         else {
@@ -691,8 +680,9 @@ _curses_window_addstr_impl(PyCursesWindowObject *self, int group_left_1,
 #else
     strtype = PyCurses_ConvertToString(self, str, &bytesobj, NULL);
 #endif
-    if (strtype == 0)
+    if (strtype == 0) {
         return NULL;
+    }
     if (use_attr) {
         attr_old = getattrs(self->win);
         (void)wattrset(self->win,attr);
@@ -2586,7 +2576,7 @@ NoArgOrFlagNoReturnFunctionBody(cbreak, flag)
 _curses.color_content
 
     color_number: short
-        The number of the color (0 - COLORS).
+        The number of the color (0 - (COLORS-1)).
     /
 
 Return the red, green, and blue (RGB) components of the specified color.
@@ -2597,27 +2587,32 @@ which will be between 0 (no component) and 1000 (maximum amount of component).
 
 static PyObject *
 _curses_color_content_impl(PyObject *module, short color_number)
-/*[clinic end generated code: output=cb15cf3120d4bfc1 input=5555abb1c11e11b7]*/
+/*[clinic end generated code: output=cb15cf3120d4bfc1 input=630f6737514db6ad]*/
 {
     short r,g,b;
 
     PyCursesInitialised;
     PyCursesInitialisedColor;
 
-    if (color_content(color_number, &r, &g, &b) != ERR)
-        return Py_BuildValue("(iii)", r, g, b);
-    else {
-        PyErr_SetString(PyCursesError,
-                        "Argument 1 was out of range. Check value of COLORS.");
+    if (color_content(color_number, &r, &g, &b) == ERR) {
+        if (color_number >= COLORS) {
+            PyErr_SetString(PyCursesError,
+                            "Argument 1 was out of range. Check value of COLORS.");
+        }
+        else {
+            PyErr_SetString(PyCursesError, "color_content() returned ERR");
+        }
         return NULL;
     }
+
+    return Py_BuildValue("(iii)", r, g, b);
 }
 
 /*[clinic input]
 _curses.color_pair
 
-    color_number: short
-        The number of the color (0 - COLORS).
+    pair_number: short
+        The number of the color pair.
     /
 
 Return the attribute value for displaying text in the specified color.
@@ -2627,13 +2622,13 @@ other A_* attributes.  pair_number() is the counterpart to this function.
 [clinic start generated code]*/
 
 static PyObject *
-_curses_color_pair_impl(PyObject *module, short color_number)
-/*[clinic end generated code: output=6a84cb6b29ecaf9a input=a9d3eb6f50e4dc12]*/
+_curses_color_pair_impl(PyObject *module, short pair_number)
+/*[clinic end generated code: output=ce609d238b70dc11 input=8dd0d5da94cb15b5]*/
 {
     PyCursesInitialised;
     PyCursesInitialisedColor;
 
-    return  PyLong_FromLong(color_pair_to_attr(color_number));
+    return  PyLong_FromLong(COLOR_PAIR(pair_number));
 }
 
 /*[clinic input]
@@ -3028,7 +3023,7 @@ _curses_has_key_impl(PyObject *module, int key)
 _curses.init_color
 
     color_number: short
-        The number of the color to be changed (0 - COLORS).
+        The number of the color to be changed (0 - (COLORS-1)).
     r: short
         Red component (0 - 1000).
     g: short
@@ -3041,13 +3036,13 @@ Change the definition of a color.
 
 When init_color() is used, all occurrences of that color on the screen
 immediately change to the new definition.  This function is a no-op on
-most terminals; it is active only if can_change_color() returns 1.
+most terminals; it is active only if can_change_color() returns true.
 [clinic start generated code]*/
 
 static PyObject *
 _curses_init_color_impl(PyObject *module, short color_number, short r,
                         short g, short b)
-/*[clinic end generated code: output=280236f5efe9776a input=f3a05bd38f619175]*/
+/*[clinic end generated code: output=280236f5efe9776a input=128601b5dc76d548]*/
 {
     PyCursesInitialised;
     PyCursesInitialisedColor;
@@ -3061,9 +3056,9 @@ _curses.init_pair
     pair_number: short
         The number of the color-pair to be changed (1 - (COLOR_PAIRS-1)).
     fg: short
-        Foreground color number (0 - COLORS).
+        Foreground color number (-1 - (COLORS-1)).
     bg: short
-        Background color number (0 - COLORS).
+        Background color number (-1 - (COLORS-1)).
     /
 
 Change the definition of a color-pair.
@@ -3075,7 +3070,7 @@ all occurrences of that color-pair are changed to the new definition.
 static PyObject *
 _curses_init_pair_impl(PyObject *module, short pair_number, short fg,
                        short bg)
-/*[clinic end generated code: output=9c2ce39c22f376b6 input=c9f0b11b17a2ac6d]*/
+/*[clinic end generated code: output=9c2ce39c22f376b6 input=12c320ec14396ea2]*/
 {
     PyCursesInitialised;
     PyCursesInitialisedColor;
@@ -3713,9 +3708,14 @@ _curses_pair_content_impl(PyObject *module, short pair_number)
     PyCursesInitialised;
     PyCursesInitialisedColor;
 
-    if (pair_content(pair_number, &f, &b)==ERR) {
-        PyErr_SetString(PyCursesError,
-                        "Argument 1 was out of range. (1..COLOR_PAIRS-1)");
+    if (pair_content(pair_number, &f, &b) == ERR) {
+        if (pair_number >= COLOR_PAIRS) {
+            PyErr_SetString(PyCursesError,
+                            "Argument 1 was out of range. (0..COLOR_PAIRS-1)");
+        }
+        else {
+            PyErr_SetString(PyCursesError, "pair_content() returned ERR");
+        }
         return NULL;
     }
 
@@ -3740,7 +3740,7 @@ _curses_pair_number_impl(PyObject *module, int attr)
     PyCursesInitialised;
     PyCursesInitialisedColor;
 
-    return PyLong_FromLong(attr_to_color_pair(attr));
+    return PyLong_FromLong(PAIR_NUMBER(attr));
 }
 
 /*[clinic input]
index d158d3bae157b2429629e4c09be2f9ec5c1135f3..42764a181d26ba07ba40d14bb1fa6b3b328a30d6 100644 (file)
@@ -1,4 +1,5 @@
 #include "Python.h"
+#include "pycore_object.h"        // _PyObject_GC_TRACK
 #include "pycore_pystate.h"       // _PyThreadState_GET()
 #include "pycore_tupleobject.h"
 #include "structmember.h"         // PyMemberDef
@@ -673,6 +674,11 @@ functools_reduce(PyObject *self, PyObject *args)
             if ((result = PyObject_Call(func, args, NULL)) == NULL) {
                 goto Fail;
             }
+            // bpo-42536: The GC may have untracked this args tuple. Since we're
+            // recycling it, make sure it's tracked again:
+            if (!_PyObject_GC_IS_TRACKED(args)) {
+                _PyObject_GC_TRACK(args);
+            }
         }
     }
 
index 5356417dd7037f4e6ffbe89878d128c027abf015..d64e0a1cfa06d6176d465fc0c91d1e389b47437d 100644 (file)
@@ -46,7 +46,7 @@
 # endif
 #endif
 
-#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__))
+#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__DragonFly__)
 # define FD_DIR "/dev/fd"
 #else
 # define FD_DIR "/proc/self/fd"
@@ -116,9 +116,9 @@ _pos_int_from_ascii(const char *name)
 }
 
 
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) || defined(__DragonFly__)
 /* When /dev/fd isn't mounted it is often a static directory populated
- * with 0 1 2 or entries for 0 .. 63 on FreeBSD, NetBSD and OpenBSD.
+ * with 0 1 2 or entries for 0 .. 63 on FreeBSD, NetBSD, OpenBSD and DragonFlyBSD.
  * NetBSD and OpenBSD have a /proc fs available (though not necessarily
  * mounted) and do not have fdescfs for /dev/fd.  MacOS X has a devfs
  * that properly supports /dev/fd.
@@ -377,7 +377,7 @@ _close_open_fds_maybe_unsafe(long start_fd, PyObject* py_fds_to_keep)
     ++start_fd;
 #endif
 
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) || defined(__DragonFly__)
     if (!_is_fdescfs_mounted_on_dev_fd())
         proc_fd_dir = NULL;
     else
@@ -753,7 +753,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
     if (groups_list != Py_None) {
 #ifdef HAVE_SETGROUPS
         Py_ssize_t i;
-        unsigned long gid;
+        gid_t gid;
 
         if (!PyList_Check(groups_list)) {
             PyErr_SetString(PyExc_TypeError,
@@ -787,10 +787,6 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
                 Py_DECREF(elem);
                 goto cleanup;
             } else {
-                /* In posixmodule.c UnsignedLong is used as a fallback value
-                * if the value provided does not fit in a Long. Since we are
-                * already doing the bounds checking on the Python side, we
-                * can go directly to an UnsignedLong here. */
                 if (!_Py_Gid_Converter(elem, &gid)) {
                     Py_DECREF(elem);
                     PyErr_SetString(PyExc_ValueError, "invalid group id");
index b80037347f13b5023d6f894e8fd2782062208d10..d20339ca3f7dfdce5aca06dd1d34cb570a1474cb 100644 (file)
@@ -1704,7 +1704,11 @@ pysqlite_connection_create_collation(pysqlite_Connection* self, PyObject* args)
                                   (callable != Py_None) ? callable : NULL,
                                   (callable != Py_None) ? pysqlite_collation_callback : NULL);
     if (rc != SQLITE_OK) {
-        PyDict_DelItem(self->collations, uppercase_name);
+        if (callable != Py_None) {
+            if (PyDict_DelItem(self->collations, uppercase_name) < 0) {
+                PyErr_Clear();
+            }
+        }
         _pysqlite_seterror(self->db, NULL);
         goto finally;
     }
index 5cfb4b97d61dfe3fb2aa8e35838b91b037c1a1d8..dd0ce7e1ea6a3368d3e892bcc1c437f4f6f741ca 100644 (file)
@@ -569,11 +569,13 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
         }
 
         if (!multiple) {
-            Py_DECREF(self->lastrowid);
             Py_BEGIN_ALLOW_THREADS
             lastrowid = sqlite3_last_insert_rowid(self->connection->db);
             Py_END_ALLOW_THREADS
-            self->lastrowid = PyLong_FromLongLong(lastrowid);
+            Py_SETREF(self->lastrowid, PyLong_FromLongLong(lastrowid));
+            if (self->lastrowid == NULL) {
+                goto error;
+            }
         }
 
         if (rc == SQLITE_ROW) {
@@ -802,8 +804,11 @@ PyObject* pysqlite_cursor_fetchmany(pysqlite_Cursor* self, PyObject* args, PyObj
     }
 
     while ((row = pysqlite_cursor_iternext(self))) {
-        PyList_Append(list, row);
-        Py_XDECREF(row);
+        if (PyList_Append(list, row) < 0) {
+            Py_DECREF(row);
+            break;
+        }
+        Py_DECREF(row);
 
         if (++counter == maxrows) {
             break;
@@ -829,8 +834,11 @@ PyObject* pysqlite_cursor_fetchall(pysqlite_Cursor* self, PyObject* args)
     }
 
     while ((row = pysqlite_cursor_iternext(self))) {
-        PyList_Append(list, row);
-        Py_XDECREF(row);
+        if (PyList_Append(list, row) < 0) {
+            Py_DECREF(row);
+            break;
+        }
+        Py_DECREF(row);
     }
 
     if (PyErr_Occurred()) {
index 793c5e71548846345c937e6728f11bef6272e1b9..b30141d4497bda320b3f0d89d8092362ef6abf59 100644 (file)
@@ -395,7 +395,8 @@ unicodeFromTclStringAndSize(const char *s, Py_ssize_t size)
 
     char *buf = NULL;
     PyErr_Clear();
-    /* Tcl encodes null character as \xc0\x80 */
+    /* Tcl encodes null character as \xc0\x80.
+       https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8 */
     if (memchr(s, '\xc0', size)) {
         char *q;
         const char *e = s + size;
@@ -419,6 +420,57 @@ unicodeFromTclStringAndSize(const char *s, Py_ssize_t size)
     if (buf != NULL) {
         PyMem_Free(buf);
     }
+    if (r == NULL || PyUnicode_KIND(r) == PyUnicode_1BYTE_KIND) {
+        return r;
+    }
+
+    /* In CESU-8 non-BMP characters are represented as a surrogate pair,
+       like in UTF-16, and then each surrogate code point is encoded in UTF-8.
+       https://en.wikipedia.org/wiki/CESU-8 */
+    Py_ssize_t len = PyUnicode_GET_LENGTH(r);
+    Py_ssize_t i, j;
+    /* All encoded surrogate characters start with \xED. */
+    i = PyUnicode_FindChar(r, 0xdcED, 0, len, 1);
+    if (i == -2) {
+        Py_DECREF(r);
+        return NULL;
+    }
+    if (i == -1) {
+        return r;
+    }
+    Py_UCS4 *u = PyUnicode_AsUCS4Copy(r);
+    Py_DECREF(r);
+    if (u == NULL) {
+        return NULL;
+    }
+    Py_UCS4 ch;
+    for (j = i; i < len; i++, u[j++] = ch) {
+        Py_UCS4 ch1, ch2, ch3, high, low;
+        /* Low surrogates U+D800 - U+DBFF are encoded as
+           \xED\xA0\x80 - \xED\xAF\xBF. */
+        ch1 = ch = u[i];
+        if (ch1 != 0xdcED) continue;
+        ch2 = u[i + 1];
+        if (!(0xdcA0 <= ch2 && ch2 <= 0xdcAF)) continue;
+        ch3 = u[i + 2];
+        if (!(0xdc80 <= ch3 && ch3 <= 0xdcBF)) continue;
+        high = 0xD000 | ((ch2 & 0x3F) << 6) | (ch3 & 0x3F);
+        assert(Py_UNICODE_IS_HIGH_SURROGATE(high));
+        /* High surrogates U+DC00 - U+DFFF are encoded as
+           \xED\xB0\x80 - \xED\xBF\xBF. */
+        ch1 = u[i + 3];
+        if (ch1 != 0xdcED) continue;
+        ch2 = u[i + 4];
+        if (!(0xdcB0 <= ch2 && ch2 <= 0xdcBF)) continue;
+        ch3 = u[i + 5];
+        if (!(0xdc80 <= ch3 && ch3 <= 0xdcBF)) continue;
+        low = 0xD000 | ((ch2 & 0x3F) << 6) | (ch3 & 0x3F);
+        assert(Py_UNICODE_IS_HIGH_SURROGATE(high));
+        ch = Py_UNICODE_JOIN_SURROGATES(high, low);
+        i += 5;
+    }
+    r = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, u, j);
+    PyMem_Free(u);
     return r;
 }
 
index 2cee65fac6dd042aefccde501251b3801f6cc371..f655768496e132ac0e5e92e55e3b5e58ca977092 100644 (file)
@@ -163,7 +163,7 @@ is_leap_year(int year);
 static size_t
 _bisect(const int64_t value, const int64_t *arr, size_t size);
 
-static void
+static int
 eject_from_strong_cache(const PyTypeObject *const type, PyObject *key);
 static void
 clear_strong_cache(const PyTypeObject *const type);
@@ -171,7 +171,7 @@ static void
 update_strong_cache(const PyTypeObject *const type, PyObject *key,
                     PyObject *zone);
 static PyObject *
-zone_from_strong_cache(const PyTypeObject *const type, PyObject *key);
+zone_from_strong_cache(const PyTypeObject *const type, PyObject *const key);
 
 static PyObject *
 zoneinfo_new_instance(PyTypeObject *type, PyObject *key)
@@ -265,7 +265,7 @@ zoneinfo_new(PyTypeObject *type, PyObject *args, PyObject *kw)
     }
 
     PyObject *instance = zone_from_strong_cache(type, key);
-    if (instance != NULL) {
+    if (instance != NULL || PyErr_Occurred()) {
         return instance;
     }
 
@@ -428,7 +428,10 @@ zoneinfo_clear_cache(PyObject *cls, PyObject *args, PyObject *kwargs)
 
         while ((item = PyIter_Next(iter))) {
             // Remove from strong cache
-            eject_from_strong_cache(type, item);
+            if (eject_from_strong_cache(type, item) < 0) {
+                Py_DECREF(item);
+                break;
+            }
 
             // Remove from weak cache
             PyObject *tmp = PyObject_CallMethodObjArgs(weak_cache, pop, item,
@@ -909,7 +912,13 @@ load_data(PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
     // Load the transition indices and list
     self->trans_list_utc =
         PyMem_Malloc(self->num_transitions * sizeof(int64_t));
+    if (self->trans_list_utc == NULL) {
+        goto error;
+    }
     trans_idx = PyMem_Malloc(self->num_transitions * sizeof(Py_ssize_t));
+    if (trans_idx == NULL) {
+        goto error;
+    }
 
     for (size_t i = 0; i < self->num_transitions; ++i) {
         PyObject *num = PyTuple_GetItem(trans_utc, i);
@@ -991,6 +1000,9 @@ load_data(PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
 
     // Build _ttinfo objects from utcoff, dstoff and abbr
     self->_ttinfos = PyMem_Malloc(self->num_ttinfos * sizeof(_ttinfo));
+    if (self->_ttinfos == NULL) {
+        goto error;
+    }
     for (size_t i = 0; i < self->num_ttinfos; ++i) {
         PyObject *tzname = PyTuple_GetItem(abbr, i);
         if (tzname == NULL) {
@@ -1006,6 +1018,9 @@ load_data(PyZoneInfo_ZoneInfo *self, PyObject *file_obj)
     // Build our mapping from transition to the ttinfo that applies
     self->trans_ttinfos =
         PyMem_Calloc(self->num_transitions, sizeof(_ttinfo *));
+    if (self->trans_ttinfos == NULL) {
+        goto error;
+    }
     for (size_t i = 0; i < self->num_transitions; ++i) {
         size_t ttinfo_idx = trans_idx[i];
         assert(ttinfo_idx < self->num_ttinfos);
@@ -1219,15 +1234,9 @@ calendarrule_new(uint8_t month, uint8_t week, uint8_t day, int8_t hour,
         return -1;
     }
 
-    // day is an unsigned integer, so day < 0 should always return false, but
-    // if day's type changes to a signed integer *without* changing this value,
-    // it may create a bug. Considering that the compiler should be able to
-    // optimize out the first comparison if day is an unsigned integer anyway,
-    // we will leave this comparison in place and disable the compiler warning.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wtype-limits"
-    if (day < 0 || day > 6) {
-#pragma GCC diagnostic pop
+    // If the 'day' parameter type is changed to a signed type,
+    // "day < 0" check must be added.
+    if (/* day < 0 || */ day > 6) {
         PyErr_Format(PyExc_ValueError, "Day must be in [0, 6]");
         return -1;
     }
@@ -2341,7 +2350,11 @@ find_in_strong_cache(const StrongCacheNode *const root, PyObject *const key)
 {
     const StrongCacheNode *node = root;
     while (node != NULL) {
-        if (PyObject_RichCompareBool(key, node->key, Py_EQ)) {
+        int rv = PyObject_RichCompareBool(key, node->key, Py_EQ);
+        if (rv < 0) {
+            return NULL;
+        }
+        if (rv) {
             return (StrongCacheNode *)node;
         }
 
@@ -2355,11 +2368,11 @@ find_in_strong_cache(const StrongCacheNode *const root, PyObject *const key)
  *
  * This function is used to enable the per-key functionality in clear_cache.
  */
-static void
+static int
 eject_from_strong_cache(const PyTypeObject *const type, PyObject *key)
 {
     if (type != &PyZoneInfo_ZoneInfoType) {
-        return;
+        return 0;
     }
 
     StrongCacheNode *node = find_in_strong_cache(ZONEINFO_STRONG_CACHE, key);
@@ -2368,6 +2381,10 @@ eject_from_strong_cache(const PyTypeObject *const type, PyObject *key)
 
         strong_cache_node_free(node);
     }
+    else if (PyErr_Occurred()) {
+        return -1;
+    }
+    return 0;
 }
 
 /* Moves a node to the front of the LRU cache.
@@ -2524,7 +2541,11 @@ zoneinfo_init_subclass(PyTypeObject *cls, PyObject *args, PyObject **kwargs)
         return NULL;
     }
 
-    PyObject_SetAttrString((PyObject *)cls, "_weak_cache", weak_cache);
+    if (PyObject_SetAttrString((PyObject *)cls, "_weak_cache",
+                               weak_cache) < 0) {
+        Py_DECREF(weak_cache);
+        return NULL;
+    }
     Py_DECREF(weak_cache);
     Py_RETURN_NONE;
 }
@@ -2624,6 +2645,9 @@ static int
 zoneinfomodule_exec(PyObject *m)
 {
     PyDateTime_IMPORT;
+    if (PyDateTimeAPI == NULL) {
+        goto error;
+    }
     PyZoneInfo_ZoneInfoType.tp_base = PyDateTimeAPI->TZInfoType;
     if (PyType_Ready(&PyZoneInfo_ZoneInfoType) < 0) {
         goto error;
index 50d7f213e04e6d010a841a58ec45c946206f11d9..66ffcdfdb3f99baac2a4850471d5d6a2db746b3c 100644 (file)
@@ -2028,7 +2028,7 @@ PyDoc_STRVAR(_curses_color_content__doc__,
 "Return the red, green, and blue (RGB) components of the specified color.\n"
 "\n"
 "  color_number\n"
-"    The number of the color (0 - COLORS).\n"
+"    The number of the color (0 - (COLORS-1)).\n"
 "\n"
 "A 3-tuple is returned, containing the R, G, B values for the given color,\n"
 "which will be between 0 (no component) and 1000 (maximum amount of component).");
@@ -2076,13 +2076,13 @@ exit:
 }
 
 PyDoc_STRVAR(_curses_color_pair__doc__,
-"color_pair($module, color_number, /)\n"
+"color_pair($module, pair_number, /)\n"
 "--\n"
 "\n"
 "Return the attribute value for displaying text in the specified color.\n"
 "\n"
-"  color_number\n"
-"    The number of the color (0 - COLORS).\n"
+"  pair_number\n"
+"    The number of the color pair.\n"
 "\n"
 "This attribute value can be combined with A_STANDOUT, A_REVERSE, and the\n"
 "other A_* attributes.  pair_number() is the counterpart to this function.");
@@ -2091,13 +2091,13 @@ PyDoc_STRVAR(_curses_color_pair__doc__,
     {"color_pair", (PyCFunction)_curses_color_pair, METH_O, _curses_color_pair__doc__},
 
 static PyObject *
-_curses_color_pair_impl(PyObject *module, short color_number);
+_curses_color_pair_impl(PyObject *module, short pair_number);
 
 static PyObject *
 _curses_color_pair(PyObject *module, PyObject *arg)
 {
     PyObject *return_value = NULL;
-    short color_number;
+    short pair_number;
 
     if (PyFloat_Check(arg)) {
         PyErr_SetString(PyExc_TypeError,
@@ -2120,10 +2120,10 @@ _curses_color_pair(PyObject *module, PyObject *arg)
             goto exit;
         }
         else {
-            color_number = (short) ival;
+            pair_number = (short) ival;
         }
     }
-    return_value = _curses_color_pair_impl(module, color_number);
+    return_value = _curses_color_pair_impl(module, pair_number);
 
 exit:
     return return_value;
@@ -2699,7 +2699,7 @@ PyDoc_STRVAR(_curses_init_color__doc__,
 "Change the definition of a color.\n"
 "\n"
 "  color_number\n"
-"    The number of the color to be changed (0 - COLORS).\n"
+"    The number of the color to be changed (0 - (COLORS-1)).\n"
 "  r\n"
 "    Red component (0 - 1000).\n"
 "  g\n"
@@ -2709,7 +2709,7 @@ PyDoc_STRVAR(_curses_init_color__doc__,
 "\n"
 "When init_color() is used, all occurrences of that color on the screen\n"
 "immediately change to the new definition.  This function is a no-op on\n"
-"most terminals; it is active only if can_change_color() returns 1.");
+"most terminals; it is active only if can_change_color() returns true.");
 
 #define _CURSES_INIT_COLOR_METHODDEF    \
     {"init_color", (PyCFunction)(void(*)(void))_curses_init_color, METH_FASTCALL, _curses_init_color__doc__},
@@ -2841,9 +2841,9 @@ PyDoc_STRVAR(_curses_init_pair__doc__,
 "  pair_number\n"
 "    The number of the color-pair to be changed (1 - (COLOR_PAIRS-1)).\n"
 "  fg\n"
-"    Foreground color number (0 - COLORS).\n"
+"    Foreground color number (-1 - (COLORS-1)).\n"
 "  bg\n"
-"    Background color number (0 - COLORS).\n"
+"    Background color number (-1 - (COLORS-1)).\n"
 "\n"
 "If the color-pair was previously initialized, the screen is refreshed and\n"
 "all occurrences of that color-pair are changed to the new definition.");
@@ -4713,4 +4713,4 @@ _curses_use_default_colors(PyObject *module, PyObject *Py_UNUSED(ignored))
 #ifndef _CURSES_USE_DEFAULT_COLORS_METHODDEF
     #define _CURSES_USE_DEFAULT_COLORS_METHODDEF
 #endif /* !defined(_CURSES_USE_DEFAULT_COLORS_METHODDEF) */
-/*[clinic end generated code: output=b53652f8acafd817 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=5e739120041df368 input=a9049054013a1b77]*/
index 18fcebdf25b465f6c24a4b848d10c0023c23f265..95ef8d79a1653388503c69275dbecc52893b7a8d 100644 (file)
@@ -2,6 +2,7 @@
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
 #include "pycore_tupleobject.h"
+#include "pycore_object.h"        // _PyObject_GC_TRACK()
 #include <stddef.h>               // offsetof()
 
 /* Itertools module written and maintained
@@ -2245,6 +2246,11 @@ product_next(productobject *lz)
             lz->result = result;
             Py_DECREF(old_result);
         }
+        // bpo-42536: The GC may have untracked this result tuple. Since we're
+        // recycling it, make sure it's tracked again:
+        else if (!_PyObject_GC_IS_TRACKED(result)) {
+            _PyObject_GC_TRACK(result);
+        }
         /* Now, we've got the only copy so we can update it in-place */
         assert (npools==0 || Py_REFCNT(result) == 1);
 
@@ -2568,6 +2574,11 @@ combinations_next(combinationsobject *co)
             co->result = result;
             Py_DECREF(old_result);
         }
+        // bpo-42536: The GC may have untracked this result tuple. Since we're
+        // recycling it, make sure it's tracked again:
+        else if (!_PyObject_GC_IS_TRACKED(result)) {
+            _PyObject_GC_TRACK(result);
+        }
         /* Now, we've got the only copy so we can update it in-place
          * CPython's empty tuple is a singleton and cached in
          * PyTuple's freelist.
@@ -2902,6 +2913,11 @@ cwr_next(cwrobject *co)
             co->result = result;
             Py_DECREF(old_result);
         }
+        // bpo-42536: The GC may have untracked this result tuple. Since we're
+        // recycling it, make sure it's tracked again:
+        else if (!_PyObject_GC_IS_TRACKED(result)) {
+            _PyObject_GC_TRACK(result);
+        }
         /* Now, we've got the only copy so we can update it in-place CPython's
            empty tuple is a singleton and cached in PyTuple's freelist. */
         assert(r == 0 || Py_REFCNT(result) == 1);
@@ -3246,6 +3262,11 @@ permutations_next(permutationsobject *po)
             po->result = result;
             Py_DECREF(old_result);
         }
+        // bpo-42536: The GC may have untracked this result tuple. Since we're
+        // recycling it, make sure it's tracked again:
+        else if (!_PyObject_GC_IS_TRACKED(result)) {
+            _PyObject_GC_TRACK(result);
+        }
         /* Now, we've got the only copy so we can update it in-place */
         assert(r == 0 || Py_REFCNT(result) == 1);
 
@@ -4515,6 +4536,11 @@ zip_longest_next(ziplongestobject *lz)
             PyTuple_SET_ITEM(result, i, item);
             Py_DECREF(olditem);
         }
+        // bpo-42536: The GC may have untracked this result tuple. Since we're
+        // recycling it, make sure it's tracked again:
+        if (!_PyObject_GC_IS_TRACKED(result)) {
+            _PyObject_GC_TRACK(result);
+        }
     } else {
         result = PyTuple_New(tuplesize);
         if (result == NULL)
index e4d9db40f22df36f8b78c4dfb3a758a2f5e6f0b9..6ed843376ae784fd7fa6ae6402d8bc463e337748 100644 (file)
@@ -74,7 +74,7 @@ typedef struct {
  * The library is free for all purposes without any express
  * guarantee it works.
  *
- * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ * Tom St Denis, tomstdenis@gmail.com, https://www.libtom.net
  */
 
 /* rotate the hard way (platform optimizations could be done) */
index 12f72f525f7ae4fe98b7244c460567968941b5e1..5e33502721c1929bd1d2a6f0567a3fabfce0d3c1 100644 (file)
  */
 #if defined(__APPLE__)
 
-#if defined(__has_builtin) && __has_builtin(__builtin_available)
+#if defined(__has_builtin)
+#if __has_builtin(__builtin_available)
+#define HAVE_BUILTIN_AVAILABLE 1
+#endif
+#endif
+
+#ifdef HAVE_BUILTIN_AVAILABLE
 #  define HAVE_FSTATAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
 #  define HAVE_FACCESSAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
 #  define HAVE_FCHMODAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
@@ -632,7 +638,7 @@ _PyLong_FromGid(gid_t gid)
 }
 
 int
-_Py_Uid_Converter(PyObject *obj, void *p)
+_Py_Uid_Converter(PyObject *obj, uid_t *p)
 {
     uid_t uid;
     PyObject *index;
@@ -719,7 +725,7 @@ _Py_Uid_Converter(PyObject *obj, void *p)
 
 success:
     Py_DECREF(index);
-    *(uid_t *)p = uid;
+    *p = uid;
     return 1;
 
 underflow:
@@ -738,7 +744,7 @@ fail:
 }
 
 int
-_Py_Gid_Converter(PyObject *obj, void *p)
+_Py_Gid_Converter(PyObject *obj, gid_t *p)
 {
     gid_t gid;
     PyObject *index;
@@ -826,7 +832,7 @@ _Py_Gid_Converter(PyObject *obj, void *p)
 
 success:
     Py_DECREF(index);
-    *(gid_t *)p = gid;
+    *p = gid;
     return 1;
 
 underflow:
index 1e00562abc3370eb44631b6c065f47e2d995fdd7..711ac686934b0285282c0c43c90ec7828652800c 100644 (file)
@@ -14,8 +14,8 @@ extern "C" {
 #ifndef MS_WINDOWS
 PyAPI_FUNC(PyObject *) _PyLong_FromUid(uid_t);
 PyAPI_FUNC(PyObject *) _PyLong_FromGid(gid_t);
-PyAPI_FUNC(int) _Py_Uid_Converter(PyObject *, void *);
-PyAPI_FUNC(int) _Py_Gid_Converter(PyObject *, void *);
+PyAPI_FUNC(int) _Py_Uid_Converter(PyObject *, uid_t *);
+PyAPI_FUNC(int) _Py_Gid_Converter(PyObject *, gid_t *);
 #endif /* MS_WINDOWS */
 
 #if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGWAIT) || \
index 12d6cc78e38a77491a21615c41573fe0ca4ad6f6..1e74f997b071129d5760e5d2dc99b85c150e8a52 100644 (file)
@@ -146,6 +146,26 @@ decode(const char *s)
 }
 
 
+/*
+Explicitly disable bracketed paste in the interactive interpreter, even if it's
+set in the inputrc, is enabled by default (eg GNU Readline 8.1), or a user calls
+readline.read_init_file(). The Python REPL has not implemented bracketed
+paste support. Also, bracketed mode writes the "\x1b[?2004h" escape sequence
+into stdout which causes test failures in applications that don't support it.
+It can still be explicitly enabled by calling readline.parse_and_bind("set
+enable-bracketed-paste on"). See bpo-42819 for more details.
+
+This should be removed if bracketed paste mode is implemented (bpo-39820).
+*/
+
+static void
+disable_bracketed_paste(void)
+{
+    if (!using_libedit_emulation) {
+        rl_variable_bind ("enable-bracketed-paste", "off");
+    }
+}
+
 /* Exported function to send one line to readline's init file parser */
 
 static PyObject *
@@ -192,6 +212,7 @@ read_init_file(PyObject *self, PyObject *args)
         errno = rl_read_init_file(NULL);
     if (errno)
         return PyErr_SetFromErrno(PyExc_OSError);
+    disable_bracketed_paste();
     Py_RETURN_NONE;
 }
 
@@ -1152,6 +1173,8 @@ setup_readline(readlinestate *mod_state)
     else
         rl_initialize();
 
+    disable_bracketed_paste();
+
     RESTORE_LOCALE(saved_locale)
     return 0;
 }
index b0656d83b3ae8bdb7ae039d49a2d3b705d45a104..9c75cc99dba77130dcf8b7b67679641a89d06b11 100644 (file)
@@ -74,7 +74,7 @@ typedef struct {
  * The library is free for all purposes without any express
  * guarantee it works.
  *
- * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+ * Tom St Denis, tomstdenis@gmail.com, https://www.libtom.net
  */
 
 /* rotate the hard way (platform optimizations could be done) */
index 8edb1d53828835ee19cb40dc1019760b8c7f3c43..9b885c72553081a672416c0bee60163a1355a274 100644 (file)
@@ -93,7 +93,7 @@ static void SHAcopy(SHAobject *src, SHAobject *dest)
  * The library is free for all purposes without any express
  * guarantee it works.
  *
- * Tom St Denis, tomstdenis@iahu.ca, http://libtom.org
+ * Tom St Denis, tomstdenis@iahu.ca, https://www.libtom.net
  */
 
 
index 561ef8ef0e8676185650403b6df8b742163dc2ed..831160c324d5593ce7729c41f433f792852495aa 100644 (file)
@@ -94,7 +94,7 @@ static void SHAcopy(SHAobject *src, SHAobject *dest)
  * The library is free for all purposes without any express
  * guarantee it works.
  *
- * Tom St Denis, tomstdenis@iahu.ca, http://libtom.org
+ * Tom St Denis, tomstdenis@iahu.ca, https://www.libtom.net
  */
 
 
index 76ef606e10b1fb57418195d3663ba3cda86fce64..be75e681d45d99c5ab4b133deb8a469d0fdcf431 100644 (file)
@@ -3407,8 +3407,9 @@ sock_getsockname(PySocketSockObject *s, PyObject *Py_UNUSED(ignored))
 PyDoc_STRVAR(getsockname_doc,
 "getsockname() -> address info\n\
 \n\
-Return the address of the local endpoint.  For IP sockets, the address\n\
-info is a pair (hostaddr, port).");
+Return the address of the local endpoint. The format depends on the\n\
+address family. For IPv4 sockets, the address info is a pair\n\
+(hostaddr, port).");
 
 
 #ifdef HAVE_GETPEERNAME         /* Cray APP doesn't have this :-( */
index 61426c7e09e4e71b2bad982b4988b61da926527f..87dc0dbbdb504a86b882678074a0534e0fce348a 100644 (file)
@@ -205,6 +205,7 @@ PyObject *
 PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
 {
     PyThreadState *tstate = _PyThreadState_GET();
+    vectorcallfunc func;
 
     /* get vectorcallfunc as in PyVectorcall_Function, but without
      * the Py_TPFLAGS_HAVE_VECTORCALL check */
@@ -215,7 +216,7 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
                       Py_TYPE(callable)->tp_name);
         return NULL;
     }
-    vectorcallfunc func = *(vectorcallfunc *)(((char *)callable) + offset);
+    memcpy(&func, (char *) callable + offset, sizeof(func));
     if (func == NULL) {
         _PyErr_Format(tstate, PyExc_TypeError,
                       "'%.200s' object does not support vectorcall",
index faee6bc901eeba0f614dec7fdb60f174c352df7e..8a056530a454593aec872222a569afc3bb904637 100644 (file)
@@ -3861,6 +3861,11 @@ dictiter_iternextitem(dictiterobject *di)
         Py_INCREF(result);
         Py_DECREF(oldkey);
         Py_DECREF(oldvalue);
+        // bpo-42536: The GC may have untracked this result tuple. Since we're
+        // recycling it, make sure it's tracked again:
+        if (!_PyObject_GC_IS_TRACKED(result)) {
+            _PyObject_GC_TRACK(result);
+        }
     }
     else {
         result = PyTuple_New(2);
@@ -3976,6 +3981,11 @@ dictreviter_iternext(dictiterobject *di)
             Py_INCREF(result);
             Py_DECREF(oldkey);
             Py_DECREF(oldvalue);
+            // bpo-42536: The GC may have untracked this result tuple. Since
+            // we're recycling it, make sure it's tracked again:
+            if (!_PyObject_GC_IS_TRACKED(result)) {
+                _PyObject_GC_TRACK(result);
+            }
         }
         else {
             result = PyTuple_New(2);
index 4a83bb45aa6678e2105593a3345779ac0e0b3b71..bdd0ea5f3971be2a30199df7138ad9f62b090247 100644 (file)
@@ -1,6 +1,7 @@
 /* enumerate object */
 
 #include "Python.h"
+#include "pycore_object.h"        // _PyObject_GC_TRACK()
 
 #include "clinic/enumobject.c.h"
 
@@ -130,6 +131,11 @@ enum_next_long(enumobject *en, PyObject* next_item)
         PyTuple_SET_ITEM(result, 1, next_item);
         Py_DECREF(old_index);
         Py_DECREF(old_item);
+        // bpo-42536: The GC may have untracked this result tuple. Since we're
+        // recycling it, make sure it's tracked again:
+        if (!_PyObject_GC_IS_TRACKED(result)) {
+            _PyObject_GC_TRACK(result);
+        }
         return result;
     }
     result = PyTuple_New(2);
@@ -175,6 +181,11 @@ enum_next(enumobject *en)
         PyTuple_SET_ITEM(result, 1, next_item);
         Py_DECREF(old_index);
         Py_DECREF(old_item);
+        // bpo-42536: The GC may have untracked this result tuple. Since we're
+        // recycling it, make sure it's tracked again:
+        if (!_PyObject_GC_IS_TRACKED(result)) {
+            _PyObject_GC_TRACK(result);
+        }
         return result;
     }
     result = PyTuple_New(2);
index e44ce727aff1e2e787586b8a71ef1de9b1cfff0e..eb72de53e98c12bea83f5f4c7924aa5d0ed46ac2 100644 (file)
@@ -2531,8 +2531,10 @@ _PyExc_Init(void)
     do { \
         PyObject *_code = PyLong_FromLong(CODE); \
         assert(_PyObject_RealIsSubclass(PyExc_ ## TYPE, PyExc_OSError)); \
-        if (!_code || PyDict_SetItem(errnomap, _code, PyExc_ ## TYPE)) \
+        if (!_code || PyDict_SetItem(errnomap, _code, PyExc_ ## TYPE)) { \
+            Py_XDECREF(_code); \
             return _PyStatus_ERR("errmap insertion problem."); \
+        } \
         Py_DECREF(_code); \
     } while (0)
 
index c5a81a5c1aab22456e2a01e23560549e438c8531..945d20593c7c90116af51b78d9854c16e4156a00 100644 (file)
@@ -428,8 +428,8 @@ ga_getattro(PyObject *self, PyObject *name)
 static PyObject *
 ga_richcompare(PyObject *a, PyObject *b, int op)
 {
-    if (!Py_IS_TYPE(a, &Py_GenericAliasType) ||
-        !Py_IS_TYPE(b, &Py_GenericAliasType) ||
+    if (!PyObject_TypeCheck(a, &Py_GenericAliasType) ||
+        !PyObject_TypeCheck(b, &Py_GenericAliasType) ||
         (op != Py_EQ && op != Py_NE))
     {
         Py_RETURN_NOTIMPLEMENTED;
@@ -563,6 +563,29 @@ static PyGetSetDef ga_properties[] = {
     {0}
 };
 
+/* A helper function to create GenericAlias' args tuple and set its attributes.
+ * Returns 1 on success, 0 on failure. 
+ */
+static inline int
+setup_ga(gaobject *alias, PyObject *origin, PyObject *args) {
+    if (!PyTuple_Check(args)) {
+        args = PyTuple_Pack(1, args);
+        if (args == NULL) {
+            return 0;
+        }
+    }
+    else {
+        Py_INCREF(args);
+    }
+
+    Py_INCREF(origin);
+    alias->origin = origin;
+    alias->args = args;
+    alias->parameters = NULL;
+    alias->weakreflist = NULL;
+    return 1;
+}
+
 static PyObject *
 ga_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
@@ -574,7 +597,15 @@ ga_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     }
     PyObject *origin = PyTuple_GET_ITEM(args, 0);
     PyObject *arguments = PyTuple_GET_ITEM(args, 1);
-    return Py_GenericAlias(origin, arguments);
+    gaobject *self = (gaobject *)type->tp_alloc(type, 0);
+    if (self == NULL) {
+        return NULL;
+    }
+    if (!setup_ga(self, origin, arguments)) {
+        type->tp_free((PyObject *)self);
+        return NULL;
+    }
+    return (PyObject *)self;
 }
 
 // TODO:
@@ -594,7 +625,7 @@ PyTypeObject Py_GenericAliasType = {
     .tp_hash = ga_hash,
     .tp_call = ga_call,
     .tp_getattro = ga_getattro,
-    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
+    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
     .tp_traverse = ga_traverse,
     .tp_richcompare = ga_richcompare,
     .tp_weaklistoffset = offsetof(gaobject, weakreflist),
@@ -609,27 +640,14 @@ PyTypeObject Py_GenericAliasType = {
 PyObject *
 Py_GenericAlias(PyObject *origin, PyObject *args)
 {
-    if (!PyTuple_Check(args)) {
-        args = PyTuple_Pack(1, args);
-        if (args == NULL) {
-            return NULL;
-        }
-    }
-    else {
-        Py_INCREF(args);
-    }
-
     gaobject *alias = PyObject_GC_New(gaobject, &Py_GenericAliasType);
     if (alias == NULL) {
-        Py_DECREF(args);
         return NULL;
     }
-
-    Py_INCREF(origin);
-    alias->origin = origin;
-    alias->args = args;
-    alias->parameters = NULL;
-    alias->weakreflist = NULL;
+    if (!setup_ga(alias, origin, args)) {
+        PyObject_GC_Del((PyObject *)alias);
+        return NULL;
+    }
     _PyObject_GC_TRACK(alias);
     return (PyObject *)alias;
 }
index d5bf499575d097a6636eaccfab4e48ba1e67138d..b9f2169a72a8ac2f04a77adc677bd7db7c9f3b3f 100644 (file)
@@ -1817,6 +1817,11 @@ odictiter_iternext(odictiterobject *di)
         Py_INCREF(result);
         Py_DECREF(PyTuple_GET_ITEM(result, 0));  /* borrowed */
         Py_DECREF(PyTuple_GET_ITEM(result, 1));  /* borrowed */
+        // bpo-42536: The GC may have untracked this result tuple. Since we're
+        // recycling it, make sure it's tracked again:
+        if (!_PyObject_GC_IS_TRACKED(result)) {
+            _PyObject_GC_TRACK(result);
+        }
     }
     else {
         result = PyTuple_New(2);
index 66d1595c943ed8483de3064d1666e98fe329f010..d27d7d07128a410dad5dd6800707c41d5946c042 100644 (file)
@@ -40,6 +40,7 @@ EXPORTS
   PyCFunction_GetSelf=python39.PyCFunction_GetSelf
   PyCFunction_New=python39.PyCFunction_New
   PyCFunction_NewEx=python39.PyCFunction_NewEx
+  PyCMethod_New=python39.PyCMethod_New
   PyCFunction_Type=python39.PyCFunction_Type DATA
   PyCallIter_New=python39.PyCallIter_New
   PyCallIter_Type=python39.PyCallIter_Type DATA
@@ -266,6 +267,8 @@ EXPORTS
   PyFloat_GetMax=python39.PyFloat_GetMax
   PyFloat_GetMin=python39.PyFloat_GetMin
   PyFloat_Type=python39.PyFloat_Type DATA
+  PyFrame_GetCode=python39.PyFrame_GetCode
+  PyFrame_GetLineNumber=python39.PyFrame_GetLineNumber
   PyFrozenSet_New=python39.PyFrozenSet_New
   PyFrozenSet_Type=python39.PyFrozenSet_Type DATA
   PyGC_Collect=python39.PyGC_Collect
@@ -453,6 +456,7 @@ EXPORTS
   PyObject_CallFunctionObjArgs=python39.PyObject_CallFunctionObjArgs
   PyObject_CallMethod=python39.PyObject_CallMethod
   PyObject_CallMethodObjArgs=python39.PyObject_CallMethodObjArgs
+  PyObject_CallNoArgs=python39.PyObject_CallNoArgs
   PyObject_CallObject=python39.PyObject_CallObject
   PyObject_Calloc=python39.PyObject_Calloc
   PyObject_CheckReadBuffer=python39.PyObject_CheckReadBuffer
@@ -569,6 +573,9 @@ EXPORTS
   PyThreadState_DeleteCurrent=python39.PyThreadState_DeleteCurrent
   PyThreadState_Get=python39.PyThreadState_Get
   PyThreadState_GetDict=python39.PyThreadState_GetDict
+  PyThreadState_GetFrame=python39.PyThreadState_GetFrame
+  PyThreadState_GetID=python39.PyThreadState_GetID
+  PyThreadState_GetInterpreter=python39.PyThreadState_GetInterpreter
   PyThreadState_New=python39.PyThreadState_New
   PyThreadState_SetAsyncExc=python39.PyThreadState_SetAsyncExc
   PyThreadState_Swap=python39.PyThreadState_Swap
index 060aecdc675cb9a83b59e641119b9b1cb1f7ad81..90fc6ba1a1460c58ac6cf6cf2ca13596a41ded52 100644 (file)
@@ -5,7 +5,7 @@
 #include "winver.h"
 
 #define PYTHON_COMPANY   "Python Software Foundation"
-#define PYTHON_COPYRIGHT "Copyright \xA9 2001-2016 Python Software Foundation. Copyright \xA9 2000 BeOpen.com. Copyright \xA9 1995-2001 CNRI. Copyright \xA9 1991-1995 SMC."
+#define PYTHON_COPYRIGHT "Copyright \xA9 2001-2021 Python Software Foundation. Copyright \xA9 2000 BeOpen.com. Copyright \xA9 1995-2001 CNRI. Copyright \xA9 1991-1995 SMC."
 
 #define MS_WINDOWS
 #include "modsupport.h"
index 9dc84a6c36864debb3a6881fc3c68aa60f1b254a..395aa0d4cb6ec7e1966322905d15b0f0545a610e 100644 (file)
@@ -53,8 +53,8 @@ echo.Fetching external libraries...
 set libraries=\r
 set libraries=%libraries%                                       bzip2-1.0.6\r
 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries%  libffi\r
-if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries%     openssl-1.1.1g\r
-set libraries=%libraries%                                       sqlite-3.33.0.0\r
+if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries%     openssl-1.1.1i\r
+set libraries=%libraries%                                       sqlite-3.34.0.0\r
 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.9.0\r
 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.9.0\r
 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tix-8.4.3.6\r
@@ -77,7 +77,7 @@ echo.Fetching external binaries...
 \r
 set binaries=\r
 if NOT "%IncludeLibffi%"=="false"  set binaries=%binaries% libffi\r
-if NOT "%IncludeSSL%"=="false"     set binaries=%binaries% openssl-bin-1.1.1g\r
+if NOT "%IncludeSSL%"=="false"     set binaries=%binaries% openssl-bin-1.1.1i\r
 if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.9.0\r
 if NOT "%IncludeSSLSrc%"=="false"  set binaries=%binaries% nasm-2.11.06\r
 \r
index 95649ea1e43b4e07fd4391cfe6f777cd076f66f5..db5f90161c93f4e3a2da5398b1f6d83ec02e9313 100644 (file)
@@ -46,6 +46,7 @@
       <WholeProgramOptimization>true</WholeProgramOptimization>\r
       <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">OnlyExplicitInline</InlineFunctionExpansion>\r
       <InlineFunctionExpansion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">OnlyExplicitInline</InlineFunctionExpansion>\r
+      <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>\r
     </ClCompile>\r
     <ClCompile Condition="$(Configuration) == 'Debug'">\r
       <Optimization>Disabled</Optimization>\r
index 3a3a78733d6741b481d249dd24698b2cc55ba050..be31a1580d9db28637454a91a2ade415fe48c5d9 100644 (file)
     <ExternalsDir>$(EXTERNALS_DIR)</ExternalsDir>\r
     <ExternalsDir Condition="$(ExternalsDir) == ''">$([System.IO.Path]::GetFullPath(`$(PySourcePath)externals`))</ExternalsDir>\r
     <ExternalsDir Condition="!HasTrailingSlash($(ExternalsDir))">$(ExternalsDir)\</ExternalsDir>\r
-    <sqlite3Dir>$(ExternalsDir)sqlite-3.33.0.0\</sqlite3Dir>\r
+    <sqlite3Dir>$(ExternalsDir)sqlite-3.34.0.0\</sqlite3Dir>\r
     <bz2Dir>$(ExternalsDir)bzip2-1.0.6\</bz2Dir>\r
     <lzmaDir>$(ExternalsDir)xz-5.2.2\</lzmaDir>\r
     <libffiDir>$(ExternalsDir)libffi\</libffiDir>\r
     <libffiOutDir>$(ExternalsDir)libffi\$(ArchName)\</libffiOutDir>\r
     <libffiIncludeDir>$(libffiOutDir)include</libffiIncludeDir>\r
-    <opensslDir>$(ExternalsDir)openssl-1.1.1g\</opensslDir>\r
-    <opensslOutDir>$(ExternalsDir)openssl-bin-1.1.1g\$(ArchName)\</opensslOutDir>\r
+    <opensslDir>$(ExternalsDir)openssl-1.1.1i\</opensslDir>\r
+    <opensslOutDir>$(ExternalsDir)openssl-bin-1.1.1i\$(ArchName)\</opensslOutDir>\r
     <opensslIncludeDir>$(opensslOutDir)include</opensslIncludeDir>\r
     <nasmDir>$(ExternalsDir)\nasm-2.11.06\</nasmDir>\r
     <zlibDir>$(ExternalsDir)\zlib-1.2.11\</zlibDir>\r
index e07cdd21a88a0aafb9a3777d4598260f9157f4d8..c06644aa036f592920806d38e3d39e0aae15c457 100644 (file)
@@ -166,7 +166,7 @@ _lzma
     Homepage:\r
         http://tukaani.org/xz/\r
 _ssl\r
-    Python wrapper for version 1.1.1c of the OpenSSL secure sockets\r
+    Python wrapper for version 1.1.1i of the OpenSSL secure sockets\r
     library, which is downloaded from our binaries repository at\r
     https://github.com/python/cpython-bin-deps.\r
 \r
@@ -185,7 +185,7 @@ _ssl
     again when building.\r
 \r
 _sqlite3\r
-    Wraps SQLite 3.33.0, which is itself built by sqlite3.vcxproj\r
+    Wraps SQLite 3.34.0, which is itself built by sqlite3.vcxproj\r
     Homepage:\r
         http://www.sqlite.org/\r
 _tkinter\r
index 0eb61db39a40a46b2fac5a808a401a288dce3f83..98008a5fc1462a6a4b8f44b979407d40a8522b1a 100644 (file)
@@ -204,192 +204,196 @@ static KeywordToken *reserved_keywords[] = {
 #define kwarg_or_starred_type 1126
 #define kwarg_or_double_starred_type 1127
 #define star_targets_type 1128
-#define star_targets_seq_type 1129
-#define star_target_type 1130
-#define star_atom_type 1131
-#define single_target_type 1132
-#define single_subscript_attribute_target_type 1133
-#define del_targets_type 1134
-#define del_target_type 1135
-#define del_t_atom_type 1136
-#define targets_type 1137
-#define target_type 1138
-#define t_primary_type 1139  // Left-recursive
-#define t_lookahead_type 1140
-#define t_atom_type 1141
-#define invalid_arguments_type 1142
-#define invalid_kwarg_type 1143
-#define invalid_named_expression_type 1144
-#define invalid_assignment_type 1145
-#define invalid_ann_assign_target_type 1146
-#define invalid_del_stmt_type 1147
-#define invalid_block_type 1148
-#define invalid_primary_type 1149  // Left-recursive
-#define invalid_comprehension_type 1150
-#define invalid_dict_comprehension_type 1151
-#define invalid_parameters_type 1152
-#define invalid_lambda_parameters_type 1153
-#define invalid_star_etc_type 1154
-#define invalid_lambda_star_etc_type 1155
-#define invalid_double_type_comments_type 1156
-#define invalid_with_item_type 1157
-#define invalid_for_target_type 1158
-#define invalid_group_type 1159
-#define invalid_import_from_targets_type 1160
-#define _loop0_1_type 1161
-#define _loop0_2_type 1162
-#define _loop0_4_type 1163
-#define _gather_3_type 1164
-#define _loop0_6_type 1165
-#define _gather_5_type 1166
-#define _loop0_8_type 1167
-#define _gather_7_type 1168
-#define _loop0_10_type 1169
-#define _gather_9_type 1170
-#define _loop1_11_type 1171
-#define _loop0_13_type 1172
-#define _gather_12_type 1173
-#define _tmp_14_type 1174
-#define _tmp_15_type 1175
-#define _tmp_16_type 1176
-#define _tmp_17_type 1177
-#define _tmp_18_type 1178
-#define _tmp_19_type 1179
-#define _tmp_20_type 1180
-#define _tmp_21_type 1181
-#define _loop1_22_type 1182
-#define _tmp_23_type 1183
-#define _tmp_24_type 1184
-#define _loop0_26_type 1185
-#define _gather_25_type 1186
-#define _loop0_28_type 1187
-#define _gather_27_type 1188
-#define _tmp_29_type 1189
-#define _tmp_30_type 1190
-#define _loop0_31_type 1191
-#define _loop1_32_type 1192
-#define _loop0_34_type 1193
-#define _gather_33_type 1194
-#define _tmp_35_type 1195
-#define _loop0_37_type 1196
-#define _gather_36_type 1197
-#define _tmp_38_type 1198
-#define _loop0_40_type 1199
-#define _gather_39_type 1200
-#define _loop0_42_type 1201
-#define _gather_41_type 1202
-#define _loop0_44_type 1203
-#define _gather_43_type 1204
-#define _loop0_46_type 1205
-#define _gather_45_type 1206
-#define _tmp_47_type 1207
-#define _loop1_48_type 1208
-#define _tmp_49_type 1209
-#define _tmp_50_type 1210
-#define _tmp_51_type 1211
-#define _tmp_52_type 1212
-#define _tmp_53_type 1213
-#define _loop0_54_type 1214
-#define _loop0_55_type 1215
-#define _loop0_56_type 1216
-#define _loop1_57_type 1217
-#define _loop0_58_type 1218
-#define _loop1_59_type 1219
-#define _loop1_60_type 1220
-#define _loop1_61_type 1221
-#define _loop0_62_type 1222
-#define _loop1_63_type 1223
-#define _loop0_64_type 1224
-#define _loop1_65_type 1225
-#define _loop0_66_type 1226
-#define _loop1_67_type 1227
-#define _loop1_68_type 1228
-#define _tmp_69_type 1229
-#define _loop1_70_type 1230
-#define _loop0_72_type 1231
-#define _gather_71_type 1232
-#define _loop1_73_type 1233
-#define _loop0_74_type 1234
-#define _loop0_75_type 1235
-#define _loop0_76_type 1236
-#define _loop1_77_type 1237
-#define _loop0_78_type 1238
-#define _loop1_79_type 1239
-#define _loop1_80_type 1240
-#define _loop1_81_type 1241
-#define _loop0_82_type 1242
-#define _loop1_83_type 1243
-#define _loop0_84_type 1244
-#define _loop1_85_type 1245
-#define _loop0_86_type 1246
-#define _loop1_87_type 1247
-#define _loop1_88_type 1248
-#define _loop1_89_type 1249
-#define _loop1_90_type 1250
-#define _tmp_91_type 1251
-#define _loop0_93_type 1252
-#define _gather_92_type 1253
-#define _tmp_94_type 1254
-#define _tmp_95_type 1255
-#define _tmp_96_type 1256
-#define _tmp_97_type 1257
-#define _loop1_98_type 1258
-#define _tmp_99_type 1259
-#define _tmp_100_type 1260
-#define _loop0_102_type 1261
-#define _gather_101_type 1262
-#define _loop1_103_type 1263
-#define _loop0_104_type 1264
-#define _loop0_105_type 1265
-#define _loop0_107_type 1266
-#define _gather_106_type 1267
-#define _tmp_108_type 1268
-#define _loop0_110_type 1269
-#define _gather_109_type 1270
-#define _loop0_112_type 1271
-#define _gather_111_type 1272
-#define _loop0_114_type 1273
-#define _gather_113_type 1274
-#define _loop0_116_type 1275
-#define _gather_115_type 1276
-#define _loop0_117_type 1277
-#define _loop0_119_type 1278
-#define _gather_118_type 1279
-#define _tmp_120_type 1280
-#define _loop0_122_type 1281
-#define _gather_121_type 1282
-#define _loop0_124_type 1283
-#define _gather_123_type 1284
-#define _tmp_125_type 1285
-#define _loop0_126_type 1286
-#define _loop0_127_type 1287
-#define _loop0_128_type 1288
-#define _tmp_129_type 1289
-#define _tmp_130_type 1290
-#define _loop0_131_type 1291
-#define _tmp_132_type 1292
-#define _loop0_133_type 1293
-#define _tmp_134_type 1294
-#define _tmp_135_type 1295
-#define _tmp_136_type 1296
-#define _tmp_137_type 1297
-#define _tmp_138_type 1298
-#define _tmp_139_type 1299
-#define _tmp_140_type 1300
-#define _tmp_141_type 1301
-#define _tmp_142_type 1302
-#define _tmp_143_type 1303
-#define _tmp_144_type 1304
-#define _tmp_145_type 1305
-#define _tmp_146_type 1306
-#define _tmp_147_type 1307
-#define _tmp_148_type 1308
-#define _tmp_149_type 1309
-#define _tmp_150_type 1310
-#define _loop1_151_type 1311
-#define _loop1_152_type 1312
-#define _tmp_153_type 1313
-#define _tmp_154_type 1314
+#define star_targets_list_seq_type 1129
+#define star_targets_tuple_seq_type 1130
+#define star_target_type 1131
+#define target_with_star_atom_type 1132
+#define star_atom_type 1133
+#define single_target_type 1134
+#define single_subscript_attribute_target_type 1135
+#define del_targets_type 1136
+#define del_target_type 1137
+#define del_t_atom_type 1138
+#define targets_type 1139
+#define target_type 1140
+#define t_primary_type 1141  // Left-recursive
+#define t_lookahead_type 1142
+#define t_atom_type 1143
+#define invalid_arguments_type 1144
+#define invalid_kwarg_type 1145
+#define invalid_named_expression_type 1146
+#define invalid_assignment_type 1147
+#define invalid_ann_assign_target_type 1148
+#define invalid_del_stmt_type 1149
+#define invalid_block_type 1150
+#define invalid_primary_type 1151  // Left-recursive
+#define invalid_comprehension_type 1152
+#define invalid_dict_comprehension_type 1153
+#define invalid_parameters_type 1154
+#define invalid_lambda_parameters_type 1155
+#define invalid_star_etc_type 1156
+#define invalid_lambda_star_etc_type 1157
+#define invalid_double_type_comments_type 1158
+#define invalid_with_item_type 1159
+#define invalid_for_target_type 1160
+#define invalid_group_type 1161
+#define invalid_import_from_targets_type 1162
+#define _loop0_1_type 1163
+#define _loop0_2_type 1164
+#define _loop0_4_type 1165
+#define _gather_3_type 1166
+#define _loop0_6_type 1167
+#define _gather_5_type 1168
+#define _loop0_8_type 1169
+#define _gather_7_type 1170
+#define _loop0_10_type 1171
+#define _gather_9_type 1172
+#define _loop1_11_type 1173
+#define _loop0_13_type 1174
+#define _gather_12_type 1175
+#define _tmp_14_type 1176
+#define _tmp_15_type 1177
+#define _tmp_16_type 1178
+#define _tmp_17_type 1179
+#define _tmp_18_type 1180
+#define _tmp_19_type 1181
+#define _tmp_20_type 1182
+#define _tmp_21_type 1183
+#define _loop1_22_type 1184
+#define _tmp_23_type 1185
+#define _tmp_24_type 1186
+#define _loop0_26_type 1187
+#define _gather_25_type 1188
+#define _loop0_28_type 1189
+#define _gather_27_type 1190
+#define _tmp_29_type 1191
+#define _tmp_30_type 1192
+#define _loop0_31_type 1193
+#define _loop1_32_type 1194
+#define _loop0_34_type 1195
+#define _gather_33_type 1196
+#define _tmp_35_type 1197
+#define _loop0_37_type 1198
+#define _gather_36_type 1199
+#define _tmp_38_type 1200
+#define _loop0_40_type 1201
+#define _gather_39_type 1202
+#define _loop0_42_type 1203
+#define _gather_41_type 1204
+#define _loop0_44_type 1205
+#define _gather_43_type 1206
+#define _loop0_46_type 1207
+#define _gather_45_type 1208
+#define _tmp_47_type 1209
+#define _loop1_48_type 1210
+#define _tmp_49_type 1211
+#define _tmp_50_type 1212
+#define _tmp_51_type 1213
+#define _tmp_52_type 1214
+#define _tmp_53_type 1215
+#define _loop0_54_type 1216
+#define _loop0_55_type 1217
+#define _loop0_56_type 1218
+#define _loop1_57_type 1219
+#define _loop0_58_type 1220
+#define _loop1_59_type 1221
+#define _loop1_60_type 1222
+#define _loop1_61_type 1223
+#define _loop0_62_type 1224
+#define _loop1_63_type 1225
+#define _loop0_64_type 1226
+#define _loop1_65_type 1227
+#define _loop0_66_type 1228
+#define _loop1_67_type 1229
+#define _loop1_68_type 1230
+#define _tmp_69_type 1231
+#define _loop1_70_type 1232
+#define _loop0_72_type 1233
+#define _gather_71_type 1234
+#define _loop1_73_type 1235
+#define _loop0_74_type 1236
+#define _loop0_75_type 1237
+#define _loop0_76_type 1238
+#define _loop1_77_type 1239
+#define _loop0_78_type 1240
+#define _loop1_79_type 1241
+#define _loop1_80_type 1242
+#define _loop1_81_type 1243
+#define _loop0_82_type 1244
+#define _loop1_83_type 1245
+#define _loop0_84_type 1246
+#define _loop1_85_type 1247
+#define _loop0_86_type 1248
+#define _loop1_87_type 1249
+#define _loop1_88_type 1250
+#define _loop1_89_type 1251
+#define _loop1_90_type 1252
+#define _tmp_91_type 1253
+#define _loop0_93_type 1254
+#define _gather_92_type 1255
+#define _tmp_94_type 1256
+#define _tmp_95_type 1257
+#define _tmp_96_type 1258
+#define _tmp_97_type 1259
+#define _loop1_98_type 1260
+#define _tmp_99_type 1261
+#define _tmp_100_type 1262
+#define _loop0_102_type 1263
+#define _gather_101_type 1264
+#define _loop1_103_type 1265
+#define _loop0_104_type 1266
+#define _loop0_105_type 1267
+#define _loop0_107_type 1268
+#define _gather_106_type 1269
+#define _tmp_108_type 1270
+#define _loop0_110_type 1271
+#define _gather_109_type 1272
+#define _loop0_112_type 1273
+#define _gather_111_type 1274
+#define _loop0_114_type 1275
+#define _gather_113_type 1276
+#define _loop0_116_type 1277
+#define _gather_115_type 1278
+#define _loop0_117_type 1279
+#define _loop0_119_type 1280
+#define _gather_118_type 1281
+#define _loop1_120_type 1282
+#define _tmp_121_type 1283
+#define _loop0_123_type 1284
+#define _gather_122_type 1285
+#define _loop0_125_type 1286
+#define _gather_124_type 1287
+#define _tmp_126_type 1288
+#define _loop0_127_type 1289
+#define _loop0_128_type 1290
+#define _loop0_129_type 1291
+#define _tmp_130_type 1292
+#define _tmp_131_type 1293
+#define _loop0_132_type 1294
+#define _tmp_133_type 1295
+#define _loop0_134_type 1296
+#define _tmp_135_type 1297
+#define _tmp_136_type 1298
+#define _tmp_137_type 1299
+#define _tmp_138_type 1300
+#define _tmp_139_type 1301
+#define _tmp_140_type 1302
+#define _tmp_141_type 1303
+#define _tmp_142_type 1304
+#define _tmp_143_type 1305
+#define _tmp_144_type 1306
+#define _tmp_145_type 1307
+#define _tmp_146_type 1308
+#define _tmp_147_type 1309
+#define _tmp_148_type 1310
+#define _tmp_149_type 1311
+#define _tmp_150_type 1312
+#define _tmp_151_type 1313
+#define _tmp_152_type 1314
+#define _loop1_153_type 1315
+#define _loop1_154_type 1316
+#define _tmp_155_type 1317
+#define _tmp_156_type 1318
 
 static mod_ty file_rule(Parser *p);
 static mod_ty interactive_rule(Parser *p);
@@ -520,8 +524,10 @@ static expr_ty starred_expression_rule(Parser *p);
 static KeywordOrStarred* kwarg_or_starred_rule(Parser *p);
 static KeywordOrStarred* kwarg_or_double_starred_rule(Parser *p);
 static expr_ty star_targets_rule(Parser *p);
-static asdl_seq* star_targets_seq_rule(Parser *p);
+static asdl_seq* star_targets_list_seq_rule(Parser *p);
+static asdl_seq* star_targets_tuple_seq_rule(Parser *p);
 static expr_ty star_target_rule(Parser *p);
+static expr_ty target_with_star_atom_rule(Parser *p);
 static expr_ty star_atom_rule(Parser *p);
 static expr_ty single_target_rule(Parser *p);
 static expr_ty single_subscript_attribute_target_rule(Parser *p);
@@ -671,21 +677,21 @@ static asdl_seq *_gather_115_rule(Parser *p);
 static asdl_seq *_loop0_117_rule(Parser *p);
 static asdl_seq *_loop0_119_rule(Parser *p);
 static asdl_seq *_gather_118_rule(Parser *p);
-static void *_tmp_120_rule(Parser *p);
-static asdl_seq *_loop0_122_rule(Parser *p);
-static asdl_seq *_gather_121_rule(Parser *p);
-static asdl_seq *_loop0_124_rule(Parser *p);
-static asdl_seq *_gather_123_rule(Parser *p);
-static void *_tmp_125_rule(Parser *p);
-static asdl_seq *_loop0_126_rule(Parser *p);
+static asdl_seq *_loop1_120_rule(Parser *p);
+static void *_tmp_121_rule(Parser *p);
+static asdl_seq *_loop0_123_rule(Parser *p);
+static asdl_seq *_gather_122_rule(Parser *p);
+static asdl_seq *_loop0_125_rule(Parser *p);
+static asdl_seq *_gather_124_rule(Parser *p);
+static void *_tmp_126_rule(Parser *p);
 static asdl_seq *_loop0_127_rule(Parser *p);
 static asdl_seq *_loop0_128_rule(Parser *p);
-static void *_tmp_129_rule(Parser *p);
+static asdl_seq *_loop0_129_rule(Parser *p);
 static void *_tmp_130_rule(Parser *p);
-static asdl_seq *_loop0_131_rule(Parser *p);
-static void *_tmp_132_rule(Parser *p);
-static asdl_seq *_loop0_133_rule(Parser *p);
-static void *_tmp_134_rule(Parser *p);
+static void *_tmp_131_rule(Parser *p);
+static asdl_seq *_loop0_132_rule(Parser *p);
+static void *_tmp_133_rule(Parser *p);
+static asdl_seq *_loop0_134_rule(Parser *p);
 static void *_tmp_135_rule(Parser *p);
 static void *_tmp_136_rule(Parser *p);
 static void *_tmp_137_rule(Parser *p);
@@ -702,10 +708,12 @@ static void *_tmp_147_rule(Parser *p);
 static void *_tmp_148_rule(Parser *p);
 static void *_tmp_149_rule(Parser *p);
 static void *_tmp_150_rule(Parser *p);
-static asdl_seq *_loop1_151_rule(Parser *p);
-static asdl_seq *_loop1_152_rule(Parser *p);
-static void *_tmp_153_rule(Parser *p);
-static void *_tmp_154_rule(Parser *p);
+static void *_tmp_151_rule(Parser *p);
+static void *_tmp_152_rule(Parser *p);
+static asdl_seq *_loop1_153_rule(Parser *p);
+static asdl_seq *_loop1_154_rule(Parser *p);
+static void *_tmp_155_rule(Parser *p);
+static void *_tmp_156_rule(Parser *p);
 
 
 // file: statements? $
@@ -12791,9 +12799,9 @@ star_targets_rule(Parser *p)
     return _res;
 }
 
-// star_targets_seq: ','.star_target+ ','?
+// star_targets_list_seq: ','.star_target+ ','?
 static asdl_seq*
-star_targets_seq_rule(Parser *p)
+star_targets_list_seq_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -12807,7 +12815,7 @@ star_targets_seq_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> star_targets_seq[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.star_target+ ','?"));
+        D(fprintf(stderr, "%*c> star_targets_list_seq[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.star_target+ ','?"));
         void *_opt_var;
         UNUSED(_opt_var); // Silence compiler warnings
         asdl_seq * a;
@@ -12817,7 +12825,7 @@ star_targets_seq_rule(Parser *p)
             (_opt_var = _PyPegen_expect_token(p, 12), 1)  // ','?
         )
         {
-            D(fprintf(stderr, "%*c+ star_targets_seq[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.star_target+ ','?"));
+            D(fprintf(stderr, "%*c+ star_targets_list_seq[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.star_target+ ','?"));
             _res = a;
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
@@ -12827,7 +12835,7 @@ star_targets_seq_rule(Parser *p)
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s star_targets_seq[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s star_targets_list_seq[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.star_target+ ','?"));
     }
     _res = NULL;
@@ -12836,11 +12844,82 @@ star_targets_seq_rule(Parser *p)
     return _res;
 }
 
-// star_target:
-//     | '*' (!'*' star_target)
-//     | t_primary '.' NAME !t_lookahead
-//     | t_primary '[' slices ']' !t_lookahead
-//     | star_atom
+// star_targets_tuple_seq: star_target ((',' star_target))+ ','? | star_target ','
+static asdl_seq*
+star_targets_tuple_seq_rule(Parser *p)
+{
+    D(p->level++);
+    if (p->error_indicator) {
+        D(p->level--);
+        return NULL;
+    }
+    asdl_seq* _res = NULL;
+    int _mark = p->mark;
+    { // star_target ((',' star_target))+ ','?
+        if (p->error_indicator) {
+            D(p->level--);
+            return NULL;
+        }
+        D(fprintf(stderr, "%*c> star_targets_tuple_seq[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target ((',' star_target))+ ','?"));
+        void *_opt_var;
+        UNUSED(_opt_var); // Silence compiler warnings
+        expr_ty a;
+        asdl_seq * b;
+        if (
+            (a = star_target_rule(p))  // star_target
+            &&
+            (b = _loop1_120_rule(p))  // ((',' star_target))+
+            &&
+            (_opt_var = _PyPegen_expect_token(p, 12), 1)  // ','?
+        )
+        {
+            D(fprintf(stderr, "%*c+ star_targets_tuple_seq[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target ((',' star_target))+ ','?"));
+            _res = _PyPegen_seq_insert_in_front ( p , a , b );
+            if (_res == NULL && PyErr_Occurred()) {
+                p->error_indicator = 1;
+                D(p->level--);
+                return NULL;
+            }
+            goto done;
+        }
+        p->mark = _mark;
+        D(fprintf(stderr, "%*c%s star_targets_tuple_seq[%d-%d]: %s failed!\n", p->level, ' ',
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target ((',' star_target))+ ','?"));
+    }
+    { // star_target ','
+        if (p->error_indicator) {
+            D(p->level--);
+            return NULL;
+        }
+        D(fprintf(stderr, "%*c> star_targets_tuple_seq[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target ','"));
+        Token * _literal;
+        expr_ty a;
+        if (
+            (a = star_target_rule(p))  // star_target
+            &&
+            (_literal = _PyPegen_expect_token(p, 12))  // token=','
+        )
+        {
+            D(fprintf(stderr, "%*c+ star_targets_tuple_seq[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target ','"));
+            _res = _PyPegen_singleton_seq ( p , a );
+            if (_res == NULL && PyErr_Occurred()) {
+                p->error_indicator = 1;
+                D(p->level--);
+                return NULL;
+            }
+            goto done;
+        }
+        p->mark = _mark;
+        D(fprintf(stderr, "%*c%s star_targets_tuple_seq[%d-%d]: %s failed!\n", p->level, ' ',
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target ','"));
+    }
+    _res = NULL;
+  done:
+    D(p->level--);
+    return _res;
+}
+
+// star_target: '*' (!'*' star_target) | target_with_star_atom
 static expr_ty
 star_target_rule(Parser *p)
 {
@@ -12875,7 +12954,7 @@ star_target_rule(Parser *p)
         if (
             (_literal = _PyPegen_expect_token(p, 16))  // token='*'
             &&
-            (a = _tmp_120_rule(p))  // !'*' star_target
+            (a = _tmp_121_rule(p))  // !'*' star_target
         )
         {
             D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (!'*' star_target)"));
@@ -12900,12 +12979,65 @@ star_target_rule(Parser *p)
         D(fprintf(stderr, "%*c%s star_target[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*' (!'*' star_target)"));
     }
+    { // target_with_star_atom
+        if (p->error_indicator) {
+            D(p->level--);
+            return NULL;
+        }
+        D(fprintf(stderr, "%*c> star_target[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "target_with_star_atom"));
+        expr_ty target_with_star_atom_var;
+        if (
+            (target_with_star_atom_var = target_with_star_atom_rule(p))  // target_with_star_atom
+        )
+        {
+            D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "target_with_star_atom"));
+            _res = target_with_star_atom_var;
+            goto done;
+        }
+        p->mark = _mark;
+        D(fprintf(stderr, "%*c%s star_target[%d-%d]: %s failed!\n", p->level, ' ',
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "target_with_star_atom"));
+    }
+    _res = NULL;
+  done:
+    _PyPegen_insert_memo(p, _mark, star_target_type, _res);
+    D(p->level--);
+    return _res;
+}
+
+// target_with_star_atom:
+//     | t_primary '.' NAME !t_lookahead
+//     | t_primary '[' slices ']' !t_lookahead
+//     | star_atom
+static expr_ty
+target_with_star_atom_rule(Parser *p)
+{
+    D(p->level++);
+    if (p->error_indicator) {
+        D(p->level--);
+        return NULL;
+    }
+    expr_ty _res = NULL;
+    if (_PyPegen_is_memoized(p, target_with_star_atom_type, &_res)) {
+        D(p->level--);
+        return _res;
+    }
+    int _mark = p->mark;
+    if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) {
+        p->error_indicator = 1;
+        D(p->level--);
+        return NULL;
+    }
+    int _start_lineno = p->tokens[_mark]->lineno;
+    UNUSED(_start_lineno); // Only used by EXTRA macro
+    int _start_col_offset = p->tokens[_mark]->col_offset;
+    UNUSED(_start_col_offset); // Only used by EXTRA macro
     { // t_primary '.' NAME !t_lookahead
         if (p->error_indicator) {
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> star_target[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "t_primary '.' NAME !t_lookahead"));
+        D(fprintf(stderr, "%*c> target_with_star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "t_primary '.' NAME !t_lookahead"));
         Token * _literal;
         expr_ty a;
         expr_ty b;
@@ -12919,7 +13051,7 @@ star_target_rule(Parser *p)
             _PyPegen_lookahead(0, t_lookahead_rule, p)
         )
         {
-            D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "t_primary '.' NAME !t_lookahead"));
+            D(fprintf(stderr, "%*c+ target_with_star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "t_primary '.' NAME !t_lookahead"));
             Token *_token = _PyPegen_get_last_nonnwhitespace_token(p);
             if (_token == NULL) {
                 D(p->level--);
@@ -12938,7 +13070,7 @@ star_target_rule(Parser *p)
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s star_target[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s target_with_star_atom[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "t_primary '.' NAME !t_lookahead"));
     }
     { // t_primary '[' slices ']' !t_lookahead
@@ -12946,7 +13078,7 @@ star_target_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> star_target[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "t_primary '[' slices ']' !t_lookahead"));
+        D(fprintf(stderr, "%*c> target_with_star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "t_primary '[' slices ']' !t_lookahead"));
         Token * _literal;
         Token * _literal_1;
         expr_ty a;
@@ -12963,7 +13095,7 @@ star_target_rule(Parser *p)
             _PyPegen_lookahead(0, t_lookahead_rule, p)
         )
         {
-            D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "t_primary '[' slices ']' !t_lookahead"));
+            D(fprintf(stderr, "%*c+ target_with_star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "t_primary '[' slices ']' !t_lookahead"));
             Token *_token = _PyPegen_get_last_nonnwhitespace_token(p);
             if (_token == NULL) {
                 D(p->level--);
@@ -12982,7 +13114,7 @@ star_target_rule(Parser *p)
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s star_target[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s target_with_star_atom[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "t_primary '[' slices ']' !t_lookahead"));
     }
     { // star_atom
@@ -12990,32 +13122,32 @@ star_target_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> star_target[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_atom"));
+        D(fprintf(stderr, "%*c> target_with_star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_atom"));
         expr_ty star_atom_var;
         if (
             (star_atom_var = star_atom_rule(p))  // star_atom
         )
         {
-            D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_atom"));
+            D(fprintf(stderr, "%*c+ target_with_star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_atom"));
             _res = star_atom_var;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s star_target[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s target_with_star_atom[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_atom"));
     }
     _res = NULL;
   done:
-    _PyPegen_insert_memo(p, _mark, star_target_type, _res);
+    _PyPegen_insert_memo(p, _mark, target_with_star_atom_type, _res);
     D(p->level--);
     return _res;
 }
 
 // star_atom:
 //     | NAME
-//     | '(' star_target ')'
-//     | '(' star_targets_seq? ')'
-//     | '[' star_targets_seq? ']'
+//     | '(' target_with_star_atom ')'
+//     | '(' star_targets_tuple_seq? ')'
+//     | '[' star_targets_list_seq? ']'
 static expr_ty
 star_atom_rule(Parser *p)
 {
@@ -13059,24 +13191,24 @@ star_atom_rule(Parser *p)
         D(fprintf(stderr, "%*c%s star_atom[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME"));
     }
-    { // '(' star_target ')'
+    { // '(' target_with_star_atom ')'
         if (p->error_indicator) {
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' star_target ')'"));
+        D(fprintf(stderr, "%*c> star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' target_with_star_atom ')'"));
         Token * _literal;
         Token * _literal_1;
         expr_ty a;
         if (
             (_literal = _PyPegen_expect_token(p, 7))  // token='('
             &&
-            (a = star_target_rule(p))  // star_target
+            (a = target_with_star_atom_rule(p))  // target_with_star_atom
             &&
             (_literal_1 = _PyPegen_expect_token(p, 8))  // token=')'
         )
         {
-            D(fprintf(stderr, "%*c+ star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' star_target ')'"));
+            D(fprintf(stderr, "%*c+ star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' target_with_star_atom ')'"));
             _res = _PyPegen_set_expr_context ( p , a , Store );
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
@@ -13087,26 +13219,26 @@ star_atom_rule(Parser *p)
         }
         p->mark = _mark;
         D(fprintf(stderr, "%*c%s star_atom[%d-%d]: %s failed!\n", p->level, ' ',
-                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' star_target ')'"));
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' target_with_star_atom ')'"));
     }
-    { // '(' star_targets_seq? ')'
+    { // '(' star_targets_tuple_seq? ')'
         if (p->error_indicator) {
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' star_targets_seq? ')'"));
+        D(fprintf(stderr, "%*c> star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' star_targets_tuple_seq? ')'"));
         Token * _literal;
         Token * _literal_1;
         void *a;
         if (
             (_literal = _PyPegen_expect_token(p, 7))  // token='('
             &&
-            (a = star_targets_seq_rule(p), 1)  // star_targets_seq?
+            (a = star_targets_tuple_seq_rule(p), 1)  // star_targets_tuple_seq?
             &&
             (_literal_1 = _PyPegen_expect_token(p, 8))  // token=')'
         )
         {
-            D(fprintf(stderr, "%*c+ star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' star_targets_seq? ')'"));
+            D(fprintf(stderr, "%*c+ star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' star_targets_tuple_seq? ')'"));
             Token *_token = _PyPegen_get_last_nonnwhitespace_token(p);
             if (_token == NULL) {
                 D(p->level--);
@@ -13126,26 +13258,26 @@ star_atom_rule(Parser *p)
         }
         p->mark = _mark;
         D(fprintf(stderr, "%*c%s star_atom[%d-%d]: %s failed!\n", p->level, ' ',
-                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' star_targets_seq? ')'"));
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' star_targets_tuple_seq? ')'"));
     }
-    { // '[' star_targets_seq? ']'
+    { // '[' star_targets_list_seq? ']'
         if (p->error_indicator) {
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'[' star_targets_seq? ']'"));
+        D(fprintf(stderr, "%*c> star_atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'[' star_targets_list_seq? ']'"));
         Token * _literal;
         Token * _literal_1;
         void *a;
         if (
             (_literal = _PyPegen_expect_token(p, 9))  // token='['
             &&
-            (a = star_targets_seq_rule(p), 1)  // star_targets_seq?
+            (a = star_targets_list_seq_rule(p), 1)  // star_targets_list_seq?
             &&
             (_literal_1 = _PyPegen_expect_token(p, 10))  // token=']'
         )
         {
-            D(fprintf(stderr, "%*c+ star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'[' star_targets_seq? ']'"));
+            D(fprintf(stderr, "%*c+ star_atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'[' star_targets_list_seq? ']'"));
             Token *_token = _PyPegen_get_last_nonnwhitespace_token(p);
             if (_token == NULL) {
                 D(p->level--);
@@ -13165,7 +13297,7 @@ star_atom_rule(Parser *p)
         }
         p->mark = _mark;
         D(fprintf(stderr, "%*c%s star_atom[%d-%d]: %s failed!\n", p->level, ' ',
-                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'[' star_targets_seq? ']'"));
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'[' star_targets_list_seq? ']'"));
     }
     _res = NULL;
   done:
@@ -13397,7 +13529,7 @@ del_targets_rule(Parser *p)
         UNUSED(_opt_var); // Silence compiler warnings
         asdl_seq * a;
         if (
-            (a = _gather_121_rule(p))  // ','.del_target+
+            (a = _gather_122_rule(p))  // ','.del_target+
             &&
             (_opt_var = _PyPegen_expect_token(p, 12), 1)  // ','?
         )
@@ -13738,7 +13870,7 @@ targets_rule(Parser *p)
         UNUSED(_opt_var); // Silence compiler warnings
         asdl_seq * a;
         if (
-            (a = _gather_123_rule(p))  // ','.target+
+            (a = _gather_124_rule(p))  // ','.target+
             &&
             (_opt_var = _PyPegen_expect_token(p, 12), 1)  // ','?
         )
@@ -14452,7 +14584,7 @@ invalid_arguments_rule(Parser *p)
             &&
             (_literal = _PyPegen_expect_token(p, 12))  // token=','
             &&
-            (_opt_var = _tmp_125_rule(p), 1)  // [args | expression for_if_clauses]
+            (_opt_var = _tmp_126_rule(p), 1)  // [args | expression for_if_clauses]
         )
         {
             D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]"));
@@ -14710,7 +14842,7 @@ invalid_assignment_rule(Parser *p)
         D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions* ':' expression"));
         Token * _literal;
         Token * _literal_1;
-        asdl_seq * _loop0_126_var;
+        asdl_seq * _loop0_127_var;
         expr_ty a;
         expr_ty expression_var;
         if (
@@ -14718,7 +14850,7 @@ invalid_assignment_rule(Parser *p)
             &&
             (_literal = _PyPegen_expect_token(p, 12))  // token=','
             &&
-            (_loop0_126_var = _loop0_126_rule(p))  // star_named_expressions*
+            (_loop0_127_var = _loop0_127_rule(p))  // star_named_expressions*
             &&
             (_literal_1 = _PyPegen_expect_token(p, 11))  // token=':'
             &&
@@ -14775,10 +14907,10 @@ invalid_assignment_rule(Parser *p)
         }
         D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* star_expressions '='"));
         Token * _literal;
-        asdl_seq * _loop0_127_var;
+        asdl_seq * _loop0_128_var;
         expr_ty a;
         if (
-            (_loop0_127_var = _loop0_127_rule(p))  // ((star_targets '='))*
+            (_loop0_128_var = _loop0_128_rule(p))  // ((star_targets '='))*
             &&
             (a = star_expressions_rule(p))  // star_expressions
             &&
@@ -14805,10 +14937,10 @@ invalid_assignment_rule(Parser *p)
         }
         D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* yield_expr '='"));
         Token * _literal;
-        asdl_seq * _loop0_128_var;
+        asdl_seq * _loop0_129_var;
         expr_ty a;
         if (
-            (_loop0_128_var = _loop0_128_rule(p))  // ((star_targets '='))*
+            (_loop0_129_var = _loop0_129_rule(p))  // ((star_targets '='))*
             &&
             (a = yield_expr_rule(p))  // yield_expr
             &&
@@ -14834,7 +14966,7 @@ invalid_assignment_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)"));
-        void *_tmp_129_var;
+        void *_tmp_130_var;
         expr_ty a;
         AugOperator* augassign_var;
         if (
@@ -14842,7 +14974,7 @@ invalid_assignment_rule(Parser *p)
             &&
             (augassign_var = augassign_rule(p))  // augassign
             &&
-            (_tmp_129_var = _tmp_129_rule(p))  // yield_expr | star_expressions
+            (_tmp_130_var = _tmp_130_rule(p))  // yield_expr | star_expressions
         )
         {
             D(fprintf(stderr, "%*c+ invalid_assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)"));
@@ -15098,11 +15230,11 @@ invalid_comprehension_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '(' | '{') starred_expression for_if_clauses"));
-        void *_tmp_130_var;
+        void *_tmp_131_var;
         expr_ty a;
         asdl_seq* for_if_clauses_var;
         if (
-            (_tmp_130_var = _tmp_130_rule(p))  // '[' | '(' | '{'
+            (_tmp_131_var = _tmp_131_rule(p))  // '[' | '(' | '{'
             &&
             (a = starred_expression_rule(p))  // starred_expression
             &&
@@ -15199,13 +15331,13 @@ invalid_parameters_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default* (slash_with_default | param_with_default+) param_no_default"));
-        asdl_seq * _loop0_131_var;
-        void *_tmp_132_var;
+        asdl_seq * _loop0_132_var;
+        void *_tmp_133_var;
         arg_ty param_no_default_var;
         if (
-            (_loop0_131_var = _loop0_131_rule(p))  // param_no_default*
+            (_loop0_132_var = _loop0_132_rule(p))  // param_no_default*
             &&
-            (_tmp_132_var = _tmp_132_rule(p))  // slash_with_default | param_with_default+
+            (_tmp_133_var = _tmp_133_rule(p))  // slash_with_default | param_with_default+
             &&
             (param_no_default_var = param_no_default_rule(p))  // param_no_default
         )
@@ -15247,13 +15379,13 @@ invalid_lambda_parameters_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default* (lambda_slash_with_default | lambda_param_with_default+) lambda_param_no_default"));
-        asdl_seq * _loop0_133_var;
-        void *_tmp_134_var;
+        asdl_seq * _loop0_134_var;
+        void *_tmp_135_var;
         arg_ty lambda_param_no_default_var;
         if (
-            (_loop0_133_var = _loop0_133_rule(p))  // lambda_param_no_default*
+            (_loop0_134_var = _loop0_134_rule(p))  // lambda_param_no_default*
             &&
-            (_tmp_134_var = _tmp_134_rule(p))  // lambda_slash_with_default | lambda_param_with_default+
+            (_tmp_135_var = _tmp_135_rule(p))  // lambda_slash_with_default | lambda_param_with_default+
             &&
             (lambda_param_no_default_var = lambda_param_no_default_rule(p))  // lambda_param_no_default
         )
@@ -15295,11 +15427,11 @@ invalid_star_etc_rule(Parser *p)
         }
         D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))"));
         Token * _literal;
-        void *_tmp_135_var;
+        void *_tmp_136_var;
         if (
             (_literal = _PyPegen_expect_token(p, 16))  // token='*'
             &&
-            (_tmp_135_var = _tmp_135_rule(p))  // ')' | ',' (')' | '**')
+            (_tmp_136_var = _tmp_136_rule(p))  // ')' | ',' (')' | '**')
         )
         {
             D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))"));
@@ -15369,11 +15501,11 @@ invalid_lambda_star_etc_rule(Parser *p)
         }
         D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))"));
         Token * _literal;
-        void *_tmp_136_var;
+        void *_tmp_137_var;
         if (
             (_literal = _PyPegen_expect_token(p, 16))  // token='*'
             &&
-            (_tmp_136_var = _tmp_136_rule(p))  // ':' | ',' (':' | '**')
+            (_tmp_137_var = _tmp_137_rule(p))  // ':' | ',' (':' | '**')
         )
         {
             D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))"));
@@ -16882,12 +17014,12 @@ _loop1_22_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> _loop1_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')"));
-        void *_tmp_137_var;
+        void *_tmp_138_var;
         while (
-            (_tmp_137_var = _tmp_137_rule(p))  // star_targets '='
+            (_tmp_138_var = _tmp_138_rule(p))  // star_targets '='
         )
         {
-            _res = _tmp_137_var;
+            _res = _tmp_138_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -17390,12 +17522,12 @@ _loop0_31_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> _loop0_31[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')"));
-        void *_tmp_138_var;
+        void *_tmp_139_var;
         while (
-            (_tmp_138_var = _tmp_138_rule(p))  // '.' | '...'
+            (_tmp_139_var = _tmp_139_rule(p))  // '.' | '...'
         )
         {
-            _res = _tmp_138_var;
+            _res = _tmp_139_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -17456,12 +17588,12 @@ _loop1_32_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> _loop1_32[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')"));
-        void *_tmp_139_var;
+        void *_tmp_140_var;
         while (
-            (_tmp_139_var = _tmp_139_rule(p))  // '.' | '...'
+            (_tmp_140_var = _tmp_140_rule(p))  // '.' | '...'
         )
         {
-            _res = _tmp_139_var;
+            _res = _tmp_140_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -19618,12 +19750,12 @@ _loop1_68_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> _loop1_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)"));
-        void *_tmp_140_var;
+        void *_tmp_141_var;
         while (
-            (_tmp_140_var = _tmp_140_rule(p))  // '@' named_expression NEWLINE
+            (_tmp_141_var = _tmp_141_rule(p))  // '@' named_expression NEWLINE
         )
         {
-            _res = _tmp_140_var;
+            _res = _tmp_141_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -19736,12 +19868,12 @@ _loop1_70_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> _loop1_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)"));
-        void *_tmp_141_var;
+        void *_tmp_142_var;
         while (
-            (_tmp_141_var = _tmp_141_rule(p))  // ',' star_expression
+            (_tmp_142_var = _tmp_142_rule(p))  // ',' star_expression
         )
         {
-            _res = _tmp_141_var;
+            _res = _tmp_142_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -19921,12 +20053,12 @@ _loop1_73_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> _loop1_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)"));
-        void *_tmp_142_var;
+        void *_tmp_143_var;
         while (
-            (_tmp_142_var = _tmp_142_rule(p))  // ',' expression
+            (_tmp_143_var = _tmp_143_rule(p))  // ',' expression
         )
         {
-            _res = _tmp_142_var;
+            _res = _tmp_143_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -20951,12 +21083,12 @@ _loop1_88_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> _loop1_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)"));
-        void *_tmp_143_var;
+        void *_tmp_144_var;
         while (
-            (_tmp_143_var = _tmp_143_rule(p))  // 'or' conjunction
+            (_tmp_144_var = _tmp_144_rule(p))  // 'or' conjunction
         )
         {
-            _res = _tmp_143_var;
+            _res = _tmp_144_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -21022,12 +21154,12 @@ _loop1_89_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> _loop1_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)"));
-        void *_tmp_144_var;
+        void *_tmp_145_var;
         while (
-            (_tmp_144_var = _tmp_144_rule(p))  // 'and' inversion
+            (_tmp_145_var = _tmp_145_rule(p))  // 'and' inversion
         )
         {
-            _res = _tmp_144_var;
+            _res = _tmp_145_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -21943,12 +22075,12 @@ _loop0_104_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> _loop0_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)"));
-        void *_tmp_145_var;
+        void *_tmp_146_var;
         while (
-            (_tmp_145_var = _tmp_145_rule(p))  // 'if' disjunction
+            (_tmp_146_var = _tmp_146_rule(p))  // 'if' disjunction
         )
         {
-            _res = _tmp_145_var;
+            _res = _tmp_146_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -22009,12 +22141,12 @@ _loop0_105_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> _loop0_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)"));
-        void *_tmp_146_var;
+        void *_tmp_147_var;
         while (
-            (_tmp_146_var = _tmp_146_rule(p))  // 'if' disjunction
+            (_tmp_147_var = _tmp_147_rule(p))  // 'if' disjunction
         )
         {
-            _res = _tmp_146_var;
+            _res = _tmp_147_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -22080,7 +22212,7 @@ _loop0_107_rule(Parser *p)
         while (
             (_literal = _PyPegen_expect_token(p, 12))  // token=','
             &&
-            (elem = _tmp_147_rule(p))  // starred_expression | named_expression !'='
+            (elem = _tmp_148_rule(p))  // starred_expression | named_expression !'='
         )
         {
             _res = elem;
@@ -22143,7 +22275,7 @@ _gather_106_rule(Parser *p)
         void *elem;
         asdl_seq * seq;
         if (
-            (elem = _tmp_147_rule(p))  // starred_expression | named_expression !'='
+            (elem = _tmp_148_rule(p))  // starred_expression | named_expression !'='
             &&
             (seq = _loop0_107_rule(p))  // _loop0_107
         )
@@ -22689,12 +22821,12 @@ _loop0_117_rule(Parser *p)
             return NULL;
         }
         D(fprintf(stderr, "%*c> _loop0_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)"));
-        void *_tmp_148_var;
+        void *_tmp_149_var;
         while (
-            (_tmp_148_var = _tmp_148_rule(p))  // ',' star_target
+            (_tmp_149_var = _tmp_149_rule(p))  // ',' star_target
         )
         {
-            _res = _tmp_148_var;
+            _res = _tmp_149_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -22842,9 +22974,80 @@ _gather_118_rule(Parser *p)
     return _res;
 }
 
-// _tmp_120: !'*' star_target
+// _loop1_120: (',' star_target)
+static asdl_seq *
+_loop1_120_rule(Parser *p)
+{
+    D(p->level++);
+    if (p->error_indicator) {
+        D(p->level--);
+        return NULL;
+    }
+    void *_res = NULL;
+    int _mark = p->mark;
+    int _start_mark = p->mark;
+    void **_children = PyMem_Malloc(sizeof(void *));
+    if (!_children) {
+        p->error_indicator = 1;
+        PyErr_NoMemory();
+        D(p->level--);
+        return NULL;
+    }
+    ssize_t _children_capacity = 1;
+    ssize_t _n = 0;
+    { // (',' star_target)
+        if (p->error_indicator) {
+            D(p->level--);
+            return NULL;
+        }
+        D(fprintf(stderr, "%*c> _loop1_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)"));
+        void *_tmp_150_var;
+        while (
+            (_tmp_150_var = _tmp_150_rule(p))  // ',' star_target
+        )
+        {
+            _res = _tmp_150_var;
+            if (_n == _children_capacity) {
+                _children_capacity *= 2;
+                void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
+                if (!_new_children) {
+                    p->error_indicator = 1;
+                    PyErr_NoMemory();
+                    D(p->level--);
+                    return NULL;
+                }
+                _children = _new_children;
+            }
+            _children[_n++] = _res;
+            _mark = p->mark;
+        }
+        p->mark = _mark;
+        D(fprintf(stderr, "%*c%s _loop1_120[%d-%d]: %s failed!\n", p->level, ' ',
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)"));
+    }
+    if (_n == 0 || p->error_indicator) {
+        PyMem_Free(_children);
+        D(p->level--);
+        return NULL;
+    }
+    asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena);
+    if (!_seq) {
+        PyMem_Free(_children);
+        p->error_indicator = 1;
+        PyErr_NoMemory();
+        D(p->level--);
+        return NULL;
+    }
+    for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);
+    PyMem_Free(_children);
+    _PyPegen_insert_memo(p, _start_mark, _loop1_120_type, _seq);
+    D(p->level--);
+    return _seq;
+}
+
+// _tmp_121: !'*' star_target
 static void *
-_tmp_120_rule(Parser *p)
+_tmp_121_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -22858,7 +23061,7 @@ _tmp_120_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target"));
+        D(fprintf(stderr, "%*c> _tmp_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target"));
         expr_ty star_target_var;
         if (
             _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 16)  // token='*'
@@ -22866,12 +23069,12 @@ _tmp_120_rule(Parser *p)
             (star_target_var = star_target_rule(p))  // star_target
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target"));
+            D(fprintf(stderr, "%*c+ _tmp_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target"));
             _res = star_target_var;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_121[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "!'*' star_target"));
     }
     _res = NULL;
@@ -22880,9 +23083,9 @@ _tmp_120_rule(Parser *p)
     return _res;
 }
 
-// _loop0_122: ',' del_target
+// _loop0_123: ',' del_target
 static asdl_seq *
-_loop0_122_rule(Parser *p)
+_loop0_123_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -22906,7 +23109,7 @@ _loop0_122_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _loop0_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target"));
+        D(fprintf(stderr, "%*c> _loop0_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target"));
         Token * _literal;
         expr_ty elem;
         while (
@@ -22937,7 +23140,7 @@ _loop0_122_rule(Parser *p)
             _mark = p->mark;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _loop0_122[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _loop0_123[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' del_target"));
     }
     asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena);
@@ -22950,14 +23153,14 @@ _loop0_122_rule(Parser *p)
     }
     for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);
     PyMem_Free(_children);
-    _PyPegen_insert_memo(p, _start_mark, _loop0_122_type, _seq);
+    _PyPegen_insert_memo(p, _start_mark, _loop0_123_type, _seq);
     D(p->level--);
     return _seq;
 }
 
-// _gather_121: del_target _loop0_122
+// _gather_122: del_target _loop0_123
 static asdl_seq *
-_gather_121_rule(Parser *p)
+_gather_122_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -22966,27 +23169,27 @@ _gather_121_rule(Parser *p)
     }
     asdl_seq * _res = NULL;
     int _mark = p->mark;
-    { // del_target _loop0_122
+    { // del_target _loop0_123
         if (p->error_indicator) {
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _gather_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_122"));
+        D(fprintf(stderr, "%*c> _gather_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_123"));
         expr_ty elem;
         asdl_seq * seq;
         if (
             (elem = del_target_rule(p))  // del_target
             &&
-            (seq = _loop0_122_rule(p))  // _loop0_122
+            (seq = _loop0_123_rule(p))  // _loop0_123
         )
         {
-            D(fprintf(stderr, "%*c+ _gather_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_122"));
+            D(fprintf(stderr, "%*c+ _gather_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_123"));
             _res = _PyPegen_seq_insert_in_front(p, elem, seq);
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _gather_121[%d-%d]: %s failed!\n", p->level, ' ',
-                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_122"));
+        D(fprintf(stderr, "%*c%s _gather_122[%d-%d]: %s failed!\n", p->level, ' ',
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_123"));
     }
     _res = NULL;
   done:
@@ -22994,9 +23197,9 @@ _gather_121_rule(Parser *p)
     return _res;
 }
 
-// _loop0_124: ',' target
+// _loop0_125: ',' target
 static asdl_seq *
-_loop0_124_rule(Parser *p)
+_loop0_125_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23020,7 +23223,7 @@ _loop0_124_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _loop0_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' target"));
+        D(fprintf(stderr, "%*c> _loop0_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' target"));
         Token * _literal;
         expr_ty elem;
         while (
@@ -23051,7 +23254,7 @@ _loop0_124_rule(Parser *p)
             _mark = p->mark;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _loop0_124[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _loop0_125[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' target"));
     }
     asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena);
@@ -23064,14 +23267,14 @@ _loop0_124_rule(Parser *p)
     }
     for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);
     PyMem_Free(_children);
-    _PyPegen_insert_memo(p, _start_mark, _loop0_124_type, _seq);
+    _PyPegen_insert_memo(p, _start_mark, _loop0_125_type, _seq);
     D(p->level--);
     return _seq;
 }
 
-// _gather_123: target _loop0_124
+// _gather_124: target _loop0_125
 static asdl_seq *
-_gather_123_rule(Parser *p)
+_gather_124_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23080,27 +23283,27 @@ _gather_123_rule(Parser *p)
     }
     asdl_seq * _res = NULL;
     int _mark = p->mark;
-    { // target _loop0_124
+    { // target _loop0_125
         if (p->error_indicator) {
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _gather_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "target _loop0_124"));
+        D(fprintf(stderr, "%*c> _gather_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "target _loop0_125"));
         expr_ty elem;
         asdl_seq * seq;
         if (
             (elem = target_rule(p))  // target
             &&
-            (seq = _loop0_124_rule(p))  // _loop0_124
+            (seq = _loop0_125_rule(p))  // _loop0_125
         )
         {
-            D(fprintf(stderr, "%*c+ _gather_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "target _loop0_124"));
+            D(fprintf(stderr, "%*c+ _gather_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "target _loop0_125"));
             _res = _PyPegen_seq_insert_in_front(p, elem, seq);
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _gather_123[%d-%d]: %s failed!\n", p->level, ' ',
-                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "target _loop0_124"));
+        D(fprintf(stderr, "%*c%s _gather_124[%d-%d]: %s failed!\n", p->level, ' ',
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "target _loop0_125"));
     }
     _res = NULL;
   done:
@@ -23108,9 +23311,9 @@ _gather_123_rule(Parser *p)
     return _res;
 }
 
-// _tmp_125: args | expression for_if_clauses
+// _tmp_126: args | expression for_if_clauses
 static void *
-_tmp_125_rule(Parser *p)
+_tmp_126_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23124,18 +23327,18 @@ _tmp_125_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args"));
+        D(fprintf(stderr, "%*c> _tmp_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args"));
         expr_ty args_var;
         if (
             (args_var = args_rule(p))  // args
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args"));
+            D(fprintf(stderr, "%*c+ _tmp_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args"));
             _res = args_var;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_126[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args"));
     }
     { // expression for_if_clauses
@@ -23143,7 +23346,7 @@ _tmp_125_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses"));
+        D(fprintf(stderr, "%*c> _tmp_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses"));
         expr_ty expression_var;
         asdl_seq* for_if_clauses_var;
         if (
@@ -23152,12 +23355,12 @@ _tmp_125_rule(Parser *p)
             (for_if_clauses_var = for_if_clauses_rule(p))  // for_if_clauses
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses"));
+            D(fprintf(stderr, "%*c+ _tmp_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses"));
             _res = _PyPegen_dummy_name(p, expression_var, for_if_clauses_var);
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_126[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression for_if_clauses"));
     }
     _res = NULL;
@@ -23166,9 +23369,9 @@ _tmp_125_rule(Parser *p)
     return _res;
 }
 
-// _loop0_126: star_named_expressions
+// _loop0_127: star_named_expressions
 static asdl_seq *
-_loop0_126_rule(Parser *p)
+_loop0_127_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23192,7 +23395,7 @@ _loop0_126_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _loop0_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions"));
+        D(fprintf(stderr, "%*c> _loop0_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions"));
         asdl_seq* star_named_expressions_var;
         while (
             (star_named_expressions_var = star_named_expressions_rule(p))  // star_named_expressions
@@ -23214,7 +23417,7 @@ _loop0_126_rule(Parser *p)
             _mark = p->mark;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _loop0_126[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _loop0_127[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expressions"));
     }
     asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena);
@@ -23227,14 +23430,14 @@ _loop0_126_rule(Parser *p)
     }
     for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);
     PyMem_Free(_children);
-    _PyPegen_insert_memo(p, _start_mark, _loop0_126_type, _seq);
+    _PyPegen_insert_memo(p, _start_mark, _loop0_127_type, _seq);
     D(p->level--);
     return _seq;
 }
 
-// _loop0_127: (star_targets '=')
+// _loop0_128: (star_targets '=')
 static asdl_seq *
-_loop0_127_rule(Parser *p)
+_loop0_128_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23258,13 +23461,13 @@ _loop0_127_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _loop0_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')"));
-        void *_tmp_149_var;
+        D(fprintf(stderr, "%*c> _loop0_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')"));
+        void *_tmp_151_var;
         while (
-            (_tmp_149_var = _tmp_149_rule(p))  // star_targets '='
+            (_tmp_151_var = _tmp_151_rule(p))  // star_targets '='
         )
         {
-            _res = _tmp_149_var;
+            _res = _tmp_151_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -23280,7 +23483,7 @@ _loop0_127_rule(Parser *p)
             _mark = p->mark;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _loop0_127[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _loop0_128[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')"));
     }
     asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena);
@@ -23293,14 +23496,14 @@ _loop0_127_rule(Parser *p)
     }
     for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);
     PyMem_Free(_children);
-    _PyPegen_insert_memo(p, _start_mark, _loop0_127_type, _seq);
+    _PyPegen_insert_memo(p, _start_mark, _loop0_128_type, _seq);
     D(p->level--);
     return _seq;
 }
 
-// _loop0_128: (star_targets '=')
+// _loop0_129: (star_targets '=')
 static asdl_seq *
-_loop0_128_rule(Parser *p)
+_loop0_129_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23324,13 +23527,13 @@ _loop0_128_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _loop0_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')"));
-        void *_tmp_150_var;
+        D(fprintf(stderr, "%*c> _loop0_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')"));
+        void *_tmp_152_var;
         while (
-            (_tmp_150_var = _tmp_150_rule(p))  // star_targets '='
+            (_tmp_152_var = _tmp_152_rule(p))  // star_targets '='
         )
         {
-            _res = _tmp_150_var;
+            _res = _tmp_152_var;
             if (_n == _children_capacity) {
                 _children_capacity *= 2;
                 void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -23346,7 +23549,7 @@ _loop0_128_rule(Parser *p)
             _mark = p->mark;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _loop0_128[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _loop0_129[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')"));
     }
     asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena);
@@ -23359,14 +23562,14 @@ _loop0_128_rule(Parser *p)
     }
     for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);
     PyMem_Free(_children);
-    _PyPegen_insert_memo(p, _start_mark, _loop0_128_type, _seq);
+    _PyPegen_insert_memo(p, _start_mark, _loop0_129_type, _seq);
     D(p->level--);
     return _seq;
 }
 
-// _tmp_129: yield_expr | star_expressions
+// _tmp_130: yield_expr | star_expressions
 static void *
-_tmp_129_rule(Parser *p)
+_tmp_130_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23380,18 +23583,18 @@ _tmp_129_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+        D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
         expr_ty yield_expr_var;
         if (
             (yield_expr_var = yield_expr_rule(p))  // yield_expr
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+            D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
             _res = yield_expr_var;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
     }
     { // star_expressions
@@ -23399,18 +23602,18 @@ _tmp_129_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+        D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
         expr_ty star_expressions_var;
         if (
             (star_expressions_var = star_expressions_rule(p))  // star_expressions
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+            D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
             _res = star_expressions_var;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
     }
     _res = NULL;
@@ -23419,9 +23622,9 @@ _tmp_129_rule(Parser *p)
     return _res;
 }
 
-// _tmp_130: '[' | '(' | '{'
+// _tmp_131: '[' | '(' | '{'
 static void *
-_tmp_130_rule(Parser *p)
+_tmp_131_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23435,18 +23638,18 @@ _tmp_130_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['"));
+        D(fprintf(stderr, "%*c> _tmp_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 9))  // token='['
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['"));
+            D(fprintf(stderr, "%*c+ _tmp_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_131[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['"));
     }
     { // '('
@@ -23454,18 +23657,18 @@ _tmp_130_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('"));
+        D(fprintf(stderr, "%*c> _tmp_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 7))  // token='('
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('"));
+            D(fprintf(stderr, "%*c+ _tmp_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_131[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('"));
     }
     { // '{'
@@ -23473,18 +23676,18 @@ _tmp_130_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'"));
+        D(fprintf(stderr, "%*c> _tmp_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 25))  // token='{'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'"));
+            D(fprintf(stderr, "%*c+ _tmp_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_131[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'"));
     }
     _res = NULL;
@@ -23493,9 +23696,9 @@ _tmp_130_rule(Parser *p)
     return _res;
 }
 
-// _loop0_131: param_no_default
+// _loop0_132: param_no_default
 static asdl_seq *
-_loop0_131_rule(Parser *p)
+_loop0_132_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23519,7 +23722,7 @@ _loop0_131_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _loop0_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+        D(fprintf(stderr, "%*c> _loop0_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
         arg_ty param_no_default_var;
         while (
             (param_no_default_var = param_no_default_rule(p))  // param_no_default
@@ -23541,7 +23744,7 @@ _loop0_131_rule(Parser *p)
             _mark = p->mark;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _loop0_131[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _loop0_132[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
     }
     asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena);
@@ -23554,14 +23757,14 @@ _loop0_131_rule(Parser *p)
     }
     for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);
     PyMem_Free(_children);
-    _PyPegen_insert_memo(p, _start_mark, _loop0_131_type, _seq);
+    _PyPegen_insert_memo(p, _start_mark, _loop0_132_type, _seq);
     D(p->level--);
     return _seq;
 }
 
-// _tmp_132: slash_with_default | param_with_default+
+// _tmp_133: slash_with_default | param_with_default+
 static void *
-_tmp_132_rule(Parser *p)
+_tmp_133_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23575,18 +23778,18 @@ _tmp_132_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default"));
+        D(fprintf(stderr, "%*c> _tmp_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default"));
         SlashWithDefault* slash_with_default_var;
         if (
             (slash_with_default_var = slash_with_default_rule(p))  // slash_with_default
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default"));
+            D(fprintf(stderr, "%*c+ _tmp_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default"));
             _res = slash_with_default_var;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_133[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default"));
     }
     { // param_with_default+
@@ -23594,18 +23797,18 @@ _tmp_132_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default+"));
-        asdl_seq * _loop1_151_var;
+        D(fprintf(stderr, "%*c> _tmp_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default+"));
+        asdl_seq * _loop1_153_var;
         if (
-            (_loop1_151_var = _loop1_151_rule(p))  // param_with_default+
+            (_loop1_153_var = _loop1_153_rule(p))  // param_with_default+
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_with_default+"));
-            _res = _loop1_151_var;
+            D(fprintf(stderr, "%*c+ _tmp_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_with_default+"));
+            _res = _loop1_153_var;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_133[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default+"));
     }
     _res = NULL;
@@ -23614,9 +23817,9 @@ _tmp_132_rule(Parser *p)
     return _res;
 }
 
-// _loop0_133: lambda_param_no_default
+// _loop0_134: lambda_param_no_default
 static asdl_seq *
-_loop0_133_rule(Parser *p)
+_loop0_134_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23640,7 +23843,7 @@ _loop0_133_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _loop0_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+        D(fprintf(stderr, "%*c> _loop0_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
         arg_ty lambda_param_no_default_var;
         while (
             (lambda_param_no_default_var = lambda_param_no_default_rule(p))  // lambda_param_no_default
@@ -23662,7 +23865,7 @@ _loop0_133_rule(Parser *p)
             _mark = p->mark;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _loop0_133[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _loop0_134[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default"));
     }
     asdl_seq *_seq = _Py_asdl_seq_new(_n, p->arena);
@@ -23675,14 +23878,14 @@ _loop0_133_rule(Parser *p)
     }
     for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);
     PyMem_Free(_children);
-    _PyPegen_insert_memo(p, _start_mark, _loop0_133_type, _seq);
+    _PyPegen_insert_memo(p, _start_mark, _loop0_134_type, _seq);
     D(p->level--);
     return _seq;
 }
 
-// _tmp_134: lambda_slash_with_default | lambda_param_with_default+
+// _tmp_135: lambda_slash_with_default | lambda_param_with_default+
 static void *
-_tmp_134_rule(Parser *p)
+_tmp_135_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23696,18 +23899,18 @@ _tmp_134_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default"));
+        D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default"));
         SlashWithDefault* lambda_slash_with_default_var;
         if (
             (lambda_slash_with_default_var = lambda_slash_with_default_rule(p))  // lambda_slash_with_default
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default"));
+            D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default"));
             _res = lambda_slash_with_default_var;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default"));
     }
     { // lambda_param_with_default+
@@ -23715,18 +23918,18 @@ _tmp_134_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+"));
-        asdl_seq * _loop1_152_var;
+        D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+"));
+        asdl_seq * _loop1_154_var;
         if (
-            (_loop1_152_var = _loop1_152_rule(p))  // lambda_param_with_default+
+            (_loop1_154_var = _loop1_154_rule(p))  // lambda_param_with_default+
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+"));
-            _res = _loop1_152_var;
+            D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+"));
+            _res = _loop1_154_var;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default+"));
     }
     _res = NULL;
@@ -23735,9 +23938,9 @@ _tmp_134_rule(Parser *p)
     return _res;
 }
 
-// _tmp_135: ')' | ',' (')' | '**')
+// _tmp_136: ')' | ',' (')' | '**')
 static void *
-_tmp_135_rule(Parser *p)
+_tmp_136_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23751,18 +23954,18 @@ _tmp_135_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
+        D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 8))  // token=')'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
+            D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'"));
     }
     { // ',' (')' | '**')
@@ -23770,21 +23973,21 @@ _tmp_135_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')"));
+        D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')"));
         Token * _literal;
-        void *_tmp_153_var;
+        void *_tmp_155_var;
         if (
             (_literal = _PyPegen_expect_token(p, 12))  // token=','
             &&
-            (_tmp_153_var = _tmp_153_rule(p))  // ')' | '**'
+            (_tmp_155_var = _tmp_155_rule(p))  // ')' | '**'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')"));
-            _res = _PyPegen_dummy_name(p, _literal, _tmp_153_var);
+            D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')"));
+            _res = _PyPegen_dummy_name(p, _literal, _tmp_155_var);
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (')' | '**')"));
     }
     _res = NULL;
@@ -23793,9 +23996,9 @@ _tmp_135_rule(Parser *p)
     return _res;
 }
 
-// _tmp_136: ':' | ',' (':' | '**')
+// _tmp_137: ':' | ',' (':' | '**')
 static void *
-_tmp_136_rule(Parser *p)
+_tmp_137_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23809,18 +24012,18 @@ _tmp_136_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
+        D(fprintf(stderr, "%*c> _tmp_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 11))  // token=':'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
+            D(fprintf(stderr, "%*c+ _tmp_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_137[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'"));
     }
     { // ',' (':' | '**')
@@ -23828,21 +24031,21 @@ _tmp_136_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')"));
+        D(fprintf(stderr, "%*c> _tmp_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')"));
         Token * _literal;
-        void *_tmp_154_var;
+        void *_tmp_156_var;
         if (
             (_literal = _PyPegen_expect_token(p, 12))  // token=','
             &&
-            (_tmp_154_var = _tmp_154_rule(p))  // ':' | '**'
+            (_tmp_156_var = _tmp_156_rule(p))  // ':' | '**'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')"));
-            _res = _PyPegen_dummy_name(p, _literal, _tmp_154_var);
+            D(fprintf(stderr, "%*c+ _tmp_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')"));
+            _res = _PyPegen_dummy_name(p, _literal, _tmp_156_var);
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_137[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (':' | '**')"));
     }
     _res = NULL;
@@ -23851,9 +24054,9 @@ _tmp_136_rule(Parser *p)
     return _res;
 }
 
-// _tmp_137: star_targets '='
+// _tmp_138: star_targets '='
 static void *
-_tmp_137_rule(Parser *p)
+_tmp_138_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23867,7 +24070,7 @@ _tmp_137_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
+        D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
         Token * _literal;
         expr_ty z;
         if (
@@ -23876,7 +24079,7 @@ _tmp_137_rule(Parser *p)
             (_literal = _PyPegen_expect_token(p, 22))  // token='='
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
+            D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
             _res = z;
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
@@ -23886,7 +24089,7 @@ _tmp_137_rule(Parser *p)
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_137[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='"));
     }
     _res = NULL;
@@ -23895,9 +24098,9 @@ _tmp_137_rule(Parser *p)
     return _res;
 }
 
-// _tmp_138: '.' | '...'
+// _tmp_139: '.' | '...'
 static void *
-_tmp_138_rule(Parser *p)
+_tmp_139_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23911,18 +24114,18 @@ _tmp_138_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'"));
+        D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 23))  // token='.'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'"));
+            D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'"));
     }
     { // '...'
@@ -23930,18 +24133,18 @@ _tmp_138_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'"));
+        D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 52))  // token='...'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'"));
+            D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'"));
     }
     _res = NULL;
@@ -23950,9 +24153,9 @@ _tmp_138_rule(Parser *p)
     return _res;
 }
 
-// _tmp_139: '.' | '...'
+// _tmp_140: '.' | '...'
 static void *
-_tmp_139_rule(Parser *p)
+_tmp_140_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -23966,18 +24169,18 @@ _tmp_139_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'"));
+        D(fprintf(stderr, "%*c> _tmp_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 23))  // token='.'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'"));
+            D(fprintf(stderr, "%*c+ _tmp_140[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_140[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'"));
     }
     { // '...'
@@ -23985,18 +24188,18 @@ _tmp_139_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'"));
+        D(fprintf(stderr, "%*c> _tmp_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 52))  // token='...'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'"));
+            D(fprintf(stderr, "%*c+ _tmp_140[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_140[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'"));
     }
     _res = NULL;
@@ -24005,9 +24208,9 @@ _tmp_139_rule(Parser *p)
     return _res;
 }
 
-// _tmp_140: '@' named_expression NEWLINE
+// _tmp_141: '@' named_expression NEWLINE
 static void *
-_tmp_140_rule(Parser *p)
+_tmp_141_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24021,7 +24224,7 @@ _tmp_140_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE"));
+        D(fprintf(stderr, "%*c> _tmp_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE"));
         Token * _literal;
         expr_ty f;
         Token * newline_var;
@@ -24033,7 +24236,7 @@ _tmp_140_rule(Parser *p)
             (newline_var = _PyPegen_expect_token(p, NEWLINE))  // token='NEWLINE'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_140[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE"));
+            D(fprintf(stderr, "%*c+ _tmp_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE"));
             _res = f;
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
@@ -24043,7 +24246,7 @@ _tmp_140_rule(Parser *p)
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_140[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_141[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE"));
     }
     _res = NULL;
@@ -24052,9 +24255,9 @@ _tmp_140_rule(Parser *p)
     return _res;
 }
 
-// _tmp_141: ',' star_expression
+// _tmp_142: ',' star_expression
 static void *
-_tmp_141_rule(Parser *p)
+_tmp_142_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24068,7 +24271,7 @@ _tmp_141_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression"));
+        D(fprintf(stderr, "%*c> _tmp_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression"));
         Token * _literal;
         expr_ty c;
         if (
@@ -24077,7 +24280,7 @@ _tmp_141_rule(Parser *p)
             (c = star_expression_rule(p))  // star_expression
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression"));
+            D(fprintf(stderr, "%*c+ _tmp_142[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression"));
             _res = c;
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
@@ -24087,7 +24290,7 @@ _tmp_141_rule(Parser *p)
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_141[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_142[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression"));
     }
     _res = NULL;
@@ -24096,9 +24299,9 @@ _tmp_141_rule(Parser *p)
     return _res;
 }
 
-// _tmp_142: ',' expression
+// _tmp_143: ',' expression
 static void *
-_tmp_142_rule(Parser *p)
+_tmp_143_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24112,7 +24315,7 @@ _tmp_142_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
+        D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
         Token * _literal;
         expr_ty c;
         if (
@@ -24121,7 +24324,7 @@ _tmp_142_rule(Parser *p)
             (c = expression_rule(p))  // expression
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_142[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression"));
+            D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression"));
             _res = c;
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
@@ -24131,7 +24334,7 @@ _tmp_142_rule(Parser *p)
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_142[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_143[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression"));
     }
     _res = NULL;
@@ -24140,9 +24343,9 @@ _tmp_142_rule(Parser *p)
     return _res;
 }
 
-// _tmp_143: 'or' conjunction
+// _tmp_144: 'or' conjunction
 static void *
-_tmp_143_rule(Parser *p)
+_tmp_144_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24156,7 +24359,7 @@ _tmp_143_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction"));
+        D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction"));
         Token * _keyword;
         expr_ty c;
         if (
@@ -24165,7 +24368,7 @@ _tmp_143_rule(Parser *p)
             (c = conjunction_rule(p))  // conjunction
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction"));
+            D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction"));
             _res = c;
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
@@ -24175,7 +24378,7 @@ _tmp_143_rule(Parser *p)
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_143[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction"));
     }
     _res = NULL;
@@ -24184,9 +24387,9 @@ _tmp_143_rule(Parser *p)
     return _res;
 }
 
-// _tmp_144: 'and' inversion
+// _tmp_145: 'and' inversion
 static void *
-_tmp_144_rule(Parser *p)
+_tmp_145_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24200,7 +24403,7 @@ _tmp_144_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion"));
+        D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion"));
         Token * _keyword;
         expr_ty c;
         if (
@@ -24209,7 +24412,7 @@ _tmp_144_rule(Parser *p)
             (c = inversion_rule(p))  // inversion
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion"));
+            D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion"));
             _res = c;
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
@@ -24219,7 +24422,7 @@ _tmp_144_rule(Parser *p)
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion"));
     }
     _res = NULL;
@@ -24228,9 +24431,9 @@ _tmp_144_rule(Parser *p)
     return _res;
 }
 
-// _tmp_145: 'if' disjunction
+// _tmp_146: 'if' disjunction
 static void *
-_tmp_145_rule(Parser *p)
+_tmp_146_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24244,7 +24447,7 @@ _tmp_145_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
+        D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
         Token * _keyword;
         expr_ty z;
         if (
@@ -24253,7 +24456,7 @@ _tmp_145_rule(Parser *p)
             (z = disjunction_rule(p))  // disjunction
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
+            D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
             _res = z;
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
@@ -24263,7 +24466,7 @@ _tmp_145_rule(Parser *p)
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction"));
     }
     _res = NULL;
@@ -24272,9 +24475,9 @@ _tmp_145_rule(Parser *p)
     return _res;
 }
 
-// _tmp_146: 'if' disjunction
+// _tmp_147: 'if' disjunction
 static void *
-_tmp_146_rule(Parser *p)
+_tmp_147_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24288,7 +24491,7 @@ _tmp_146_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
+        D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
         Token * _keyword;
         expr_ty z;
         if (
@@ -24297,7 +24500,7 @@ _tmp_146_rule(Parser *p)
             (z = disjunction_rule(p))  // disjunction
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
+            D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
             _res = z;
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
@@ -24307,7 +24510,7 @@ _tmp_146_rule(Parser *p)
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction"));
     }
     _res = NULL;
@@ -24316,9 +24519,9 @@ _tmp_146_rule(Parser *p)
     return _res;
 }
 
-// _tmp_147: starred_expression | named_expression !'='
+// _tmp_148: starred_expression | named_expression !'='
 static void *
-_tmp_147_rule(Parser *p)
+_tmp_148_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24332,18 +24535,18 @@ _tmp_147_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression"));
+        D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression"));
         expr_ty starred_expression_var;
         if (
             (starred_expression_var = starred_expression_rule(p))  // starred_expression
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression"));
+            D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression"));
             _res = starred_expression_var;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression"));
     }
     { // named_expression !'='
@@ -24351,7 +24554,7 @@ _tmp_147_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression !'='"));
+        D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression !'='"));
         expr_ty named_expression_var;
         if (
             (named_expression_var = named_expression_rule(p))  // named_expression
@@ -24359,12 +24562,12 @@ _tmp_147_rule(Parser *p)
             _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22)  // token='='
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression !'='"));
+            D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression !'='"));
             _res = named_expression_var;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "named_expression !'='"));
     }
     _res = NULL;
@@ -24373,9 +24576,9 @@ _tmp_147_rule(Parser *p)
     return _res;
 }
 
-// _tmp_148: ',' star_target
+// _tmp_149: ',' star_target
 static void *
-_tmp_148_rule(Parser *p)
+_tmp_149_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24389,7 +24592,7 @@ _tmp_148_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target"));
+        D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target"));
         Token * _literal;
         expr_ty c;
         if (
@@ -24398,7 +24601,7 @@ _tmp_148_rule(Parser *p)
             (c = star_target_rule(p))  // star_target
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target"));
+            D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target"));
             _res = c;
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
@@ -24408,7 +24611,7 @@ _tmp_148_rule(Parser *p)
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target"));
     }
     _res = NULL;
@@ -24417,9 +24620,53 @@ _tmp_148_rule(Parser *p)
     return _res;
 }
 
-// _tmp_149: star_targets '='
+// _tmp_150: ',' star_target
 static void *
-_tmp_149_rule(Parser *p)
+_tmp_150_rule(Parser *p)
+{
+    D(p->level++);
+    if (p->error_indicator) {
+        D(p->level--);
+        return NULL;
+    }
+    void * _res = NULL;
+    int _mark = p->mark;
+    { // ',' star_target
+        if (p->error_indicator) {
+            D(p->level--);
+            return NULL;
+        }
+        D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target"));
+        Token * _literal;
+        expr_ty c;
+        if (
+            (_literal = _PyPegen_expect_token(p, 12))  // token=','
+            &&
+            (c = star_target_rule(p))  // star_target
+        )
+        {
+            D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target"));
+            _res = c;
+            if (_res == NULL && PyErr_Occurred()) {
+                p->error_indicator = 1;
+                D(p->level--);
+                return NULL;
+            }
+            goto done;
+        }
+        p->mark = _mark;
+        D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ',
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target"));
+    }
+    _res = NULL;
+  done:
+    D(p->level--);
+    return _res;
+}
+
+// _tmp_151: star_targets '='
+static void *
+_tmp_151_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24433,7 +24680,7 @@ _tmp_149_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
+        D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
         Token * _literal;
         expr_ty star_targets_var;
         if (
@@ -24442,12 +24689,12 @@ _tmp_149_rule(Parser *p)
             (_literal = _PyPegen_expect_token(p, 22))  // token='='
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
+            D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
             _res = _PyPegen_dummy_name(p, star_targets_var, _literal);
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='"));
     }
     _res = NULL;
@@ -24456,9 +24703,9 @@ _tmp_149_rule(Parser *p)
     return _res;
 }
 
-// _tmp_150: star_targets '='
+// _tmp_152: star_targets '='
 static void *
-_tmp_150_rule(Parser *p)
+_tmp_152_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24472,7 +24719,7 @@ _tmp_150_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
+        D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
         Token * _literal;
         expr_ty star_targets_var;
         if (
@@ -24481,12 +24728,12 @@ _tmp_150_rule(Parser *p)
             (_literal = _PyPegen_expect_token(p, 22))  // token='='
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
+            D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
             _res = _PyPegen_dummy_name(p, star_targets_var, _literal);
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='"));
     }
     _res = NULL;
@@ -24495,9 +24742,9 @@ _tmp_150_rule(Parser *p)
     return _res;
 }
 
-// _loop1_151: param_with_default
+// _loop1_153: param_with_default
 static asdl_seq *
-_loop1_151_rule(Parser *p)
+_loop1_153_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24521,7 +24768,7 @@ _loop1_151_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _loop1_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
+        D(fprintf(stderr, "%*c> _loop1_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
         NameDefaultPair* param_with_default_var;
         while (
             (param_with_default_var = param_with_default_rule(p))  // param_with_default
@@ -24543,7 +24790,7 @@ _loop1_151_rule(Parser *p)
             _mark = p->mark;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _loop1_151[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _loop1_153[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default"));
     }
     if (_n == 0 || p->error_indicator) {
@@ -24561,14 +24808,14 @@ _loop1_151_rule(Parser *p)
     }
     for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);
     PyMem_Free(_children);
-    _PyPegen_insert_memo(p, _start_mark, _loop1_151_type, _seq);
+    _PyPegen_insert_memo(p, _start_mark, _loop1_153_type, _seq);
     D(p->level--);
     return _seq;
 }
 
-// _loop1_152: lambda_param_with_default
+// _loop1_154: lambda_param_with_default
 static asdl_seq *
-_loop1_152_rule(Parser *p)
+_loop1_154_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24592,7 +24839,7 @@ _loop1_152_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _loop1_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
+        D(fprintf(stderr, "%*c> _loop1_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
         NameDefaultPair* lambda_param_with_default_var;
         while (
             (lambda_param_with_default_var = lambda_param_with_default_rule(p))  // lambda_param_with_default
@@ -24614,7 +24861,7 @@ _loop1_152_rule(Parser *p)
             _mark = p->mark;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _loop1_152[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _loop1_154[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default"));
     }
     if (_n == 0 || p->error_indicator) {
@@ -24632,14 +24879,14 @@ _loop1_152_rule(Parser *p)
     }
     for (int i = 0; i < _n; i++) asdl_seq_SET(_seq, i, _children[i]);
     PyMem_Free(_children);
-    _PyPegen_insert_memo(p, _start_mark, _loop1_152_type, _seq);
+    _PyPegen_insert_memo(p, _start_mark, _loop1_154_type, _seq);
     D(p->level--);
     return _seq;
 }
 
-// _tmp_153: ')' | '**'
+// _tmp_155: ')' | '**'
 static void *
-_tmp_153_rule(Parser *p)
+_tmp_155_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24653,18 +24900,18 @@ _tmp_153_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
+        D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 8))  // token=')'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
+            D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'"));
     }
     { // '**'
@@ -24672,18 +24919,18 @@ _tmp_153_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'"));
+        D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 35))  // token='**'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'"));
+            D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'"));
     }
     _res = NULL;
@@ -24692,9 +24939,9 @@ _tmp_153_rule(Parser *p)
     return _res;
 }
 
-// _tmp_154: ':' | '**'
+// _tmp_156: ':' | '**'
 static void *
-_tmp_154_rule(Parser *p)
+_tmp_156_rule(Parser *p)
 {
     D(p->level++);
     if (p->error_indicator) {
@@ -24708,18 +24955,18 @@ _tmp_154_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
+        D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 11))  // token=':'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
+            D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'"));
     }
     { // '**'
@@ -24727,18 +24974,18 @@ _tmp_154_rule(Parser *p)
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'"));
+        D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'"));
         Token * _literal;
         if (
             (_literal = _PyPegen_expect_token(p, 35))  // token='**'
         )
         {
-            D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'"));
+            D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'"));
             _res = _literal;
             goto done;
         }
         p->mark = _mark;
-        D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ',
+        D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'"));
     }
     _res = NULL;
index fb0c4aff9d3d000720d3692be2238ec4612fb852..c852e5b827c0cc06332068aaede67af797799ada 100644 (file)
@@ -410,7 +410,7 @@ fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end,
     Parser *p2 = _PyPegen_Parser_New(tok, Py_fstring_input, p->flags, p->feature_version,
                                      NULL, p->arena);
     p2->starting_lineno = t->lineno + lines - 1;
-    p2->starting_col_offset = p->tok->first_lineno == p->tok->lineno ? t->col_offset + cols : cols;
+    p2->starting_col_offset = t->col_offset + cols;
 
     expr = _PyPegen_run_parser(p2);
 
index 199b09c4d8c41e61fda2938c81733eb3859a35c2..614012df9b12a2bf8ce0a87ba5a40a654152ab0a 100644 (file)
@@ -2619,6 +2619,11 @@ zip_next(zipobject *lz)
             PyTuple_SET_ITEM(result, i, item);
             Py_DECREF(olditem);
         }
+        // bpo-42536: The GC may have untracked this result tuple. Since we're
+        // recycling it, make sure it's tracked again:
+        if (!_PyObject_GC_IS_TRACKED(result)) {
+            _PyObject_GC_TRACK(result);
+        }
     } else {
         result = PyTuple_New(tuplesize);
         if (result == NULL)
index 397ac34e8073df4c570d5a019e92b06e1b88f180..ddc090988f1589507b1f5e76ccec1ac78f95f671 100644 (file)
@@ -1165,6 +1165,13 @@ set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works)
             return 0;
         }
 
+#ifdef __linux__
+        if (errno == EBADF) {
+            // On Linux, ioctl(FIOCLEX) will fail with EBADF for O_PATH file descriptors
+            // Fall through to the fcntl() path
+        }
+        else
+#endif
         if (errno != ENOTTY && errno != EACCES) {
             if (raise)
                 PyErr_SetFromErrno(PyExc_OSError);
index 299ccc08c44f8348ae3a13bbe69b9401eb607090..7fdeb314d5261b97ceea5c876b82a58bc2a238d5 100644 (file)
@@ -4,7 +4,7 @@
 
 static const char cprt[] =
 "\
-Copyright (c) 2001-2020 Python Software Foundation.\n\
+Copyright (c) 2001-2021 Python Software Foundation.\n\
 All Rights Reserved.\n\
 \n\
 Copyright (c) 2000 BeOpen.com.\n\
index 70748dc584f0bc95222da1194bebb4acc5a6798a..04540989f3043371a1493b624e6aa257f50dfd33 100644 (file)
@@ -64,11 +64,15 @@ extern Py_EXPORTED_SYMBOL grammar _PyParser_Grammar; /* From graminit.c */
 static void flush_io(void);
 static PyObject *run_mod(mod_ty, PyObject *, PyObject *, PyObject *,
                           PyCompilerFlags *, PyArena *);
-static PyObject *run_pyc_file(FILE *, const char *, PyObject *, PyObject *,
+static PyObject *run_pyc_file(FILE *, PyObject *, PyObject *,
                               PyCompilerFlags *);
 static void err_input(perrdetail *);
 static void err_free(perrdetail *);
 static int PyRun_InteractiveOneObjectEx(FILE *, PyObject *, PyCompilerFlags *);
+static PyObject* pyrun_file(FILE *fp, PyObject *filename, int start,
+                            PyObject *globals, PyObject *locals, int closeit,
+                            PyCompilerFlags *flags);
+
 
 /* Parse input from a file and execute it */
 int
@@ -310,82 +314,89 @@ PyRun_InteractiveOneFlags(FILE *fp, const char *filename_str, PyCompilerFlags *f
    the file type, and, if we may close it, at the first few bytes. */
 
 static int
-maybe_pyc_file(FILE *fp, const char* filename, const char* ext, int closeit)
+maybe_pyc_file(FILE *fp, PyObject *filename, int closeit)
 {
-    if (strcmp(ext, ".pyc") == 0)
+    PyObject *ext = PyUnicode_FromString(".pyc");
+    if (ext == NULL) {
+        return -1;
+    }
+    Py_ssize_t endswith = PyUnicode_Tailmatch(filename, ext, 0, PY_SSIZE_T_MAX, +1);
+    Py_DECREF(ext);
+    if (endswith) {
         return 1;
+    }
 
     /* Only look into the file if we are allowed to close it, since
        it then should also be seekable. */
-    if (closeit) {
-        /* Read only two bytes of the magic. If the file was opened in
-           text mode, the bytes 3 and 4 of the magic (\r\n) might not
-           be read as they are on disk. */
-        unsigned int halfmagic = PyImport_GetMagicNumber() & 0xFFFF;
-        unsigned char buf[2];
-        /* Mess:  In case of -x, the stream is NOT at its start now,
-           and ungetc() was used to push back the first newline,
-           which makes the current stream position formally undefined,
-           and a x-platform nightmare.
-           Unfortunately, we have no direct way to know whether -x
-           was specified.  So we use a terrible hack:  if the current
-           stream position is not 0, we assume -x was specified, and
-           give up.  Bug 132850 on SourceForge spells out the
-           hopelessness of trying anything else (fseek and ftell
-           don't work predictably x-platform for text-mode files).
-        */
-        int ispyc = 0;
-        if (ftell(fp) == 0) {
-            if (fread(buf, 1, 2, fp) == 2 &&
-                ((unsigned int)buf[1]<<8 | buf[0]) == halfmagic)
-                ispyc = 1;
-            rewind(fp);
-        }
-        return ispyc;
+    if (!closeit) {
+        return 0;
     }
-    return 0;
+
+    /* Read only two bytes of the magic. If the file was opened in
+       text mode, the bytes 3 and 4 of the magic (\r\n) might not
+       be read as they are on disk. */
+    unsigned int halfmagic = PyImport_GetMagicNumber() & 0xFFFF;
+    unsigned char buf[2];
+    /* Mess:  In case of -x, the stream is NOT at its start now,
+       and ungetc() was used to push back the first newline,
+       which makes the current stream position formally undefined,
+       and a x-platform nightmare.
+       Unfortunately, we have no direct way to know whether -x
+       was specified.  So we use a terrible hack:  if the current
+       stream position is not 0, we assume -x was specified, and
+       give up.  Bug 132850 on SourceForge spells out the
+       hopelessness of trying anything else (fseek and ftell
+       don't work predictably x-platform for text-mode files).
+    */
+    int ispyc = 0;
+    if (ftell(fp) == 0) {
+        if (fread(buf, 1, 2, fp) == 2 &&
+            ((unsigned int)buf[1]<<8 | buf[0]) == halfmagic)
+            ispyc = 1;
+        rewind(fp);
+    }
+    return ispyc;
 }
 
+
 static int
-set_main_loader(PyObject *d, const char *filename, const char *loader_name)
+set_main_loader(PyObject *d, PyObject *filename, const char *loader_name)
 {
-    PyObject *filename_obj, *bootstrap, *loader_type = NULL, *loader;
-    int result = 0;
-
-    filename_obj = PyUnicode_DecodeFSDefault(filename);
-    if (filename_obj == NULL)
-        return -1;
     PyInterpreterState *interp = _PyInterpreterState_GET();
-    bootstrap = PyObject_GetAttrString(interp->importlib,
-                                       "_bootstrap_external");
-    if (bootstrap != NULL) {
-        loader_type = PyObject_GetAttrString(bootstrap, loader_name);
-        Py_DECREF(bootstrap);
+    PyObject *bootstrap = PyObject_GetAttrString(interp->importlib,
+                                                 "_bootstrap_external");
+    if (bootstrap == NULL) {
+        return -1;
     }
+
+    PyObject *loader_type = PyObject_GetAttrString(bootstrap, loader_name);
+    Py_DECREF(bootstrap);
     if (loader_type == NULL) {
-        Py_DECREF(filename_obj);
         return -1;
     }
-    loader = PyObject_CallFunction(loader_type, "sN", "__main__", filename_obj);
+
+    PyObject *loader = PyObject_CallFunction(loader_type,
+                                             "sO", "__main__", filename);
     Py_DECREF(loader_type);
     if (loader == NULL) {
         return -1;
     }
+
     if (PyDict_SetItemString(d, "__loader__", loader) < 0) {
-        result = -1;
+        Py_DECREF(loader);
+        return -1;
     }
     Py_DECREF(loader);
-    return result;
+    return 0;
 }
 
-int
-PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
-                        PyCompilerFlags *flags)
+
+static int
+pyrun_simple_file(FILE *fp, PyObject *filename, int closeit,
+                  PyCompilerFlags *flags)
 {
     PyObject *m, *d, *v;
-    const char *ext;
     int set_file_name = 0, ret = -1;
-    size_t len;
 
     m = PyImport_AddModule("__main__");
     if (m == NULL)
@@ -393,29 +404,29 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
     Py_INCREF(m);
     d = PyModule_GetDict(m);
     if (PyDict_GetItemString(d, "__file__") == NULL) {
-        PyObject *f;
-        f = PyUnicode_DecodeFSDefault(filename);
-        if (f == NULL)
-            goto done;
-        if (PyDict_SetItemString(d, "__file__", f) < 0) {
-            Py_DECREF(f);
+        if (PyDict_SetItemString(d, "__file__", filename) < 0) {
             goto done;
         }
         if (PyDict_SetItemString(d, "__cached__", Py_None) < 0) {
-            Py_DECREF(f);
             goto done;
         }
         set_file_name = 1;
-        Py_DECREF(f);
     }
-    len = strlen(filename);
-    ext = filename + len - (len > 4 ? 4 : 0);
-    if (maybe_pyc_file(fp, filename, ext, closeit)) {
+
+    int pyc = maybe_pyc_file(fp, filename, closeit);
+    if (pyc < 0) {
+        goto done;
+    }
+
+    if (pyc) {
         FILE *pyc_fp;
         /* Try to run a pyc file. First, re-open in binary */
-        if (closeit)
+        if (closeit) {
             fclose(fp);
-        if ((pyc_fp = _Py_fopen(filename, "rb")) == NULL) {
+        }
+
+        pyc_fp = _Py_fopen_obj(filename, "rb");
+        if (pyc_fp == NULL) {
             fprintf(stderr, "python: Can't reopen .pyc file\n");
             goto done;
         }
@@ -426,17 +437,17 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
             fclose(pyc_fp);
             goto done;
         }
-        v = run_pyc_file(pyc_fp, filename, d, d, flags);
+        v = run_pyc_file(pyc_fp, d, d, flags);
     } else {
         /* When running from stdin, leave __main__.__loader__ alone */
-        if (strcmp(filename, "<stdin>") != 0 &&
+        if (PyUnicode_CompareWithASCIIString(filename, "<stdin>") != 0 &&
             set_main_loader(d, filename, "SourceFileLoader") < 0) {
             fprintf(stderr, "python: failed to set __main__.__loader__\n");
             ret = -1;
             goto done;
         }
-        v = PyRun_FileExFlags(fp, filename, Py_file_input, d, d,
-                              closeit, flags);
+        v = pyrun_file(fp, filename, Py_file_input, d, d,
+                       closeit, flags);
     }
     flush_io();
     if (v == NULL) {
@@ -459,6 +470,21 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
     return ret;
 }
 
+
+int
+PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
+                        PyCompilerFlags *flags)
+{
+    PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename);
+    if (filename_obj == NULL) {
+        return -1;
+    }
+    int res = pyrun_simple_file(fp, filename_obj, closeit, flags);
+    Py_DECREF(filename_obj);
+    return res;
+}
+
+
 int
 PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags)
 {
@@ -1081,24 +1107,18 @@ PyRun_StringFlags(const char *str, int start, PyObject *globals,
     return ret;
 }
 
-PyObject *
-PyRun_FileExFlags(FILE *fp, const char *filename_str, int start, PyObject *globals,
-                  PyObject *locals, int closeit, PyCompilerFlags *flags)
+
+static PyObject *
+pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals,
+           PyObject *locals, int closeit, PyCompilerFlags *flags)
 {
-    PyObject *ret = NULL;
+    PyArena *arena = PyArena_New();
+    if (arena == NULL) {
+        return NULL;
+    }
+
     mod_ty mod;
-    PyArena *arena = NULL;
-    PyObject *filename;
     int use_peg = _PyInterpreterState_GET()->config._use_peg_parser;
-
-    filename = PyUnicode_DecodeFSDefault(filename_str);
-    if (filename == NULL)
-        goto exit;
-
-    arena = PyArena_New();
-    if (arena == NULL)
-        goto exit;
-
     if (use_peg) {
         mod = PyPegen_ASTFromFileObject(fp, filename, start, NULL, NULL, NULL,
                                         flags, NULL, arena);
@@ -1108,20 +1128,40 @@ PyRun_FileExFlags(FILE *fp, const char *filename_str, int start, PyObject *globa
                                          flags, NULL, arena);
     }
 
-    if (closeit)
+    if (closeit) {
         fclose(fp);
-    if (mod == NULL) {
-        goto exit;
     }
-    ret = run_mod(mod, filename, globals, locals, flags, arena);
 
-exit:
-    Py_XDECREF(filename);
-    if (arena != NULL)
-        PyArena_Free(arena);
+    PyObject *ret;
+    if (mod != NULL) {
+        ret = run_mod(mod, filename, globals, locals, flags, arena);
+    }
+    else {
+        ret = NULL;
+    }
+    PyArena_Free(arena);
+
     return ret;
 }
 
+
+PyObject *
+PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals,
+                  PyObject *locals, int closeit, PyCompilerFlags *flags)
+{
+    PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename);
+    if (filename_obj == NULL) {
+        return NULL;
+    }
+
+    PyObject *res = pyrun_file(fp, filename_obj, start, globals,
+                               locals, closeit, flags);
+    Py_DECREF(filename_obj);
+    return res;
+
+}
+
+
 static void
 flush_io(void)
 {
@@ -1202,8 +1242,8 @@ run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals,
 }
 
 static PyObject *
-run_pyc_file(FILE *fp, const char *filename, PyObject *globals,
-             PyObject *locals, PyCompilerFlags *flags)
+run_pyc_file(FILE *fp, PyObject *globals, PyObject *locals,
+             PyCompilerFlags *flags)
 {
     PyThreadState *tstate = _PyThreadState_GET();
     PyCodeObject *co;
index 99b63af11f8beec518173d59be570d7944417f20..5d3a65cc160e04a46161c0caa50179c6ba65f65c 100644 (file)
@@ -622,7 +622,8 @@ PyTraceBack_Print(PyObject *v, PyObject *f)
     return err;
 }
 
-/* Reverse a string. For example, "abcd" becomes "dcba".
+/* Format an integer in range [0; 0xffffffff] to decimal and write it
+   into the file fd.
 
    This function is signal safe. */
 
index a9ab26056c588ae4b0556e0201e72dca0cb61522..0a36bc16a958b839444089992eaf0e02cfb0eea7 100644 (file)
@@ -1,4 +1,4 @@
-This is Python version 3.9.1
+This is Python version 3.9.2
 ============================
 
 .. image:: https://travis-ci.org/python/cpython.svg?branch=3.9
@@ -22,7 +22,7 @@ This is Python version 3.9.1
    :target: https://python.zulipchat.com
 
 
-Copyright (c) 2001-2020 Python Software Foundation.  All rights reserved.
+Copyright (c) 2001-2021 Python Software Foundation.  All rights reserved.
 
 See the end of this file for further copyright and license information.
 
@@ -250,7 +250,7 @@ See :pep:`596` for Python 3.9 release details.
 Copyright and License Information
 ---------------------------------
 
-Copyright (c) 2001-2020 Python Software Foundation.  All rights reserved.
+Copyright (c) 2001-2021 Python Software Foundation.  All rights reserved.
 
 Copyright (c) 2000 BeOpen.com.  All rights reserved.
 
index 83aa508a46a93e79664d02fc09be9b3be0489ed4..d66e1e2708e758de448e1d31923294272761fdc0 100755 (executable)
@@ -93,6 +93,7 @@ import modulefinder
 import getopt
 import os
 import sys
+import sysconfig
 
 
 # Import the freeze-private modules
@@ -226,7 +227,7 @@ def main():
         extensions_c = 'frozen_extensions.c'
     if ishome:
         print("(Using Python source directory)")
-        binlib = exec_prefix
+        configdir = exec_prefix
         incldir = os.path.join(prefix, 'Include')
         config_h_dir = exec_prefix
         config_c_in = os.path.join(prefix, 'Modules', 'config.c.in')
@@ -235,22 +236,21 @@ def main():
         if win:
             frozendllmain_c = os.path.join(exec_prefix, 'Pc\\frozen_dllmain.c')
     else:
-        binlib = os.path.join(exec_prefix,
-                              'lib', 'python%s' % version,
-                              'config-%s' % flagged_version)
+        configdir = sysconfig.get_config_var('LIBPL')
         incldir = os.path.join(prefix, 'include', 'python%s' % flagged_version)
         config_h_dir = os.path.join(exec_prefix, 'include',
                                     'python%s' % flagged_version)
-        config_c_in = os.path.join(binlib, 'config.c.in')
-        frozenmain_c = os.path.join(binlib, 'frozenmain.c')
-        makefile_in = os.path.join(binlib, 'Makefile')
-        frozendllmain_c = os.path.join(binlib, 'frozen_dllmain.c')
+        config_c_in = os.path.join(configdir, 'config.c.in')
+        frozenmain_c = os.path.join(configdir, 'frozenmain.c')
+        makefile_in = os.path.join(configdir, 'Makefile')
+        frozendllmain_c = os.path.join(configdir, 'frozen_dllmain.c')
+    libdir = sysconfig.get_config_var('LIBDIR')
     supp_sources = []
     defines = []
     includes = ['-I' + incldir, '-I' + config_h_dir]
 
     # sanity check of directories and files
-    check_dirs = [prefix, exec_prefix, binlib, incldir]
+    check_dirs = [prefix, exec_prefix, configdir, incldir]
     if not win:
         # These are not directories on Windows.
         check_dirs = check_dirs + extensions
@@ -457,7 +457,7 @@ def main():
 
     cflags = ['$(OPT)']
     cppflags = defines + includes
-    libs = [os.path.join(binlib, '$(LDLIBRARY)')]
+    libs = [os.path.join(libdir, '$(LDLIBRARY)')]
 
     somevars = {}
     if os.path.exists(makefile_in):
index 33bf5ac821fffc201b6d4a741920070fad04511a..aeaa63e540d8b54b8296f429d77b68a985d5acbe 100755 (executable)
@@ -468,7 +468,7 @@ class InstanceProxy(object):
     def __repr__(self):
         if isinstance(self.attrdict, dict):
             kwargs = ', '.join(["%s=%r" % (arg, val)
-                                for arg, val in self.attrdict.iteritems()])
+                                for arg, val in self.attrdict.items()])
             return '<%s(%s) at remote 0x%x>' % (self.cl_name,
                                                 kwargs, self.address)
         else:
index 518acbe8e4cb2f320ba72a907929f5748821297c..8ed376a7b8554878c97fc9e5eae423a9801fb82c 100644 (file)
@@ -90,7 +90,7 @@ if (-not $skipupload) {
     $d = "$target/$($p[0])/"\r
     & $plink -batch $user@$server mkdir $d\r
     & $plink -batch $user@$server chgrp downloads $d\r
-    & $plink -batch $user@$server chmod g-x,o+rx $d\r
+    & $plink -batch $user@$server chmod o+rx $d\r
     & $pscp -batch $chm.FullName "$user@${server}:$d"\r
     if (-not $?) { throw "Failed to upload $chm" }\r
 \r
@@ -115,7 +115,7 @@ if (-not $skipupload) {
             $sd = "$d$($a.Name)$($p[1])/"\r
             & $plink -batch $user@$server mkdir $sd\r
             & $plink -batch $user@$server chgrp downloads $sd\r
-            & $plink -batch $user@$server chmod g-x,o+rx $sd\r
+            & $plink -batch $user@$server chmod o+rx $sd\r
             & $pscp -batch $msi.FullName "$user@${server}:$sd"\r
             if (-not $?) { throw "Failed to upload $msi" }\r
             & $plink -batch $user@$server chgrp downloads $sd*\r
index ef12198a2183884d85dfdd12a1eaf38c732e6d38..ea456e577e12a991a265ed0df98adcffc2940afa 100644 (file)
@@ -36,15 +36,11 @@ class PyncheWidget:
         else:
             # Is there already a default root for Tk, say because we're
             # running under Guido's IDE? :-) Two conditions say no, either the
-            # import fails or _default_root is None.
-            tkroot = None
-            try:
-                from Tkinter import _default_root
-                tkroot = self.__tkroot = _default_root
-            except ImportError:
-                pass
+            # _default_root is None or it is unset.
+            tkroot = getattr(tkinter, '_default_root', None)
             if not tkroot:
-                tkroot = self.__tkroot = Tk(className='Pynche')
+                tkroot = Tk(className='Pynche')
+            self.__tkroot = tkroot
             # but this isn't our top level widget, so make it invisible
             tkroot.withdraw()
         # create the menubar
index 2d379feb4b7bf0c0556fa76449669d282a7ac5af..1252335472f561421e81454183ad1af445f9e6fc 100755 (executable)
--- a/configure
+++ b/configure
@@ -11072,10 +11072,10 @@ else
       main() {
         pthread_attr_t attr;
         pthread_t id;
-        if (pthread_attr_init(&attr)) exit(-1);
-        if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)) exit(-1);
-        if (pthread_create(&id, &attr, foo, NULL)) exit(-1);
-        exit(0);
+        if (pthread_attr_init(&attr)) return (-1);
+        if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)) return (-1);
+        if (pthread_create(&id, &attr, foo, NULL)) return (-1);
+        return (0);
       }
 _ACEOF
 if ac_fn_c_try_run "$LINENO"; then :
@@ -15083,7 +15083,7 @@ else
   int main()
   {
        /* Success: exit code 0 */
-        exit((((wchar_t) -1) < ((wchar_t) 0)) ? 0 : 1);
+        return ((((wchar_t) -1) < ((wchar_t) 0)) ? 0 : 1);
   }
 
 _ACEOF
@@ -15382,13 +15382,7 @@ _ACEOF
 
 fi
 
-
-case $ac_sys_system in
-    Linux*|GNU*|Darwin|VxWorks)
-       EXT_SUFFIX=.${SOABI}${SHLIB_SUFFIX};;
-    *)
-       EXT_SUFFIX=${SHLIB_SUFFIX};;
-esac
+EXT_SUFFIX=.${SOABI}${SHLIB_SUFFIX}
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking LDVERSION" >&5
 $as_echo_n "checking LDVERSION... " >&6; }
@@ -15464,7 +15458,7 @@ else
 
 int main()
 {
-       exit(((-1)>>3 == -1) ? 0 : 1);
+       return (((-1)>>3 == -1) ? 0 : 1);
 }
 
 _ACEOF
@@ -15934,6 +15928,7 @@ else
 /* end confdefs.h.  */
 
 #include <poll.h>
+#include <unistd.h>
 
 int main()
 {
index c968d149c22d44fffb0c7378ae114dd656992379..972287a9c476613fff5deacb7db9e13a99e84485 100644 (file)
@@ -3313,10 +3313,10 @@ if test "$posix_threads" = "yes"; then
       main() {
         pthread_attr_t attr;
         pthread_t id;
-        if (pthread_attr_init(&attr)) exit(-1);
-        if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)) exit(-1);
-        if (pthread_create(&id, &attr, foo, NULL)) exit(-1);
-        exit(0);
+        if (pthread_attr_init(&attr)) return (-1);
+        if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)) return (-1);
+        if (pthread_create(&id, &attr, foo, NULL)) return (-1);
+        return (0);
       }]])],
       [ac_cv_pthread_system_supported=yes],
       [ac_cv_pthread_system_supported=no],
@@ -4725,7 +4725,7 @@ then
   int main()
   {
        /* Success: exit code 0 */
-        exit((((wchar_t) -1) < ((wchar_t) 0)) ? 0 : 1);
+        return ((((wchar_t) -1) < ((wchar_t) 0)) ? 0 : 1);
   }
   ]])],
   [ac_cv_wchar_t_signed=yes],
@@ -4783,12 +4783,7 @@ if test "$Py_DEBUG" = 'true' -a "$with_trace_refs" != "yes"; then
 fi
 
 AC_SUBST(EXT_SUFFIX)
-case $ac_sys_system in
-    Linux*|GNU*|Darwin|VxWorks)
-       EXT_SUFFIX=.${SOABI}${SHLIB_SUFFIX};;
-    *)
-       EXT_SUFFIX=${SHLIB_SUFFIX};;
-esac
+EXT_SUFFIX=.${SOABI}${SHLIB_SUFFIX}
 
 AC_MSG_CHECKING(LDVERSION)
 LDVERSION='$(VERSION)$(ABIFLAGS)'
@@ -4847,7 +4842,7 @@ AC_CACHE_VAL(ac_cv_rshift_extends_sign, [
 AC_RUN_IFELSE([AC_LANG_SOURCE([[
 int main()
 {
-       exit(((-1)>>3 == -1) ? 0 : 1);
+       return (((-1)>>3 == -1) ? 0 : 1);
 }
 ]])],
 [ac_cv_rshift_extends_sign=yes],
@@ -4994,6 +4989,7 @@ AC_MSG_CHECKING(for broken poll())
 AC_CACHE_VAL(ac_cv_broken_poll,
 AC_RUN_IFELSE([AC_LANG_SOURCE([[
 #include <poll.h>
+#include <unistd.h>
 
 int main()
 {
index bd5f73692441cb0d12b843a91afc9918e1d5b08e..d42eb9d1174ec5f10488736c428483df217488bd 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -1013,7 +1013,7 @@ class PyBuildExt(build_ext):
             os_release = int(os.uname()[2].split('.')[0])
             dep_target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
             if (dep_target and
-                    (tuple(int(n) for n in str(dep_target).split('.')[0:2])
+                    (tuple(int(n) for n in dep_target.split('.')[0:2])
                         < (10, 5) ) ):
                 os_release = 8
             if os_release < 9: