diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2241b0b8aa409e..4e5328282f1224 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -111,6 +111,9 @@ jobs: run: make smelly - name: Check limited ABI symbols run: make check-limited-abi + - name: Check for unsupported C global variables + if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME + run: make check-c-globals build_win32: name: 'Windows (x86)' diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 8836c973f1f579..ddf7dc780b2745 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -86,6 +86,12 @@ Printing and clearing An exception must be set when calling this function. +.. c:function: void PyErr_DisplayException(PyObject *exc) + + Print the standard traceback display of ``exc`` to ``sys.stderr``, including + chained exceptions and notes. + + .. versionadded:: 3.12 Raising exceptions ================== diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 8c90d1e8991c10..cb5d64a50487fe 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -228,3 +228,36 @@ garbage collection runs. Returns the current state, 0 for disabled and 1 for enabled. .. versionadded:: 3.10 + + +Querying Garbage Collector State +-------------------------------- + +The C-API provides the following interface for querying information about +the garbage collector. + +.. c:function:: void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) + + Run supplied *callback* on all live GC-capable objects. *arg* is passed through to + all invocations of *callback*. + + .. warning:: + If new objects are (de)allocated by the callback it is undefined if they + will be visited. + + Garbage collection is disabled during operation. Explicitly running a collection + in the callback may lead to undefined behaviour e.g. visiting the same objects + multiple times or not at all. + + .. versionadded:: 3.12 + +.. c:type:: int (*gcvisitobjects_t)(PyObject *object, void *arg) + + Type of the visitor function to be passed to :c:func:`PyUnstable_GC_VisitObjects`. + *arg* is the same as the *arg* passed to ``PyUnstable_GC_VisitObjects``. + Return ``0`` to continue iteration, return ``1`` to stop iteration. Other return + values are reserved for now so behavior on returning anything else is undefined. + + .. versionadded:: 3.12 + + diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index b50ee3b3803e29..38e324fb6409bc 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -513,7 +513,7 @@ Process-wide parameters program name is ``'/usr/local/bin/python'``, the prefix is ``'/usr/local'``. The returned string points into static storage; the caller should not modify its value. This corresponds to the :makevar:`prefix` variable in the top-level - :file:`Makefile` and the ``--prefix`` argument to the :program:`configure` + :file:`Makefile` and the :option:`--prefix` argument to the :program:`configure` script at build time. The value is available to Python code as ``sys.prefix``. It is only useful on Unix. See also the next function. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 85eb24a495b640..acd4e033dfbc4b 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -78,19 +78,19 @@ used by extension writers. Structure member names do not have a reserved prefix. The header files are typically installed with Python. On Unix, these are located in the directories :file:`{prefix}/include/pythonversion/` and -:file:`{exec_prefix}/include/pythonversion/`, where :envvar:`prefix` and -:envvar:`exec_prefix` are defined by the corresponding parameters to Python's +:file:`{exec_prefix}/include/pythonversion/`, where :option:`prefix <--prefix>` and +:option:`exec_prefix <--exec-prefix>` are defined by the corresponding parameters to Python's :program:`configure` script and *version* is ``'%d.%d' % sys.version_info[:2]``. On Windows, the headers are installed -in :file:`{prefix}/include`, where :envvar:`prefix` is the installation +in :file:`{prefix}/include`, where ``prefix`` is the installation directory specified to the installer. To include the headers, place both directories (if different) on your compiler's search path for includes. Do *not* place the parent directories on the search path and then use ``#include ``; this will break on multi-platform builds since the platform independent headers under -:envvar:`prefix` include the platform specific headers from -:envvar:`exec_prefix`. +:option:`prefix <--prefix>` include the platform specific headers from +:option:`exec_prefix <--exec-prefix>`. C++ users should note that although the API is defined entirely using C, the header files properly declare the entry points to be ``extern "C"``. As a result, diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 84c72e7e108b64..0a12bb9e8c54f0 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -179,6 +179,15 @@ Object Protocol If *o1* and *o2* are the same object, :c:func:`PyObject_RichCompareBool` will always return ``1`` for :const:`Py_EQ` and ``0`` for :const:`Py_NE`. +.. c:function:: PyObject* PyObject_Format(PyObject *obj, PyObject *format_spec) + + Format *obj* using *format_spec*. This is equivalent to the Python + expression ``format(obj, format_spec)``. + + *format_spec* may be ``NULL``. In this case the call is equivalent + to ``format(obj)``. + Returns the formatted string on success, ``NULL`` on failure. + .. c:function:: PyObject* PyObject_Repr(PyObject *o) .. index:: builtin: repr diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 68ab0b5061f434..4cc06d22baaa93 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -133,6 +133,7 @@ function,PyErr_BadInternalCall,3.2,, function,PyErr_CheckSignals,3.2,, function,PyErr_Clear,3.2,, function,PyErr_Display,3.2,, +function,PyErr_DisplayException,3.12,, function,PyErr_ExceptionMatches,3.2,, function,PyErr_Fetch,3.2,, function,PyErr_Format,3.2,, diff --git a/Doc/library/__main__.rst b/Doc/library/__main__.rst index 6a2a7a7317f711..761c88710f9891 100644 --- a/Doc/library/__main__.rst +++ b/Doc/library/__main__.rst @@ -259,7 +259,7 @@ one mentioned below are preferred. See :mod:`venv` for an example of a package with a minimal ``__main__.py`` in the standard library. It doesn't contain a ``if __name__ == '__main__'`` - block. You can invoke it with ``python3 -m venv [directory]``. + block. You can invoke it with ``python -m venv [directory]``. See :mod:`runpy` for more details on the :option:`-m` flag to the interpreter executable. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 9b984243282268..a0900cd25a7731 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -804,6 +804,10 @@ Waiting Primitives .. versionchanged:: 3.11 Passing coroutine objects to ``wait()`` directly is forbidden. + .. versionchanged:: 3.12 + Added support for generators yielding tasks. + + .. function:: as_completed(aws, *, timeout=None) Run :ref:`awaitable objects ` in the *aws* @@ -814,9 +818,6 @@ Waiting Primitives Raises :exc:`TimeoutError` if the timeout occurs before all Futures are done. - .. versionchanged:: 3.10 - Removed the *loop* parameter. - Example:: for coro in as_completed(aws): diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst index 0e266b6a45782a..345b64001c1ace 100644 --- a/Doc/library/email.utils.rst +++ b/Doc/library/email.utils.rst @@ -13,19 +13,17 @@ module: .. function:: localtime(dt=None) - Return local time as an aware datetime object. If called without - arguments, return current time. Otherwise *dt* argument should be a - :class:`~datetime.datetime` instance, and it is converted to the local time - zone according to the system time zone database. If *dt* is naive (that - is, ``dt.tzinfo`` is ``None``), it is assumed to be in local time. In this - case, a positive or zero value for *isdst* causes ``localtime`` to presume - initially that summer time (for example, Daylight Saving Time) is or is not - (respectively) in effect for the specified time. A negative value for - *isdst* causes the ``localtime`` to attempt to divine whether summer time - is in effect for the specified time. - - .. versionadded:: 3.3 + Return local time as an aware datetime object. If called without + arguments, return current time. Otherwise *dt* argument should be a + :class:`~datetime.datetime` instance, and it is converted to the local time + zone according to the system time zone database. If *dt* is naive (that + is, ``dt.tzinfo`` is ``None``), it is assumed to be in local time. The + *isdst* parameter is ignored. + .. versionadded:: 3.3 + + .. deprecated-removed:: 3.12 3.14 + The *isdst* parameter. .. function:: make_msgid(idstring=None, domain=None) diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 988d1a317f5960..6e084101995e25 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -73,7 +73,7 @@ something into it: .. code-block:: shell-session - $ python3 -m venv example + $ python -m venv example $ source example/bin/activate (example) $ python -m pip install wheel diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index d85a17effb04a2..5daadfd3759f4b 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -195,7 +195,7 @@ loops that truncate the stream. if n < 1: raise ValueError('n must be at least one') it = iter(iterable) - while (batch := tuple(islice(it, n))): + while batch := tuple(islice(it, n)): yield batch .. versionadded:: 3.12 @@ -872,11 +872,23 @@ which incur interpreter overhead. (x - 5) (x + 4) (x - 3) expands to: x³ -4x² -17x + 60 """ # polynomial_from_roots([5, -4, 3]) --> [1, -4, -17, 60] - roots = list(map(operator.neg, roots)) - return [ - sum(map(math.prod, combinations(roots, k))) - for k in range(len(roots) + 1) - ] + expansion = [1] + for r in roots: + expansion = convolve(expansion, (1, -r)) + return list(expansion) + + def polynomial_eval(coefficients, x): + """Evaluate a polynomial at a specific value. + + Computes with better numeric stability than Horner's method. + """ + # Evaluate x³ -4x² -17x + 60 at x = 2.5 + # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125 + n = len(coefficients) + if n == 0: + return x * 0 # coerce zero to the type of x + powers = map(pow, repeat(x), reversed(range(n))) + return math.sumprod(coefficients, powers) def iter_index(iterable, value, start=0): "Return indices where a value occurs in a sequence or iterable." @@ -1245,6 +1257,37 @@ which incur interpreter overhead. >>> list(convolve(data, [1, -2, 1])) [20, 0, -36, 24, -20, 20, -20, -4, 16] + >>> from fractions import Fraction + >>> from decimal import Decimal + >>> polynomial_eval([1, -4, -17, 60], x=2) + 18 + >>> x = 2; x**3 - 4*x**2 -17*x + 60 + 18 + >>> polynomial_eval([1, -4, -17, 60], x=2.5) + 8.125 + >>> x = 2.5; x**3 - 4*x**2 -17*x + 60 + 8.125 + >>> polynomial_eval([1, -4, -17, 60], x=Fraction(2, 3)) + Fraction(1274, 27) + >>> x = Fraction(2, 3); x**3 - 4*x**2 -17*x + 60 + Fraction(1274, 27) + >>> polynomial_eval([1, -4, -17, 60], x=Decimal('1.75')) + Decimal('23.359375') + >>> x = Decimal('1.75'); x**3 - 4*x**2 -17*x + 60 + Decimal('23.359375') + >>> polynomial_eval([], 2) + 0 + >>> polynomial_eval([], 2.5) + 0.0 + >>> polynomial_eval([], Fraction(2, 3)) + Fraction(0, 1) + >>> polynomial_eval([], Decimal('1.75')) + Decimal('0.00') + >>> polynomial_eval([11], 7) == 11 + True + >>> polynomial_eval([11, 2], 7) == 11 * 7 + 2 + True + >>> polynomial_from_roots([5, -4, 3]) [1, -4, -17, 60] >>> factored = lambda x: (x - 5) * (x + 4) * (x - 3) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 5b9f49be1fad55..7bb501c5946817 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2858,6 +2858,12 @@ features: Added support for the :class:`~os.PathLike` interface. Added support for :class:`bytes` paths on Windows. + .. versionchanged:: 3.12 + The ``st_ctime`` attribute of a stat result is deprecated on Windows. + The file creation time is properly available as ``st_birthtime``, and + in the future ``st_ctime`` may be changed to return zero or the + metadata change time, if available. + .. function:: stat(path, *, dir_fd=None, follow_symlinks=True) @@ -2973,10 +2979,12 @@ features: .. attribute:: st_ctime - Platform dependent: + Time of most recent metadata change expressed in seconds. - * the time of most recent metadata change on Unix, - * the time of creation on Windows, expressed in seconds. + .. versionchanged:: 3.12 + ``st_ctime`` is deprecated on Windows. Use ``st_birthtime`` for + the file creation time. In the future, ``st_ctime`` will contain + the time of the most recent metadata change, as for other platforms. .. attribute:: st_atime_ns @@ -2989,29 +2997,48 @@ features: .. attribute:: st_ctime_ns - Platform dependent: + Time of most recent metadata change expressed in nanoseconds as an + integer. + + .. versionchanged:: 3.12 + ``st_ctime_ns`` is deprecated on Windows. Use ``st_birthtime_ns`` + for the file creation time. In the future, ``st_ctime`` will contain + the time of the most recent metadata change, as for other platforms. + + .. attribute:: st_birthtime + + Time of file creation expressed in seconds. This attribute is not + always available, and may raise :exc:`AttributeError`. + + .. versionchanged:: 3.12 + ``st_birthtime`` is now available on Windows. + + .. attribute:: st_birthtime_ns - * the time of most recent metadata change on Unix, - * the time of creation on Windows, expressed in nanoseconds as an - integer. + Time of file creation expressed in nanoseconds as an integer. + This attribute is not always available, and may raise + :exc:`AttributeError`. + + .. versionadded:: 3.12 .. note:: The exact meaning and resolution of the :attr:`st_atime`, - :attr:`st_mtime`, and :attr:`st_ctime` attributes depend on the operating - system and the file system. For example, on Windows systems using the FAT - or FAT32 file systems, :attr:`st_mtime` has 2-second resolution, and - :attr:`st_atime` has only 1-day resolution. See your operating system - documentation for details. + :attr:`st_mtime`, :attr:`st_ctime` and :attr:`st_birthtime` attributes + depend on the operating system and the file system. For example, on + Windows systems using the FAT32 file systems, :attr:`st_mtime` has + 2-second resolution, and :attr:`st_atime` has only 1-day resolution. + See your operating system documentation for details. Similarly, although :attr:`st_atime_ns`, :attr:`st_mtime_ns`, - and :attr:`st_ctime_ns` are always expressed in nanoseconds, many - systems do not provide nanosecond precision. On systems that do - provide nanosecond precision, the floating-point object used to - store :attr:`st_atime`, :attr:`st_mtime`, and :attr:`st_ctime` - cannot preserve all of it, and as such will be slightly inexact. - If you need the exact timestamps you should always use - :attr:`st_atime_ns`, :attr:`st_mtime_ns`, and :attr:`st_ctime_ns`. + :attr:`st_ctime_ns` and :attr:`st_birthtime_ns` are always expressed in + nanoseconds, many systems do not provide nanosecond precision. On + systems that do provide nanosecond precision, the floating-point object + used to store :attr:`st_atime`, :attr:`st_mtime`, :attr:`st_ctime` and + :attr:`st_birthtime` cannot preserve all of it, and as such will be + slightly inexact. If you need the exact timestamps you should always use + :attr:`st_atime_ns`, :attr:`st_mtime_ns`, :attr:`st_ctime_ns` and + :attr:`st_birthtime_ns`. On some Unix systems (such as Linux), the following attributes may also be available: @@ -3041,10 +3068,6 @@ features: File generation number. - .. attribute:: st_birthtime - - Time of file creation. - On Solaris and derivatives, the following attributes may also be available: @@ -3117,6 +3140,25 @@ features: files as :const:`S_IFCHR`, :const:`S_IFIFO` or :const:`S_IFBLK` as appropriate. + .. versionchanged:: 3.12 + On Windows, :attr:`st_ctime` is deprecated. Eventually, it will + contain the last metadata change time, for consistency with other + platforms, but for now still contains creation time. + Use :attr:`st_birthtime` for the creation time. + + .. versionchanged:: 3.12 + On Windows, :attr:`st_ino` may now be up to 128 bits, depending + on the file system. Previously it would not be above 64 bits, and + larger file identifiers would be arbitrarily packed. + + .. versionchanged:: 3.12 + On Windows, :attr:`st_rdev` no longer returns a value. Previously + it would contain the same as :attr:`st_dev`, which was incorrect. + + .. versionadded:: 3.12 + Added the :attr:`st_birthtime` member on Windows. + + .. function:: statvfs(path) Perform a :c:func:`statvfs` system call on the given path. The return value is @@ -3909,7 +3951,7 @@ to be ignored. .. note:: - The standard way to exit is ``sys.exit(n)``. :func:`_exit` should + The standard way to exit is :func:`sys.exit(n) `. :func:`!_exit` should normally only be used in the child process after a :func:`fork`. The following exit codes are defined and can be used with :func:`_exit`, diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 4ae12a5d03a78d..5988477af03abd 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -58,7 +58,7 @@ of the debugger is:: :file:`pdb.py` can also be invoked as a script to debug other scripts. For example:: - python3 -m pdb myscript.py + python -m pdb myscript.py When invoked as a script, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally. After post-mortem debugging (or @@ -72,7 +72,7 @@ useful than quitting the debugger upon program's exit. .. versionadded:: 3.7 :file:`pdb.py` now accepts a ``-m`` option that execute modules similar to the way - ``python3 -m`` does. As with a script, the debugger will pause execution just + ``python -m`` does. As with a script, the debugger will pause execution just before the first line of the module. @@ -513,7 +513,7 @@ can be overridden by the local file. :file:`.pdbrc` file):: # Print instance variables (usage "pi classInst") - alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k]) + alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") # Print instance variables in self alias ps pi self diff --git a/Doc/library/random.rst b/Doc/library/random.rst index 4522f5a8d26b9d..098684d7270ffa 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -610,7 +610,8 @@ from the combinatoric iterators in the :mod:`itertools` module: return tuple(pool[i] for i in indices) def random_combination_with_replacement(iterable, r): - "Random selection from itertools.combinations_with_replacement(iterable, r)" + "Choose r elements with replacement. Order the result to match the iterable." + # Result will be in set(itertools.combinations_with_replacement(iterable, r)). pool = tuple(iterable) n = len(pool) indices = sorted(random.choices(range(n), k=r)) diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index b33dbe21b1fa19..acba66258fe8f0 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -292,15 +292,15 @@ Directory and files operations .. versionadded:: 3.8 The *dirs_exist_ok* parameter. -.. function:: rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None) +.. function:: rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None) .. index:: single: directory; deleting Delete an entire directory tree; *path* must point to a directory (but not a symbolic link to a directory). If *ignore_errors* is true, errors resulting from failed removals will be ignored; if false or omitted, such errors are - handled by calling a handler specified by *onerror* or, if that is omitted, - they raise an exception. + handled by calling a handler specified by *onexc* or *onerror* or, if both + are omitted, exceptions are propagated to the caller. This function can support :ref:`paths relative to directory descriptors `. @@ -315,14 +315,17 @@ Directory and files operations otherwise. Applications can use the :data:`rmtree.avoids_symlink_attacks` function attribute to determine which case applies. - If *onerror* is provided, it must be a callable that accepts three - parameters: *function*, *path*, and *excinfo*. + If *onexc* is provided, it must be a callable that accepts three parameters: + *function*, *path*, and *excinfo*. The first parameter, *function*, is the function which raised the exception; it depends on the platform and implementation. The second parameter, *path*, will be the path name passed to *function*. The third parameter, - *excinfo*, will be the exception information returned by - :func:`sys.exc_info`. Exceptions raised by *onerror* will not be caught. + *excinfo*, is the exception that was raised. Exceptions raised by *onexc* + will not be caught. + + The deprecated *onerror* is similar to *onexc*, except that the third + parameter it receives is the tuple returned from :func:`sys.exc_info`. .. audit-event:: shutil.rmtree path,dir_fd shutil.rmtree @@ -337,6 +340,9 @@ Directory and files operations .. versionchanged:: 3.11 The *dir_fd* parameter. + .. versionchanged:: 3.12 + Added the *onexc* parameter, deprecated *onerror*. + .. attribute:: rmtree.avoids_symlink_attacks Indicates whether the current platform and implementation provides a @@ -509,7 +515,7 @@ rmtree example ~~~~~~~~~~~~~~ This example shows how to remove a directory tree on Windows where some -of the files have their read-only bit set. It uses the onerror callback +of the files have their read-only bit set. It uses the onexc callback to clear the readonly bit and reattempt the remove. Any subsequent failure will propagate. :: @@ -521,7 +527,7 @@ will propagate. :: os.chmod(path, stat.S_IWRITE) func(path) - shutil.rmtree(directory, onerror=remove_readonly) + shutil.rmtree(directory, onexc=remove_readonly) .. _archiving-operations: diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index ff036ad56acba8..4b2d13ab3a8fcd 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -272,9 +272,9 @@ Module functions :param float timeout: How many seconds the connection should wait before raising - an exception, if the database is locked by another connection. - If another connection opens a transaction to modify the database, - it will be locked until that transaction is committed. + an :exc:`OperationalError` when a table is locked. + If another connection opens a transaction to modify a table, + that table will be locked until the transaction is committed. Default five seconds. :param int detect_types: @@ -911,7 +911,7 @@ Connection objects Call this method from a different thread to abort any queries that might be executing on the connection. - Aborted queries will raise an exception. + Aborted queries will raise an :exc:`OperationalError`. .. method:: set_authorizer(authorizer_callback) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 30f2a0765cc955..4b60b7c643b62c 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1218,7 +1218,7 @@ SSL sockets also have the following additional methods and attributes: .. method:: SSLSocket.shared_ciphers() - Return the list of ciphers shared by the client during the handshake. Each + Return the list of ciphers available in both the client and server. Each entry of the returned list is a three-value tuple containing the name of the cipher, the version of the SSL protocol that defines its use, and the number of secret bits the cipher uses. :meth:`~SSLSocket.shared_ciphers` returns diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 550f808a16dfaa..bcfc6e5cfce611 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -335,11 +335,10 @@ Notes: single: ceil() (in module math) single: trunc() (in module math) pair: numeric; conversions - pair: C; language - Conversion from floating point to integer may round or truncate - as in C; see functions :func:`math.floor` and :func:`math.ceil` for - well-defined conversions. + Conversion from :class:`float` to :class:`int` truncates, discarding the + fractional part. See functions :func:`math.floor` and :func:`math.ceil` for + alternative conversions. (4) float also accepts the strings "nan" and "inf" with an optional prefix "+" diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 23c5bbed0c6f9c..b3b9b5e74ac068 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1102,22 +1102,25 @@ always available. .. versionadded:: 3.5 +.. data:: last_exc + + This variable is not always defined; it is set to the exception instance + when an exception is not handled and the interpreter prints an error message + and a stack traceback. Its intended use is to allow an interactive user to + import a debugger module and engage in post-mortem debugging without having + to re-execute the command that caused the error. (Typical use is + ``import pdb; pdb.pm()`` to enter the post-mortem debugger; see :mod:`pdb` + module for more information.) + + .. versionadded:: 3.12 .. data:: last_type last_value last_traceback - These three variables are not always defined; they are set when an exception is - not handled and the interpreter prints an error message and a stack traceback. - Their intended use is to allow an interactive user to import a debugger module - and engage in post-mortem debugging without having to re-execute the command - that caused the error. (Typical use is ``import pdb; pdb.pm()`` to enter the - post-mortem debugger; see :mod:`pdb` module for - more information.) - - The meaning of the variables is the same as that of the return values from - :func:`exc_info` above. - + These three variables are deprecated; use :data:`sys.last_exc` instead. + They hold the legacy representation of ``sys.last_exc``, as returned + from :func:`exc_info` above. .. data:: maxsize @@ -1323,7 +1326,7 @@ always available. A string giving the site-specific directory prefix where the platform independent Python files are installed; on Unix, the default is - ``'/usr/local'``. This can be set at build time with the ``--prefix`` + :file:`/usr/local`. This can be set at build time with the :option:`--prefix` argument to the :program:`configure` script. See :ref:`installation_paths` for derived paths. diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 8eb0b35eaa12df..240ab139838db9 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -61,7 +61,7 @@ running from a virtual environment. A virtual environment may be "activated" using a script in its binary directory (``bin`` on POSIX; ``Scripts`` on Windows). This will prepend that directory to your :envvar:`!PATH`, so that running -:program:`!python` will invoke the environment's Python interpreter +:program:`python` will invoke the environment's Python interpreter and you can run installed scripts without having to use their full path. The invocation of the activation script is platform-specific (:samp:`{}` must be replaced by the path to the directory @@ -84,7 +84,7 @@ containing the virtual environment): +-------------+------------+--------------------------------------------------+ .. versionadded:: 3.4 - :program:`!fish` and :program:`!csh` activation scripts. + :program:`fish` and :program:`csh` activation scripts. .. versionadded:: 3.8 PowerShell activation scripts installed under POSIX for PowerShell Core diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index f447bbb1216d52..1865d09fcaa127 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1944,8 +1944,10 @@ Notes on using *__slots__* descriptor directly from the base class). This renders the meaning of the program undefined. In the future, a check may be added to prevent this. -* Nonempty *__slots__* does not work for classes derived from "variable-length" - built-in types such as :class:`int`, :class:`bytes` and :class:`tuple`. +* :exc:`TypeError` will be raised if nonempty *__slots__* are defined for a + class derived from a + :c:member:`"variable-length" built-in type ` such as + :class:`int`, :class:`bytes`, and :class:`tuple`. * Any non-string :term:`iterable` may be assigned to *__slots__*. diff --git a/Doc/tutorial/modules.rst b/Doc/tutorial/modules.rst index ad70d92994af49..4daafa49a34d2e 100644 --- a/Doc/tutorial/modules.rst +++ b/Doc/tutorial/modules.rst @@ -438,7 +438,7 @@ When importing the package, Python searches through the directories on The :file:`__init__.py` files are required to make Python treat directories containing the file as packages. This prevents directories with a common name, -such as ``string``, unintentionally hiding valid modules that occur later +such as ``string``, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, :file:`__init__.py` can just be an empty file, but it can also execute initialization code for the package or set the ``__all__`` variable, described later. diff --git a/Doc/tutorial/venv.rst b/Doc/tutorial/venv.rst index 05f0e6bbcc1b04..d1bba098d7d23b 100644 --- a/Doc/tutorial/venv.rst +++ b/Doc/tutorial/venv.rst @@ -44,7 +44,7 @@ whichever version you want. To create a virtual environment, decide upon a directory where you want to place it, and run the :mod:`venv` module as a script with the directory path:: - python3 -m venv tutorial-env + python -m venv tutorial-env This will create the ``tutorial-env`` directory if it doesn't exist, and also create directories inside it containing a copy of the Python diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 8936bd381c9d97..ce858ab2c8d79e 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -216,6 +216,22 @@ WebAssembly Options Install Options --------------- +.. cmdoption:: --prefix=PREFIX + + Install architecture-independent files in PREFIX. On Unix, it + defaults to :file:`/usr/local`. + + This value can be retrived at runtime using :data:`sys.prefix`. + + As an example, one can use ``--prefix="$HOME/.local/"`` to install + a Python in its home directory. + +.. cmdoption:: --exec-prefix=EPREFIX + + Install architecture-dependent files in EPREFIX, defaults to :option:`--prefix`. + + This value can be retrived at runtime using :data:`sys.exec_prefix`. + .. cmdoption:: --disable-test-modules Don't build nor install test modules, like the :mod:`test` package or the diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 24c02c99f871d5..067ff4cce5e48d 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -93,7 +93,7 @@ Python-related paths and files ============================== These are subject to difference depending on local installation conventions; -:envvar:`prefix` (``${prefix}``) and :envvar:`exec_prefix` (``${exec_prefix}``) +:option:`prefix <--prefix>` and :option:`exec_prefix <--exec-prefix>` are installation-dependent and should be interpreted as for GNU software; they may be the same. diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index d535b254f05698..43ee6b7807d57e 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -1,7 +1,7 @@ Creation of :ref:`virtual environments ` is done by executing the command ``venv``:: - python3 -m venv /path/to/new/virtual/environment + python -m venv /path/to/new/virtual/environment Running this command creates the target directory (creating any parent directories that don't exist already) and places a ``pyvenv.cfg`` file in it diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 9f33dbc808ddc0..b7c956d7f78456 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -237,6 +237,13 @@ asyncio * Add C implementation of :func:`asyncio.current_task` for 4x-6x speedup. (Contributed by Itamar Ostricher and Pranav Thulasiram Bhat in :gh:`100344`.) +* :func:`asyncio.iscoroutine` now returns ``False`` for generators as + :mod:`asyncio` does not support legacy generator-based coroutines. + (Contributed by Kumar Aditya in :gh:`102748`.) + +* :func:`asyncio.wait` now accepts generators yielding tasks. + (Contributed by Kumar Aditya in :gh:`78530`.) + inspect ------- @@ -302,6 +309,16 @@ os functions on Windows for enumerating drives, volumes and mount points. (Contributed by Steve Dower in :gh:`102519`.) +* :func:`os.stat` and :func:`os.lstat` are now more accurate on Windows. + The ``st_birthtime`` field will now be filled with the creation time + of the file, and ``st_ctime`` is deprecated but still contains the + creation time (but in the future will return the last metadata change, + for consistency with other platforms). ``st_dev`` may be up to 64 bits + and ``st_ino`` up to 128 bits depending on your file system, and + ``st_rdev`` is always set to zero rather than incorrect values. + Both functions may be significantly faster on newer releases of + Windows. (Contributed by Steve Dower in :gh:`99726`.) + os.path ------- @@ -320,6 +337,12 @@ shutil of the process to *root_dir* to perform archiving. (Contributed by Serhiy Storchaka in :gh:`74696`.) +* :func:`shutil.rmtree` now accepts a new argument *onexc* which is an + error handler like *onerror* but which expects an exception instance + rather than a *(typ, val, tb)* triplet. *onerror* is deprecated and + will be removed in Python 3.14. + (Contributed by Irit Katriel in :gh:`102828`.) + sqlite3 ------- @@ -380,6 +403,12 @@ sys with contributions from Gregory P. Smith [Google] and Mark Shannon in :gh:`96123`.) +* Add :data:`sys.last_exc` which holds the last unhandled exception that + was raised (for post-mortem debugging use cases). Deprecate the + three fields that have the same information in its legacy form: + :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback`. + (Contributed by Irit Katriel in :gh:`102778`.) + Optimizations ============= @@ -465,6 +494,20 @@ Deprecated warning at compile time. This field will be removed in Python 3.14. (Contributed by Ramvikrams and Kumar Aditya in :gh:`101193`. PEP by Ken Jin.) +* The ``st_ctime`` fields return by :func:`os.stat` and :func:`os.lstat` on + Windows are deprecated. In a future release, they will contain the last + metadata change time, consistent with other platforms. For now, they still + contain the creation time, which is also available in the new ``st_birthtime`` + field. (Contributed by Steve Dower in :gh:`99726`.) + +* The :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback` + fields are deprecated. Use :data:`sys.last_exc` instead. + (Contributed by Irit Katriel in :gh:`102778`.) + +* The *onerror* argument of :func:`shutil.rmtree` is deprecated as will be removed + in Python 3.14. Use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.) + + Pending Removal in Python 3.13 ------------------------------ @@ -523,6 +566,9 @@ Pending Removal in Python 3.14 * Creating :c:data:`immutable types ` with mutable bases using the C API. +* Deprecated the *isdst* parameter in :func:`email.utils.localtime`. + (Contributed by Alan Williams in :gh:`72346`.) + * ``__package__`` and ``__cached__`` will cease to be set or taken into consideration by the import system (:gh:`97879`). @@ -541,6 +587,9 @@ Pending Removal in Python 3.14 functions that have been deprecated since Python 2 but only gained a proper :exc:`DeprecationWarning` in 3.12. Remove them in 3.14. +* The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12, + and will be removed in 3.14. + Pending Removal in Future Versions ---------------------------------- @@ -924,6 +973,10 @@ New Features the :attr:`~BaseException.args` passed to the exception's constructor. (Contributed by Mark Shannon in :gh:`101578`.) +* Add :c:func:`PyErr_DisplayException`, which takes an exception instance, + to replace the legacy-api :c:func:`PyErr_Display`. (Contributed by + Irit Katriel in :gh:`102755`). + Porting to Python 3.12 ---------------------- @@ -982,6 +1035,16 @@ Porting to Python 3.12 effects, these side effects are no longer duplicated. (Contributed by Victor Stinner in :gh:`98724`.) +* The interpreter's error indicator is now always normalized. This means + that :c:func:`PyErr_SetObject`, :c:func:`PyErr_SetString` and the other + functions that set the error indicator now normalize the exception + before storing it. (Contributed by Mark Shannon in :gh:`101578`.) + +* ``_Py_RefTotal`` is no longer authoritative and only kept around + for ABI compabitility. Note that it is an internal global and only + available on debug builds. If you happen to be using it then you'll + need to start using ``_Py_GetGlobalRefTotal()``. + Deprecated ---------- @@ -1052,6 +1115,9 @@ Deprecated :c:func:`PyErr_SetRaisedException` instead. (Contributed by Mark Shannon in :gh:`101578`.) +* :c:func:`PyErr_Display` is deprecated. Use :c:func:`PyErr_DisplayException` + instead. (Contributed by Irit Katriel in :gh:`102755`). + Removed ------- diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index a070fa9ff3a038..8bc681b1a93f5c 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -25,6 +25,7 @@ PyAPI_FUNC(PyStatus) PyStatus_Exit(int exitcode); PyAPI_FUNC(int) PyStatus_IsError(PyStatus err); PyAPI_FUNC(int) PyStatus_IsExit(PyStatus err); PyAPI_FUNC(int) PyStatus_Exception(PyStatus err); +PyAPI_FUNC(PyObject *) _PyErr_SetFromPyStatus(PyStatus status); /* --- PyWideStringList ------------------------------------------------ */ diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 7b687d311359c3..859ffb91e223dc 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -11,7 +11,11 @@ PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); #endif #ifdef Py_REF_DEBUG -PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); +/* These are useful as debugging aids when chasing down refleaks. */ +PyAPI_FUNC(Py_ssize_t) _Py_GetGlobalRefTotal(void); +# define _Py_GetRefTotal() _Py_GetGlobalRefTotal() +PyAPI_FUNC(Py_ssize_t) _Py_GetLegacyRefTotal(void); +PyAPI_FUNC(Py_ssize_t) _PyInterpreterState_GetRefTotal(PyInterpreterState *); #endif diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index 0d9cc9922f7368..65bdc942f5067a 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -112,23 +112,9 @@ PyAPI_FUNC(PyObject *) _PyErr_FormatFromCause( /* In exceptions.c */ -/* Helper that attempts to replace the current exception with one of the - * same type but with a prefix added to the exception text. The resulting - * exception description looks like: - * - * prefix (exc_type: original_exc_str) - * - * Only some exceptions can be safely replaced. If the function determines - * it isn't safe to perform the replacement, it will leave the original - * unmodified exception in place. - * - * Returns a borrowed reference to the new exception (if any), NULL if the - * existing exception was left in place. - */ -PyAPI_FUNC(PyObject *) _PyErr_TrySetFromCause( - const char *prefix_format, /* ASCII-encoded string */ - ... - ); +PyAPI_FUNC(int) _PyException_AddNote( + PyObject *exc, + PyObject *note); /* In signalmodule.c */ diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h index e1f83acbffc360..821b169d7a1759 100644 --- a/Include/cpython/pylifecycle.h +++ b/Include/cpython/pylifecycle.h @@ -62,5 +62,6 @@ PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn); PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn); PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category); -PyAPI_FUNC(PyThreadState *) _Py_NewInterpreterFromConfig( - const _PyInterpreterConfig *); +PyAPI_FUNC(PyStatus) _Py_NewInterpreterFromConfig( + PyThreadState **tstate_p, + const _PyInterpreterConfig *config); diff --git a/Include/internal/pycore_fileutils.h b/Include/internal/pycore_fileutils.h index 445ac0a3d955d9..ef6642d00f1b54 100644 --- a/Include/internal/pycore_fileutils.h +++ b/Include/internal/pycore_fileutils.h @@ -66,7 +66,7 @@ PyAPI_FUNC(PyObject *) _Py_device_encoding(int); #ifdef MS_WINDOWS struct _Py_stat_struct { - unsigned long st_dev; + uint64_t st_dev; uint64_t st_ino; unsigned short st_mode; int st_nlink; @@ -80,8 +80,11 @@ struct _Py_stat_struct { int st_mtime_nsec; time_t st_ctime; int st_ctime_nsec; + time_t st_birthtime; + int st_birthtime_nsec; unsigned long st_file_attributes; unsigned long st_reparse_tag; + uint64_t st_ino_high; }; #else # define _Py_stat_struct stat diff --git a/Include/internal/pycore_fileutils_windows.h b/Include/internal/pycore_fileutils_windows.h new file mode 100644 index 00000000000000..44874903b092f3 --- /dev/null +++ b/Include/internal/pycore_fileutils_windows.h @@ -0,0 +1,80 @@ +#ifndef Py_INTERNAL_FILEUTILS_WINDOWS_H +#define Py_INTERNAL_FILEUTILS_WINDOWS_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "Py_BUILD_CORE must be defined to include this header" +#endif + +#ifdef MS_WINDOWS + +#if !defined(NTDDI_WIN10_NI) || !(NTDDI_VERSION >= NTDDI_WIN10_NI) +typedef struct _FILE_STAT_BASIC_INFORMATION { + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ULONG DeviceType; + ULONG DeviceCharacteristics; + ULONG Reserved; + FILE_ID_128 FileId128; + LARGE_INTEGER VolumeSerialNumber; +} FILE_STAT_BASIC_INFORMATION; + +typedef enum _FILE_INFO_BY_NAME_CLASS { + FileStatByNameInfo, + FileStatLxByNameInfo, + FileCaseSensitiveByNameInfo, + FileStatBasicByNameInfo, + MaximumFileInfoByNameClass +} FILE_INFO_BY_NAME_CLASS; +#endif + +typedef BOOL (WINAPI *PGetFileInformationByName)( + PCWSTR FileName, + FILE_INFO_BY_NAME_CLASS FileInformationClass, + PVOID FileInfoBuffer, + ULONG FileInfoBufferSize +); + +static inline BOOL _Py_GetFileInformationByName( + PCWSTR FileName, + FILE_INFO_BY_NAME_CLASS FileInformationClass, + PVOID FileInfoBuffer, + ULONG FileInfoBufferSize +) { + static PGetFileInformationByName GetFileInformationByName = NULL; + static int GetFileInformationByName_init = -1; + + if (GetFileInformationByName_init < 0) { + HMODULE hMod = LoadLibraryW(L"api-ms-win-core-file-l2-1-4"); + GetFileInformationByName_init = 0; + if (hMod) { + GetFileInformationByName = (PGetFileInformationByName)GetProcAddress( + hMod, "GetFileInformationByName"); + if (GetFileInformationByName) { + GetFileInformationByName_init = 1; + } else { + FreeLibrary(hMod); + } + } + } + + if (GetFileInformationByName_init <= 0) { + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; + } + return GetFileInformationByName(FileName, FileInformationClass, FileInfoBuffer, FileInfoBufferSize); +} + +#endif + +#endif diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 4b12ae523c3260..14dfd9ea5823ed 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -995,6 +995,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(kw2)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(lambda)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_exc)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_node)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_traceback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_type)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 17fb9ffbbf9f11..6f430bb25eb8d3 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -481,6 +481,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(kw2) STRUCT_FOR_ID(lambda) STRUCT_FOR_ID(last) + STRUCT_FOR_ID(last_exc) STRUCT_FOR_ID(last_node) STRUCT_FOR_ID(last_traceback) STRUCT_FOR_ID(last_type) diff --git a/Include/internal/pycore_initconfig.h b/Include/internal/pycore_initconfig.h index 69f88d7d1d46b8..4cbd14a61d4545 100644 --- a/Include/internal/pycore_initconfig.h +++ b/Include/internal/pycore_initconfig.h @@ -44,8 +44,6 @@ struct pyruntimestate; #define _PyStatus_UPDATE_FUNC(err) \ do { (err).func = _PyStatus_GET_FUNC(); } while (0) -PyObject* _PyErr_SetFromPyStatus(PyStatus status); - /* --- PyWideStringList ------------------------------------------------ */ #define _PyWideStringList_INIT (PyWideStringList){.length = 0, .items = NULL} diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 9efed0a1cf90c2..1f2c0db2eb5f27 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -25,6 +25,7 @@ extern "C" { #include "pycore_import.h" // struct _import_state #include "pycore_list.h" // struct _Py_list_state #include "pycore_global_objects.h" // struct _Py_interp_static_objects +#include "pycore_object_state.h" // struct _py_object_state #include "pycore_tuple.h" // struct _Py_tuple_state #include "pycore_typeobject.h" // struct type_cache #include "pycore_unicodeobject.h" // struct _Py_unicode_state @@ -111,6 +112,7 @@ struct _is { PyObject *dict; /* Stores per-interpreter state */ + PyObject *sysdict_copy; PyObject *builtins_copy; // Initialized to _PyEval_EvalFrameDefault(). _PyFrameEvalFunction eval_frame; @@ -137,6 +139,7 @@ struct _is { // One bit is set for each non-NULL entry in code_watchers uint8_t active_code_watchers; + struct _py_object_state object_state; struct _Py_unicode_state unicode; struct _Py_float_state float_state; struct _Py_long_state long_state; diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 318e6f3371c0c3..d6bbafd4b6cccc 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -43,17 +43,19 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc( built against the pre-3.12 stable ABI. */ PyAPI_DATA(Py_ssize_t) _Py_RefTotal; -extern void _Py_AddRefTotal(Py_ssize_t); -extern void _Py_IncRefTotal(void); -extern void _Py_DecRefTotal(void); -# define _Py_DEC_REFTOTAL() _Py_RefTotal-- +extern void _Py_AddRefTotal(PyInterpreterState *, Py_ssize_t); +extern void _Py_IncRefTotal(PyInterpreterState *); +extern void _Py_DecRefTotal(PyInterpreterState *); + +# define _Py_DEC_REFTOTAL(interp) \ + interp->object_state.reftotal-- #endif // Increment reference count by n static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n) { #ifdef Py_REF_DEBUG - _Py_AddRefTotal(n); + _Py_AddRefTotal(_PyInterpreterState_GET(), n); #endif op->ob_refcnt += n; } @@ -64,7 +66,7 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) { _Py_DECREF_STAT_INC(); #ifdef Py_REF_DEBUG - _Py_DEC_REFTOTAL(); + _Py_DEC_REFTOTAL(_PyInterpreterState_GET()); #endif if (--op->ob_refcnt != 0) { assert(op->ob_refcnt > 0); @@ -82,7 +84,7 @@ _Py_DECREF_NO_DEALLOC(PyObject *op) { _Py_DECREF_STAT_INC(); #ifdef Py_REF_DEBUG - _Py_DEC_REFTOTAL(); + _Py_DEC_REFTOTAL(_PyInterpreterState_GET()); #endif op->ob_refcnt--; #ifdef Py_DEBUG @@ -225,6 +227,8 @@ static inline void _PyObject_GC_UNTRACK( #endif #ifdef Py_REF_DEBUG +extern void _PyInterpreterState_FinalizeRefTotal(PyInterpreterState *); +extern void _Py_FinalizeRefTotal(_PyRuntimeState *); extern void _PyDebug_PrintTotalRefs(void); #endif diff --git a/Include/internal/pycore_object_state.h b/Include/internal/pycore_object_state.h new file mode 100644 index 00000000000000..94005d77881432 --- /dev/null +++ b/Include/internal/pycore_object_state.h @@ -0,0 +1,31 @@ +#ifndef Py_INTERNAL_OBJECT_STATE_H +#define Py_INTERNAL_OBJECT_STATE_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +struct _py_object_runtime_state { +#ifdef Py_REF_DEBUG + Py_ssize_t interpreter_leaks; +#else + int _not_used; +#endif +}; + +struct _py_object_state { +#ifdef Py_REF_DEBUG + Py_ssize_t reftotal; +#else + int _not_used; +#endif +}; + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_OBJECT_STATE_H */ diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index e7a31807205254..a899e848bb8b3c 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -87,6 +87,7 @@ PyAPI_FUNC(PyObject*) _PyErr_WriteUnraisableDefaultHook(PyObject *unraisable); PyAPI_FUNC(void) _PyErr_Print(PyThreadState *tstate); PyAPI_FUNC(void) _PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *tb); +PyAPI_FUNC(void) _PyErr_DisplayException(PyObject *file, PyObject *exc); PyAPI_FUNC(void) _PyThreadState_DeleteCurrent(PyThreadState *tstate); diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 520109ca440444..de757dfa93bc26 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -15,6 +15,7 @@ extern "C" { #include "pycore_global_objects.h" // struct _Py_global_objects #include "pycore_import.h" // struct _import_runtime_state #include "pycore_interp.h" // PyInterpreterState +#include "pycore_object_state.h" // struct _py_object_runtime_state #include "pycore_parser.h" // struct _parser_runtime_state #include "pycore_pymem.h" // struct _pymem_allocators #include "pycore_pyhash.h" // struct pyhash_runtime_state @@ -150,6 +151,7 @@ typedef struct pyruntimestate { void *open_code_userdata; _Py_AuditHookEntry *audit_hook_head; + struct _py_object_runtime_state object_state; struct _Py_float_runtime_state float_state; struct _Py_unicode_runtime_state unicode_state; diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index b240be57369d9d..0452c4c61551de 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -987,6 +987,7 @@ extern "C" { INIT_ID(kw2), \ INIT_ID(lambda), \ INIT_ID(last), \ + INIT_ID(last_exc), \ INIT_ID(last_node), \ INIT_ID(last_traceback), \ INIT_ID(last_type), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 52af37a8e60aa8..0a8865942e6d5b 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -13,1332 +13,1999 @@ static inline void _PyUnicode_InitStaticStrings(void) { PyObject *string; string = &_Py_ID(CANCELLED); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(FINISHED); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(False); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(JSONDecodeError); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(PENDING); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(Py_Repr); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(TextIOWrapper); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(True); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(WarningMessage); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_WindowsConsoleIO); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__IOBase_closed); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__abc_tpflags__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__abs__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__abstractmethods__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__add__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__aenter__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__aexit__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__aiter__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__all__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__and__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__anext__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__annotations__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__args__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__asyncio_running_event_loop__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__await__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__bases__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__bool__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__build_class__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__builtins__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__bytes__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__call__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__cantrace__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__class__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__class_getitem__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__classcell__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__complex__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__contains__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__copy__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ctypes_from_outparam__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__del__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__delattr__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__delete__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__delitem__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__dict__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__dictoffset__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__dir__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__divmod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__doc__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__enter__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__eq__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__exit__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__file__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__float__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__floordiv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__format__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__fspath__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ge__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__get__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getattr__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getattribute__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getinitargs__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getitem__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getnewargs__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getnewargs_ex__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getstate__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__gt__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__hash__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__iadd__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__iand__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ifloordiv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ilshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__imatmul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__imod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__import__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__imul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__index__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__init__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__init_subclass__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__instancecheck__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__int__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__invert__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ior__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ipow__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__irshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__isabstractmethod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__isub__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__iter__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__itruediv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ixor__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__le__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__len__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__length_hint__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__lltrace__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__loader__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__lshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__lt__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__main__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__matmul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__missing__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__mod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__module__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__mro_entries__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__mul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__name__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ne__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__neg__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__new__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__newobj__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__newobj_ex__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__next__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__notes__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__or__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__orig_class__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__origin__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__package__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__parameters__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__path__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__pos__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__pow__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__prepare__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__qualname__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__radd__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rand__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rdivmod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__reduce__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__reduce_ex__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__repr__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__reversed__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rfloordiv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rlshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rmatmul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rmod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rmul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ror__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__round__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rpow__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rrshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rsub__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rtruediv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rxor__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__set__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__set_name__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__setattr__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__setitem__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__setstate__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__sizeof__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__slotnames__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__slots__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__spec__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__str__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__sub__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__subclasscheck__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__subclasshook__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__truediv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__trunc__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__typing_is_unpacked_typevartuple__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__typing_prepare_subst__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__typing_subst__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__typing_unpacked_tuple_args__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__warningregistry__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__weaklistoffset__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__weakref__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__xor__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_abc_impl); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_abstract_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_active); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_annotation); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_anonymous_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_argtypes_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_as_parameter_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_asyncio_future_blocking); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_blksize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_bootstrap); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_check_retval_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_dealloc_warn); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_feature_version); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_fields_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_finalizing); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_find_and_load); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_fix_up_module); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_flags_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_get_sourcefile); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_handle_fromlist); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_initializing); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_io); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_is_text_encoding); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_length_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_limbo); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_lock_unlock_module); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_loop); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_needs_com_addref_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_pack_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_restype_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_showwarnmsg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_shutdown); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_slotnames); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_strptime_datetime); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_swappedbytes_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_type_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_uninitialized_submodules); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_warn_unawaited_coroutine); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_xoptions); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(a); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(abs_tol); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(access); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(add); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(add_done_callback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(after_in_child); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(after_in_parent); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(aggregate_class); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(append); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(argdefs); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(arguments); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(argv); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(as_integer_ratio); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ast); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(attribute); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(authorizer_callback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(autocommit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(b); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(backtick); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(base); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(before); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(big); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(binary_form); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(block); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffer); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffer_callback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffer_size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffering); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffers); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(bufsize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(builtins); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(byteorder); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(bytes); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(bytes_per_sep); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(c); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(c_call); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(c_exception); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(c_return); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cached_statements); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cadata); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cafile); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(call); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(call_exception_handler); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(call_soon); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cancel); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(capath); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(category); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cb_type); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(certfile); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(check_same_thread); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(clear); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(close); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(closed); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(closefd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(closure); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_argcount); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_cellvars); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_code); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_consts); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_exceptiontable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_filename); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_firstlineno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_flags); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_freevars); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_kwonlyargcount); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_linetable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_name); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_names); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_nlocals); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_posonlyargcount); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_qualname); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_stacksize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_varnames); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(code); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(command); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(comment_factory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(consts); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(context); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cookie); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(copy); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(copyreg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(coro); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(count); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cwd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(d); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(data); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(database); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(decode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(decoder); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(default); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(defaultaction); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(delete); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(depth); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(detect_types); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(deterministic); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(device); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dict); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dictcomp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(difference_update); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(digest); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(digest_size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(digestmod); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dir_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(discard); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dispatch_table); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(displayhook); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dklen); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(doc); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dont_inherit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dst); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dst_dir_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(duration); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(e); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(effective_ids); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(element_factory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(encode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(encoding); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(end); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(end_lineno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(end_offset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(endpos); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(env); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(errors); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(event); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(eventmask); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(exc_type); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(exc_value); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(excepthook); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(exception); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(exp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(extend); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(facility); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(factory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(false); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(family); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fanout); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fd2); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fdel); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fget); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(file); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(file_actions); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(filename); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fileno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(filepath); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fillvalue); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(filters); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(final); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(find_class); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fix_imports); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(flags); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(flush); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(follow_symlinks); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(format); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(frequency); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(from_param); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fromlist); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fromtimestamp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fromutc); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(func); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(future); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(generation); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(genexpr); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get_debug); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get_event_loop); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get_loop); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get_source); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(getattr); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(getstate); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(gid); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(globals); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(groupindex); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(groups); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(handle); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(hash_name); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(header); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(headers); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(hi); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(hook); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(id); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ident); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ignore); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(imag); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(importlib); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(in_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(incoming); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(indexgroup); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(inf); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(inheritable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(initial); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(initial_bytes); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(initial_value); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(initval); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(inner_size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(input); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(insert_comments); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(insert_pis); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(instructions); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(intern); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(intersection); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(isatty); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(isinstance); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(isoformat); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(isolation_level); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(istext); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(item); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(items); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(iter); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(iterable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(iterations); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(join); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(jump); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(keepends); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(key); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(keyfile); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(keys); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(kind); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(kw); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(kw1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(kw2); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(lambda); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last); + assert(_PyUnicode_CheckConsistency(string, 1)); + PyUnicode_InternInPlace(&string); + string = &_Py_ID(last_exc); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last_node); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last_traceback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last_type); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last_value); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(latin1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(leaf_size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(len); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(length); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(level); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(limit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(line); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(line_buffering); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(lineno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(listcomp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(little); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(lo); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(locale); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(locals); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(logoption); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(loop); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mapping); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(match); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(max_length); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxdigits); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxevents); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxmem); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxsplit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxvalue); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(memLevel); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(memlimit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(message); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(metaclass); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(method); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mod); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(module); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(module_globals); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(modules); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mro); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(msg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mycmp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_arg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_fields); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_sequence_fields); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_unnamed_fields); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(name); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(name_from); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(namespace_separator); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(namespaces); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(narg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ndigits); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(new_limit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(newline); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(newlines); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(next); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(node_depth); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(node_offset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ns); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(nstype); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(nt); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(null); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(number); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(obj); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(object); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(offset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(offset_dst); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(offset_src); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(on_type_read); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(onceregistry); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(only_keys); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(oparg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(opcode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(open); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(opener); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(operation); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(optimize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(options); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(order); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(out_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(outgoing); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(overlapped); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(owner); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(p); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pages); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(parent); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(password); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(path); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pattern); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(peek); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(persistent_id); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(persistent_load); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(person); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pi_factory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pid); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(policy); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pos); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pos1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pos2); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(posix); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(print_file_and_line); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(priority); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(progress); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(progress_handler); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(proto); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(protocol); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ps1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ps2); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(query); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(quotetabs); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(r); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(raw); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(read); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(read1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readall); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readinto); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readinto1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readline); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readonly); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(real); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reducer_override); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(registry); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(rel_tol); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reload); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(repl); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(replace); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reserved); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(resetids); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(return); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reverse); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reversed); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(s); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(salt); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sched_priority); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(scheduler); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(seek); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(seekable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(selectors); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(self); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(send); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sep); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sequence); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(server_hostname); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(server_side); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(session); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setcomp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setpgroup); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setsid); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setsigdef); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setsigmask); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setstate); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(shape); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(show_cmd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(signed); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sizehint); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(skip_file_prefixes); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sleep); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sock); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sort); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sound); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(source); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(source_traceback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(src); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(src_dir_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(stacklevel); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(start); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(statement); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(status); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(stderr); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(stdin); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(stdout); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(step); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(store_name); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(strategy); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(strftime); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(strict); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(strict_mode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(string); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sub_key); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(symmetric_difference_update); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tabsize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tag); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(target); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(target_is_directory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(task); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tb_frame); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tb_lasti); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tb_lineno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tb_next); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tell); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(template); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(term); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(text); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(threading); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(throw); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(timeout); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(times); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(timetuple); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(top); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(trace_callback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(traceback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(trailers); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(translate); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(true); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(truncate); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(twice); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(txt); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(type); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tz); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tzname); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(uid); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(unlink); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(unraisablehook); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(uri); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(usedforsecurity); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(value); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(values); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(version); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(volume); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(warnings); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(warnoptions); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(wbits); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(week); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(weekday); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(which); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(who); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(withdata); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(writable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(write); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(write_through); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(x); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(year); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(zdict); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); } /* End auto-generated code */ diff --git a/Include/object.h b/Include/object.h index 844b9c4a51c3e4..fc577353c1cc13 100644 --- a/Include/object.h +++ b/Include/object.h @@ -494,14 +494,9 @@ you can count such references to the type object.) extern Py_ssize_t _Py_RefTotal; # define _Py_INC_REFTOTAL() _Py_RefTotal++ # define _Py_DEC_REFTOTAL() _Py_RefTotal-- -# elif defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -extern void _Py_IncRefTotal(void); -extern void _Py_DecRefTotal(void); -# define _Py_INC_REFTOTAL() _Py_IncRefTotal() -# define _Py_DEC_REFTOTAL() _Py_DecRefTotal() # elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 > 0x030C0000 -extern void _Py_IncRefTotal_DO_NOT_USE_THIS(void); -extern void _Py_DecRefTotal_DO_NOT_USE_THIS(void); +PyAPI_FUNC(void) _Py_IncRefTotal_DO_NOT_USE_THIS(void); +PyAPI_FUNC(void) _Py_DecRefTotal_DO_NOT_USE_THIS(void); # define _Py_INC_REFTOTAL() _Py_IncRefTotal_DO_NOT_USE_THIS() # define _Py_DEC_REFTOTAL() _Py_DecRefTotal_DO_NOT_USE_THIS() # endif diff --git a/Include/objimpl.h b/Include/objimpl.h index dde8df34835328..ef871c5ea93ebe 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -157,6 +157,25 @@ PyAPI_FUNC(int) PyGC_Enable(void); PyAPI_FUNC(int) PyGC_Disable(void); PyAPI_FUNC(int) PyGC_IsEnabled(void); + +#if !defined(Py_LIMITED_API) +/* Visit all live GC-capable objects, similar to gc.get_objects(None). The + * supplied callback is called on every such object with the void* arg set + * to the supplied arg. Returning 0 from the callback ends iteration, returning + * 1 allows iteration to continue. Returning any other value may result in + * undefined behaviour. + * + * If new objects are (de)allocated by the callback it is undefined if they + * will be visited. + + * Garbage collection is disabled during operation. Explicitly running a + * collection in the callback may lead to undefined behaviour e.g. visiting the + * same objects multiple times or not at all. + */ +typedef int (*gcvisitobjects_t)(PyObject*, void*); +PyAPI_FUNC(void) PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void* arg); +#endif + /* Test if a type has a GC head */ #define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) diff --git a/Include/pythonrun.h b/Include/pythonrun.h index 1b208b734ab1bf..154c7450cb934f 100644 --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -13,6 +13,10 @@ PyAPI_FUNC(void) PyErr_Print(void); PyAPI_FUNC(void) PyErr_PrintEx(int); PyAPI_FUNC(void) PyErr_Display(PyObject *, PyObject *, PyObject *); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030C0000 +PyAPI_FUNC(void) PyErr_DisplayException(PyObject *); +#endif + /* Stuff with no proper home (yet) */ PyAPI_DATA(int) (*PyOS_InputHook)(void); diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index c62233b81a5c95..9d7724c33474cc 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -481,15 +481,8 @@ def __getitem__(self, item): # rather than the default types.GenericAlias object. Most of the # code is copied from typing's _GenericAlias and the builtin # types.GenericAlias. - if not isinstance(item, tuple): item = (item,) - # A special case in PEP 612 where if X = Callable[P, int], - # then X[int, str] == X[[int, str]]. - if (len(self.__parameters__) == 1 - and _is_param_expr(self.__parameters__[0]) - and item and not _is_param_expr(item[0])): - item = (item,) new_args = super().__getitem__(item).__args__ @@ -517,9 +510,8 @@ def _type_repr(obj): Copied from :mod:`typing` since collections.abc shouldn't depend on that module. + (Keep this roughly in sync with the typing version.) """ - if isinstance(obj, GenericAlias): - return repr(obj) if isinstance(obj, type): if obj.__module__ == 'builtins': return obj.__qualname__ diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py index 7fda0e449d500a..ab4f30eb51ba2c 100644 --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -25,8 +25,7 @@ def iscoroutinefunction(func): # Prioritize native coroutine check to speed-up # asyncio.iscoroutine. -_COROUTINE_TYPES = (types.CoroutineType, types.GeneratorType, - collections.abc.Coroutine) +_COROUTINE_TYPES = (types.CoroutineType, collections.abc.Coroutine) _iscoroutine_typecache = set() diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 911419e1769c17..0fdea3697ece3d 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -10,7 +10,21 @@ class TaskGroup: + """Asynchronous context manager for managing groups of tasks. + Example use: + + async with asyncio.TaskGroup() as group: + task1 = group.create_task(some_coroutine(...)) + task2 = group.create_task(other_coroutine(...)) + print("Both tasks have completed now.") + + All tasks are awaited when the context manager exits. + + Any exceptions other than `asyncio.CancelledError` raised within + a task will cancel all remaining tasks and wait for them to exit. + The exceptions are then combined and raised as an `ExceptionGroup`. + """ def __init__(self): self._entered = False self._exiting = False @@ -135,6 +149,10 @@ async def __aexit__(self, et, exc, tb): self._errors = None def create_task(self, coro, *, name=None, context=None): + """Create a new task in this group and return it. + + Similar to `asyncio.create_task`. + """ if not self._entered: raise RuntimeError(f"TaskGroup {self!r} has not been entered") if self._exiting and not self._tasks: diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 1c20754b839b69..c90d32c97add78 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -25,7 +25,6 @@ from . import exceptions from . import futures from . import timeouts -from .coroutines import _is_coroutine # Helper to generate new task names # This uses itertools.count() instead of a "+= 1" operation because the latter @@ -635,11 +634,14 @@ def ensure_future(coro_or_future, *, loop=None): raise ValueError('The future belongs to a different loop than ' 'the one specified as the loop argument') return coro_or_future - called_wrap_awaitable = False + should_close = True if not coroutines.iscoroutine(coro_or_future): if inspect.isawaitable(coro_or_future): + async def _wrap_awaitable(awaitable): + return await awaitable + coro_or_future = _wrap_awaitable(coro_or_future) - called_wrap_awaitable = True + should_close = False else: raise TypeError('An asyncio.Future, a coroutine or an awaitable ' 'is required') @@ -649,23 +651,11 @@ def ensure_future(coro_or_future, *, loop=None): try: return loop.create_task(coro_or_future) except RuntimeError: - if not called_wrap_awaitable: + if should_close: coro_or_future.close() raise -@types.coroutine -def _wrap_awaitable(awaitable): - """Helper for asyncio.ensure_future(). - - Wraps awaitable (an object with __await__) into a coroutine - that will later be wrapped in a Task by ensure_future(). - """ - return (yield from awaitable.__await__()) - -_wrap_awaitable._is_coroutine = _is_coroutine - - class _GatheringFuture(futures.Future): """Helper for gather(). diff --git a/Lib/asyncio/timeouts.py b/Lib/asyncio/timeouts.py index 94d25535fbc059..d07b291005e8f9 100644 --- a/Lib/asyncio/timeouts.py +++ b/Lib/asyncio/timeouts.py @@ -25,8 +25,18 @@ class _State(enum.Enum): @final class Timeout: + """Asynchronous context manager for cancelling overdue coroutines. + + Use `timeout()` or `timeout_at()` rather than instantiating this class directly. + """ def __init__(self, when: Optional[float]) -> None: + """Schedule a timeout that will trigger at a given loop time. + + - If `when` is `None`, the timeout will never trigger. + - If `when < loop.time()`, the timeout will trigger on the next + iteration of the event loop. + """ self._state = _State.CREATED self._timeout_handler: Optional[events.TimerHandle] = None @@ -34,9 +44,11 @@ def __init__(self, when: Optional[float]) -> None: self._when = when def when(self) -> Optional[float]: + """Return the current deadline.""" return self._when def reschedule(self, when: Optional[float]) -> None: + """Reschedule the timeout.""" assert self._state is not _State.CREATED if self._state is not _State.ENTERED: raise RuntimeError( diff --git a/Lib/code.py b/Lib/code.py index 76000f8c8b2c1e..2bd5fa3e795a61 100644 --- a/Lib/code.py +++ b/Lib/code.py @@ -106,6 +106,7 @@ def showsyntaxerror(self, filename=None): """ type, value, tb = sys.exc_info() + sys.last_exc = value sys.last_type = type sys.last_value = value sys.last_traceback = tb @@ -119,7 +120,7 @@ def showsyntaxerror(self, filename=None): else: # Stuff in the right filename value = SyntaxError(msg, (filename, lineno, offset, line)) - sys.last_value = value + sys.last_exc = sys.last_value = value if sys.excepthook is sys.__excepthook__: lines = traceback.format_exception_only(type, value) self.write(''.join(lines)) @@ -138,6 +139,7 @@ def showtraceback(self): """ sys.last_type, sys.last_value, last_tb = ei = sys.exc_info() sys.last_traceback = last_tb + sys.last_exc = ei[1] try: lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next) if sys.excepthook is sys.__excepthook__: diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 3a8637b6fa1b47..816edab99f63e3 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -366,6 +366,11 @@ def run(self): if self.is_shutting_down(): self.flag_executor_shutting_down() + # When only canceled futures remain in pending_work_items, our + # next call to wait_result_broken_or_wakeup would hang forever. + # This makes sure we have some running futures or none at all. + self.add_call_item_to_queue() + # Since no new work items can be added, it is safe to shutdown # this thread if there are no pending work items. if not self.pending_work_items: diff --git a/Lib/dis.py b/Lib/dis.py index 9edde6ae8258da..c3d152b4de0469 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -118,7 +118,10 @@ def distb(tb=None, *, file=None, show_caches=False, adaptive=False): """Disassemble a traceback (default: last traceback).""" if tb is None: try: - tb = sys.last_traceback + if hasattr(sys, 'last_exc'): + tb = sys.last_exc.__traceback__ + else: + tb = sys.last_traceback except AttributeError: raise RuntimeError("no last traceback to disassemble") from None while tb.tb_next: tb = tb.tb_next diff --git a/Lib/email/utils.py b/Lib/email/utils.py index cfdfeb3f1a86e4..4d014bacd6182e 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -331,41 +331,23 @@ def collapse_rfc2231_value(value, errors='replace', # better than not having it. # -def localtime(dt=None, isdst=-1): +def localtime(dt=None, isdst=None): """Return local time as an aware datetime object. If called without arguments, return current time. Otherwise *dt* argument should be a datetime instance, and it is converted to the local time zone according to the system time zone database. If *dt* is naive (that is, dt.tzinfo is None), it is assumed to be in local time. - In this case, a positive or zero value for *isdst* causes localtime to - presume initially that summer time (for example, Daylight Saving Time) - is or is not (respectively) in effect for the specified time. A - negative value for *isdst* causes the localtime() function to attempt - to divine whether summer time is in effect for the specified time. + The isdst parameter is ignored. """ + if isdst is not None: + import warnings + warnings._deprecated( + "The 'isdst' parameter to 'localtime'", + message='{name} is deprecated and slated for removal in Python {remove}', + remove=(3, 14), + ) if dt is None: - return datetime.datetime.now(datetime.timezone.utc).astimezone() - if dt.tzinfo is not None: - return dt.astimezone() - # We have a naive datetime. Convert to a (localtime) timetuple and pass to - # system mktime together with the isdst hint. System mktime will return - # seconds since epoch. - tm = dt.timetuple()[:-1] + (isdst,) - seconds = time.mktime(tm) - localtm = time.localtime(seconds) - try: - delta = datetime.timedelta(seconds=localtm.tm_gmtoff) - tz = datetime.timezone(delta, localtm.tm_zone) - except AttributeError: - # Compute UTC offset and compare with the value implied by tm_isdst. - # If the values match, use the zone name implied by tm_isdst. - delta = dt - datetime.datetime(*time.gmtime(seconds)[:6]) - dst = time.daylight and localtm.tm_isdst > 0 - gmtoff = -(time.altzone if dst else time.timezone) - if delta == datetime.timedelta(seconds=gmtoff): - tz = datetime.timezone(delta, time.tzname[dst]) - else: - tz = datetime.timezone(delta) - return dt.replace(tzinfo=tz) + dt = datetime.datetime.now() + return dt.astimezone() diff --git a/Lib/opcode.py b/Lib/opcode.py index 23529d87a09ef9..d4a2d554cf67de 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -377,14 +377,6 @@ def pseudo_op(name, op, real_ops): _specialized_instructions = [ opcode for family in _specializations.values() for opcode in family ] -_specialization_stats = [ - "success", - "failure", - "hit", - "deferred", - "miss", - "deopt", -] _cache_format = { "LOAD_GLOBAL": { diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 23f9290861ae57..d7ee2388a5d538 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -1191,45 +1191,47 @@ def expanduser(self): def walk(self, top_down=True, on_error=None, follow_symlinks=False): """Walk the directory tree from this directory, similar to os.walk().""" sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks) - return self._walk(top_down, on_error, follow_symlinks) - - def _walk(self, top_down, on_error, follow_symlinks): - # We may not have read permission for self, in which case we can't - # get a list of the files the directory contains. os.walk - # always suppressed the exception then, rather than blow up for a - # minor reason when (say) a thousand readable directories are still - # left to visit. That logic is copied here. - try: - scandir_it = self._scandir() - except OSError as error: - if on_error is not None: - on_error(error) - return - - with scandir_it: - dirnames = [] - filenames = [] - for entry in scandir_it: - try: - is_dir = entry.is_dir(follow_symlinks=follow_symlinks) - except OSError: - # Carried over from os.path.isdir(). - is_dir = False - - if is_dir: - dirnames.append(entry.name) - else: - filenames.append(entry.name) - - if top_down: - yield self, dirnames, filenames - - for dirname in dirnames: - dirpath = self._make_child_relpath(dirname) - yield from dirpath._walk(top_down, on_error, follow_symlinks) + paths = [self] + + while paths: + path = paths.pop() + if isinstance(path, tuple): + yield path + continue + + # We may not have read permission for self, in which case we can't + # get a list of the files the directory contains. os.walk() + # always suppressed the exception in that instance, rather than + # blow up for a minor reason when (say) a thousand readable + # directories are still left to visit. That logic is copied here. + try: + scandir_it = path._scandir() + except OSError as error: + if on_error is not None: + on_error(error) + continue + + with scandir_it: + dirnames = [] + filenames = [] + for entry in scandir_it: + try: + is_dir = entry.is_dir(follow_symlinks=follow_symlinks) + except OSError: + # Carried over from os.path.isdir(). + is_dir = False + + if is_dir: + dirnames.append(entry.name) + else: + filenames.append(entry.name) + + if top_down: + yield path, dirnames, filenames + else: + paths.append((path, dirnames, filenames)) - if not top_down: - yield self, dirnames, filenames + paths += [path._make_child_relpath(d) for d in reversed(dirnames)] class PosixPath(Path, PurePosixPath): diff --git a/Lib/pdb.py b/Lib/pdb.py index f11fc55536810f..3543f53282db15 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1739,7 +1739,11 @@ def post_mortem(t=None): def pm(): """Enter post-mortem debugging of the traceback found in sys.last_traceback.""" - post_mortem(sys.last_traceback) + if hasattr(sys, 'last_exc'): + tb = sys.last_exc.__traceback__ + else: + tb = sys.last_traceback + post_mortem(tb) # Main program for testing diff --git a/Lib/platform.py b/Lib/platform.py index f2b0d1d1bd3f5d..790ef860bf106e 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -1040,20 +1040,6 @@ def processor(): r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)" r'\[([^\]]+)\]?', re.ASCII) # "[compiler]" -_ironpython_sys_version_parser = re.compile( - r'IronPython\s*' - r'([\d\.]+)' - r'(?: \(([\d\.]+)\))?' - r' on (.NET [\d\.]+)', re.ASCII) - -# IronPython covering 2.6 and 2.7 -_ironpython26_sys_version_parser = re.compile( - r'([\d.]+)\s*' - r'\(IronPython\s*' - r'[\d.]+\s*' - r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)' -) - _pypy_sys_version_parser = re.compile( r'([\w.+]+)\s*' r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*' @@ -1090,25 +1076,7 @@ def _sys_version(sys_version=None): if result is not None: return result - # Parse it - if 'IronPython' in sys_version: - # IronPython - name = 'IronPython' - if sys_version.startswith('IronPython'): - match = _ironpython_sys_version_parser.match(sys_version) - else: - match = _ironpython26_sys_version_parser.match(sys_version) - - if match is None: - raise ValueError( - 'failed to parse IronPython sys.version: %s' % - repr(sys_version)) - - version, alt_version, compiler = match.groups() - buildno = '' - builddate = '' - - elif sys.platform.startswith('java'): + if sys.platform.startswith('java'): # Jython name = 'Jython' match = _sys_version_parser.match(sys_version) @@ -1171,7 +1139,6 @@ def python_implementation(): Currently, the following implementations are identified: 'CPython' (C implementation of Python), - 'IronPython' (.NET implementation of Python), 'Jython' (Java implementation of Python), 'PyPy' (Python implementation of Python). diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 0a693f45230c93..78d8fd5357f72a 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -389,8 +389,17 @@ def synopsis(filename, cache={}): class ErrorDuringImport(Exception): """Errors that occurred while trying to import something to document it.""" def __init__(self, filename, exc_info): + if not isinstance(exc_info, tuple): + assert isinstance(exc_info, BaseException) + self.exc = type(exc_info) + self.value = exc_info + self.tb = exc_info.__traceback__ + else: + warnings.warn("A tuple value for exc_info is deprecated, use an exception instance", + DeprecationWarning) + + self.exc, self.value, self.tb = exc_info self.filename = filename - self.exc, self.value, self.tb = exc_info def __str__(self): exc = self.exc.__name__ @@ -411,8 +420,8 @@ def importfile(path): spec = importlib.util.spec_from_file_location(name, path, loader=loader) try: return importlib._bootstrap._load(spec) - except: - raise ErrorDuringImport(path, sys.exc_info()) + except BaseException as err: + raise ErrorDuringImport(path, err) def safeimport(path, forceload=0, cache={}): """Import a module; handle errors; return None if the module isn't found. @@ -440,21 +449,20 @@ def safeimport(path, forceload=0, cache={}): cache[key] = sys.modules[key] del sys.modules[key] module = __import__(path) - except: + except BaseException as err: # Did the error occur before or after the module was found? - (exc, value, tb) = info = sys.exc_info() if path in sys.modules: # An error occurred while executing the imported module. - raise ErrorDuringImport(sys.modules[path].__file__, info) - elif exc is SyntaxError: + raise ErrorDuringImport(sys.modules[path].__file__, err) + elif type(err) is SyntaxError: # A SyntaxError occurred before we could execute the module. - raise ErrorDuringImport(value.filename, info) - elif issubclass(exc, ImportError) and value.name == path: + raise ErrorDuringImport(err.filename, err) + elif isinstance(err, ImportError) and err.name == path: # No such module in the path. return None else: # Some other error occurred during the importing process. - raise ErrorDuringImport(path, sys.exc_info()) + raise ErrorDuringImport(path, err) for part in path.split('.')[1:]: try: module = getattr(module, part) except AttributeError: return None @@ -1997,8 +2005,8 @@ def __call__(self, request=_GoInteractive): if request is not self._GoInteractive: try: self.help(request) - except ImportError as e: - self.output.write(f'{e}\n') + except ImportError as err: + self.output.write(f'{err}\n') else: self.intro() self.interact() @@ -2405,8 +2413,8 @@ def run(self): docsvr = DocServer(self.host, self.port, self.ready) self.docserver = docsvr docsvr.serve_until_quit() - except Exception as e: - self.error = e + except Exception as err: + self.error = err def ready(self, server): self.serving = True diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 573065b4b714d9..ad1b6aca6b95bc 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -4799,7 +4799,7 @@ 'pdb.pm()\n' '\n' ' Enter post-mortem debugging of the traceback found in\n' - ' "sys.last_traceback".\n' + ' "sys.last_exc".\n' '\n' 'The "run*" functions and "set_trace()" are aliases for ' 'instantiating\n' @@ -13858,7 +13858,7 @@ 'if\n' ' the interpreter is interactive, it is also made available to ' 'the\n' - ' user as "sys.last_traceback".\n' + ' user as "sys.last_exc".\n' '\n' ' For explicitly created tracebacks, it is up to the creator ' 'of\n' diff --git a/Lib/shutil.py b/Lib/shutil.py index 867925aa10cc04..b0576407e02ffb 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -10,6 +10,7 @@ import fnmatch import collections import errno +import warnings try: import zlib @@ -575,12 +576,12 @@ def _rmtree_islink(path): return os.path.islink(path) # version vulnerable to race conditions -def _rmtree_unsafe(path, onerror): +def _rmtree_unsafe(path, onexc): try: with os.scandir(path) as scandir_it: entries = list(scandir_it) - except OSError: - onerror(os.scandir, path, sys.exc_info()) + except OSError as err: + onexc(os.scandir, path, err) entries = [] for entry in entries: fullname = entry.path @@ -596,28 +597,28 @@ def _rmtree_unsafe(path, onerror): # a directory with a symlink after the call to # os.scandir or entry.is_dir above. raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, fullname, sys.exc_info()) + except OSError as err: + onexc(os.path.islink, fullname, err) continue - _rmtree_unsafe(fullname, onerror) + _rmtree_unsafe(fullname, onexc) else: try: os.unlink(fullname) - except OSError: - onerror(os.unlink, fullname, sys.exc_info()) + except OSError as err: + onexc(os.unlink, fullname, err) try: os.rmdir(path) - except OSError: - onerror(os.rmdir, path, sys.exc_info()) + except OSError as err: + onexc(os.rmdir, path, err) # Version using fd-based APIs to protect against races -def _rmtree_safe_fd(topfd, path, onerror): +def _rmtree_safe_fd(topfd, path, onexc): try: with os.scandir(topfd) as scandir_it: entries = list(scandir_it) except OSError as err: err.filename = path - onerror(os.scandir, path, sys.exc_info()) + onexc(os.scandir, path, err) return for entry in entries: fullname = os.path.join(path, entry.name) @@ -630,25 +631,25 @@ def _rmtree_safe_fd(topfd, path, onerror): try: orig_st = entry.stat(follow_symlinks=False) is_dir = stat.S_ISDIR(orig_st.st_mode) - except OSError: - onerror(os.lstat, fullname, sys.exc_info()) + except OSError as err: + onexc(os.lstat, fullname, err) continue if is_dir: try: dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd) dirfd_closed = False - except OSError: - onerror(os.open, fullname, sys.exc_info()) + except OSError as err: + onexc(os.open, fullname, err) else: try: if os.path.samestat(orig_st, os.fstat(dirfd)): - _rmtree_safe_fd(dirfd, fullname, onerror) + _rmtree_safe_fd(dirfd, fullname, onexc) try: os.close(dirfd) dirfd_closed = True os.rmdir(entry.name, dir_fd=topfd) - except OSError: - onerror(os.rmdir, fullname, sys.exc_info()) + except OSError as err: + onexc(os.rmdir, fullname, err) else: try: # This can only happen if someone replaces @@ -656,23 +657,23 @@ def _rmtree_safe_fd(topfd, path, onerror): # os.scandir or stat.S_ISDIR above. raise OSError("Cannot call rmtree on a symbolic " "link") - except OSError: - onerror(os.path.islink, fullname, sys.exc_info()) + except OSError as err: + onexc(os.path.islink, fullname, err) finally: if not dirfd_closed: os.close(dirfd) else: try: os.unlink(entry.name, dir_fd=topfd) - except OSError: - onerror(os.unlink, fullname, sys.exc_info()) + except OSError as err: + onexc(os.unlink, fullname, err) _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <= os.supports_dir_fd and os.scandir in os.supports_fd and os.stat in os.supports_follow_symlinks) -def rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None): +def rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None): """Recursively delete a directory tree. If dir_fd is not None, it should be a file descriptor open to a directory; @@ -680,21 +681,44 @@ def rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None): dir_fd may not be implemented on your platform. If it is unavailable, using it will raise a NotImplementedError. - If ignore_errors is set, errors are ignored; otherwise, if onerror - is set, it is called to handle the error with arguments (func, + If ignore_errors is set, errors are ignored; otherwise, if onexc or + onerror is set, it is called to handle the error with arguments (func, path, exc_info) where func is platform and implementation dependent; path is the argument to that function that caused it to fail; and - exc_info is a tuple returned by sys.exc_info(). If ignore_errors - is false and onerror is None, an exception is raised. + the value of exc_info describes the exception. For onexc it is the + exception instance, and for onerror it is a tuple as returned by + sys.exc_info(). If ignore_errors is false and both onexc and + onerror are None, the exception is reraised. + onerror is deprecated and only remains for backwards compatibility. + If both onerror and onexc are set, onerror is ignored and onexc is used. """ + + if onerror is not None: + warnings.warn("onerror argument is deprecated, use onexc instead", + DeprecationWarning) + sys.audit("shutil.rmtree", path, dir_fd) if ignore_errors: - def onerror(*args): + def onexc(*args): pass - elif onerror is None: - def onerror(*args): + elif onerror is None and onexc is None: + def onexc(*args): raise + elif onexc is None: + if onerror is None: + def onexc(*args): + raise + else: + # delegate to onerror + def onexc(*args): + func, path, exc = args + if exc is None: + exc_info = None, None, None + else: + exc_info = type(exc), exc, exc.__traceback__ + return onerror(func, path, exc_info) + if _use_fd_functions: # While the unsafe rmtree works fine on bytes, the fd based does not. if isinstance(path, bytes): @@ -703,30 +727,30 @@ def onerror(*args): # lstat()/open()/fstat() trick. try: orig_st = os.lstat(path, dir_fd=dir_fd) - except Exception: - onerror(os.lstat, path, sys.exc_info()) + except Exception as err: + onexc(os.lstat, path, err) return try: fd = os.open(path, os.O_RDONLY, dir_fd=dir_fd) fd_closed = False - except Exception: - onerror(os.open, path, sys.exc_info()) + except Exception as err: + onexc(os.open, path, err) return try: if os.path.samestat(orig_st, os.fstat(fd)): - _rmtree_safe_fd(fd, path, onerror) + _rmtree_safe_fd(fd, path, onexc) try: os.close(fd) fd_closed = True os.rmdir(path, dir_fd=dir_fd) - except OSError: - onerror(os.rmdir, path, sys.exc_info()) + except OSError as err: + onexc(os.rmdir, path, err) else: try: # symlinks to directories are forbidden, see bug #1669 raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, path, sys.exc_info()) + except OSError as err: + onexc(os.path.islink, path, err) finally: if not fd_closed: os.close(fd) @@ -737,11 +761,11 @@ def onerror(*args): if _rmtree_islink(path): # symlinks to directories are forbidden, see bug #1669 raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, path, sys.exc_info()) - # can't continue even if onerror hook returns + except OSError as err: + onexc(os.path.islink, path, err) + # can't continue even if onexc hook returns return - return _rmtree_unsafe(path, onerror) + return _rmtree_unsafe(path, onexc) # Allow introspection of whether or not the hardening against symlink # attacks is supported on the current platform diff --git a/Lib/statistics.py b/Lib/statistics.py index 7d5d750193a5ab..6bd214bbfe2ff5 100644 --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -1036,7 +1036,7 @@ def covariance(x, y, /): raise StatisticsError('covariance requires at least two data points') xbar = fsum(x) / n ybar = fsum(y) / n - sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y)) + sxy = sumprod((xi - xbar for xi in x), (yi - ybar for yi in y)) return sxy / (n - 1) @@ -1074,11 +1074,14 @@ def correlation(x, y, /, *, method='linear'): start = (n - 1) / -2 # Center rankings around zero x = _rank(x, start=start) y = _rank(y, start=start) - xbar = fsum(x) / n - ybar = fsum(y) / n - sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y)) - sxx = fsum((d := xi - xbar) * d for xi in x) - syy = fsum((d := yi - ybar) * d for yi in y) + else: + xbar = fsum(x) / n + ybar = fsum(y) / n + x = [xi - xbar for xi in x] + y = [yi - ybar for yi in y] + sxy = sumprod(x, y) + sxx = sumprod(x, x) + syy = sumprod(y, y) try: return sxy / sqrt(sxx * syy) except ZeroDivisionError: @@ -1131,14 +1134,13 @@ def linear_regression(x, y, /, *, proportional=False): raise StatisticsError('linear regression requires that both inputs have same number of data points') if n < 2: raise StatisticsError('linear regression requires at least two data points') - if proportional: - sxy = fsum(xi * yi for xi, yi in zip(x, y)) - sxx = fsum(xi * xi for xi in x) - else: + if not proportional: xbar = fsum(x) / n ybar = fsum(y) / n - sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y)) - sxx = fsum((d := xi - xbar) * d for xi in x) + x = [xi - xbar for xi in x] # List because used three times below + y = (yi - ybar for yi in y) # Generator because only used once below + sxy = sumprod(x, y) + 0.0 # Add zero to coerce result to a float + sxx = sumprod(x, x) try: slope = sxy / sxx # equivalent to: covariance(x, y) / variance(x) except ZeroDivisionError: diff --git a/Lib/tempfile.py b/Lib/tempfile.py index bb18d60db0d919..cf06092f826bcc 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -864,8 +864,8 @@ def __init__(self, suffix=None, prefix=None, dir=None, @classmethod def _rmtree(cls, name, ignore_errors=False): - def onerror(func, path, exc_info): - if issubclass(exc_info[0], PermissionError): + def onexc(func, path, exc): + if isinstance(exc, PermissionError): def resetperms(path): try: _os.chflags(path, 0) @@ -885,13 +885,13 @@ def resetperms(path): cls._rmtree(path, ignore_errors=ignore_errors) except FileNotFoundError: pass - elif issubclass(exc_info[0], FileNotFoundError): + elif isinstance(exc, FileNotFoundError): pass else: if not ignore_errors: raise - _shutil.rmtree(name, onerror=onerror) + _shutil.rmtree(name, onexc=onexc) @classmethod def _cleanup(cls, name, warn_message, ignore_errors=False): diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index db831069c7aeb8..fb4ab15f7041ed 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -69,8 +69,7 @@ def test_stack_effect_jump(self): class SpecializationStatsTests(unittest.TestCase): def test_specialization_stats(self): - stat_names = opcode._specialization_stats - + stat_names = ["success", "failure", "hit", "deferred", "miss", "deopt"] specialized_opcodes = [ op.lower() for op in opcode._specializations diff --git a/Lib/test/test_asyncio/test_pep492.py b/Lib/test/test_asyncio/test_pep492.py index f833f788dcb98f..dc25a46985e349 100644 --- a/Lib/test/test_asyncio/test_pep492.py +++ b/Lib/test/test_asyncio/test_pep492.py @@ -119,6 +119,12 @@ async def foo(): pass self.assertTrue(asyncio.iscoroutine(FakeCoro())) + def test_iscoroutine_generator(self): + def foo(): yield + + self.assertFalse(asyncio.iscoroutine(foo())) + + def test_iscoroutinefunction(self): async def foo(): pass self.assertTrue(asyncio.iscoroutinefunction(foo)) diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index e533d5273e9f38..731fa0c5a60b9b 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -8,6 +8,7 @@ import re import sys import traceback +import types import unittest from unittest import mock from types import GenericAlias @@ -274,6 +275,20 @@ async def coro(): loop.run_until_complete(fut) self.assertEqual(fut.result(), 'ok') + def test_ensure_future_task_awaitable(self): + class Aw: + def __await__(self): + return asyncio.sleep(0, result='ok').__await__() + + loop = asyncio.new_event_loop() + self.set_event_loop(loop) + task = asyncio.ensure_future(Aw(), loop=loop) + loop.run_until_complete(task) + self.assertTrue(task.done()) + self.assertEqual(task.result(), 'ok') + self.assertIsInstance(task.get_coro(), types.CoroutineType) + loop.close() + def test_ensure_future_neither(self): with self.assertRaises(TypeError): asyncio.ensure_future('ok') @@ -1358,6 +1373,22 @@ async def foo(): self.assertEqual(res, 42) self.assertAlmostEqual(0.15, loop.time()) + + def test_wait_generator(self): + async def func(a): + return a + + loop = self.new_test_loop() + + async def main(): + tasks = (self.new_task(loop, func(i)) for i in range(10)) + done, pending = await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED) + self.assertEqual(len(done), 10) + self.assertEqual(len(pending), 0) + + loop.run_until_complete(main()) + + def test_as_completed(self): def gen(): diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py index 33d0ea15c6de0e..96999470a7c69a 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -1889,8 +1889,8 @@ async def test_fork_not_share_event_loop(self): os.write(w, b'LOOP:' + str(id(loop)).encode()) except RuntimeError: os.write(w, b'NO LOOP') - except: - os.write(w, b'ERROR:' + ascii(sys.exc_info()).encode()) + except BaseException as e: + os.write(w, b'ERROR:' + ascii(e).encode()) finally: os._exit(0) else: diff --git a/Lib/test/test_bigmem.py b/Lib/test/test_bigmem.py index 859f1539e20b80..c9ab1c1de9e186 100644 --- a/Lib/test/test_bigmem.py +++ b/Lib/test/test_bigmem.py @@ -1248,6 +1248,15 @@ def test_sort(self, size): self.assertEqual(l[-10:], [5] * 10) +class DictTest(unittest.TestCase): + + @bigmemtest(size=357913941, memuse=160) + def test_dict(self, size): + # https://github.com/python/cpython/issues/102701 + d = dict.fromkeys(range(size)) + d[size] = 1 + + if __name__ == '__main__': if len(sys.argv) > 1: support.set_memlimit(sys.argv[1]) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 3d9dcf12f2dad8..ccfbeede0be949 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -568,11 +568,15 @@ def test_locale_calendar_formatweekday(self): try: # formatweekday uses different day names based on the available width. cal = calendar.LocaleTextCalendar(locale='en_US') + # For really short widths, the abbreviated name is truncated. + self.assertEqual(cal.formatweekday(0, 1), "M") + self.assertEqual(cal.formatweekday(0, 2), "Mo") # For short widths, a centered, abbreviated name is used. + self.assertEqual(cal.formatweekday(0, 3), "Mon") self.assertEqual(cal.formatweekday(0, 5), " Mon ") - # For really short widths, even the abbreviated name is truncated. - self.assertEqual(cal.formatweekday(0, 2), "Mo") + self.assertEqual(cal.formatweekday(0, 8), " Mon ") # For long widths, the full day name is used. + self.assertEqual(cal.formatweekday(0, 9), " Monday ") self.assertEqual(cal.formatweekday(0, 10), " Monday ") except locale.Error: raise unittest.SkipTest('cannot set the en_US locale') diff --git a/Lib/test/test_capi/test_exceptions.py b/Lib/test/test_capi/test_exceptions.py index 55f131699a2567..b1c1a61e20685e 100644 --- a/Lib/test/test_capi/test_exceptions.py +++ b/Lib/test/test_capi/test_exceptions.py @@ -169,5 +169,25 @@ class Broken(Exception, metaclass=Meta): with self.assertRaises(ZeroDivisionError) as e: _testcapi.exc_set_object(Broken, Broken()) + def test_set_object_and_fetch(self): + class Broken(Exception): + def __init__(self, *arg): + raise ValueError("Broken __init__") + + exc = _testcapi.exc_set_object_fetch(Broken, 'abcd') + self.assertIsInstance(exc, ValueError) + self.assertEqual(exc.__notes__[0], + "Normalization failed: type=Broken args='abcd'") + + class BadArg: + def __repr__(self): + raise TypeError('Broken arg type') + + exc = _testcapi.exc_set_object_fetch(Broken, BadArg()) + self.assertIsInstance(exc, ValueError) + self.assertEqual(exc.__notes__[0], + 'Normalization failed: type=Broken args=') + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_check_c_globals.py b/Lib/test/test_check_c_globals.py deleted file mode 100644 index 670be52422f799..00000000000000 --- a/Lib/test/test_check_c_globals.py +++ /dev/null @@ -1,34 +0,0 @@ -import unittest -import test.test_tools -from test.support.warnings_helper import save_restore_warnings_filters - - -# TODO: gh-92584: c-analyzer uses distutils which was removed in Python 3.12 -raise unittest.SkipTest("distutils has been removed in Python 3.12") - - -test.test_tools.skip_if_missing('c-analyzer') -with test.test_tools.imports_under_tool('c-analyzer'): - # gh-95349: Save/restore warnings filters to leave them unchanged. - # Importing the c-analyzer imports docutils which imports pkg_resources - # which adds a warnings filter. - with save_restore_warnings_filters(): - from cpython.__main__ import main - - -class ActualChecks(unittest.TestCase): - - # XXX Also run the check in "make check". - #@unittest.expectedFailure - # Failing on one of the buildbots (see https://bugs.python.org/issue36876). - @unittest.skip('activate this once all the globals have been resolved') - def test_check_c_globals(self): - try: - main('check', {}) - except NotImplementedError: - raise unittest.SkipTest('not supported on this host') - - -if __name__ == '__main__': - # Test needs to be a package, so we can do relative imports. - unittest.main() diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index e3add0c1ee926c..376175f90f63eb 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -2819,24 +2819,19 @@ def test_binary_to_text_denylists_text_transforms(self): self.assertIsNone(failure.exception.__cause__) @unittest.skipUnless(zlib, "Requires zlib support") - def test_custom_zlib_error_is_wrapped(self): + def test_custom_zlib_error_is_noted(self): # Check zlib codec gives a good error for malformed input - msg = "^decoding with 'zlib_codec' codec failed" - with self.assertRaisesRegex(Exception, msg) as failure: + msg = "decoding with 'zlib_codec' codec failed" + with self.assertRaises(Exception) as failure: codecs.decode(b"hello", "zlib_codec") - self.assertIsInstance(failure.exception.__cause__, - type(failure.exception)) + self.assertEqual(msg, failure.exception.__notes__[0]) - def test_custom_hex_error_is_wrapped(self): + def test_custom_hex_error_is_noted(self): # Check hex codec gives a good error for malformed input - msg = "^decoding with 'hex_codec' codec failed" - with self.assertRaisesRegex(Exception, msg) as failure: + msg = "decoding with 'hex_codec' codec failed" + with self.assertRaises(Exception) as failure: codecs.decode(b"hello", "hex_codec") - self.assertIsInstance(failure.exception.__cause__, - type(failure.exception)) - - # Unfortunately, the bz2 module throws OSError, which the codec - # machinery currently can't wrap :( + self.assertEqual(msg, failure.exception.__notes__[0]) # Ensure codec aliases from http://bugs.python.org/issue7475 work def test_aliases(self): @@ -2860,11 +2855,8 @@ def test_uu_invalid(self): self.assertRaises(ValueError, codecs.decode, b"", "uu-codec") -# The codec system tries to wrap exceptions in order to ensure the error -# mentions the operation being performed and the codec involved. We -# currently *only* want this to happen for relatively stateless -# exceptions, where the only significant information they contain is their -# type and a single str argument. +# The codec system tries to add notes to exceptions in order to ensure +# the error mentions the operation being performed and the codec involved. # Use a local codec registry to avoid appearing to leak objects when # registering multiple search functions @@ -2874,10 +2866,10 @@ def _get_test_codec(codec_name): return _TEST_CODECS.get(codec_name) -class ExceptionChainingTest(unittest.TestCase): +class ExceptionNotesTest(unittest.TestCase): def setUp(self): - self.codec_name = 'exception_chaining_test' + self.codec_name = 'exception_notes_test' codecs.register(_get_test_codec) self.addCleanup(codecs.unregister, _get_test_codec) @@ -2901,91 +2893,77 @@ def set_codec(self, encode, decode): _TEST_CODECS[self.codec_name] = codec_info @contextlib.contextmanager - def assertWrapped(self, operation, exc_type, msg): - full_msg = r"{} with {!r} codec failed \({}: {}\)".format( - operation, self.codec_name, exc_type.__name__, msg) - with self.assertRaisesRegex(exc_type, full_msg) as caught: + def assertNoted(self, operation, exc_type, msg): + full_msg = r"{} with {!r} codec failed".format( + operation, self.codec_name) + with self.assertRaises(exc_type) as caught: yield caught - self.assertIsInstance(caught.exception.__cause__, exc_type) - self.assertIsNotNone(caught.exception.__cause__.__traceback__) + self.assertIn(full_msg, caught.exception.__notes__[0]) + caught.exception.__notes__.clear() def raise_obj(self, *args, **kwds): # Helper to dynamically change the object raised by a test codec raise self.obj_to_raise - def check_wrapped(self, obj_to_raise, msg, exc_type=RuntimeError): + def check_note(self, obj_to_raise, msg, exc_type=RuntimeError): self.obj_to_raise = obj_to_raise self.set_codec(self.raise_obj, self.raise_obj) - with self.assertWrapped("encoding", exc_type, msg): + with self.assertNoted("encoding", exc_type, msg): "str_input".encode(self.codec_name) - with self.assertWrapped("encoding", exc_type, msg): + with self.assertNoted("encoding", exc_type, msg): codecs.encode("str_input", self.codec_name) - with self.assertWrapped("decoding", exc_type, msg): + with self.assertNoted("decoding", exc_type, msg): b"bytes input".decode(self.codec_name) - with self.assertWrapped("decoding", exc_type, msg): + with self.assertNoted("decoding", exc_type, msg): codecs.decode(b"bytes input", self.codec_name) def test_raise_by_type(self): - self.check_wrapped(RuntimeError, "") + self.check_note(RuntimeError, "") def test_raise_by_value(self): - msg = "This should be wrapped" - self.check_wrapped(RuntimeError(msg), msg) + msg = "This should be noted" + self.check_note(RuntimeError(msg), msg) def test_raise_grandchild_subclass_exact_size(self): - msg = "This should be wrapped" + msg = "This should be noted" class MyRuntimeError(RuntimeError): __slots__ = () - self.check_wrapped(MyRuntimeError(msg), msg, MyRuntimeError) + self.check_note(MyRuntimeError(msg), msg, MyRuntimeError) def test_raise_subclass_with_weakref_support(self): - msg = "This should be wrapped" + msg = "This should be noted" class MyRuntimeError(RuntimeError): pass - self.check_wrapped(MyRuntimeError(msg), msg, MyRuntimeError) - - def check_not_wrapped(self, obj_to_raise, msg): - def raise_obj(*args, **kwds): - raise obj_to_raise - self.set_codec(raise_obj, raise_obj) - with self.assertRaisesRegex(RuntimeError, msg): - "str input".encode(self.codec_name) - with self.assertRaisesRegex(RuntimeError, msg): - codecs.encode("str input", self.codec_name) - with self.assertRaisesRegex(RuntimeError, msg): - b"bytes input".decode(self.codec_name) - with self.assertRaisesRegex(RuntimeError, msg): - codecs.decode(b"bytes input", self.codec_name) + self.check_note(MyRuntimeError(msg), msg, MyRuntimeError) - def test_init_override_is_not_wrapped(self): + def test_init_override(self): class CustomInit(RuntimeError): def __init__(self): pass - self.check_not_wrapped(CustomInit, "") + self.check_note(CustomInit, "") - def test_new_override_is_not_wrapped(self): + def test_new_override(self): class CustomNew(RuntimeError): def __new__(cls): return super().__new__(cls) - self.check_not_wrapped(CustomNew, "") + self.check_note(CustomNew, "") - def test_instance_attribute_is_not_wrapped(self): - msg = "This should NOT be wrapped" + def test_instance_attribute(self): + msg = "This should be noted" exc = RuntimeError(msg) exc.attr = 1 - self.check_not_wrapped(exc, "^{}$".format(msg)) + self.check_note(exc, "^{}$".format(msg)) - def test_non_str_arg_is_not_wrapped(self): - self.check_not_wrapped(RuntimeError(1), "1") + def test_non_str_arg(self): + self.check_note(RuntimeError(1), "1") - def test_multiple_args_is_not_wrapped(self): + def test_multiple_args(self): msg_re = r"^\('a', 'b', 'c'\)$" - self.check_not_wrapped(RuntimeError('a', 'b', 'c'), msg_re) + self.check_note(RuntimeError('a', 'b', 'c'), msg_re) # http://bugs.python.org/issue19609 - def test_codec_lookup_failure_not_wrapped(self): + def test_codec_lookup_failure(self): msg = "^unknown encoding: {}$".format(self.codec_name) - # The initial codec lookup should not be wrapped with self.assertRaisesRegex(LookupError, msg): "str input".encode(self.codec_name) with self.assertRaisesRegex(LookupError, msg): diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py index b3520ae3994e03..a20cb844a293c9 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -14,6 +14,7 @@ from logging.handlers import QueueHandler import os import queue +import signal import sys import threading import time @@ -397,6 +398,33 @@ def test_hang_gh83386(self): self.assertFalse(err) self.assertEqual(out.strip(), b"apple") + def test_hang_gh94440(self): + """shutdown(wait=True) doesn't hang when a future was submitted and + quickly canceled right before shutdown. + + See https://github.com/python/cpython/issues/94440. + """ + if not hasattr(signal, 'alarm'): + raise unittest.SkipTest( + "Tested platform does not support the alarm signal") + + def timeout(_signum, _frame): + raise RuntimeError("timed out waiting for shutdown") + + kwargs = {} + if getattr(self, 'ctx', None): + kwargs['mp_context'] = self.get_context() + executor = self.executor_type(max_workers=1, **kwargs) + executor.submit(int).result() + old_handler = signal.signal(signal.SIGALRM, timeout) + try: + signal.alarm(5) + executor.submit(int).cancel() + executor.shutdown(wait=True) + finally: + signal.alarm(0) + signal.signal(signal.SIGALRM, old_handler) + class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase): def test_threads_terminate(self): diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index b77e3b06d0c1f1..fa1de1c7ded1b3 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1026,6 +1026,10 @@ def test_disassemble_try_finally(self): self.do_disassembly_test(_tryfinallyconst, dis_tryfinallyconst) def test_dis_none(self): + try: + del sys.last_exc + except AttributeError: + pass try: del sys.last_traceback except AttributeError: @@ -1043,7 +1047,7 @@ def test_dis_traceback(self): 1/0 except Exception as e: tb = e.__traceback__ - sys.last_traceback = tb + sys.last_exc = e tb_dis = self.get_disassemble_as_string(tb.tb_frame.f_code, tb.tb_lasti) self.do_disassembly_test(None, tb_dis, True) @@ -1900,6 +1904,10 @@ def test_findlabels(self): class TestDisTraceback(DisTestBase): def setUp(self) -> None: + try: # We need to clean up existing tracebacks + del sys.last_exc + except AttributeError: + pass try: # We need to clean up existing tracebacks del sys.last_traceback except AttributeError: diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py index 78afb358035e81..25fa48c5ee217b 100644 --- a/Lib/test/test_email/test_utils.py +++ b/Lib/test/test_email/test_utils.py @@ -83,14 +83,14 @@ def test_localtime_is_tz_aware_daylight_false(self): def test_localtime_daylight_true_dst_false(self): test.support.patch(self, time, 'daylight', True) t0 = datetime.datetime(2012, 3, 12, 1, 1) - t1 = utils.localtime(t0, isdst=-1) + t1 = utils.localtime(t0) t2 = utils.localtime(t1) self.assertEqual(t1, t2) def test_localtime_daylight_false_dst_false(self): test.support.patch(self, time, 'daylight', False) t0 = datetime.datetime(2012, 3, 12, 1, 1) - t1 = utils.localtime(t0, isdst=-1) + t1 = utils.localtime(t0) t2 = utils.localtime(t1) self.assertEqual(t1, t2) @@ -98,7 +98,7 @@ def test_localtime_daylight_false_dst_false(self): def test_localtime_daylight_true_dst_true(self): test.support.patch(self, time, 'daylight', True) t0 = datetime.datetime(2012, 3, 12, 1, 1) - t1 = utils.localtime(t0, isdst=1) + t1 = utils.localtime(t0) t2 = utils.localtime(t1) self.assertEqual(t1, t2) @@ -106,7 +106,7 @@ def test_localtime_daylight_true_dst_true(self): def test_localtime_daylight_false_dst_true(self): test.support.patch(self, time, 'daylight', False) t0 = datetime.datetime(2012, 3, 12, 1, 1) - t1 = utils.localtime(t0, isdst=1) + t1 = utils.localtime(t0) t2 = utils.localtime(t1) self.assertEqual(t1, t2) @@ -157,6 +157,11 @@ def test_variable_tzname(self): t1 = utils.localtime(t0) self.assertEqual(t1.tzname(), 'EET') + def test_isdst_deprecation(self): + with self.assertWarns(DeprecationWarning): + t0 = datetime.datetime(1990, 1, 1) + t1 = utils.localtime(t0, isdst=True) + # Issue #24836: The timezone files are out of date (pre 2011k) # on Mac OS X Snow Leopard. @test.support.requires_mac_ver(10, 7) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 2b14590b2c21af..a11bb441f06e8e 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -4579,15 +4579,14 @@ class Double(Enum): TWO = 2 self.assertEqual(Double.__doc__, None) - - def test_doc_1(self): + def test_doc_3(self): class Triple(Enum): ONE = 1 TWO = 2 THREE = 3 self.assertEqual(Triple.__doc__, None) - def test_doc_1(self): + def test_doc_4(self): class Quadruple(Enum): ONE = 1 TWO = 2 diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 4ae71e431c56dc..284f26be717794 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -599,8 +599,8 @@ def test_notes(self): def testWithTraceback(self): try: raise IndexError(4) - except: - tb = sys.exc_info()[2] + except Exception as e: + tb = e.__traceback__ e = BaseException().with_traceback(tb) self.assertIsInstance(e, BaseException) @@ -653,8 +653,8 @@ def test_invalid_delattr(self): def testNoneClearsTracebackAttr(self): try: raise IndexError(4) - except: - tb = sys.exc_info()[2] + except Exception as e: + tb = e.__traceback__ e = Exception() e.__traceback__ = tb @@ -1337,11 +1337,11 @@ class MyException(Exception, metaclass=Meta): def g(): try: return g() - except RecursionError: - return sys.exc_info() - e, v, tb = g() - self.assertIsInstance(v, RecursionError, type(v)) - self.assertIn("maximum recursion depth exceeded", str(v)) + except RecursionError as e: + return e + exc = g() + self.assertIsInstance(exc, RecursionError, type(exc)) + self.assertIn("maximum recursion depth exceeded", str(exc)) @cpython_only diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 7014bc97100cb4..9fe559d4b7eed5 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -1846,7 +1846,7 @@ def batched_recipe(iterable, n): if n < 1: raise ValueError('n must be at least one') it = iter(iterable) - while (batch := tuple(islice(it, n))): + while batch := tuple(islice(it, n)): yield batch for iterable, n in product( diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 253e2a23238f12..74ece3ffb4ed17 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -556,6 +556,15 @@ def trunc(x): return x nanosecondy = getattr(result, name + "_ns") // 10000 self.assertAlmostEqual(floaty, nanosecondy, delta=2) + # Ensure both birthtime and birthtime_ns roughly agree, if present + try: + floaty = int(result.st_birthtime * 100000) + nanosecondy = result.st_birthtime_ns // 10000 + except AttributeError: + pass + else: + self.assertAlmostEqual(floaty, nanosecondy, delta=2) + try: result[200] self.fail("No exception raised") @@ -2683,12 +2692,17 @@ def test_listvolumes(self): def test_listmounts(self): for volume in os.listvolumes(): - mounts = os.listmounts(volume) - self.assertIsInstance(mounts, list) - self.assertSetEqual( - set(mounts), - self.known_mounts & set(mounts), - ) + try: + mounts = os.listmounts(volume) + except OSError as ex: + if support.verbose: + print("Skipping", volume, "because of", ex) + else: + self.assertIsInstance(mounts, list) + self.assertSetEqual( + set(mounts), + self.known_mounts & set(mounts), + ) @unittest.skipUnless(hasattr(os, 'readlink'), 'needs os.readlink()') @@ -4229,7 +4243,8 @@ def assert_stat_equal(self, stat1, stat2, skip_fields): for attr in dir(stat1): if not attr.startswith("st_"): continue - if attr in ("st_dev", "st_ino", "st_nlink"): + if attr in ("st_dev", "st_ino", "st_nlink", "st_ctime", + "st_ctime_ns"): continue self.assertEqual(getattr(stat1, attr), getattr(stat2, attr), diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index cd43d3854dad15..9e0908193fc11f 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -13,6 +13,7 @@ from unittest import mock from test.support import import_helper +from test.support import set_recursion_limit from test.support import is_emscripten, is_wasi from test.support import os_helper from test.support.os_helper import TESTFN, FakePath @@ -2805,6 +2806,18 @@ def test_walk_many_open_files(self): self.assertEqual(next(it), expected) path = path / 'd' + def test_walk_above_recursion_limit(self): + recursion_limit = 40 + # directory_depth > recursion_limit + directory_depth = recursion_limit + 10 + base = pathlib.Path(os_helper.TESTFN, 'deep') + path = pathlib.Path(base, *(['d'] * directory_depth)) + path.mkdir(parents=True) + + with set_recursion_limit(recursion_limit): + list(base.walk()) + list(base.walk(top_down=False)) + class PathTest(_BasePathTest, unittest.TestCase): cls = pathlib.Path diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 72942dda342418..216973350319fe 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -123,10 +123,6 @@ def test_sys_version(self): for input, output in ( ('2.4.3 (#1, Jun 21 2006, 13:54:21) \n[GCC 3.3.4 (pre 3.3.5 20040809)]', ('CPython', '2.4.3', '', '', '1', 'Jun 21 2006 13:54:21', 'GCC 3.3.4 (pre 3.3.5 20040809)')), - ('IronPython 1.0.60816 on .NET 2.0.50727.42', - ('IronPython', '1.0.60816', '', '', '', '', '.NET 2.0.50727.42')), - ('IronPython 1.0 (1.0.61005.1977) on .NET 2.0.50727.42', - ('IronPython', '1.0.0', '', '', '', '', '.NET 2.0.50727.42')), ('2.4.3 (truncation, date, t) \n[GCC]', ('CPython', '2.4.3', '', '', 'truncation', 'date t', 'GCC')), ('2.4.3 (truncation, date, ) \n[GCC]', @@ -161,20 +157,11 @@ def test_sys_version(self): ('r261:67515', 'Dec 6 2008 15:26:00'), 'GCC 4.0.1 (Apple Computer, Inc. build 5370)'), - ("IronPython 2.0 (2.0.0.0) on .NET 2.0.50727.3053", None, "cli") + ("3.10.8 (tags/v3.10.8:aaaf517424, Feb 14 2023, 16:28:12) [GCC 9.4.0]", + None, "linux") : - ("IronPython", "2.0.0", "", "", ("", ""), - ".NET 2.0.50727.3053"), - - ("2.6.1 (IronPython 2.6.1 (2.6.10920.0) on .NET 2.0.50727.1433)", None, "cli") - : - ("IronPython", "2.6.1", "", "", ("", ""), - ".NET 2.0.50727.1433"), - - ("2.7.4 (IronPython 2.7.4 (2.7.0.40) on Mono 4.0.30319.1 (32-bit))", None, "cli") - : - ("IronPython", "2.7.4", "", "", ("", ""), - "Mono 4.0.30319.1 (32-bit)"), + ('CPython', '3.10.8', '', '', + ('tags/v3.10.8:aaaf517424', 'Feb 14 2023 16:28:12'), 'GCC 9.4.0'), ("2.5 (trunk:6107, Mar 26 2009, 13:02:18) \n[Java HotSpot(TM) Client VM (\"Apple Computer, Inc.\")]", ('Jython', 'trunk', '6107'), "java1.5.0_16") @@ -205,6 +192,9 @@ def test_sys_version(self): self.assertEqual(platform.python_build(), info[4]) self.assertEqual(platform.python_compiler(), info[5]) + with self.assertRaises(ValueError): + platform._sys_version('2. 4.3 (truncation) \n[GCC]') + def test_system_alias(self): res = platform.system_alias( platform.system(), diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 8fe62216ecdca0..1c0589ced9ea89 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -23,6 +23,7 @@ unregister_unpack_format, get_unpack_formats, SameFileError, _GiveupOnFastCopy) import tarfile +import warnings import zipfile try: import posix @@ -195,7 +196,7 @@ def test_rmtree_works_on_bytes(self): shutil.rmtree(victim) @os_helper.skip_unless_symlink - def test_rmtree_fails_on_symlink(self): + def test_rmtree_fails_on_symlink_onerror(self): tmp = self.mkdtemp() dir_ = os.path.join(tmp, 'dir') os.mkdir(dir_) @@ -207,12 +208,32 @@ def test_rmtree_fails_on_symlink(self): errors = [] def onerror(*args): errors.append(args) - shutil.rmtree(link, onerror=onerror) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(link, onerror=onerror) self.assertEqual(len(errors), 1) self.assertIs(errors[0][0], os.path.islink) self.assertEqual(errors[0][1], link) self.assertIsInstance(errors[0][2][1], OSError) + @os_helper.skip_unless_symlink + def test_rmtree_fails_on_symlink_onexc(self): + tmp = self.mkdtemp() + dir_ = os.path.join(tmp, 'dir') + os.mkdir(dir_) + link = os.path.join(tmp, 'link') + os.symlink(dir_, link) + self.assertRaises(OSError, shutil.rmtree, link) + self.assertTrue(os.path.exists(dir_)) + self.assertTrue(os.path.lexists(link)) + errors = [] + def onexc(*args): + errors.append(args) + shutil.rmtree(link, onexc=onexc) + self.assertEqual(len(errors), 1) + self.assertIs(errors[0][0], os.path.islink) + self.assertEqual(errors[0][1], link) + self.assertIsInstance(errors[0][2], OSError) + @os_helper.skip_unless_symlink def test_rmtree_works_on_symlinks(self): tmp = self.mkdtemp() @@ -236,7 +257,7 @@ def test_rmtree_works_on_symlinks(self): self.assertTrue(os.path.exists(file1)) @unittest.skipUnless(_winapi, 'only relevant on Windows') - def test_rmtree_fails_on_junctions(self): + def test_rmtree_fails_on_junctions_onerror(self): tmp = self.mkdtemp() dir_ = os.path.join(tmp, 'dir') os.mkdir(dir_) @@ -249,12 +270,33 @@ def test_rmtree_fails_on_junctions(self): errors = [] def onerror(*args): errors.append(args) - shutil.rmtree(link, onerror=onerror) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(link, onerror=onerror) self.assertEqual(len(errors), 1) self.assertIs(errors[0][0], os.path.islink) self.assertEqual(errors[0][1], link) self.assertIsInstance(errors[0][2][1], OSError) + @unittest.skipUnless(_winapi, 'only relevant on Windows') + def test_rmtree_fails_on_junctions_onexc(self): + tmp = self.mkdtemp() + dir_ = os.path.join(tmp, 'dir') + os.mkdir(dir_) + link = os.path.join(tmp, 'link') + _winapi.CreateJunction(dir_, link) + self.addCleanup(os_helper.unlink, link) + self.assertRaises(OSError, shutil.rmtree, link) + self.assertTrue(os.path.exists(dir_)) + self.assertTrue(os.path.lexists(link)) + errors = [] + def onexc(*args): + errors.append(args) + shutil.rmtree(link, onexc=onexc) + self.assertEqual(len(errors), 1) + self.assertIs(errors[0][0], os.path.islink) + self.assertEqual(errors[0][1], link) + self.assertIsInstance(errors[0][2], OSError) + @unittest.skipUnless(_winapi, 'only relevant on Windows') def test_rmtree_works_on_junctions(self): tmp = self.mkdtemp() @@ -277,7 +319,7 @@ def test_rmtree_works_on_junctions(self): self.assertTrue(os.path.exists(dir3)) self.assertTrue(os.path.exists(file1)) - def test_rmtree_errors(self): + def test_rmtree_errors_onerror(self): # filename is guaranteed not to exist filename = tempfile.mktemp(dir=self.mkdtemp()) self.assertRaises(FileNotFoundError, shutil.rmtree, filename) @@ -298,7 +340,8 @@ def test_rmtree_errors(self): errors = [] def onerror(*args): errors.append(args) - shutil.rmtree(filename, onerror=onerror) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(filename, onerror=onerror) self.assertEqual(len(errors), 2) self.assertIs(errors[0][0], os.scandir) self.assertEqual(errors[0][1], filename) @@ -309,6 +352,37 @@ def onerror(*args): self.assertIsInstance(errors[1][2][1], NotADirectoryError) self.assertEqual(errors[1][2][1].filename, filename) + def test_rmtree_errors_onexc(self): + # filename is guaranteed not to exist + filename = tempfile.mktemp(dir=self.mkdtemp()) + self.assertRaises(FileNotFoundError, shutil.rmtree, filename) + # test that ignore_errors option is honored + shutil.rmtree(filename, ignore_errors=True) + + # existing file + tmpdir = self.mkdtemp() + write_file((tmpdir, "tstfile"), "") + filename = os.path.join(tmpdir, "tstfile") + with self.assertRaises(NotADirectoryError) as cm: + shutil.rmtree(filename) + self.assertEqual(cm.exception.filename, filename) + self.assertTrue(os.path.exists(filename)) + # test that ignore_errors option is honored + shutil.rmtree(filename, ignore_errors=True) + self.assertTrue(os.path.exists(filename)) + errors = [] + def onexc(*args): + errors.append(args) + shutil.rmtree(filename, onexc=onexc) + self.assertEqual(len(errors), 2) + self.assertIs(errors[0][0], os.scandir) + self.assertEqual(errors[0][1], filename) + self.assertIsInstance(errors[0][2], NotADirectoryError) + self.assertEqual(errors[0][2].filename, filename) + self.assertIs(errors[1][0], os.rmdir) + self.assertEqual(errors[1][1], filename) + self.assertIsInstance(errors[1][2], NotADirectoryError) + self.assertEqual(errors[1][2].filename, filename) @unittest.skipIf(sys.platform[:6] == 'cygwin', "This test can't be run on Cygwin (issue #1071513).") @@ -336,7 +410,8 @@ def test_on_error(self): self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode) self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode) - shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) # Test whether onerror has actually been called. self.assertEqual(self.errorState, 3, "Expected call to onerror function did not happen.") @@ -368,6 +443,105 @@ def check_args_to_onerror(self, func, arg, exc): self.assertTrue(issubclass(exc[0], OSError)) self.errorState = 3 + @unittest.skipIf(sys.platform[:6] == 'cygwin', + "This test can't be run on Cygwin (issue #1071513).") + @os_helper.skip_if_dac_override + @os_helper.skip_unless_working_chmod + def test_on_exc(self): + self.errorState = 0 + os.mkdir(TESTFN) + self.addCleanup(shutil.rmtree, TESTFN) + + self.child_file_path = os.path.join(TESTFN, 'a') + self.child_dir_path = os.path.join(TESTFN, 'b') + os_helper.create_empty_file(self.child_file_path) + os.mkdir(self.child_dir_path) + old_dir_mode = os.stat(TESTFN).st_mode + old_child_file_mode = os.stat(self.child_file_path).st_mode + old_child_dir_mode = os.stat(self.child_dir_path).st_mode + # Make unwritable. + new_mode = stat.S_IREAD|stat.S_IEXEC + os.chmod(self.child_file_path, new_mode) + os.chmod(self.child_dir_path, new_mode) + os.chmod(TESTFN, new_mode) + + self.addCleanup(os.chmod, TESTFN, old_dir_mode) + self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode) + self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode) + + shutil.rmtree(TESTFN, onexc=self.check_args_to_onexc) + # Test whether onexc has actually been called. + self.assertEqual(self.errorState, 3, + "Expected call to onexc function did not happen.") + + def check_args_to_onexc(self, func, arg, exc): + # test_rmtree_errors deliberately runs rmtree + # on a directory that is chmod 500, which will fail. + # This function is run when shutil.rmtree fails. + # 99.9% of the time it initially fails to remove + # a file in the directory, so the first time through + # func is os.remove. + # However, some Linux machines running ZFS on + # FUSE experienced a failure earlier in the process + # at os.listdir. The first failure may legally + # be either. + if self.errorState < 2: + if func is os.unlink: + self.assertEqual(arg, self.child_file_path) + elif func is os.rmdir: + self.assertEqual(arg, self.child_dir_path) + else: + self.assertIs(func, os.listdir) + self.assertIn(arg, [TESTFN, self.child_dir_path]) + self.assertTrue(isinstance(exc, OSError)) + self.errorState += 1 + else: + self.assertEqual(func, os.rmdir) + self.assertEqual(arg, TESTFN) + self.assertTrue(isinstance(exc, OSError)) + self.errorState = 3 + + @unittest.skipIf(sys.platform[:6] == 'cygwin', + "This test can't be run on Cygwin (issue #1071513).") + @os_helper.skip_if_dac_override + @os_helper.skip_unless_working_chmod + def test_both_onerror_and_onexc(self): + onerror_called = False + onexc_called = False + + def onerror(*args): + nonlocal onerror_called + onerror_called = True + + def onexc(*args): + nonlocal onexc_called + onexc_called = True + + os.mkdir(TESTFN) + self.addCleanup(shutil.rmtree, TESTFN) + + self.child_file_path = os.path.join(TESTFN, 'a') + self.child_dir_path = os.path.join(TESTFN, 'b') + os_helper.create_empty_file(self.child_file_path) + os.mkdir(self.child_dir_path) + old_dir_mode = os.stat(TESTFN).st_mode + old_child_file_mode = os.stat(self.child_file_path).st_mode + old_child_dir_mode = os.stat(self.child_dir_path).st_mode + # Make unwritable. + new_mode = stat.S_IREAD|stat.S_IEXEC + os.chmod(self.child_file_path, new_mode) + os.chmod(self.child_dir_path, new_mode) + os.chmod(TESTFN, new_mode) + + self.addCleanup(os.chmod, TESTFN, old_dir_mode) + self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode) + self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode) + + with self.assertWarns(DeprecationWarning): + shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc) + self.assertTrue(onexc_called) + self.assertFalse(onerror_called) + def test_rmtree_does_not_choke_on_failing_lstat(self): try: orig_lstat = os.lstat diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index a313da29b4a4fd..60f106f2d1a1c2 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -5492,10 +5492,10 @@ def alarm_handler(signal, frame): self.fail("caught timeout instead of Alarm") except Alarm: pass - except: + except BaseException as e: self.fail("caught other exception instead of Alarm:" " %s(%s):\n%s" % - (sys.exc_info()[:2] + (traceback.format_exc(),))) + (type(e), e, traceback.format_exc())) else: self.fail("nothing caught") finally: diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 695e213cdc7b75..3013abfa730ed5 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -606,7 +606,6 @@ def test_serialize_deserialize(self): with cx: cx.execute("create table t(t)") data = cx.serialize() - self.assertEqual(len(data), 8192) # Remove test table, verify that it was removed. with cx: diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index d4eb2d2e81fe0f..1317efb33c2306 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -151,7 +151,6 @@ def data_file(*name): OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0) OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0) OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0) -OP_IGNORE_UNEXPECTED_EOF = getattr(ssl, "OP_IGNORE_UNEXPECTED_EOF", 0) # Ubuntu has patched OpenSSL and changed behavior of security level 2 # see https://bugs.python.org/issue41561#msg389003 @@ -958,8 +957,7 @@ def test_options(self): # SSLContext also enables these by default default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE | OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE | - OP_ENABLE_MIDDLEBOX_COMPAT | - OP_IGNORE_UNEXPECTED_EOF) + OP_ENABLE_MIDDLEBOX_COMPAT) self.assertEqual(default, ctx.options) with warnings_helper.check_warnings(): ctx.options |= ssl.OP_NO_TLSv1 @@ -2084,13 +2082,13 @@ def test_bio_handshake(self): self.assertIs(sslobj._sslobj.owner, sslobj) self.assertIsNone(sslobj.cipher()) self.assertIsNone(sslobj.version()) - self.assertIsNotNone(sslobj.shared_ciphers()) + self.assertIsNone(sslobj.shared_ciphers()) self.assertRaises(ValueError, sslobj.getpeercert) if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: self.assertIsNone(sslobj.get_channel_binding('tls-unique')) self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) self.assertTrue(sslobj.cipher()) - self.assertIsNotNone(sslobj.shared_ciphers()) + self.assertIsNone(sslobj.shared_ciphers()) self.assertIsNotNone(sslobj.version()) self.assertTrue(sslobj.getpeercert()) if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: @@ -2120,6 +2118,20 @@ def test_bio_read_write_data(self): self.assertEqual(buf, b'foo\n') self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap) + def test_transport_eof(self): + client_context, server_context, hostname = testing_context() + with socket.socket(socket.AF_INET) as sock: + sock.connect(self.server_addr) + incoming = ssl.MemoryBIO() + outgoing = ssl.MemoryBIO() + sslobj = client_context.wrap_bio(incoming, outgoing, + server_hostname=hostname) + self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) + + # Simulate EOF from the transport. + incoming.write_eof() + self.assertRaises(ssl.SSLEOFError, sslobj.read) + @support.requires_resource('network') class NetworkedTests(unittest.TestCase): @@ -4039,7 +4051,7 @@ def cb_wrong_return_type(ssl_sock, server_name, initial_context): def test_shared_ciphers(self): client_context, server_context, hostname = testing_context() client_context.set_ciphers("AES128:AES256") - server_context.set_ciphers("AES256") + server_context.set_ciphers("AES256:eNULL") expected_algs = [ "AES256", "AES-256", # TLS 1.3 ciphers are always enabled diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index e77c1c8409880d..2feaaf8603b831 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -166,6 +166,7 @@ def test_windows_feature_macros(self): "PyErr_CheckSignals", "PyErr_Clear", "PyErr_Display", + "PyErr_DisplayException", "PyErr_ExceptionMatches", "PyErr_Fetch", "PyErr_Format", diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py index 31a3cb6b53a6f2..f0fa6454b1f91a 100644 --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -1,4 +1,4 @@ -"""Test suite for statistics module, including helper NumericTestCase and +x = """Test suite for statistics module, including helper NumericTestCase and approx_equal function. """ @@ -2610,6 +2610,16 @@ def test_proportional(self): self.assertAlmostEqual(slope, 20 + 1/150) self.assertEqual(intercept, 0.0) + def test_float_output(self): + x = [Fraction(2, 3), Fraction(3, 4)] + y = [Fraction(4, 5), Fraction(5, 6)] + slope, intercept = statistics.linear_regression(x, y) + self.assertTrue(isinstance(slope, float)) + self.assertTrue(isinstance(intercept, float)) + slope, intercept = statistics.linear_regression(x, y, proportional=True) + self.assertTrue(isinstance(slope, float)) + self.assertTrue(isinstance(intercept, float)) + class TestNormalDist: # General note on precision: The pdf(), cdf(), and overlap() methods diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index b839985def9a12..fb578c5ae6e5d5 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1649,8 +1649,8 @@ def test_pythontypes(self): check(_ast.AST(), size('P')) try: raise TypeError - except TypeError: - tb = sys.exc_info()[2] + except TypeError as e: + tb = e.__traceback__ # traceback if tb is not None: check(tb, size('2P2i')) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 92c5a000585855..399c59f8780d8e 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -296,15 +296,15 @@ class PrintExceptionAtExit(object): def __init__(self): try: x = 1 / 0 - except Exception: - self.exc_info = sys.exc_info() - # self.exc_info[1] (traceback) contains frames: + except Exception as e: + self.exc = e + # self.exc.__traceback__ contains frames: # explicitly clear the reference to self in the current # frame to break a reference cycle self = None def __del__(self): - traceback.print_exception(*self.exc_info) + traceback.print_exception(self.exc) # Keep a reference in the module namespace to call the destructor # when the module is unloaded @@ -394,6 +394,8 @@ def get_exception(self, callable, slice_start=0, slice_end=-1): class CAPIExceptionFormattingMixin: + LEGACY = 0 + def get_exception(self, callable, slice_start=0, slice_end=-1): from _testcapi import exception_print try: @@ -401,11 +403,13 @@ def get_exception(self, callable, slice_start=0, slice_end=-1): self.fail("No exception thrown.") except Exception as e: with captured_output("stderr") as tbstderr: - exception_print(e) + exception_print(e, self.LEGACY) return tbstderr.getvalue().splitlines()[slice_start:slice_end] callable_line = get_exception.__code__.co_firstlineno + 3 +class CAPIExceptionFormattingLegacyMixin(CAPIExceptionFormattingMixin): + LEGACY = 1 @requires_debug_ranges() class TracebackErrorLocationCaretTestBase: @@ -912,6 +916,16 @@ class CPythonTracebackErrorCaretTests( Same set of tests as above but with Python's internal traceback printing. """ +@cpython_only +@requires_debug_ranges() +class CPythonTracebackErrorCaretTests( + CAPIExceptionFormattingLegacyMixin, + TracebackErrorLocationCaretTestBase, + unittest.TestCase, +): + """ + Same set of tests as above but with Python's legacy internal traceback printing. + """ class TracebackFormatTests(unittest.TestCase): @@ -923,8 +937,8 @@ def check_traceback_format(self, cleanup_func=None): from _testcapi import traceback_print try: self.some_exception() - except KeyError: - type_, value, tb = sys.exc_info() + except KeyError as e: + tb = e.__traceback__ if cleanup_func is not None: # Clear the inner frames, not this one cleanup_func(tb.tb_next) @@ -1228,8 +1242,8 @@ def __eq__(self, other): except UnhashableException: try: raise ex1 - except UnhashableException: - exc_type, exc_val, exc_tb = sys.exc_info() + except UnhashableException as e: + exc_val = e with captured_output("stderr") as stderr_f: exception_print(exc_val) @@ -2133,8 +2147,8 @@ def assertEqualExcept(actual, expected, ignore): def test_extract_tb(self): try: self.last_raises5() - except Exception: - exc_type, exc_value, tb = sys.exc_info() + except Exception as e: + tb = e.__traceback__ def extract(**kwargs): return traceback.extract_tb(tb, **kwargs) @@ -2160,12 +2174,12 @@ def extract(**kwargs): def test_format_exception(self): try: self.last_raises5() - except Exception: - exc_type, exc_value, tb = sys.exc_info() + except Exception as e: + exc = e # [1:-1] to exclude "Traceback (...)" header and # exception type and value def extract(**kwargs): - return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1] + return traceback.format_exception(exc, **kwargs)[1:-1] with support.swap_attr(sys, 'tracebacklimit', 1000): nolim = extract() @@ -2203,8 +2217,8 @@ def inner(): try: outer() - except: - type_, value, tb = sys.exc_info() + except BaseException as e: + tb = e.__traceback__ # Initial assertion: there's one local in the inner frame. inner_frame = tb.tb_next.tb_next.tb_next.tb_frame @@ -2282,8 +2296,8 @@ def deeper(): def test_walk_tb(self): try: 1/0 - except Exception: - _, _, tb = sys.exc_info() + except Exception as e: + tb = e.__traceback__ s = list(traceback.walk_tb(tb)) self.assertEqual(len(s), 1) @@ -2386,10 +2400,10 @@ def f(): def g(): try: f() - except: - return sys.exc_info() + except Exception as e: + return e.__traceback__ - exc_info = g() + tb = g() class Skip_G(traceback.StackSummary): def format_frame_summary(self, frame_summary): @@ -2398,7 +2412,7 @@ def format_frame_summary(self, frame_summary): return super().format_frame_summary(frame_summary) stack = Skip_G.extract( - traceback.walk_tb(exc_info[2])).format() + traceback.walk_tb(tb)).format() self.assertEqual(len(stack), 1) lno = f.__code__.co_firstlineno + 1 @@ -2416,17 +2430,17 @@ class TestTracebackException(unittest.TestCase): def test_smoke(self): try: 1/0 - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(e) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(e.__traceback__)) self.assertEqual(None, exc.__cause__) self.assertEqual(None, exc.__context__) self.assertEqual(False, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_from_exception(self): # Check all the parameters are accepted. @@ -2435,9 +2449,10 @@ def foo(): try: foo() except Exception as e: - exc_info = sys.exc_info() + exc_obj = e + tb = e.__traceback__ self.expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False, + traceback.walk_tb(tb), limit=1, lookup_lines=False, capture_locals=True) self.exc = traceback.TracebackException.from_exception( e, limit=1, lookup_lines=False, capture_locals=True) @@ -2447,8 +2462,8 @@ def foo(): self.assertEqual(None, exc.__context__) self.assertEqual(False, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_cause(self): try: @@ -2459,18 +2474,18 @@ def test_cause(self): exc_context = traceback.TracebackException(*exc_info_context) cause = Exception("cause") raise Exception("uh oh") from cause - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(e) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(e.__traceback__)) exc_cause = traceback.TracebackException(Exception, cause, None) self.assertEqual(exc_cause, exc.__cause__) self.assertEqual(exc_context, exc.__context__) self.assertEqual(True, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_context(self): try: @@ -2480,17 +2495,17 @@ def test_context(self): exc_info_context = sys.exc_info() exc_context = traceback.TracebackException(*exc_info_context) raise Exception("uh oh") - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(e) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(e.__traceback__)) self.assertEqual(None, exc.__cause__) self.assertEqual(exc_context, exc.__context__) self.assertEqual(False, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_long_context_chain(self): def f(): @@ -2501,12 +2516,12 @@ def f(): try: f() - except RecursionError: - exc_info = sys.exc_info() + except RecursionError as e: + exc_obj = e else: self.fail("Exception not raised") - te = traceback.TracebackException(*exc_info) + te = traceback.TracebackException.from_exception(exc_obj) res = list(te.format()) # many ZeroDiv errors followed by the RecursionError @@ -2524,18 +2539,18 @@ def test_compact_with_cause(self): finally: cause = Exception("cause") raise Exception("uh oh") from cause - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info, compact=True) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(exc_obj, compact=True) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(exc_obj.__traceback__)) exc_cause = traceback.TracebackException(Exception, cause, None) self.assertEqual(exc_cause, exc.__cause__) self.assertEqual(None, exc.__context__) self.assertEqual(True, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_compact_no_cause(self): try: @@ -2545,37 +2560,37 @@ def test_compact_no_cause(self): exc_info_context = sys.exc_info() exc_context = traceback.TracebackException(*exc_info_context) raise Exception("uh oh") - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info, compact=True) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(e, compact=True) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(exc_obj.__traceback__)) self.assertEqual(None, exc.__cause__) self.assertEqual(exc_context, exc.__context__) self.assertEqual(False, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_no_refs_to_exception_and_traceback_objects(self): try: 1/0 - except Exception: - exc_info = sys.exc_info() + except Exception as e: + exc_obj = e - refcnt1 = sys.getrefcount(exc_info[1]) - refcnt2 = sys.getrefcount(exc_info[2]) - exc = traceback.TracebackException(*exc_info) - self.assertEqual(sys.getrefcount(exc_info[1]), refcnt1) - self.assertEqual(sys.getrefcount(exc_info[2]), refcnt2) + refcnt1 = sys.getrefcount(exc_obj) + refcnt2 = sys.getrefcount(exc_obj.__traceback__) + exc = traceback.TracebackException.from_exception(exc_obj) + self.assertEqual(sys.getrefcount(exc_obj), refcnt1) + self.assertEqual(sys.getrefcount(exc_obj.__traceback__), refcnt2) def test_comparison_basic(self): try: 1/0 - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) - exc2 = traceback.TracebackException(*exc_info) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(exc_obj) + exc2 = traceback.TracebackException.from_exception(exc_obj) self.assertIsNot(exc, exc2) self.assertEqual(exc, exc2) self.assertNotEqual(exc, object()) @@ -2594,28 +2609,28 @@ def raise_with_locals(): try: raise_with_locals() - except Exception: - exc_info = sys.exc_info() + except Exception as e: + exc_obj = e - exc = traceback.TracebackException(*exc_info) - exc1 = traceback.TracebackException(*exc_info, limit=10) - exc2 = traceback.TracebackException(*exc_info, limit=2) + exc = traceback.TracebackException.from_exception(exc_obj) + exc1 = traceback.TracebackException.from_exception(exc_obj, limit=10) + exc2 = traceback.TracebackException.from_exception(exc_obj, limit=2) self.assertEqual(exc, exc1) # limit=10 gets all frames self.assertNotEqual(exc, exc2) # limit=2 truncates the output # locals change the output - exc3 = traceback.TracebackException(*exc_info, capture_locals=True) + exc3 = traceback.TracebackException.from_exception(exc_obj, capture_locals=True) self.assertNotEqual(exc, exc3) # there are no locals in the innermost frame - exc4 = traceback.TracebackException(*exc_info, limit=-1) - exc5 = traceback.TracebackException(*exc_info, limit=-1, capture_locals=True) + exc4 = traceback.TracebackException.from_exception(exc_obj, limit=-1) + exc5 = traceback.TracebackException.from_exception(exc_obj, limit=-1, capture_locals=True) self.assertEqual(exc4, exc5) # there are locals in the next-to-innermost frame - exc6 = traceback.TracebackException(*exc_info, limit=-2) - exc7 = traceback.TracebackException(*exc_info, limit=-2, capture_locals=True) + exc6 = traceback.TracebackException.from_exception(exc_obj, limit=-2) + exc7 = traceback.TracebackException.from_exception(exc_obj, limit=-2, capture_locals=True) self.assertNotEqual(exc6, exc7) def test_comparison_equivalent_exceptions_are_equal(self): @@ -2623,8 +2638,8 @@ def test_comparison_equivalent_exceptions_are_equal(self): for _ in range(2): try: 1/0 - except: - excs.append(traceback.TracebackException(*sys.exc_info())) + except Exception as e: + excs.append(traceback.TracebackException.from_exception(e)) self.assertEqual(excs[0], excs[1]) self.assertEqual(list(excs[0].format()), list(excs[1].format())) @@ -2640,9 +2655,9 @@ def __eq__(self, other): except UnhashableException: try: raise ex1 - except UnhashableException: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) + except UnhashableException as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(exc_obj) formatted = list(exc.format()) self.assertIn('UnhashableException: ex2\n', formatted[2]) self.assertIn('UnhashableException: ex1\n', formatted[6]) @@ -2655,11 +2670,10 @@ def recurse(n): 1/0 try: recurse(10) - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info, limit=5) + except Exception as e: + exc = traceback.TracebackException.from_exception(e, limit=5) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2]), limit=5) + traceback.walk_tb(e.__traceback__), limit=5) self.assertEqual(expected_stack, exc.stack) def test_lookup_lines(self): @@ -2706,9 +2720,9 @@ def f(): x = 12 try: x/0 - except Exception: - return sys.exc_info() - exc = traceback.TracebackException(*f(), capture_locals=True) + except Exception as e: + return e + exc = traceback.TracebackException.from_exception(f(), capture_locals=True) output = StringIO() exc.print(file=output) self.assertEqual( @@ -2723,7 +2737,7 @@ def f(): class TestTracebackException_ExceptionGroups(unittest.TestCase): def setUp(self): super().setUp() - self.eg_info = self._get_exception_group() + self.eg = self._get_exception_group() def _get_exception_group(self): def f(): @@ -2753,26 +2767,26 @@ def g(v): except Exception as e: exc4 = e raise ExceptionGroup("eg2", [exc3, exc4]) - except ExceptionGroup: - return sys.exc_info() + except ExceptionGroup as eg: + return eg self.fail('Exception Not Raised') def test_exception_group_construction(self): - eg_info = self.eg_info - teg1 = traceback.TracebackException(*eg_info) - teg2 = traceback.TracebackException.from_exception(eg_info[1]) + eg = self.eg + teg1 = traceback.TracebackException(type(eg), eg, eg.__traceback__) + teg2 = traceback.TracebackException.from_exception(eg) self.assertIsNot(teg1, teg2) self.assertEqual(teg1, teg2) def test_exception_group_format_exception_only(self): - teg = traceback.TracebackException(*self.eg_info) + teg = traceback.TracebackException.from_exception(self.eg) formatted = ''.join(teg.format_exception_only()).split('\n') expected = "ExceptionGroup: eg2 (2 sub-exceptions)\n".split('\n') self.assertEqual(formatted, expected) def test_exception_group_format(self): - teg = traceback.TracebackException(*self.eg_info) + teg = traceback.TracebackException.from_exception(self.eg) formatted = ''.join(teg.format()).split('\n') lno_f = self.lno_f @@ -2884,18 +2898,18 @@ def test_max_group_depth(self): def test_comparison(self): try: - raise self.eg_info[1] - except ExceptionGroup: - exc_info = sys.exc_info() + raise self.eg + except ExceptionGroup as e: + exc = e for _ in range(5): try: - raise exc_info[1] - except: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) - exc2 = traceback.TracebackException(*exc_info) - exc3 = traceback.TracebackException(*exc_info, limit=300) - ne = traceback.TracebackException(*exc_info, limit=3) + raise exc + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(exc_obj) + exc2 = traceback.TracebackException.from_exception(exc_obj) + exc3 = traceback.TracebackException.from_exception(exc_obj, limit=300) + ne = traceback.TracebackException.from_exception(exc_obj, limit=3) self.assertIsNot(exc, exc2) self.assertEqual(exc, exc2) self.assertEqual(exc, exc3) @@ -2987,7 +3001,7 @@ class MyClass: def test_getattr_suggestions_do_not_trigger_for_big_dicts(self): class A: blech = None - # A class with a very big __dict__ will not be consider + # A class with a very big __dict__ will not be considered # for suggestions. for index in range(2000): setattr(A, f"index_{index}", None) diff --git a/Lib/test/test_ttk/test_extensions.py b/Lib/test/test_ttk/test_extensions.py index 6135c49701f08e..d5e069716971fe 100644 --- a/Lib/test/test_ttk/test_extensions.py +++ b/Lib/test/test_ttk/test_extensions.py @@ -45,7 +45,9 @@ def test_widget_destroy(self): # value which causes the tracing callback to be called and then # it tries calling instance attributes not yet defined. ttk.LabeledScale(self.root, variable=myvar) - if hasattr(sys, 'last_type'): + if hasattr(sys, 'last_exc'): + self.assertNotEqual(type(sys.last_exc), tkinter.TclError) + elif hasattr(sys, 'last_type'): self.assertNotEqual(sys.last_type, tkinter.TclError) def test_initialization(self): diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index c17be6cd0bbc4a..c9f55de95c548f 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1921,14 +1921,29 @@ def test_weakref(self): self.assertEqual(weakref.ref(alias)(), alias) def test_pickle(self): + global T_pickle, P_pickle, TS_pickle # needed for pickling Callable = self.Callable - alias = Callable[[int, str], float] - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - s = pickle.dumps(alias, proto) - loaded = pickle.loads(s) - self.assertEqual(alias.__origin__, loaded.__origin__) - self.assertEqual(alias.__args__, loaded.__args__) - self.assertEqual(alias.__parameters__, loaded.__parameters__) + T_pickle = TypeVar('T_pickle') + P_pickle = ParamSpec('P_pickle') + TS_pickle = TypeVarTuple('TS_pickle') + + samples = [ + Callable[[int, str], float], + Callable[P_pickle, int], + Callable[P_pickle, T_pickle], + Callable[Concatenate[int, P_pickle], int], + Callable[Concatenate[*TS_pickle, P_pickle], int], + ] + for alias in samples: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(alias=alias, proto=proto): + s = pickle.dumps(alias, proto) + loaded = pickle.loads(s) + self.assertEqual(alias.__origin__, loaded.__origin__) + self.assertEqual(alias.__args__, loaded.__args__) + self.assertEqual(alias.__parameters__, loaded.__parameters__) + + del T_pickle, P_pickle, TS_pickle # cleaning up global state def test_var_substitution(self): Callable = self.Callable @@ -1954,6 +1969,16 @@ def test_var_substitution(self): self.assertEqual(C5[int, str, float], Callable[[typing.List[int], tuple[str, int], float], int]) + def test_type_subst_error(self): + Callable = self.Callable + P = ParamSpec('P') + T = TypeVar('T') + + pat = "Expected a list of types, an ellipsis, ParamSpec, or Concatenate." + + with self.assertRaisesRegex(TypeError, pat): + Callable[P, T][0, int] + def test_type_erasure(self): Callable = self.Callable class C1(Callable): @@ -3809,6 +3834,51 @@ class Y(C[int]): self.assertEqual(Y.__qualname__, 'GenericTests.test_repr_2..Y') + def test_repr_3(self): + T = TypeVar('T') + T1 = TypeVar('T1') + P = ParamSpec('P') + P2 = ParamSpec('P2') + Ts = TypeVarTuple('Ts') + + class MyCallable(Generic[P, T]): + pass + + class DoubleSpec(Generic[P, P2, T]): + pass + + class TsP(Generic[*Ts, P]): + pass + + object_to_expected_repr = { + MyCallable[P, T]: "MyCallable[~P, ~T]", + MyCallable[Concatenate[T1, P], T]: "MyCallable[typing.Concatenate[~T1, ~P], ~T]", + MyCallable[[], bool]: "MyCallable[[], bool]", + MyCallable[[int], bool]: "MyCallable[[int], bool]", + MyCallable[[int, str], bool]: "MyCallable[[int, str], bool]", + MyCallable[[int, list[int]], bool]: "MyCallable[[int, list[int]], bool]", + MyCallable[Concatenate[*Ts, P], T]: "MyCallable[typing.Concatenate[*Ts, ~P], ~T]", + + DoubleSpec[P2, P, T]: "DoubleSpec[~P2, ~P, ~T]", + DoubleSpec[[int], [str], bool]: "DoubleSpec[[int], [str], bool]", + DoubleSpec[[int, int], [str, str], bool]: "DoubleSpec[[int, int], [str, str], bool]", + + TsP[*Ts, P]: "TsP[*Ts, ~P]", + TsP[int, str, list[int], []]: "TsP[int, str, list[int], []]", + TsP[int, [str, list[int]]]: "TsP[int, [str, list[int]]]", + + # These lines are just too long to fit: + MyCallable[Concatenate[*Ts, P], int][int, str, [bool, float]]: + "MyCallable[[int, str, bool, float], int]", + } + + for obj, expected_repr in object_to_expected_repr.items(): + with self.subTest(obj=obj, expected_repr=expected_repr): + self.assertRegex( + repr(obj), + fr"^{re.escape(MyCallable.__module__)}.*\.{re.escape(expected_repr)}$", + ) + def test_eq_1(self): self.assertEqual(Generic, Generic) self.assertEqual(Generic[T], Generic[T]) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 7565e0f7e46073..479daf0e5abfc3 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -2400,6 +2400,7 @@ def report_callback_exception(self, exc, val, tb): should when sys.stderr is None.""" import traceback print("Exception in Tkinter callback", file=sys.stderr) + sys.last_exc = val sys.last_type = exc sys.last_value = val sys.last_traceback = tb diff --git a/Lib/traceback.py b/Lib/traceback.py index c43c4720ae5a15..9e720ac9948fce 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -179,7 +179,7 @@ def _safe_string(value, what, func=str): # -- def print_exc(limit=None, file=None, chain=True): - """Shorthand for 'print_exception(*sys.exc_info(), limit, file)'.""" + """Shorthand for 'print_exception(*sys.exc_info(), limit, file, chain)'.""" print_exception(*sys.exc_info(), limit=limit, file=file, chain=chain) def format_exc(limit=None, chain=True): @@ -187,12 +187,16 @@ def format_exc(limit=None, chain=True): return "".join(format_exception(*sys.exc_info(), limit=limit, chain=chain)) def print_last(limit=None, file=None, chain=True): - """This is a shorthand for 'print_exception(sys.last_type, - sys.last_value, sys.last_traceback, limit, file)'.""" - if not hasattr(sys, "last_type"): + """This is a shorthand for 'print_exception(sys.last_exc, limit, file, chain)'.""" + if not hasattr(sys, "last_exc") and not hasattr(sys, "last_type"): raise ValueError("no last exception") - print_exception(sys.last_type, sys.last_value, sys.last_traceback, - limit, file, chain) + + if hasattr(sys, "last_exc"): + print_exception(sys.last_exc, limit, file, chain) + else: + print_exception(sys.last_type, sys.last_value, sys.last_traceback, + limit, file, chain) + # # Printing and Extracting Stacks. diff --git a/Lib/typing.py b/Lib/typing.py index 8d40e923bb1d08..3ee9679e50c0c4 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -230,16 +230,20 @@ def _type_repr(obj): typically enough to uniquely identify a type. For everything else, we fall back on repr(obj). """ - if isinstance(obj, types.GenericAlias): - return repr(obj) + # When changing this function, don't forget about + # `_collections_abc._type_repr`, which does the same thing + # and must be consistent with this one. if isinstance(obj, type): if obj.__module__ == 'builtins': return obj.__qualname__ return f'{obj.__module__}.{obj.__qualname__}' if obj is ...: - return('...') + return '...' if isinstance(obj, types.FunctionType): return obj.__name__ + if isinstance(obj, tuple): + # Special case for `repr` of types with `ParamSpec`: + return '[' + ', '.join(_type_repr(t) for t in obj) + ']' return repr(obj) diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index 44974d433b4696..4336597e68f625 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -542,11 +542,15 @@ def register_standard_browsers(): # First try to use the default Windows browser register("windows-default", WindowsDefault) - # Detect some common Windows browsers, fallback to IE - iexplore = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), - "Internet Explorer\\IEXPLORE.EXE") + # Detect some common Windows browsers, fallback to Microsoft Edge + # location in 64-bit Windows + edge64 = os.path.join(os.environ.get("PROGRAMFILES(x86)", "C:\\Program Files (x86)"), + "Microsoft\\Edge\\Application\\msedge.exe") + # location in 32-bit Windows + edge32 = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), + "Microsoft\\Edge\\Application\\msedge.exe") for browser in ("firefox", "firebird", "seamonkey", "mozilla", - "netscape", "opera", iexplore): + "opera", edge64, edge32): if shutil.which(browser): register(browser, None, BackgroundBrowser(browser)) else: @@ -709,11 +713,12 @@ def open(self, url, new=0, autoraise=True): def main(): import getopt - usage = """Usage: %s [-n | -t] url + usage = """Usage: %s [-n | -t | -h] url -n: open new window - -t: open new tab""" % sys.argv[0] + -t: open new tab + -h, --help: show help""" % sys.argv[0] try: - opts, args = getopt.getopt(sys.argv[1:], 'ntd') + opts, args = getopt.getopt(sys.argv[1:], 'ntdh',['help']) except getopt.error as msg: print(msg, file=sys.stderr) print(usage, file=sys.stderr) @@ -722,6 +727,9 @@ def main(): for o, a in opts: if o == '-n': new_win = 1 elif o == '-t': new_win = 2 + elif o == '-h' or o == '--help': + print(usage, file=sys.stderr) + sys.exit() if len(args) != 1: print(usage, file=sys.stderr) sys.exit(1) diff --git a/Makefile.pre.in b/Makefile.pre.in index 1a1853bf3d7871..74e4171b010d0f 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1485,6 +1485,7 @@ regen-cases: PYTHONPATH=$(srcdir)/Tools/cases_generator \ $(PYTHON_FOR_REGEN) \ $(srcdir)/Tools/cases_generator/generate_cases.py \ + --emit-line-directives \ -o $(srcdir)/Python/generated_cases.c.h.new \ -m $(srcdir)/Python/opcode_metadata.h.new \ $(srcdir)/Python/bytecodes.c @@ -1698,6 +1699,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_moduleobject.h \ $(srcdir)/Include/internal/pycore_namespace.h \ $(srcdir)/Include/internal/pycore_object.h \ + $(srcdir)/Include/internal/pycore_object_state.h \ $(srcdir)/Include/internal/pycore_obmalloc.h \ $(srcdir)/Include/internal/pycore_obmalloc_init.h \ $(srcdir)/Include/internal/pycore_pathconfig.h \ @@ -2560,6 +2562,12 @@ distclean: clobber docclean smelly: all $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/build/smelly.py +# Check if any unsupported C global variables have been added. +check-c-globals: + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/c-analyzer/check-c-globals.py \ + --format summary \ + --traceback + # Find files with funny names funny: find $(SUBDIRS) $(SUBDIRSTOO) \ diff --git a/Misc/ACKS b/Misc/ACKS index 7bbde3af99782b..8cf5166a2bb1f4 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1385,6 +1385,7 @@ Thomas Perl Mathieu Perreault Mark Perrego Trevor Perrin +Yonatan Perry Gabriel de Perthuis Tim Peters Benjamin Peterson diff --git a/Misc/NEWS.d/3.12.0a2.rst b/Misc/NEWS.d/3.12.0a2.rst index 117be21a3221b6..d871384903e7cd 100644 --- a/Misc/NEWS.d/3.12.0a2.rst +++ b/Misc/NEWS.d/3.12.0a2.rst @@ -959,7 +959,7 @@ Fix ``make regen-test-levenshtein`` for out-of-tree builds. Don't use vendored ``libmpdec`` headers if :option:`--with-system-libmpdec` is passed to :program:`configure`. Don't use vendored ``libexpat`` headers -if :option:`--with-system-expat` is passed to :program:`!configure`. +if :option:`--with-system-expat` is passed to :program:`configure`. .. diff --git a/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst b/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst new file mode 100644 index 00000000000000..0350237ebc7390 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst @@ -0,0 +1 @@ +Add a new (unstable) C-API function for iterating over GC'able objects using a callback: ``PyUnstable_VisitObjects``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst new file mode 100644 index 00000000000000..42d96b54677e41 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst @@ -0,0 +1,2 @@ +Fix SSE2 and SSE3 detection in ``_blake2`` internal module. Patch by Max +Bachmann. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst new file mode 100644 index 00000000000000..b0269dd3d92bd5 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst @@ -0,0 +1 @@ +Fix potential nullptr dereference and use of uninitialized memory in fileutils. Patch by Max Bachmann. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst new file mode 100644 index 00000000000000..e0d061c37299f2 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst @@ -0,0 +1 @@ +:mod:`codecs` encoding/decoding errors now get the context information (which operation and which codecs) attached as :pep:`678` notes instead of through chaining a new instance of the exception. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst new file mode 100644 index 00000000000000..5bdc9ed2f37adc --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst @@ -0,0 +1,2 @@ +Improve import time of ``platform`` by removing IronPython version parsing. The IronPython version parsing +was not functional (see https://github.com/IronLanguages/ironpython3/issues/1667). diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst new file mode 100644 index 00000000000000..0b95b5ec98e811 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst @@ -0,0 +1 @@ +Add note to exception raised in ``PyErr_SetObject`` when normalization fails. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst new file mode 100644 index 00000000000000..d09af8d060d405 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst @@ -0,0 +1,3 @@ +Add :c:func:`PyErr_DisplayException` which takes just an exception instance, +to replace the legacy :c:func:`PyErr_Display` which takes the ``(typ, exc, +tb)`` triplet. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst new file mode 100644 index 00000000000000..4e1f31893377ba --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst @@ -0,0 +1 @@ +Fix overflow when creating very large dict. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst new file mode 100644 index 00000000000000..b5da227afa5a69 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst @@ -0,0 +1,3 @@ +Add :data:`sys.last_exc` and deprecate :data:`sys.last_type`, :data:`sys.last_value` +and :data:`sys.last_traceback`, +which hold the same information in its legacy form. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst new file mode 100644 index 00000000000000..28c9a8465180db --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst @@ -0,0 +1 @@ +Fixed ``stacktop`` value on tracing entries to avoid corruption on garbage collection. diff --git a/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst b/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst new file mode 100644 index 00000000000000..149ddd706c358f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst @@ -0,0 +1 @@ +Added deprecation warning to *isdst* parameter of :func:`email.utils.localtime`. diff --git a/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst b/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst new file mode 100644 index 00000000000000..3eee82e59dfafb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst @@ -0,0 +1,2 @@ +Fix a :mod:`concurrent.futures.process` bug where ``ProcessPoolExecutor`` shutdown +could hang after a future has been quickly submitted and canceled. diff --git a/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst b/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst new file mode 100644 index 00000000000000..d0f4ccbdd3e39f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst @@ -0,0 +1,7 @@ +When built against OpenSSL 3.0, the :mod:`ssl` module had a bug where it +reported unauthenticated EOFs (i.e. without close_notify) as a clean TLS-level +EOF. It now raises :exc:`~ssl.SSLEOFError`, matching the behavior in previous +versions of OpenSSL. The :attr:`~ssl.SSLContext.options` attribute on +:class:`~ssl.SSLContext` also no longer includes +:data:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to +specify the previous OpenSSL 3.0 behavior. diff --git a/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst b/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst new file mode 100644 index 00000000000000..766b1d4d477b72 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst @@ -0,0 +1 @@ +Fix incorrect results from :meth:`ssl.SSLSocket.shared_ciphers` diff --git a/Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst b/Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst new file mode 100644 index 00000000000000..f9ac1475dceb00 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst @@ -0,0 +1 @@ +Fix pathlib.Path.walk RecursionError on deep directory trees by rewriting it using iteration instead of recursion. diff --git a/Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst b/Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst new file mode 100644 index 00000000000000..63d0a7286920a4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst @@ -0,0 +1 @@ +Added -h and --help arguments to the webbrowser CLI diff --git a/Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst b/Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst new file mode 100644 index 00000000000000..eff77c40e30c48 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst @@ -0,0 +1 @@ +:meth:`asyncio.Task.get_coro` now always returns a coroutine when wrapping an awaitable object. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst b/Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst new file mode 100644 index 00000000000000..333068369bc4f7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst @@ -0,0 +1,3 @@ +Typing: Improve the ``repr`` of generic aliases for classes generic over a +:class:`~typing.ParamSpec`. (Use square brackets to represent a parameter +list.) diff --git a/Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst b/Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst new file mode 100644 index 00000000000000..3de09f86754f3e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst @@ -0,0 +1,2 @@ +Optimized fmean(), correlation(), covariance(), and linear_regression() +using the new math.sumprod() function. diff --git a/Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst b/Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst new file mode 100644 index 00000000000000..b1dc67f38fe85d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst @@ -0,0 +1,3 @@ +:func:`asyncio.iscoroutine` now returns ``False`` for generators as +:mod:`asyncio` does not support legacy generator-based coroutines. +Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst b/Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst new file mode 100644 index 00000000000000..bdb46d08c5c4af --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst @@ -0,0 +1 @@ +:func:`asyncio.wait` now accepts generators yielding tasks. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst b/Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst new file mode 100644 index 00000000000000..be9b2bab24a381 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst @@ -0,0 +1,3 @@ +Add the ``onexc`` arg to :func:`shutil.rmtree`, which is like ``onerror`` +but expects an exception instance rather than an exc_info tuple. Deprecate +``onerror``. diff --git a/Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst b/Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst new file mode 100644 index 00000000000000..673b38974e4d1b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst @@ -0,0 +1 @@ +Improve performance of :func:`math.log` arguments handling by removing the argument clinic. diff --git a/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst new file mode 100644 index 00000000000000..a9c19ce060e3ab --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst @@ -0,0 +1 @@ +Improved test_locale_calendar_formatweekday of calendar. diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst b/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst new file mode 100644 index 00000000000000..5c282769878563 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst @@ -0,0 +1 @@ +``Misc/gdbinit`` was removed. diff --git a/Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst b/Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst new file mode 100644 index 00000000000000..e2578620017894 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst @@ -0,0 +1,2 @@ +Improves correctness of stat results for Windows, and uses faster API when +available diff --git a/Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst b/Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst new file mode 100644 index 00000000000000..5669ebbb442c24 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst @@ -0,0 +1 @@ +Update :mod:`webbrowser` to fall back to Microsoft Edge instead of Internet Explorer. diff --git a/Misc/gdbinit b/Misc/gdbinit deleted file mode 100644 index e8f62ba6476423..00000000000000 --- a/Misc/gdbinit +++ /dev/null @@ -1,176 +0,0 @@ -# If you use the GNU debugger gdb to debug the Python C runtime, you -# might find some of the following commands useful. Copy this to your -# ~/.gdbinit file and it'll get loaded into gdb automatically when you -# start it up. Then, at the gdb prompt you can do things like: -# -# (gdb) pyo apyobjectptr -# -# refcounts: 1 -# address : 84a7a2c -# $1 = void -# (gdb) -# -# NOTE: If you have gdb 7 or later, it supports debugging of Python directly -# with embedded macros that you may find superior to what is in here. -# See Tools/gdb/libpython.py and http://bugs.python.org/issue8032. - -define pyo - # side effect of calling _PyObject_Dump is to dump the object's - # info - assigning just prevents gdb from printing the - # NULL return value - set $_unused_void = _PyObject_Dump($arg0) -end -document pyo - Prints a representation of the object to stderr, along with the - number of reference counts it currently has and the hex address the - object is allocated at. The argument must be a PyObject* -end - -define pyg - print _PyGC_Dump($arg0) -end -document pyg - Prints a representation of the object to stderr, along with the - number of reference counts it currently has and the hex address the - object is allocated at. The argument must be a PyGC_Head* -end - -define pylocals - set $_i = 0 - while $_i < f->f_code->co_nlocals - if f->f_localsplus + $_i != 0 - set $_names = f->f_code->co_varnames - set $_name = PyUnicode_AsUTF8(PyTuple_GetItem($_names, $_i)) - printf "%s:\n", $_name - pyo f->f_localsplus[$_i] - end - set $_i = $_i + 1 - end -end -document pylocals - Print the local variables of the current frame. -end - -# A rewrite of the Python interpreter's line number calculator in GDB's -# command language -define lineno - set $__continue = 1 - set $__co = f->f_code - set $__lasti = f->f_lasti - set $__sz = ((PyVarObject *)$__co->co_lnotab)->ob_size/2 - set $__p = (unsigned char *)((PyBytesObject *)$__co->co_lnotab)->ob_sval - set $__li = $__co->co_firstlineno - set $__ad = 0 - while ($__sz-1 >= 0 && $__continue) - set $__sz = $__sz - 1 - set $__ad = $__ad + *$__p - set $__p = $__p + 1 - if ($__ad > $__lasti) - set $__continue = 0 - else - set $__li = $__li + *$__p - set $__p = $__p + 1 - end - end - printf "%d", $__li -end - -define pyframev - pyframe - pylocals -end -document pyframev - Print the current frame - verbose -end - -define pyframe - set $__fn = PyUnicode_AsUTF8(f->f_code->co_filename) - set $__n = PyUnicode_AsUTF8(f->f_code->co_name) - printf "%s (", $__fn - lineno - printf "): %s\n", $__n -### Uncomment these lines when using from within Emacs/XEmacs so it will -### automatically track/display the current Python source line -# printf "%c%c%s:", 032, 032, $__fn -# lineno -# printf ":1\n" -end - -### Use these at your own risk. It appears that a bug in gdb causes it -### to crash in certain circumstances. - -#define up -# up-silently 1 -# printframe -#end - -#define down -# down-silently 1 -# printframe -#end - -define printframe - if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault - pyframe - else - frame - end -end - -# Here's a somewhat fragile way to print the entire Python stack from gdb. -# It's fragile because the tests for the value of $pc depend on the layout -# of specific functions in the C source code. - -# Explanation of while and if tests: We want to pop up the stack until we -# land in Py_Main (this is probably an incorrect assumption in an embedded -# interpreter, but the test can be extended by an interested party). If -# Py_Main <= $pc <= Py_GetArgcArv is true, $pc is in Py_Main(), so the while -# tests succeeds as long as it's not true. In a similar fashion the if -# statement tests to see if we are in PyEval_EvalFrameEx(). - -# Note: The name of the main interpreter function and the function which -# follow it has changed over time. This version of pystack works with this -# version of Python. If you try using it with older or newer versions of -# the interpreter you may will have to change the functions you compare with -# $pc. - -define pystack - while $pc < Py_Main || $pc > Py_GetArgcArgv - if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault - pyframe - end - up-silently 1 - end - select-frame 0 -end -document pystack - Print the entire Python call stack -end - -define pystackv - while $pc < Py_Main || $pc > Py_GetArgcArgv - if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault - pyframev - end - up-silently 1 - end - select-frame 0 -end -document pystackv - Print the entire Python call stack - verbose mode -end - -define pu - set $uni = $arg0 - set $i = 0 - while (*$uni && $i++<100) - if (*$uni < 0x80) - print *(char*)$uni++ - else - print /x *(short*)$uni++ - end - end -end -document pu - Generally useful macro to print a Unicode string -end diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 21ff9616133445..23baeeeae79193 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -609,6 +609,8 @@ added = '3.2' [function.PyErr_Display] added = '3.2' +[function.PyErr_DisplayException] + added = '3.12' [function.PyErr_ExceptionMatches] added = '3.2' [function.PyErr_Fetch] diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index b12290d436cbeb..fe1b9f8f5380c1 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -169,7 +169,7 @@ @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c -@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c +@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/pyos.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_blake2/impl/blake2-config.h b/Modules/_blake2/impl/blake2-config.h index f5dd6faa9e6867..c09cb4bcf06723 100644 --- a/Modules/_blake2/impl/blake2-config.h +++ b/Modules/_blake2/impl/blake2-config.h @@ -53,7 +53,7 @@ #endif #endif -#ifdef HAVE_SSE41 +#ifdef HAVE_SSE4_1 #ifndef HAVE_SSSE3 #define HAVE_SSSE3 #endif diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 68131f3b54d2ea..ba4a9760f7b906 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -910,7 +910,9 @@ deque_rotate(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(rotate_doc, -"Rotate the deque n steps to the right (default n=1). If n is negative, rotates left."); +"rotate(n)\n\n" +"Rotate the deque *n* steps to the right (default ``n=1``). " +"If *n* is negative, rotates left."); static PyObject * deque_reverse(dequeobject *deque, PyObject *unused) @@ -951,7 +953,8 @@ deque_reverse(dequeobject *deque, PyObject *unused) } PyDoc_STRVAR(reverse_doc, -"D.reverse() -- reverse *IN PLACE*"); +"reverse()\n\n" +"Reverse the elements of the deque *IN PLACE*."); static PyObject * deque_count(dequeobject *deque, PyObject *v) @@ -990,7 +993,8 @@ deque_count(dequeobject *deque, PyObject *v) } PyDoc_STRVAR(count_doc, -"D.count(value) -> integer -- return number of occurrences of value"); +"count(x) -> int\n\n" +"Count the number of deque elements equal to *x*."); static int deque_contains(dequeobject *deque, PyObject *v) @@ -1098,8 +1102,10 @@ deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(index_doc, -"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n" -"Raises ValueError if the value is not present."); +"index(x, [start, [stop]]) -> int\n\n" +"Return the position of *x* in the deque " +"(at or after index *start* and before index *stop*). " +"Returns the first match or raises a ValueError if not found."); /* insert(), remove(), and delitem() are implemented in terms of rotate() for simplicity and reasonable performance near the end @@ -1144,10 +1150,13 @@ deque_insert(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(insert_doc, -"D.insert(index, object) -- insert object before index"); +"insert(i, x)\n\n" +"Insert *x* into the deque at position *i*."); PyDoc_STRVAR(remove_doc, -"D.remove(value) -- remove first occurrence of value."); +"remove(x)\n\n" +"Remove the first occurrence of *x*." +"If not found, raises a ValueError."); static int valid_index(Py_ssize_t i, Py_ssize_t limit) @@ -1518,7 +1527,8 @@ deque_sizeof(dequeobject *deque, void *unused) } PyDoc_STRVAR(sizeof_doc, -"D.__sizeof__() -- size of D in memory, in bytes"); +"__sizeof__() -> int\n\n" +"Size of the deque in memory, in bytes."); static PyObject * deque_get_maxlen(dequeobject *deque, void *Py_UNUSED(ignored)) @@ -1553,7 +1563,8 @@ static PySequenceMethods deque_as_sequence = { static PyObject *deque_iter(dequeobject *deque); static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)); PyDoc_STRVAR(reversed_doc, - "D.__reversed__() -- return a reverse iterator over the deque"); +"__reversed__()\n\n" +"Return a reverse iterator over the deque."); static PyMethodDef deque_methods[] = { {"append", (PyCFunction)deque_append, @@ -1598,9 +1609,8 @@ static PyMethodDef deque_methods[] = { }; PyDoc_STRVAR(deque_doc, -"deque([iterable[, maxlen]]) --> deque object\n\ -\n\ -A list-like sequence optimized for data accesses near its endpoints."); +"deque([iterable[, maxlen]]) -> collections.deque\n\n" +"A list-like sequence optimized for data accesses near its endpoints."); static PyTypeObject deque_type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -1979,7 +1989,8 @@ new_defdict(defdictobject *dd, PyObject *arg) dd->default_factory ? dd->default_factory : Py_None, arg, NULL); } -PyDoc_STRVAR(defdict_copy_doc, "D.copy() -> a shallow copy of D."); +PyDoc_STRVAR(defdict_copy_doc, "copy() -> collections.deque\n\n" +"A shallow copy of the deque."); static PyObject * defdict_copy(defdictobject *dd, PyObject *Py_UNUSED(ignored)) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 1506755427fc0d..5644cc05c45800 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -11,6 +11,7 @@ #include "Python.h" #include "_iomodule.h" #include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_initconfig.h" // _PyStatus_OK() #ifdef HAVE_SYS_TYPES_H #include @@ -666,12 +667,40 @@ static PyTypeObject* static_types[] = { }; +PyStatus +_PyIO_InitTypes(PyInterpreterState *interp) +{ + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + + // Set type base classes +#ifdef HAVE_WINDOWS_CONSOLE_IO + PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; +#endif + + for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { + PyTypeObject *type = static_types[i]; + if (_PyStaticType_InitBuiltin(type) < 0) { + return _PyStatus_ERR("Can't initialize builtin type"); + } + } + + return _PyStatus_OK(); +} + void -_PyIO_Fini(void) +_PyIO_FiniTypes(PyInterpreterState *interp) { + if (!_Py_IsMainInterpreter(interp)) { + return; + } + + // Deallocate types in the reverse order to deallocate subclasses before + // their base classes. for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types) - 1; i >= 0; i--) { - PyTypeObject *exc = static_types[i]; - _PyStaticType_Dealloc(exc); + PyTypeObject *type = static_types[i]; + _PyStaticType_Dealloc(type); } } @@ -717,11 +746,6 @@ PyInit__io(void) goto fail; } - // Set type base classes -#ifdef HAVE_WINDOWS_CONSOLE_IO - PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; -#endif - // Add types for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { PyTypeObject *type = static_types[i]; diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 28112317bc289e..36b66cdb5310c6 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -318,9 +318,7 @@ typedef struct { * store exception information on the socket. The handshake, read, write, * and shutdown methods check for chained exceptions. */ - PyObject *exc_type; - PyObject *exc_value; - PyObject *exc_tb; + PyObject *exc; } PySSLSocket; typedef struct { @@ -564,13 +562,11 @@ fill_and_set_sslerror(_sslmodulestate *state, static int PySSL_ChainExceptions(PySSLSocket *sslsock) { - if (sslsock->exc_type == NULL) + if (sslsock->exc == NULL) return 0; - _PyErr_ChainExceptions(sslsock->exc_type, sslsock->exc_value, sslsock->exc_tb); - sslsock->exc_type = NULL; - sslsock->exc_value = NULL; - sslsock->exc_tb = NULL; + _PyErr_ChainExceptions1(sslsock->exc); + sslsock->exc = NULL; return -1; } @@ -664,6 +660,16 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) ERR_GET_REASON(e) == SSL_R_CERTIFICATE_VERIFY_FAILED) { type = state->PySSLCertVerificationErrorObject; } +#if defined(SSL_R_UNEXPECTED_EOF_WHILE_READING) + /* OpenSSL 3.0 changed transport EOF from SSL_ERROR_SYSCALL with + * zero return value to SSL_ERROR_SSL with a special error code. */ + if (ERR_GET_LIB(e) == ERR_LIB_SSL && + ERR_GET_REASON(e) == SSL_R_UNEXPECTED_EOF_WHILE_READING) { + p = PY_SSL_ERROR_EOF; + type = state->PySSLEOFErrorObject; + errstr = "EOF occurred in violation of protocol"; + } +#endif break; } default: @@ -807,9 +813,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, self->owner = NULL; self->server_hostname = NULL; self->err = err; - self->exc_type = NULL; - self->exc_value = NULL; - self->exc_tb = NULL; + self->exc = NULL; /* Make sure the SSL error state is initialized */ ERR_clear_error(); @@ -1994,24 +1998,44 @@ static PyObject * _ssl__SSLSocket_shared_ciphers_impl(PySSLSocket *self) /*[clinic end generated code: output=3d174ead2e42c4fd input=0bfe149da8fe6306]*/ { - STACK_OF(SSL_CIPHER) *ciphers; - int i; + STACK_OF(SSL_CIPHER) *server_ciphers; + STACK_OF(SSL_CIPHER) *client_ciphers; + int i, len; PyObject *res; + const SSL_CIPHER* cipher; + + /* Rather than use SSL_get_shared_ciphers, we use an equivalent algorithm because: + + 1) It returns a colon seperated list of strings, in an undefined + order, that we would have to post process back into tuples. + 2) It will return a truncated string with no indication that it has + done so, if the buffer is too small. + */ - ciphers = SSL_get_ciphers(self->ssl); - if (!ciphers) + server_ciphers = SSL_get_ciphers(self->ssl); + if (!server_ciphers) Py_RETURN_NONE; - res = PyList_New(sk_SSL_CIPHER_num(ciphers)); + client_ciphers = SSL_get_client_ciphers(self->ssl); + if (!client_ciphers) + Py_RETURN_NONE; + + res = PyList_New(sk_SSL_CIPHER_num(server_ciphers)); if (!res) return NULL; - for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { - PyObject *tup = cipher_to_tuple(sk_SSL_CIPHER_value(ciphers, i)); + len = 0; + for (i = 0; i < sk_SSL_CIPHER_num(server_ciphers); i++) { + cipher = sk_SSL_CIPHER_value(server_ciphers, i); + if (sk_SSL_CIPHER_find(client_ciphers, cipher) < 0) + continue; + + PyObject *tup = cipher_to_tuple(cipher); if (!tup) { Py_DECREF(res); return NULL; } - PyList_SET_ITEM(res, i, tup); + PyList_SET_ITEM(res, len++, tup); } + Py_SET_SIZE(res, len); return res; } @@ -2179,9 +2203,7 @@ Passed as \"self\" in servername callback."); static int PySSL_traverse(PySSLSocket *self, visitproc visit, void *arg) { - Py_VISIT(self->exc_type); - Py_VISIT(self->exc_value); - Py_VISIT(self->exc_tb); + Py_VISIT(self->exc); Py_VISIT(Py_TYPE(self)); return 0; } @@ -2189,9 +2211,7 @@ PySSL_traverse(PySSLSocket *self, visitproc visit, void *arg) static int PySSL_clear(PySSLSocket *self) { - Py_CLEAR(self->exc_type); - Py_CLEAR(self->exc_value); - Py_CLEAR(self->exc_tb); + Py_CLEAR(self->exc); return 0; } @@ -2536,7 +2556,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, PySSL_SetError(self, retval, __FILE__, __LINE__); goto error; } - if (self->exc_type != NULL) + if (self->exc != NULL) goto error; done: @@ -2662,7 +2682,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) PySSL_SetError(self, ret, __FILE__, __LINE__); return NULL; } - if (self->exc_type != NULL) + if (self->exc != NULL) goto error; if (sock) /* It's already INCREF'ed */ @@ -3102,10 +3122,6 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) #endif #ifdef SSL_OP_SINGLE_ECDH_USE options |= SSL_OP_SINGLE_ECDH_USE; -#endif -#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF - /* Make OpenSSL 3.0.0 behave like 1.1.1 */ - options |= SSL_OP_IGNORE_UNEXPECTED_EOF; #endif SSL_CTX_set_options(self->ctx, options); diff --git a/Modules/_ssl/debughelpers.c b/Modules/_ssl/debughelpers.c index 08f3457035b90c..217f224942556e 100644 --- a/Modules/_ssl/debughelpers.c +++ b/Modules/_ssl/debughelpers.c @@ -74,7 +74,7 @@ _PySSL_msg_callback(int write_p, int version, int content_type, buf, len ); if (res == NULL) { - PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb); + ssl_obj->exc = PyErr_GetRaisedException(); } else { Py_DECREF(res); } @@ -138,8 +138,7 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line) lock = PyThread_allocate_lock(); if (lock == NULL) { PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); - PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, - &ssl_obj->exc_tb); + ssl_obj->exc = PyErr_GetRaisedException(); return; } } @@ -156,7 +155,7 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line) errno = e; PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, ssl_obj->ctx->keylog_filename); - PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb); + ssl_obj->exc = PyErr_GetRaisedException(); } PyGILState_Release(threadstate); } diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index a0575213987ffc..6099f7d20eb56a 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -39,20 +39,23 @@ err_restore(PyObject *self, PyObject *args) { static PyObject * exception_print(PyObject *self, PyObject *args) { - PyObject *value; - PyObject *tb = NULL; + PyObject *exc; + int legacy = 0; - if (!PyArg_ParseTuple(args, "O:exception_print", &value)) { + if (!PyArg_ParseTuple(args, "O|i:exception_print", &exc, &legacy)) { return NULL; } - - if (PyExceptionInstance_Check(value)) { - tb = PyException_GetTraceback(value); + if (legacy) { + PyObject *tb = NULL; + if (PyExceptionInstance_Check(exc)) { + tb = PyException_GetTraceback(exc); + } + PyErr_Display((PyObject *) Py_TYPE(exc), exc, tb); + Py_XDECREF(tb); + } + else { + PyErr_DisplayException(exc); } - - PyErr_Display((PyObject *) Py_TYPE(value), value, tb); - Py_XDECREF(tb); - Py_RETURN_NONE; } @@ -92,6 +95,26 @@ exc_set_object(PyObject *self, PyObject *args) return NULL; } +static PyObject * +exc_set_object_fetch(PyObject *self, PyObject *args) +{ + PyObject *exc; + PyObject *obj; + PyObject *type; + PyObject *value; + PyObject *tb; + + if (!PyArg_ParseTuple(args, "OO:exc_set_object", &exc, &obj)) { + return NULL; + } + + PyErr_SetObject(exc, obj); + PyErr_Fetch(&type, &value, &tb); + Py_XDECREF(type); + Py_XDECREF(tb); + return value; +} + static PyObject * raise_exception(PyObject *self, PyObject *args) { @@ -262,6 +285,7 @@ static PyMethodDef test_methods[] = { {"make_exception_with_doc", _PyCFunction_CAST(make_exception_with_doc), METH_VARARGS | METH_KEYWORDS}, {"exc_set_object", exc_set_object, METH_VARARGS}, + {"exc_set_object_fetch", exc_set_object_fetch, METH_VARARGS}, {"raise_exception", raise_exception, METH_VARARGS}, {"raise_memoryerror", raise_memoryerror, METH_NOARGS}, {"set_exc_info", test_set_exc_info, METH_VARARGS}, diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index c8f31dc8e39fae..60ec81dad2ba9e 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -38,6 +38,7 @@ int _PyTestCapi_Init_Float(PyObject *module); int _PyTestCapi_Init_Structmember(PyObject *module); int _PyTestCapi_Init_Exceptions(PyObject *module); int _PyTestCapi_Init_Code(PyObject *module); +int _PyTestCapi_Init_PyOS(PyObject *module); #ifdef LIMITED_API_AVAILABLE int _PyTestCapi_Init_VectorcallLimited(PyObject *module); diff --git a/Modules/_testcapi/pyos.c b/Modules/_testcapi/pyos.c new file mode 100644 index 00000000000000..63140e914875db --- /dev/null +++ b/Modules/_testcapi/pyos.c @@ -0,0 +1,60 @@ +#include "parts.h" + + +static PyObject * +test_PyOS_mystrnicmp(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + assert(PyOS_mystrnicmp("", "", 0) == 0); + assert(PyOS_mystrnicmp("", "", 1) == 0); + + assert(PyOS_mystrnicmp("insert", "ins", 3) == 0); + assert(PyOS_mystrnicmp("ins", "insert", 3) == 0); + assert(PyOS_mystrnicmp("insect", "insert", 3) == 0); + + assert(PyOS_mystrnicmp("insert", "insert", 6) == 0); + assert(PyOS_mystrnicmp("Insert", "insert", 6) == 0); + assert(PyOS_mystrnicmp("INSERT", "insert", 6) == 0); + assert(PyOS_mystrnicmp("insert", "insert", 10) == 0); + + assert(PyOS_mystrnicmp("invert", "insert", 6) == ('v' - 's')); + assert(PyOS_mystrnicmp("insert", "invert", 6) == ('s' - 'v')); + assert(PyOS_mystrnicmp("insert", "ins\0rt", 6) == 'e'); + + // GH-21845 + assert(PyOS_mystrnicmp("insert\0a", "insert\0b", 8) == 0); + + Py_RETURN_NONE; +} + +static PyObject * +test_PyOS_mystricmp(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + assert(PyOS_mystricmp("", "") == 0); + assert(PyOS_mystricmp("insert", "insert") == 0); + assert(PyOS_mystricmp("Insert", "insert") == 0); + assert(PyOS_mystricmp("INSERT", "insert") == 0); + assert(PyOS_mystricmp("insert", "ins") == 'e'); + assert(PyOS_mystricmp("ins", "insert") == -'e'); + + // GH-21845 + assert(PyOS_mystricmp("insert", "ins\0rt") == 'e'); + assert(PyOS_mystricmp("invert", "insert") == ('v' - 's')); + + Py_RETURN_NONE; +} + +static PyMethodDef test_methods[] = { + {"test_PyOS_mystrnicmp", test_PyOS_mystrnicmp, METH_NOARGS, NULL}, + {"test_PyOS_mystricmp", test_PyOS_mystricmp, METH_NOARGS, NULL}, + {NULL}, +}; + +int +_PyTestCapi_Init_PyOS(PyObject *mod) +{ + if (PyModule_AddFunctions(mod, test_methods) < 0) { + return -1; + } + + return 0; +} diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index ea67017a1ba3b1..3d9a2aeeb7cfd5 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1538,15 +1538,19 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) .allow_daemon_threads = allow_daemon_threads, .check_multi_interp_extensions = check_multi_interp_extensions, }; - substate = _Py_NewInterpreterFromConfig(&config); - if (substate == NULL) { + PyStatus status = _Py_NewInterpreterFromConfig(&substate, &config); + if (PyStatus_Exception(status)) { /* Since no new thread state was created, there is no exception to propagate; raise a fresh one after swapping in the old thread state. */ PyThreadState_Swap(mainstate); + _PyErr_SetFromPyStatus(status); + PyObject *exc = PyErr_GetRaisedException(); PyErr_SetString(PyExc_RuntimeError, "sub-interpreter creation failed"); + _PyErr_ChainExceptions1(exc); return NULL; } + assert(substate != NULL); r = PyRun_SimpleStringFlags(code, &cflags); Py_EndInterpreter(substate); @@ -3310,6 +3314,73 @@ function_set_kw_defaults(PyObject *self, PyObject *args) Py_RETURN_NONE; } +struct gc_visit_state_basic { + PyObject *target; + int found; +}; + +static int +gc_visit_callback_basic(PyObject *obj, void *arg) +{ + struct gc_visit_state_basic *state = (struct gc_visit_state_basic *)arg; + if (obj == state->target) { + state->found = 1; + return 0; + } + return 1; +} + +static PyObject * +test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(ignored)) +{ + PyObject *obj; + struct gc_visit_state_basic state; + + obj = PyList_New(0); + if (obj == NULL) { + return NULL; + } + state.target = obj; + state.found = 0; + + PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state); + Py_DECREF(obj); + if (!state.found) { + PyErr_SetString( + PyExc_AssertionError, + "test_gc_visit_objects_basic: Didn't find live list"); + return NULL; + } + Py_RETURN_NONE; +} + +static int +gc_visit_callback_exit_early(PyObject *obj, void *arg) + { + int *visited_i = (int *)arg; + (*visited_i)++; + if (*visited_i == 2) { + return 0; + } + return 1; +} + +static PyObject * +test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(ignored)) +{ + int visited_i = 0; + PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i); + if (visited_i != 2) { + PyErr_SetString( + PyExc_AssertionError, + "test_gc_visit_objects_exit_early: did not exit when expected"); + } + Py_RETURN_NONE; +} + + static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyMethodDef TestMethods[] = { @@ -3452,6 +3523,8 @@ static PyMethodDef TestMethods[] = { {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL}, {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, + {"test_gc_visit_objects_basic", test_gc_visit_objects_basic, METH_NOARGS, NULL}, + {"test_gc_visit_objects_exit_early", test_gc_visit_objects_exit_early, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; @@ -4081,6 +4154,9 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_Code(m) < 0) { return NULL; } + if (_PyTestCapi_Init_PyOS(m) < 0) { + return NULL; + } #ifndef LIMITED_API_AVAILABLE PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False); diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 76fb87fa3a34e1..9648f080cd756c 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -526,15 +526,20 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds) ? (_PyInterpreterConfig)_PyInterpreterConfig_INIT : (_PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT; // XXX Possible GILState issues? - PyThreadState *tstate = _Py_NewInterpreterFromConfig(&config); + PyThreadState *tstate = NULL; + PyStatus status = _Py_NewInterpreterFromConfig(&tstate, &config); PyThreadState_Swap(save_tstate); - if (tstate == NULL) { + if (PyStatus_Exception(status)) { /* Since no new thread state was created, there is no exception to propagate; raise a fresh one after swapping in the old thread state. */ + _PyErr_SetFromPyStatus(status); + PyObject *exc = PyErr_GetRaisedException(); PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed"); + _PyErr_ChainExceptions1(exc); return NULL; } + assert(tstate != NULL); PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate); PyObject *idobj = _PyInterpreterState_GetIDObject(interp); if (idobj == NULL) { diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h index 1f9725883b9820..bc5bbceb4c92b6 100644 --- a/Modules/clinic/mathmodule.c.h +++ b/Modules/clinic/mathmodule.c.h @@ -186,49 +186,6 @@ math_modf(PyObject *module, PyObject *arg) return return_value; } -PyDoc_STRVAR(math_log__doc__, -"log(x, [base=math.e])\n" -"Return the logarithm of x to the given base.\n" -"\n" -"If the base not specified, returns the natural logarithm (base e) of x."); - -#define MATH_LOG_METHODDEF \ - {"log", (PyCFunction)math_log, METH_VARARGS, math_log__doc__}, - -static PyObject * -math_log_impl(PyObject *module, PyObject *x, int group_right_1, - PyObject *base); - -static PyObject * -math_log(PyObject *module, PyObject *args) -{ - PyObject *return_value = NULL; - PyObject *x; - int group_right_1 = 0; - PyObject *base = NULL; - - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:log", &x)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO:log", &x, &base)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "math.log requires 1 to 2 arguments"); - goto exit; - } - return_value = math_log_impl(module, x, group_right_1, base); - -exit: - return return_value; -} - PyDoc_STRVAR(math_log2__doc__, "log2($module, x, /)\n" "--\n" @@ -954,4 +911,4 @@ math_ulp(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=899211ec70e4506c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a6437a3ba18c486a input=a9049054013a1b77]*/ diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 5879c5e11fe14a..4eaa5490b6134c 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2401,3 +2401,27 @@ PyObject_GC_IsFinalized(PyObject *obj) } return 0; } + +void +PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) +{ + size_t i; + GCState *gcstate = get_gc_state(); + int origenstate = gcstate->enabled; + gcstate->enabled = 0; + for (i = 0; i < NUM_GENERATIONS; i++) { + PyGC_Head *gc_list, *gc; + gc_list = GEN_HEAD(gcstate, i); + for (gc = GC_NEXT(gc_list); gc != gc_list; gc = GC_NEXT(gc)) { + PyObject *op = FROM_GC(gc); + Py_INCREF(op); + int res = callback(op, arg); + Py_DECREF(op); + if (!res) { + goto done; + } + } + } +done: + gcstate->enabled = origenstate; +} diff --git a/Modules/getpath.c b/Modules/getpath.c index 2f20521592ce2e..237fe8c0c2c221 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -446,7 +446,10 @@ getpath_realpath(PyObject *Py_UNUSED(self) , PyObject *args) if (s) { *s = L'\0'; } - path2 = _Py_normpath(_Py_join_relfile(path, resolved), -1); + path2 = _Py_join_relfile(path, resolved); + if (path2) { + path2 = _Py_normpath(path2, -1); + } PyMem_RawFree((void *)path); path = path2; } diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 544560e8322c72..473936edb3f5cd 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -92,6 +92,113 @@ get_math_module_state(PyObject *module) return (math_module_state *)state; } +/* +Double and triple length extended precision algorithms from: + + Accurate Sum and Dot Product + by Takeshi Ogita, Siegfried M. Rump, and Shin’Ichi Oishi + https://doi.org/10.1137/030601818 + https://www.tuhh.de/ti3/paper/rump/OgRuOi05.pdf + +*/ + +typedef struct{ double hi; double lo; } DoubleLength; + +static DoubleLength +dl_fast_sum(double a, double b) +{ + /* Algorithm 1.1. Compensated summation of two floating point numbers. */ + assert(fabs(a) >= fabs(b)); + double x = a + b; + double y = (a - x) + b; + return (DoubleLength) {x, y}; +} + +static DoubleLength +dl_sum(double a, double b) +{ + /* Algorithm 3.1 Error-free transformation of the sum */ + double x = a + b; + double z = x - a; + double y = (a - (x - z)) + (b - z); + return (DoubleLength) {x, y}; +} + +#ifndef UNRELIABLE_FMA + +static DoubleLength +dl_mul(double x, double y) +{ + /* Algorithm 3.5. Error-free transformation of a product */ + double z = x * y; + double zz = fma(x, y, -z); + return (DoubleLength) {z, zz}; +} + +#else + +/* + The default implementation of dl_mul() depends on the C math library + having an accurate fma() function as required by § 7.12.13.1 of the + C99 standard. + + The UNRELIABLE_FMA option is provided as a slower but accurate + alternative for builds where the fma() function is found wanting. + The speed penalty may be modest (17% slower on an Apple M1 Max), + so don't hesitate to enable this build option. + + The algorithms are from the T. J. Dekker paper: + A Floating-Point Technique for Extending the Available Precision + https://csclub.uwaterloo.ca/~pbarfuss/dekker1971.pdf +*/ + +static DoubleLength +dl_split(double x) { + // Dekker (5.5) and (5.6). + double t = x * 134217729.0; // Veltkamp constant = 2.0 ** 27 + 1 + double hi = t - (t - x); + double lo = x - hi; + return (DoubleLength) {hi, lo}; +} + +static DoubleLength +dl_mul(double x, double y) +{ + // Dekker (5.12) and mul12() + DoubleLength xx = dl_split(x); + DoubleLength yy = dl_split(y); + double p = xx.hi * yy.hi; + double q = xx.hi * yy.lo + xx.lo * yy.hi; + double z = p + q; + double zz = p - z + q + xx.lo * yy.lo; + return (DoubleLength) {z, zz}; +} + +#endif + +typedef struct { double hi; double lo; double tiny; } TripleLength; + +static const TripleLength tl_zero = {0.0, 0.0, 0.0}; + +static TripleLength +tl_fma(double x, double y, TripleLength total) +{ + /* Algorithm 5.10 with SumKVert for K=3 */ + DoubleLength pr = dl_mul(x, y); + DoubleLength sm = dl_sum(total.hi, pr.hi); + DoubleLength r1 = dl_sum(total.lo, pr.lo); + DoubleLength r2 = dl_sum(r1.hi, sm.lo); + return (TripleLength) {sm.hi, r2.hi, total.tiny + r1.lo + r2.lo}; +} + +static double +tl_to_d(TripleLength total) +{ + DoubleLength last = dl_sum(total.lo, total.hi); + return total.tiny + last.lo + last.hi; +} + + /* sin(pi*x), giving accurate results for all finite x (especially x integral or close to an integer). This is here for use in the @@ -2177,33 +2284,22 @@ loghelper(PyObject* arg, double (*func)(double)) } -/*[clinic input] -math.log - - x: object - [ - base: object(c_default="NULL") = math.e - ] - / - -Return the logarithm of x to the given base. - -If the base not specified, returns the natural logarithm (base e) of x. -[clinic start generated code]*/ - +/* AC: cannot convert yet, see gh-102839 and gh-89381, waiting + for support of multiple signatures */ static PyObject * -math_log_impl(PyObject *module, PyObject *x, int group_right_1, - PyObject *base) -/*[clinic end generated code: output=7b5a39e526b73fc9 input=0f62d5726cbfebbd]*/ +math_log(PyObject *module, PyObject * const *args, Py_ssize_t nargs) { PyObject *num, *den; PyObject *ans; - num = loghelper(x, m_log); - if (num == NULL || base == NULL) + if (!_PyArg_CheckPositional("log", nargs, 1, 2)) + return NULL; + + num = loghelper(args[0], m_log); + if (num == NULL || nargs == 1) return num; - den = loghelper(base, m_log); + den = loghelper(args[1], m_log); if (den == NULL) { Py_DECREF(num); return NULL; @@ -2215,6 +2311,10 @@ math_log_impl(PyObject *module, PyObject *x, int group_right_1, return ans; } +PyDoc_STRVAR(math_log_doc, +"log(x, [base=math.e])\n\ +Return the logarithm of x to the given base.\n\n\ +If the base not specified, returns the natural logarithm (base e) of x."); /*[clinic input] math.log2 @@ -2301,6 +2401,7 @@ that are almost always correctly rounded, four techniques are used: * lossless scaling using a power-of-two scaling factor * accurate squaring using Veltkamp-Dekker splitting [1] + or an equivalent with an fma() call * compensated summation using a variant of the Neumaier algorithm [2] * differential correction of the square root [3] @@ -2339,9 +2440,8 @@ Since lo**2 is less than 1/2 ulp(csum), we have csum+lo*lo == csum. To minimize loss of information during the accumulation of fractional values, each term has a separate accumulator. This also breaks up sequential dependencies in the inner loop so the CPU can maximize -floating point throughput. [4] On a 2.6 GHz Haswell, adding one -dimension has an incremental cost of only 5ns -- for example when -moving from hypot(x,y) to hypot(x,y,z). +floating point throughput. [4] On an Apple M1 Max, hypot(*vec) +takes only 3.33 µsec when len(vec) == 1000. The square root differential correction is needed because a correctly rounded square root of a correctly rounded sum of @@ -2359,14 +2459,21 @@ algorithm, effectively doubling the number of accurate bits. This technique is used in Dekker's SQRT2 algorithm and again in Borges' ALGORITHM 4 and 5. -Without proof for all cases, hypot() cannot claim to be always -correctly rounded. However for n <= 1000, prior to the final addition -that rounds the overall result, the internal accuracy of "h" together -with its correction of "x / (2.0 * h)" is at least 100 bits. [6] -Also, hypot() was tested against a Decimal implementation with -prec=300. After 100 million trials, no incorrectly rounded examples -were found. In addition, perfect commutativity (all permutations are -exactly equal) was verified for 1 billion random inputs with n=5. [7] +The hypot() function is faithfully rounded (less than 1 ulp error) +and usually correctly rounded (within 1/2 ulp). The squaring +step is exact. The Neumaier summation computes as if in doubled +precision (106 bits) and has the advantage that its input squares +are non-negative so that the condition number of the sum is one. +The square root with a differential correction is likewise computed +as if in doubled precision. + +For n <= 1000, prior to the final addition that rounds the overall +result, the internal accuracy of "h" together with its correction of +"x / (2.0 * h)" is at least 100 bits. [6] Also, hypot() was tested +against a Decimal implementation with prec=300. After 100 million +trials, no incorrectly rounded examples were found. In addition, +perfect commutativity (all permutations are exactly equal) was +verified for 1 billion random inputs with n=5. [7] References: @@ -2383,9 +2490,8 @@ exactly equal) was verified for 1 billion random inputs with n=5. [7] static inline double vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) { - const double T27 = 134217729.0; /* ldexp(1.0, 27) + 1.0) */ - double x, scale, oldcsum, csum = 1.0, frac1 = 0.0, frac2 = 0.0, frac3 = 0.0; - double t, hi, lo, h; + double x, h, scale, csum = 1.0, frac1 = 0.0, frac2 = 0.0; + DoubleLength pr, sm; int max_e; Py_ssize_t i; @@ -2399,82 +2505,37 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) return max; } frexp(max, &max_e); - if (max_e >= -1023) { - scale = ldexp(1.0, -max_e); - assert(max * scale >= 0.5); - assert(max * scale < 1.0); + if (max_e < -1023) { + /* When max_e < -1023, ldexp(1.0, -max_e) would overflow. */ for (i=0 ; i < n ; i++) { - x = vec[i]; - assert(Py_IS_FINITE(x) && fabs(x) <= max); - - x *= scale; - assert(fabs(x) < 1.0); - - t = x * T27; - hi = t - (t - x); - lo = x - hi; - assert(hi + lo == x); - - x = hi * hi; - assert(x <= 1.0); - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac1 += (oldcsum - csum) + x; - - x = 2.0 * hi * lo; - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac2 += (oldcsum - csum) + x; - - assert(csum + lo * lo == csum); - frac3 += lo * lo; + vec[i] /= DBL_MIN; // convert subnormals to normals } - h = sqrt(csum - 1.0 + (frac1 + frac2 + frac3)); - - x = h; - t = x * T27; - hi = t - (t - x); - lo = x - hi; - assert (hi + lo == x); - - x = -hi * hi; - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac1 += (oldcsum - csum) + x; - - x = -2.0 * hi * lo; - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac2 += (oldcsum - csum) + x; - - x = -lo * lo; - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac3 += (oldcsum - csum) + x; - - x = csum - 1.0 + (frac1 + frac2 + frac3); - return (h + x / (2.0 * h)) / scale; - } - /* When max_e < -1023, ldexp(1.0, -max_e) overflows. - So instead of multiplying by a scale, we just divide by *max*. - */ + return DBL_MIN * vector_norm(n, vec, max / DBL_MIN, found_nan); + } + scale = ldexp(1.0, -max_e); + assert(max * scale >= 0.5); + assert(max * scale < 1.0); for (i=0 ; i < n ; i++) { x = vec[i]; assert(Py_IS_FINITE(x) && fabs(x) <= max); - x /= max; - x = x*x; - assert(x <= 1.0); - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac1 += (oldcsum - csum) + x; - } - return max * sqrt(csum - 1.0 + frac1); + x *= scale; // lossless scaling + assert(fabs(x) < 1.0); + pr = dl_mul(x, x); // lossless squaring + assert(pr.hi <= 1.0); + sm = dl_fast_sum(csum, pr.hi); // lossless addition + csum = sm.hi; + frac1 += pr.lo; // lossy addition + frac2 += sm.lo; // lossy addition + } + h = sqrt(csum - 1.0 + (frac1 + frac2)); + pr = dl_mul(-h, h); + sm = dl_fast_sum(csum, pr.hi); + csum = sm.hi; + frac1 += pr.lo; + frac2 += sm.lo; + x = csum - 1.0 + (frac1 + frac2); + h += x / (2.0 * h); // differential correction + return h / scale; } #define NUM_STACK_ELEMS 16 @@ -2646,102 +2707,6 @@ long_add_would_overflow(long a, long b) return (a > 0) ? (b > LONG_MAX - a) : (b < LONG_MIN - a); } -/* -Double and triple length extended precision algorithms from: - - Accurate Sum and Dot Product - by Takeshi Ogita, Siegfried M. Rump, and Shin’Ichi Oishi - https://doi.org/10.1137/030601818 - https://www.tuhh.de/ti3/paper/rump/OgRuOi05.pdf - -*/ - -typedef struct{ double hi; double lo; } DoubleLength; - -static DoubleLength -dl_sum(double a, double b) -{ - /* Algorithm 3.1 Error-free transformation of the sum */ - double x = a + b; - double z = x - a; - double y = (a - (x - z)) + (b - z); - return (DoubleLength) {x, y}; -} - -#ifndef UNRELIABLE_FMA - -static DoubleLength -dl_mul(double x, double y) -{ - /* Algorithm 3.5. Error-free transformation of a product */ - double z = x * y; - double zz = fma(x, y, -z); - return (DoubleLength) {z, zz}; -} - -#else - -/* - The default implementation of dl_mul() depends on the C math library - having an accurate fma() function as required by § 7.12.13.1 of the - C99 standard. - - The UNRELIABLE_FMA option is provided as a slower but accurate - alternative for builds where the fma() function is found wanting. - The speed penalty may be modest (17% slower on an Apple M1 Max), - so don't hesitate to enable this build option. - - The algorithms are from the T. J. Dekker paper: - A Floating-Point Technique for Extending the Available Precision - https://csclub.uwaterloo.ca/~pbarfuss/dekker1971.pdf -*/ - -static DoubleLength -dl_split(double x) { - // Dekker (5.5) and (5.6). - double t = x * 134217729.0; // Veltkamp constant = 2.0 ** 27 + 1 - double hi = t - (t - x); - double lo = x - hi; - return (DoubleLength) {hi, lo}; -} - -static DoubleLength -dl_mul(double x, double y) -{ - // Dekker (5.12) and mul12() - DoubleLength xx = dl_split(x); - DoubleLength yy = dl_split(y); - double p = xx.hi * yy.hi; - double q = xx.hi * yy.lo + xx.lo * yy.hi; - double z = p + q; - double zz = p - z + q + xx.lo * yy.lo; - return (DoubleLength) {z, zz}; -} - -#endif - -typedef struct { double hi; double lo; double tiny; } TripleLength; - -static const TripleLength tl_zero = {0.0, 0.0, 0.0}; - -static TripleLength -tl_fma(double x, double y, TripleLength total) -{ - /* Algorithm 5.10 with SumKVert for K=3 */ - DoubleLength pr = dl_mul(x, y); - DoubleLength sm = dl_sum(total.hi, pr.hi); - DoubleLength r1 = dl_sum(total.lo, pr.lo); - DoubleLength r2 = dl_sum(r1.hi, sm.lo); - return (TripleLength) {sm.hi, r2.hi, total.tiny + r1.lo + r2.lo}; -} - -static double -tl_to_d(TripleLength total) -{ - DoubleLength last = dl_sum(total.lo, total.hi); - return total.tiny + last.lo + last.hi; -} - /*[clinic input] math.sumprod @@ -4073,7 +4038,7 @@ static PyMethodDef math_methods[] = { {"lcm", _PyCFunction_CAST(math_lcm), METH_FASTCALL, math_lcm_doc}, MATH_LDEXP_METHODDEF {"lgamma", math_lgamma, METH_O, math_lgamma_doc}, - MATH_LOG_METHODDEF + {"log", _PyCFunction_CAST(math_log), METH_FASTCALL, math_log_doc}, {"log1p", math_log1p, METH_O, math_log1p_doc}, MATH_LOG10_METHODDEF MATH_LOG2_METHODDEF diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 7d91f7e4bac76b..e38caf7cc0abee 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -41,6 +41,7 @@ #ifndef MS_WINDOWS # include "posixmodule.h" #else +# include "pycore_fileutils_windows.h" # include "winreparse.h" #endif @@ -668,8 +669,11 @@ PyOS_AfterFork(void) #ifdef MS_WINDOWS /* defined in fileutils.c */ void _Py_time_t_to_FILE_TIME(time_t, int, FILETIME *); -void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *, - ULONG, struct _Py_stat_struct *); +void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *, ULONG, + FILE_BASIC_INFO *, FILE_ID_INFO *, + struct _Py_stat_struct *); +void _Py_stat_basic_info_to_stat(FILE_STAT_BASIC_INFORMATION *, + struct _Py_stat_struct *); #endif @@ -1819,12 +1823,39 @@ attributes_from_dir(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *re return TRUE; } + +static void +update_st_mode_from_path(const wchar_t *path, DWORD attr, + struct _Py_stat_struct *result) +{ + if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { + /* Fix the file execute permissions. This hack sets S_IEXEC if + the filename has an extension that is commonly used by files + that CreateProcessW can execute. A real implementation calls + GetSecurityInfo, OpenThreadToken/OpenProcessToken, and + AccessCheck to check for generic read, write, and execute + access. */ + const wchar_t *fileExtension = wcsrchr(path, '.'); + if (fileExtension) { + if (_wcsicmp(fileExtension, L".exe") == 0 || + _wcsicmp(fileExtension, L".bat") == 0 || + _wcsicmp(fileExtension, L".cmd") == 0 || + _wcsicmp(fileExtension, L".com") == 0) { + result->st_mode |= 0111; + } + } + } +} + + static int -win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, - BOOL traverse) +win32_xstat_slow_impl(const wchar_t *path, struct _Py_stat_struct *result, + BOOL traverse) { HANDLE hFile; BY_HANDLE_FILE_INFORMATION fileInfo; + FILE_BASIC_INFO basicInfo; + FILE_ID_INFO idInfo; FILE_ATTRIBUTE_TAG_INFO tagInfo = { 0 }; DWORD fileType, error; BOOL isUnhandledTag = FALSE; @@ -1954,12 +1985,16 @@ win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, for an unhandled tag. */ } else if (!isUnhandledTag) { CloseHandle(hFile); - return win32_xstat_impl(path, result, TRUE); + return win32_xstat_slow_impl(path, result, TRUE); } } } - if (!GetFileInformationByHandle(hFile, &fileInfo)) { + if (!GetFileInformationByHandle(hFile, &fileInfo) || + !GetFileInformationByHandleEx(hFile, FileBasicInfo, + &basicInfo, sizeof(basicInfo)) || + !GetFileInformationByHandleEx(hFile, FileIdInfo, + &idInfo, sizeof(idInfo))) { switch (GetLastError()) { case ERROR_INVALID_PARAMETER: case ERROR_INVALID_FUNCTION: @@ -1975,25 +2010,8 @@ win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, } } - _Py_attribute_data_to_stat(&fileInfo, tagInfo.ReparseTag, result); - - if (!(fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - /* Fix the file execute permissions. This hack sets S_IEXEC if - the filename has an extension that is commonly used by files - that CreateProcessW can execute. A real implementation calls - GetSecurityInfo, OpenThreadToken/OpenProcessToken, and - AccessCheck to check for generic read, write, and execute - access. */ - const wchar_t *fileExtension = wcsrchr(path, '.'); - if (fileExtension) { - if (_wcsicmp(fileExtension, L".exe") == 0 || - _wcsicmp(fileExtension, L".bat") == 0 || - _wcsicmp(fileExtension, L".cmd") == 0 || - _wcsicmp(fileExtension, L".com") == 0) { - result->st_mode |= 0111; - } - } - } + _Py_attribute_data_to_stat(&fileInfo, tagInfo.ReparseTag, &basicInfo, &idInfo, result); + update_st_mode_from_path(path, fileInfo.dwFileAttributes, result); cleanup: if (hFile != INVALID_HANDLE_VALUE) { @@ -2010,6 +2028,39 @@ win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, return retval; } +static int +win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, + BOOL traverse) +{ + FILE_STAT_BASIC_INFORMATION statInfo; + if (_Py_GetFileInformationByName(path, FileStatBasicByNameInfo, + &statInfo, sizeof(statInfo))) { + if (// Cannot use fast path for reparse points ... + !(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + // ... unless it's a name surrogate (symlink) and we're not following + || (!traverse && IsReparseTagNameSurrogate(statInfo.ReparseTag)) + ) { + _Py_stat_basic_info_to_stat(&statInfo, result); + update_st_mode_from_path(path, statInfo.FileAttributes, result); + return 0; + } + } else { + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_NOT_READY: + case ERROR_BAD_NET_NAME: + /* These errors aren't worth retrying with the slow path */ + return -1; + case ERROR_NOT_SUPPORTED: + /* indicates the API couldn't be loaded */ + break; + } + } + + return win32_xstat_slow_impl(path, result, traverse); +} + static int win32_xstat(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse) { @@ -2017,6 +2068,10 @@ win32_xstat(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse) setting it to a POSIX error. Callers should use GetLastError. */ int code = win32_xstat_impl(path, result, traverse); errno = 0; + + /* ctime is only deprecated from 3.12, so we copy birthtime across */ + result->st_ctime = result->st_birthtime; + result->st_ctime_nsec = result->st_birthtime_nsec; return code; } /* About the following functions: win32_lstat_w, win32_stat, win32_stat_w @@ -2087,9 +2142,12 @@ static PyStructSequence_Field stat_result_fields[] = { #ifdef HAVE_STRUCT_STAT_ST_GEN {"st_gen", "generation number"}, #endif -#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME +#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) || defined(MS_WINDOWS) {"st_birthtime", "time of creation"}, #endif +#ifdef MS_WINDOWS + {"st_birthtime_ns", "time of creation in nanoseconds"}, +#endif #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES {"st_file_attributes", "Windows file attribute bits"}, #endif @@ -2132,16 +2190,22 @@ static PyStructSequence_Field stat_result_fields[] = { #define ST_GEN_IDX ST_FLAGS_IDX #endif -#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME +#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) || defined(MS_WINDOWS) #define ST_BIRTHTIME_IDX (ST_GEN_IDX+1) #else #define ST_BIRTHTIME_IDX ST_GEN_IDX #endif -#ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES -#define ST_FILE_ATTRIBUTES_IDX (ST_BIRTHTIME_IDX+1) +#ifdef MS_WINDOWS +#define ST_BIRTHTIME_NS_IDX (ST_BIRTHTIME_IDX+1) #else -#define ST_FILE_ATTRIBUTES_IDX ST_BIRTHTIME_IDX +#define ST_BIRTHTIME_NS_IDX ST_BIRTHTIME_IDX +#endif + +#if defined(HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES) || defined(MS_WINDOWS) +#define ST_FILE_ATTRIBUTES_IDX (ST_BIRTHTIME_NS_IDX+1) +#else +#define ST_FILE_ATTRIBUTES_IDX ST_BIRTHTIME_NS_IDX #endif #ifdef HAVE_STRUCT_STAT_ST_FSTYPE @@ -2310,7 +2374,7 @@ _posix_free(void *module) } static void -fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long nsec) +fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index, time_t sec, unsigned long nsec) { PyObject *s = _PyLong_FromTime_t(sec); PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec); @@ -2334,12 +2398,18 @@ fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long ns goto exit; } - PyStructSequence_SET_ITEM(v, index, s); - PyStructSequence_SET_ITEM(v, index+3, float_s); - PyStructSequence_SET_ITEM(v, index+6, ns_total); - s = NULL; - float_s = NULL; - ns_total = NULL; + if (s_index >= 0) { + PyStructSequence_SET_ITEM(v, s_index, s); + s = NULL; + } + if (f_index >= 0) { + PyStructSequence_SET_ITEM(v, f_index, float_s); + float_s = NULL; + } + if (ns_index >= 0) { + PyStructSequence_SET_ITEM(v, ns_index, ns_total); + ns_total = NULL; + } exit: Py_XDECREF(s); Py_XDECREF(ns_fractional); @@ -2348,6 +2418,33 @@ fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long ns Py_XDECREF(float_s); } +#ifdef MS_WINDOWS +static PyObject* +_pystat_l128_from_l64_l64(uint64_t low, uint64_t high) +{ + PyObject *o_low = PyLong_FromUnsignedLongLong(low); + if (!o_low || !high) { + return o_low; + } + PyObject *o_high = PyLong_FromUnsignedLongLong(high); + PyObject *l64 = o_high ? PyLong_FromLong(64) : NULL; + if (!l64) { + Py_XDECREF(o_high); + Py_DECREF(o_low); + return NULL; + } + Py_SETREF(o_high, PyNumber_Lshift(o_high, l64)); + Py_DECREF(l64); + if (!o_high) { + Py_DECREF(o_low); + return NULL; + } + Py_SETREF(o_low, PyNumber_Add(o_low, o_high)); + Py_DECREF(o_high); + return o_low; +} +#endif + /* pack a system stat C structure into the Python stat tuple (used by posix_stat() and posix_fstat()) */ static PyObject* @@ -2360,12 +2457,13 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) return NULL; PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode)); +#ifdef MS_WINDOWS + PyStructSequence_SET_ITEM(v, 1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high)); + PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLongLong(st->st_dev)); +#else static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino), "stat.st_ino is larger than unsigned long long"); PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino)); -#ifdef MS_WINDOWS - PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLong(st->st_dev)); -#else PyStructSequence_SET_ITEM(v, 2, _PyLong_FromDev(st->st_dev)); #endif PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long)st->st_nlink)); @@ -2395,9 +2493,9 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) #else ansec = mnsec = cnsec = 0; #endif - fill_time(module, v, 7, st->st_atime, ansec); - fill_time(module, v, 8, st->st_mtime, mnsec); - fill_time(module, v, 9, st->st_ctime, cnsec); + fill_time(module, v, 7, 10, 13, st->st_atime, ansec); + fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec); + fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec); #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX, @@ -2415,7 +2513,7 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) PyStructSequence_SET_ITEM(v, ST_GEN_IDX, PyLong_FromLong((long)st->st_gen)); #endif -#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME +#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) { PyObject *val; unsigned long bsec,bnsec; @@ -2429,6 +2527,9 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX, val); } +#elif defined(MS_WINDOWS) + fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX, + st->st_birthtime, st->st_birthtime_nsec); #endif #ifdef HAVE_STRUCT_STAT_ST_FLAGS PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX, @@ -14639,7 +14740,7 @@ DirEntry_from_find_data(PyObject *module, path_t *path, WIN32_FIND_DATAW *dataW) } find_data_to_file_info(dataW, &file_info, &reparse_tag); - _Py_attribute_data_to_stat(&file_info, reparse_tag, &entry->win32_lstat); + _Py_attribute_data_to_stat(&file_info, reparse_tag, NULL, NULL, &entry->win32_lstat); return (PyObject *)entry; diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index b7927750e334b7..6a6f8cf7392e1c 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -353,7 +353,7 @@ remove_unusable_flags(PyObject *m) } #ifndef MS_WINDOWS_DESKTOP info.dwOSVersionInfoSize = sizeof(info); - if (!GetVersionExW((OSVERSIONINFOW*) &info)) { + if (!GetVersionEx((OSVERSIONINFO*) &info)) { PyErr_SetFromWindowsErr(0); return -1; } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 687a654bdae137..2d8dab6f378006 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -3067,7 +3067,7 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize) PyObject_Realloc(v, PyBytesObject_SIZE + newsize); if (*pv == NULL) { #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif PyObject_Free(v); PyErr_NoMemory(); diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 227e438a8dfffc..2ef520044340ee 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -304,7 +304,7 @@ static inline void dictkeys_incref(PyDictKeysObject *dk) { #ifdef Py_REF_DEBUG - _Py_IncRefTotal(); + _Py_IncRefTotal(_PyInterpreterState_GET()); #endif dk->dk_refcnt++; } @@ -314,7 +314,7 @@ dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk) { assert(dk->dk_refcnt > 0); #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif if (--dk->dk_refcnt == 0) { free_keys_object(interp, dk); @@ -596,7 +596,7 @@ new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode) assert(log2_size >= PyDict_LOG_MINSIZE); - usable = USABLE_FRACTION(1<dk_refcnt = 1; dk->dk_log2_size = log2_size; @@ -824,7 +824,7 @@ clone_combined_dict_keys(PyDictObject *orig) we have it now; calling dictkeys_incref would be an error as keys->dk_refcnt is already set to 1 (after memcpy). */ #ifdef Py_REF_DEBUG - _Py_IncRefTotal(); + _Py_IncRefTotal(_PyInterpreterState_GET()); #endif return keys; } @@ -1530,7 +1530,7 @@ dictresize(PyInterpreterState *interp, PyDictObject *mp, // We can not use free_keys_object here because key's reference // are moved already. #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif if (oldkeys == Py_EMPTY_KEYS) { oldkeys->dk_refcnt--; diff --git a/Objects/exceptions.c b/Objects/exceptions.c index c6fb6a3f19b2d0..a355244cf997e6 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -3749,113 +3749,18 @@ _PyExc_Fini(PyInterpreterState *interp) _PyExc_FiniTypes(interp); } -/* Helper to do the equivalent of "raise X from Y" in C, but always using - * the current exception rather than passing one in. - * - * We currently limit this to *only* exceptions that use the BaseException - * tp_init and tp_new methods, since we can be reasonably sure we can wrap - * those correctly without losing data and without losing backwards - * compatibility. - * - * We also aim to rule out *all* exceptions that might be storing additional - * state, whether by having a size difference relative to BaseException, - * additional arguments passed in during construction or by having a - * non-empty instance dict. - * - * We need to be very careful with what we wrap, since changing types to - * a broader exception type would be backwards incompatible for - * existing codecs, and with different init or new method implementations - * may either not support instantiation with PyErr_Format or lose - * information when instantiated that way. - * - * XXX (ncoghlan): This could be made more comprehensive by exploiting the - * fact that exceptions are expected to support pickling. If more builtin - * exceptions (e.g. AttributeError) start to be converted to rich - * exceptions with additional attributes, that's probably a better approach - * to pursue over adding special cases for particular stateful subclasses. - * - * Returns a borrowed reference to the new exception (if any), NULL if the - * existing exception was left in place. - */ -PyObject * -_PyErr_TrySetFromCause(const char *format, ...) -{ - PyObject* msg_prefix; - PyObject *instance_args; - Py_ssize_t num_args, caught_type_size, base_exc_size; - va_list vargs; - int same_basic_size; - - PyObject *exc = PyErr_GetRaisedException(); - PyTypeObject *caught_type = Py_TYPE(exc); - /* Ensure type info indicates no extra state is stored at the C level - * and that the type can be reinstantiated using PyErr_Format - */ - caught_type_size = caught_type->tp_basicsize; - base_exc_size = _PyExc_BaseException.tp_basicsize; - same_basic_size = ( - caught_type_size == base_exc_size || - (_PyType_SUPPORTS_WEAKREFS(caught_type) && - (caught_type_size == base_exc_size + (Py_ssize_t)sizeof(PyObject *)) - ) - ); - if (caught_type->tp_init != (initproc)BaseException_init || - caught_type->tp_new != BaseException_new || - !same_basic_size || - caught_type->tp_itemsize != _PyExc_BaseException.tp_itemsize) { - /* We can't be sure we can wrap this safely, since it may contain - * more state than just the exception type. Accordingly, we just - * leave it alone. - */ - PyErr_SetRaisedException(exc); - return NULL; - } - - /* Check the args are empty or contain a single string */ - instance_args = ((PyBaseExceptionObject *)exc)->args; - num_args = PyTuple_GET_SIZE(instance_args); - if (num_args > 1 || - (num_args == 1 && - !PyUnicode_CheckExact(PyTuple_GET_ITEM(instance_args, 0)))) { - /* More than 1 arg, or the one arg we do have isn't a string - */ - PyErr_SetRaisedException(exc); - return NULL; - } - - /* Ensure the instance dict is also empty */ - if (!_PyObject_IsInstanceDictEmpty(exc)) { - /* While we could potentially copy a non-empty instance dictionary - * to the replacement exception, for now we take the more - * conservative path of leaving exceptions with attributes set - * alone. - */ - PyErr_SetRaisedException(exc); - return NULL; - } - - /* For exceptions that we can wrap safely, we chain the original - * exception to a new one of the exact same type with an - * error message that mentions the additional details and the - * original exception. - * - * It would be nice to wrap OSError and various other exception - * types as well, but that's quite a bit trickier due to the extra - * state potentially stored on OSError instances. - */ - va_start(vargs, format); - msg_prefix = PyUnicode_FromFormatV(format, vargs); - va_end(vargs); - if (msg_prefix == NULL) { - Py_DECREF(exc); - return NULL; +int +_PyException_AddNote(PyObject *exc, PyObject *note) +{ + if (!PyExceptionInstance_Check(exc)) { + PyErr_Format(PyExc_TypeError, + "exc must be an exception, not '%s'", + Py_TYPE(exc)->tp_name); + return -1; } - - PyErr_Format((PyObject*)Py_TYPE(exc), "%U (%s: %S)", - msg_prefix, Py_TYPE(exc)->tp_name, exc); - Py_DECREF(msg_prefix); - PyObject *new_exc = PyErr_GetRaisedException(); - PyException_SetCause(new_exc, exc); - PyErr_SetRaisedException(new_exc); - return new_exc; + PyObject *r = BaseException_add_note(exc, note); + int res = r == NULL ? -1 : 0; + Py_XDECREF(r); + return res; } + diff --git a/Objects/object.c b/Objects/object.c index dff5e2afa16ab8..9dd5eb998217f6 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -54,37 +54,100 @@ _PyObject_CheckConsistency(PyObject *op, int check_content) #ifdef Py_REF_DEBUG +/* We keep the legacy symbol around for backward compatibility. */ Py_ssize_t _Py_RefTotal; +static inline Py_ssize_t +get_legacy_reftotal(void) +{ + return _Py_RefTotal; +} +#endif + +#ifdef Py_REF_DEBUG + +# define REFTOTAL(interp) \ + interp->object_state.reftotal + +static inline void +reftotal_increment(PyInterpreterState *interp) +{ + REFTOTAL(interp)++; +} + static inline void -reftotal_increment(void) +reftotal_decrement(PyInterpreterState *interp) { - _Py_RefTotal++; + REFTOTAL(interp)--; } static inline void -reftotal_decrement(void) +reftotal_add(PyInterpreterState *interp, Py_ssize_t n) +{ + REFTOTAL(interp) += n; +} + +static inline Py_ssize_t get_global_reftotal(_PyRuntimeState *); + +/* We preserve the number of refs leaked during runtime finalization, + so they can be reported if the runtime is initialized again. */ +// XXX We don't lose any information by dropping this, +// so we should consider doing so. +static Py_ssize_t last_final_reftotal = 0; + +void +_Py_FinalizeRefTotal(_PyRuntimeState *runtime) { - _Py_RefTotal--; + last_final_reftotal = get_global_reftotal(runtime); + runtime->object_state.interpreter_leaks = 0; } void -_Py_AddRefTotal(Py_ssize_t n) +_PyInterpreterState_FinalizeRefTotal(PyInterpreterState *interp) { - _Py_RefTotal += n; + interp->runtime->object_state.interpreter_leaks += REFTOTAL(interp); + REFTOTAL(interp) = 0; } -Py_ssize_t -_Py_GetRefTotal(void) +static inline Py_ssize_t +get_reftotal(PyInterpreterState *interp) { - return _Py_RefTotal; + /* For a single interpreter, we ignore the legacy _Py_RefTotal, + since we can't determine which interpreter updated it. */ + return REFTOTAL(interp); +} + +static inline Py_ssize_t +get_global_reftotal(_PyRuntimeState *runtime) +{ + Py_ssize_t total = 0; + + /* Add up the total from each interpreter. */ + HEAD_LOCK(&_PyRuntime); + PyInterpreterState *interp = PyInterpreterState_Head(); + for (; interp != NULL; interp = PyInterpreterState_Next(interp)) { + total += REFTOTAL(interp); + } + HEAD_UNLOCK(&_PyRuntime); + + /* Add in the updated value from the legacy _Py_RefTotal. */ + total += get_legacy_reftotal(); + total += last_final_reftotal; + total += runtime->object_state.interpreter_leaks; + + return total; } +#undef REFTOTAL + void _PyDebug_PrintTotalRefs(void) { + _PyRuntimeState *runtime = &_PyRuntime; fprintf(stderr, "[%zd refs, %zd blocks]\n", - _Py_GetRefTotal(), _Py_GetAllocatedBlocks()); + get_global_reftotal(runtime), _Py_GetAllocatedBlocks()); + /* It may be helpful to also print the "legacy" reftotal separately. + Likewise for the total for each interpreter. */ } #endif /* Py_REF_DEBUG */ @@ -139,30 +202,56 @@ _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op) filename, lineno, __func__); } -/* This is exposed strictly for use in Py_INCREF(). */ -PyAPI_FUNC(void) +/* This is used strictly by Py_INCREF(). */ +void _Py_IncRefTotal_DO_NOT_USE_THIS(void) { - reftotal_increment(); + reftotal_increment(_PyInterpreterState_GET()); } -/* This is exposed strictly for use in Py_DECREF(). */ -PyAPI_FUNC(void) +/* This is used strictly by Py_DECREF(). */ +void _Py_DecRefTotal_DO_NOT_USE_THIS(void) { - reftotal_decrement(); + reftotal_decrement(_PyInterpreterState_GET()); } void -_Py_IncRefTotal(void) +_Py_IncRefTotal(PyInterpreterState *interp) { - reftotal_increment(); + reftotal_increment(interp); } void -_Py_DecRefTotal(void) +_Py_DecRefTotal(PyInterpreterState *interp) +{ + reftotal_decrement(interp); +} + +void +_Py_AddRefTotal(PyInterpreterState *interp, Py_ssize_t n) +{ + reftotal_add(interp, n); +} + +/* This includes the legacy total + and any carried over from the last runtime init/fini cycle. */ +Py_ssize_t +_Py_GetGlobalRefTotal(void) +{ + return get_global_reftotal(&_PyRuntime); +} + +Py_ssize_t +_Py_GetLegacyRefTotal(void) +{ + return get_legacy_reftotal(); +} + +Py_ssize_t +_PyInterpreterState_GetRefTotal(PyInterpreterState *interp) { - reftotal_decrement(); + return get_reftotal(interp); } #endif /* Py_REF_DEBUG */ @@ -182,21 +271,18 @@ Py_DecRef(PyObject *o) void _Py_IncRef(PyObject *o) { -#ifdef Py_REF_DEBUG - reftotal_increment(); -#endif Py_INCREF(o); } void _Py_DecRef(PyObject *o) { -#ifdef Py_REF_DEBUG - reftotal_decrement(); -#endif Py_DECREF(o); } + +/**************************************/ + PyObject * PyObject_Init(PyObject *op, PyTypeObject *tp) { @@ -2077,7 +2163,7 @@ void _Py_NewReference(PyObject *op) { #ifdef Py_REF_DEBUG - reftotal_increment(); + reftotal_increment(_PyInterpreterState_GET()); #endif new_reference(op); } diff --git a/Objects/structseq.c b/Objects/structseq.c index c20962ecd82563..2a5343815866d3 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -592,7 +592,7 @@ _PyStructSequence_FiniType(PyTypeObject *type) // Don't use Py_DECREF(): static type must not be deallocated Py_SET_REFCNT(type, 0); #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif // Make sure that _PyStructSequence_InitType() will initialize diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 59c0251639d3dd..61fab4078d66ba 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -944,7 +944,7 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) if (sv == NULL) { *pv = NULL; #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif PyObject_GC_Del(v); return -1; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f0654c239f6635..a37f97c71ec763 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -317,11 +317,27 @@ _PyType_InitCache(PyInterpreterState *interp) entry->version = 0; // Set to None so _PyType_Lookup() can use Py_SETREF(), // rather than using slower Py_XSETREF(). - entry->name = Py_NewRef(Py_None); + // (See _PyType_FixCacheRefcounts() about the refcount.) + entry->name = Py_None; entry->value = NULL; } } +// This is the temporary fix used by pycore_create_interpreter(), +// in pylifecycle.c. _PyType_InitCache() is called before the GIL +// has been created (for the main interpreter) and without the +// "current" thread state set. This causes crashes when the +// reftotal is updated, so we don't modify the refcount in +// _PyType_InitCache(), and instead do it later by calling +// _PyType_FixCacheRefcounts(). +// XXX This workaround should be removed once we have immortal +// objects (PEP 683). +void +_PyType_FixCacheRefcounts(void) +{ + _Py_RefcntAdd(Py_None, (1 << MCACHE_SIZE_EXP)); +} + static unsigned int _PyType_ClearCache(PyInterpreterState *interp) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 2d50f9c340f2f3..b9fb53147b9b51 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14533,6 +14533,15 @@ _PyUnicode_InitGlobalObjects(PyInterpreterState *interp) return _PyStatus_OK(); } + // Initialize the global interned dict + PyObject *interned = PyDict_New(); + if (interned == NULL) { + PyErr_Clear(); + return _PyStatus_ERR("failed to create interned dict"); + } + + set_interned_dict(interned); + /* Intern statically allocated string identifiers and deepfreeze strings. * This must be done before any module initialization so that statically * allocated string identifiers are used instead of heap allocated strings. @@ -14600,14 +14609,7 @@ PyUnicode_InternInPlace(PyObject **p) } PyObject *interned = get_interned_dict(); - if (interned == NULL) { - interned = PyDict_New(); - if (interned == NULL) { - PyErr_Clear(); /* Don't leave an exception */ - return; - } - set_interned_dict(interned); - } + assert(interned != NULL); PyObject *t = PyDict_SetDefault(interned, s, s); if (t == NULL) { diff --git a/PC/python3dll.c b/PC/python3dll.c index e300819365756e..706affa18351b3 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -192,6 +192,7 @@ EXPORT_FUNC(PyErr_BadInternalCall) EXPORT_FUNC(PyErr_CheckSignals) EXPORT_FUNC(PyErr_Clear) EXPORT_FUNC(PyErr_Display) +EXPORT_FUNC(PyErr_DisplayException) EXPORT_FUNC(PyErr_ExceptionMatches) EXPORT_FUNC(PyErr_Fetch) EXPORT_FUNC(PyErr_Format) diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 4cc184bfc1ac82..439cd687fda61d 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -109,6 +109,7 @@ + diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index fbdaf04ce37cb1..0e42e4982c21ff 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -57,6 +57,9 @@ Source Files + + Source Files + diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj index d07db3a6815058..f4640454a73070 100644 --- a/PCbuild/python.vcxproj +++ b/PCbuild/python.vcxproj @@ -95,7 +95,7 @@ Console 2000000 - 4000000 + 8000000 diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 85dc8caa458ed9..c754b2165745ff 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -216,6 +216,7 @@ + @@ -238,6 +239,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 98e7d59ba1020c..90ed0602821bff 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -555,6 +555,9 @@ Include\internal + + Include\internal + Include\internal @@ -618,6 +621,9 @@ Include\internal + + Include\internal + Include\internal diff --git a/PCbuild/pythonw.vcxproj b/PCbuild/pythonw.vcxproj index e7216dec3a1af0..e23635e5ea9411 100644 --- a/PCbuild/pythonw.vcxproj +++ b/PCbuild/pythonw.vcxproj @@ -89,7 +89,8 @@ - 2000000 + 2000000 + 8000000 diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 74582ecbbda103..ce2a58b6e30475 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -778,9 +778,7 @@ dummy_func( } assert(exc && PyExceptionInstance_Check(exc)); Py_INCREF(exc); - PyObject *typ = Py_NewRef(PyExceptionInstance_Class(exc)); - PyObject *tb = PyException_GetTraceback(exc); - _PyErr_Restore(tstate, typ, exc, tb); + _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } @@ -791,9 +789,7 @@ dummy_func( } else { Py_INCREF(exc); - PyObject *typ = Py_NewRef(PyExceptionInstance_Class(exc)); - PyObject *tb = PyException_GetTraceback(exc); - _PyErr_Restore(tstate, typ, exc, tb); + _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } } @@ -3030,20 +3026,10 @@ dummy_func( value = result; } - /* If value is a unicode object, and there's no fmt_spec, - then we know the result of format(value) is value - itself. In that case, skip calling format(). I plan to - move this optimization in to PyObject_Format() - itself. */ - if (PyUnicode_CheckExact(value) && fmt_spec == NULL) { - /* Do nothing, just transfer ownership to result. */ - result = value; - } else { - /* Actually call format(). */ - result = PyObject_Format(value, fmt_spec); - DECREF_INPUTS(); - ERROR_IF(result == NULL, error); - } + result = PyObject_Format(value, fmt_spec); + Py_DECREF(value); + Py_XDECREF(fmt_spec); + ERROR_IF(result == NULL, error); } inst(COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top)) { diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 98b72ec1b36428..c2257515a30599 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -310,6 +310,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { _PyFrame_SetStackPointer(frame, stack_pointer); \ int err = trace_function_entry(tstate, frame); \ stack_pointer = _PyFrame_GetStackPointer(frame); \ + frame->stacktop = -1; \ if (err) { \ goto error; \ } \ diff --git a/Python/codecs.c b/Python/codecs.c index b2087b499dfdba..9d800f9856c2f7 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -382,20 +382,27 @@ PyObject *PyCodec_StreamWriter(const char *encoding, return codec_getstreamcodec(encoding, stream, errors, 3); } -/* Helper that tries to ensure the reported exception chain indicates the - * codec that was invoked to trigger the failure without changing the type - * of the exception raised. - */ static void -wrap_codec_error(const char *operation, - const char *encoding) +add_note_to_codec_error(const char *operation, + const char *encoding) { - /* TrySetFromCause will replace the active exception with a suitably - * updated clone if it can, otherwise it will leave the original - * exception alone. - */ - _PyErr_TrySetFromCause("%s with '%s' codec failed", - operation, encoding); + PyObject *exc = PyErr_GetRaisedException(); + if (exc == NULL) { + return; + } + PyObject *note = PyUnicode_FromFormat("%s with '%s' codec failed", + operation, encoding); + if (note == NULL) { + _PyErr_ChainExceptions1(exc); + return; + } + int res = _PyException_AddNote(exc, note); + Py_DECREF(note); + if (res < 0) { + _PyErr_ChainExceptions1(exc); + return; + } + PyErr_SetRaisedException(exc); } /* Encode an object (e.g. a Unicode object) using the given encoding @@ -418,7 +425,7 @@ _PyCodec_EncodeInternal(PyObject *object, result = PyObject_Call(encoder, args, NULL); if (result == NULL) { - wrap_codec_error("encoding", encoding); + add_note_to_codec_error("encoding", encoding); goto onError; } @@ -463,7 +470,7 @@ _PyCodec_DecodeInternal(PyObject *object, result = PyObject_Call(decoder, args, NULL); if (result == NULL) { - wrap_codec_error("decoding", encoding); + add_note_to_codec_error("decoding", encoding); goto onError; } if (!PyTuple_Check(result) || diff --git a/Python/compile.c b/Python/compile.c index 29e55b8b30c56b..99296050445f50 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -595,17 +595,52 @@ static int instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { memset(g, 0, sizeof(cfg_builder)); RETURN_IF_ERROR(cfg_builder_init(g)); - /* Note: there can be more than one label for the same offset */ + + /* There can be more than one label for the same offset. The + * offset2lbl maping selects one of them which we use consistently. + */ + + int *offset2lbl = PyMem_Malloc(seq->s_used * sizeof(int)); + if (offset2lbl == NULL) { + PyErr_NoMemory(); + return ERROR; + } for (int i = 0; i < seq->s_used; i++) { - for (int j=0; j < seq->s_labelmap_size; j++) { - if (seq->s_labelmap[j] == i) { - jump_target_label lbl = {j}; - RETURN_IF_ERROR(cfg_builder_use_label(g, lbl)); + offset2lbl[i] = -1; + } + for (int lbl=0; lbl < seq->s_labelmap_size; lbl++) { + int offset = seq->s_labelmap[lbl]; + if (offset >= 0) { + assert(offset < seq->s_used); + offset2lbl[offset] = lbl; + } + } + + for (int i = 0; i < seq->s_used; i++) { + int lbl = offset2lbl[i]; + if (lbl >= 0) { + assert (lbl < seq->s_labelmap_size); + jump_target_label lbl_ = {lbl}; + if (cfg_builder_use_label(g, lbl_) < 0) { + goto error; } } instruction *instr = &seq->s_instrs[i]; - RETURN_IF_ERROR(cfg_builder_addop(g, instr->i_opcode, instr->i_oparg, instr->i_loc)); + int opcode = instr->i_opcode; + int oparg = instr->i_oparg; + if (HAS_TARGET(opcode)) { + int offset = seq->s_labelmap[oparg]; + assert(offset >= 0 && offset < seq->s_used); + int lbl = offset2lbl[offset]; + assert(lbl >= 0 && lbl < seq->s_labelmap_size); + oparg = lbl; + } + if (cfg_builder_addop(g, opcode, oparg, instr->i_loc) < 0) { + goto error; + } } + PyMem_Free(offset2lbl); + int nblocks = 0; for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { nblocks++; @@ -615,6 +650,9 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { return ERROR; } return SUCCESS; +error: + PyMem_Free(offset2lbl); + return ERROR; } diff --git a/Python/errors.c b/Python/errors.c index bbf6d397ce8097..ab14770c6e810c 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -135,6 +135,28 @@ _PyErr_GetTopmostException(PyThreadState *tstate) return exc_info; } +static PyObject * +get_normalization_failure_note(PyThreadState *tstate, PyObject *exception, PyObject *value) +{ + PyObject *args = PyObject_Repr(value); + if (args == NULL) { + _PyErr_Clear(tstate); + args = PyUnicode_FromFormat(""); + } + PyObject *note; + const char *tpname = ((PyTypeObject*)exception)->tp_name; + if (args == NULL) { + _PyErr_Clear(tstate); + note = PyUnicode_FromFormat("Normalization failed: type=%s", tpname); + } + else { + note = PyUnicode_FromFormat("Normalization failed: type=%s args=%S", + tpname, args); + Py_DECREF(args); + } + return note; +} + void _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value) { @@ -160,19 +182,27 @@ _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value) Py_XINCREF(value); if (!is_subclass) { /* We must normalize the value right now */ - PyObject *fixed_value; /* Issue #23571: functions must not be called with an exception set */ _PyErr_Clear(tstate); - fixed_value = _PyErr_CreateException(exception, value); - Py_XDECREF(value); + PyObject *fixed_value = _PyErr_CreateException(exception, value); if (fixed_value == NULL) { + PyObject *exc = _PyErr_GetRaisedException(tstate); + assert(PyExceptionInstance_Check(exc)); + + PyObject *note = get_normalization_failure_note(tstate, exception, value); + Py_XDECREF(value); + if (note != NULL) { + /* ignore errors in _PyException_AddNote - they will be overwritten below */ + _PyException_AddNote(exc, note); + Py_DECREF(note); + } + _PyErr_SetRaisedException(tstate, exc); return; } - - value = fixed_value; + Py_XSETREF(value, fixed_value); } exc_value = _PyErr_GetTopmostException(tstate)->exc_value; @@ -636,17 +666,15 @@ _PyErr_ChainExceptions(PyObject *typ, PyObject *val, PyObject *tb) } if (_PyErr_Occurred(tstate)) { - PyObject *typ2, *val2, *tb2; - _PyErr_Fetch(tstate, &typ2, &val2, &tb2); _PyErr_NormalizeException(tstate, &typ, &val, &tb); if (tb != NULL) { PyException_SetTraceback(val, tb); Py_DECREF(tb); } Py_DECREF(typ); - _PyErr_NormalizeException(tstate, &typ2, &val2, &tb2); - PyException_SetContext(val2, val); - _PyErr_Restore(tstate, typ2, val2, tb2); + PyObject *exc2 = _PyErr_GetRaisedException(tstate); + PyException_SetContext(exc2, val); + _PyErr_SetRaisedException(tstate, exc2); } else { _PyErr_Restore(tstate, typ, val, tb); @@ -727,27 +755,15 @@ static PyObject * _PyErr_FormatVFromCause(PyThreadState *tstate, PyObject *exception, const char *format, va_list vargs) { - PyObject *exc, *val, *val2, *tb; - assert(_PyErr_Occurred(tstate)); - _PyErr_Fetch(tstate, &exc, &val, &tb); - _PyErr_NormalizeException(tstate, &exc, &val, &tb); - if (tb != NULL) { - PyException_SetTraceback(val, tb); - Py_DECREF(tb); - } - Py_DECREF(exc); + PyObject *exc = _PyErr_GetRaisedException(tstate); assert(!_PyErr_Occurred(tstate)); - _PyErr_FormatV(tstate, exception, format, vargs); - - _PyErr_Fetch(tstate, &exc, &val2, &tb); - _PyErr_NormalizeException(tstate, &exc, &val2, &tb); - PyException_SetCause(val2, Py_NewRef(val)); - PyException_SetContext(val2, Py_NewRef(val)); - Py_DECREF(val); - _PyErr_Restore(tstate, exc, val2, tb); - + PyObject *exc2 = _PyErr_GetRaisedException(tstate); + PyException_SetCause(exc2, Py_NewRef(exc)); + PyException_SetContext(exc2, Py_NewRef(exc)); + Py_DECREF(exc); + _PyErr_SetRaisedException(tstate, exc2); return NULL; } @@ -1668,19 +1684,18 @@ static void PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, int end_lineno, int end_col_offset) { - PyObject *exc, *v, *tb, *tmp; PyThreadState *tstate = _PyThreadState_GET(); /* add attributes for the line number and filename for the error */ - _PyErr_Fetch(tstate, &exc, &v, &tb); - _PyErr_NormalizeException(tstate, &exc, &v, &tb); + PyObject *exc = _PyErr_GetRaisedException(tstate); /* XXX check that it is, indeed, a syntax error. It might not * be, though. */ - tmp = PyLong_FromLong(lineno); - if (tmp == NULL) + PyObject *tmp = PyLong_FromLong(lineno); + if (tmp == NULL) { _PyErr_Clear(tstate); + } else { - if (PyObject_SetAttr(v, &_Py_ID(lineno), tmp)) { + if (PyObject_SetAttr(exc, &_Py_ID(lineno), tmp)) { _PyErr_Clear(tstate); } Py_DECREF(tmp); @@ -1692,7 +1707,7 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, _PyErr_Clear(tstate); } } - if (PyObject_SetAttr(v, &_Py_ID(offset), tmp ? tmp : Py_None)) { + if (PyObject_SetAttr(exc, &_Py_ID(offset), tmp ? tmp : Py_None)) { _PyErr_Clear(tstate); } Py_XDECREF(tmp); @@ -1704,7 +1719,7 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, _PyErr_Clear(tstate); } } - if (PyObject_SetAttr(v, &_Py_ID(end_lineno), tmp ? tmp : Py_None)) { + if (PyObject_SetAttr(exc, &_Py_ID(end_lineno), tmp ? tmp : Py_None)) { _PyErr_Clear(tstate); } Py_XDECREF(tmp); @@ -1716,20 +1731,20 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, _PyErr_Clear(tstate); } } - if (PyObject_SetAttr(v, &_Py_ID(end_offset), tmp ? tmp : Py_None)) { + if (PyObject_SetAttr(exc, &_Py_ID(end_offset), tmp ? tmp : Py_None)) { _PyErr_Clear(tstate); } Py_XDECREF(tmp); tmp = NULL; if (filename != NULL) { - if (PyObject_SetAttr(v, &_Py_ID(filename), filename)) { + if (PyObject_SetAttr(exc, &_Py_ID(filename), filename)) { _PyErr_Clear(tstate); } tmp = PyErr_ProgramTextObject(filename, lineno); if (tmp) { - if (PyObject_SetAttr(v, &_Py_ID(text), tmp)) { + if (PyObject_SetAttr(exc, &_Py_ID(text), tmp)) { _PyErr_Clear(tstate); } Py_DECREF(tmp); @@ -1738,17 +1753,17 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, _PyErr_Clear(tstate); } } - if (exc != PyExc_SyntaxError) { - if (_PyObject_LookupAttr(v, &_Py_ID(msg), &tmp) < 0) { + if ((PyObject *)Py_TYPE(exc) != PyExc_SyntaxError) { + if (_PyObject_LookupAttr(exc, &_Py_ID(msg), &tmp) < 0) { _PyErr_Clear(tstate); } else if (tmp) { Py_DECREF(tmp); } else { - tmp = PyObject_Str(v); + tmp = PyObject_Str(exc); if (tmp) { - if (PyObject_SetAttr(v, &_Py_ID(msg), tmp)) { + if (PyObject_SetAttr(exc, &_Py_ID(msg), tmp)) { _PyErr_Clear(tstate); } Py_DECREF(tmp); @@ -1758,19 +1773,19 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, } } - if (_PyObject_LookupAttr(v, &_Py_ID(print_file_and_line), &tmp) < 0) { + if (_PyObject_LookupAttr(exc, &_Py_ID(print_file_and_line), &tmp) < 0) { _PyErr_Clear(tstate); } else if (tmp) { Py_DECREF(tmp); } else { - if (PyObject_SetAttr(v, &_Py_ID(print_file_and_line), Py_None)) { + if (PyObject_SetAttr(exc, &_Py_ID(print_file_and_line), Py_None)) { _PyErr_Clear(tstate); } } } - _PyErr_Restore(tstate, exc, v, tb); + _PyErr_SetRaisedException(tstate, exc); } void diff --git a/Python/fileutils.c b/Python/fileutils.c index 4ac759c45a3a1e..969b7163b5ac18 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -8,6 +8,8 @@ #ifdef MS_WINDOWS # include # include +# include // FILE_DEVICE_* constants +# include "pycore_fileutils_windows.h" // FILE_STAT_BASIC_INFORMATION # if defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) # define PATHCCH_ALLOW_LONG_PATHS 0x01 # else @@ -1056,6 +1058,13 @@ FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out) *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t); } +static void +LARGE_INTEGER_to_time_t_nsec(LARGE_INTEGER *in_ptr, time_t *time_out, int* nsec_out) +{ + *nsec_out = (int)(in_ptr->QuadPart % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ + *time_out = Py_SAFE_DOWNCAST((in_ptr->QuadPart / 10000000) - secs_between_epochs, __int64, time_t); +} + void _Py_time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) { @@ -1085,33 +1094,126 @@ attributes_to_mode(DWORD attr) return m; } + +typedef union { + FILE_ID_128 id; + struct { + uint64_t st_ino; + uint64_t st_ino_high; + }; +} id_128_to_ino; + + void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, + FILE_BASIC_INFO *basic_info, FILE_ID_INFO *id_info, struct _Py_stat_struct *result) { memset(result, 0, sizeof(*result)); result->st_mode = attributes_to_mode(info->dwFileAttributes); result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow; - result->st_dev = info->dwVolumeSerialNumber; - result->st_rdev = result->st_dev; - FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result->st_ctime_nsec); - FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); - FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); + result->st_dev = id_info ? id_info->VolumeSerialNumber : info->dwVolumeSerialNumber; + result->st_rdev = 0; + /* st_ctime is deprecated, but we preserve the legacy value in our caller, not here */ + if (basic_info) { + LARGE_INTEGER_to_time_t_nsec(&basic_info->CreationTime, &result->st_birthtime, &result->st_birthtime_nsec); + LARGE_INTEGER_to_time_t_nsec(&basic_info->ChangeTime, &result->st_ctime, &result->st_ctime_nsec); + LARGE_INTEGER_to_time_t_nsec(&basic_info->LastWriteTime, &result->st_mtime, &result->st_mtime_nsec); + LARGE_INTEGER_to_time_t_nsec(&basic_info->LastAccessTime, &result->st_atime, &result->st_atime_nsec); + } else { + FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_birthtime, &result->st_birthtime_nsec); + FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); + FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); + } result->st_nlink = info->nNumberOfLinks; - result->st_ino = (((uint64_t)info->nFileIndexHigh) << 32) + info->nFileIndexLow; + + if (id_info) { + id_128_to_ino file_id; + file_id.id = id_info->FileId; + result->st_ino = file_id.st_ino; + result->st_ino_high = file_id.st_ino_high; + } else { + /* should only occur for DirEntry_from_find_data, in which case the + index is likely to be zero anyway. */ + result->st_ino = (((uint64_t)info->nFileIndexHigh) << 32) + info->nFileIndexLow; + } + /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will open other name surrogate reparse points without traversing them. To detect/handle these, check st_file_attributes and st_reparse_tag. */ result->st_reparse_tag = reparse_tag; if (info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && reparse_tag == IO_REPARSE_TAG_SYMLINK) { - /* first clear the S_IFMT bits */ - result->st_mode ^= (result->st_mode & S_IFMT); - /* now set the bits that make this a symlink */ - result->st_mode |= S_IFLNK; + /* set the bits that make this a symlink */ + result->st_mode = (result->st_mode & ~S_IFMT) | S_IFLNK; } result->st_file_attributes = info->dwFileAttributes; } + +void +_Py_stat_basic_info_to_stat(FILE_STAT_BASIC_INFORMATION *info, + struct _Py_stat_struct *result) +{ + memset(result, 0, sizeof(*result)); + result->st_mode = attributes_to_mode(info->FileAttributes); + result->st_size = info->EndOfFile.QuadPart; + LARGE_INTEGER_to_time_t_nsec(&info->CreationTime, &result->st_birthtime, &result->st_birthtime_nsec); + LARGE_INTEGER_to_time_t_nsec(&info->ChangeTime, &result->st_ctime, &result->st_ctime_nsec); + LARGE_INTEGER_to_time_t_nsec(&info->LastWriteTime, &result->st_mtime, &result->st_mtime_nsec); + LARGE_INTEGER_to_time_t_nsec(&info->LastAccessTime, &result->st_atime, &result->st_atime_nsec); + result->st_nlink = info->NumberOfLinks; + result->st_dev = info->VolumeSerialNumber.QuadPart; + /* File systems with less than 128-bits zero pad into this field */ + id_128_to_ino file_id; + file_id.id = info->FileId128; + result->st_ino = file_id.st_ino; + result->st_ino_high = file_id.st_ino_high; + /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will + open other name surrogate reparse points without traversing them. To + detect/handle these, check st_file_attributes and st_reparse_tag. */ + result->st_reparse_tag = info->ReparseTag; + if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && + info->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + /* set the bits that make this a symlink */ + result->st_mode = (result->st_mode & ~S_IFMT) | S_IFLNK; + } + result->st_file_attributes = info->FileAttributes; + switch (info->DeviceType) { + case FILE_DEVICE_DISK: + case FILE_DEVICE_VIRTUAL_DISK: + case FILE_DEVICE_DFS: + case FILE_DEVICE_CD_ROM: + case FILE_DEVICE_CONTROLLER: + case FILE_DEVICE_DATALINK: + break; + case FILE_DEVICE_DISK_FILE_SYSTEM: + case FILE_DEVICE_CD_ROM_FILE_SYSTEM: + case FILE_DEVICE_NETWORK_FILE_SYSTEM: + result->st_mode = (result->st_mode & ~S_IFMT) | 0x6000; /* _S_IFBLK */ + break; + case FILE_DEVICE_CONSOLE: + case FILE_DEVICE_NULL: + case FILE_DEVICE_KEYBOARD: + case FILE_DEVICE_MODEM: + case FILE_DEVICE_MOUSE: + case FILE_DEVICE_PARALLEL_PORT: + case FILE_DEVICE_PRINTER: + case FILE_DEVICE_SCREEN: + case FILE_DEVICE_SERIAL_PORT: + case FILE_DEVICE_SOUND: + result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFCHR; + break; + case FILE_DEVICE_NAMED_PIPE: + result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFIFO; + break; + default: + if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFDIR; + } + break; + } +} + #endif /* Return information about a file. @@ -1131,6 +1233,8 @@ _Py_fstat_noraise(int fd, struct _Py_stat_struct *status) { #ifdef MS_WINDOWS BY_HANDLE_FILE_INFORMATION info; + FILE_BASIC_INFO basicInfo; + FILE_ID_INFO idInfo; HANDLE h; int type; @@ -1162,14 +1266,16 @@ _Py_fstat_noraise(int fd, struct _Py_stat_struct *status) return 0; } - if (!GetFileInformationByHandle(h, &info)) { + if (!GetFileInformationByHandle(h, &info) || + !GetFileInformationByHandleEx(h, FileBasicInfo, &basicInfo, sizeof(basicInfo)) || + !GetFileInformationByHandleEx(h, FileIdInfo, &idInfo, sizeof(idInfo))) { /* The Win32 error is already set, but we also set errno for callers who expect it */ errno = winerror_to_errno(GetLastError()); return -1; } - _Py_attribute_data_to_stat(&info, 0, status); + _Py_attribute_data_to_stat(&info, 0, &basicInfo, &idInfo, status); return 0; #else return fstat(fd, status); @@ -2233,7 +2339,10 @@ _Py_join_relfile(const wchar_t *dirname, const wchar_t *relfile) } assert(wcslen(dirname) < MAXPATHLEN); assert(wcslen(relfile) < MAXPATHLEN - wcslen(dirname)); - join_relfile(filename, bufsize, dirname, relfile); + if (join_relfile(filename, bufsize, dirname, relfile) < 0) { + PyMem_RawFree(filename); + return NULL; + } return filename; } @@ -2271,6 +2380,7 @@ _Py_find_basename(const wchar_t *filename) wchar_t * _Py_normpath(wchar_t *path, Py_ssize_t size) { + assert(path != NULL); if (!path[0] || size == 0) { return path; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index b1dbb58d956367..34b608fced0402 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,20 +8,24 @@ } TARGET(RESUME) { + #line 89 "Python/bytecodes.c" assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { goto handle_eval_breaker; } + #line 18 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_CLOSURE) { PyObject *value; + #line 97 "Python/bytecodes.c" /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); + #line 29 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -29,9 +33,11 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; + #line 104 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); + #line 41 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -39,9 +45,11 @@ TARGET(LOAD_FAST) { PyObject *value; + #line 110 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 53 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -50,8 +58,10 @@ TARGET(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value; + #line 116 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); + #line 65 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -59,7 +69,9 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; + #line 121 "Python/bytecodes.c" SETLOCAL(oparg, value); + #line 75 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -69,17 +81,21 @@ PyObject *_tmp_2; { PyObject *value; + #line 110 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 89 "Python/generated_cases.c.h" _tmp_2 = value; } oparg = (next_instr++)->op.arg; { PyObject *value; + #line 110 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 99 "Python/generated_cases.c.h" _tmp_1 = value; } STACK_GROW(2); @@ -93,16 +109,20 @@ PyObject *_tmp_2; { PyObject *value; + #line 110 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 117 "Python/generated_cases.c.h" _tmp_2 = value; } oparg = (next_instr++)->op.arg; { PyObject *value; + #line 116 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); + #line 126 "Python/generated_cases.c.h" _tmp_1 = value; } STACK_GROW(2); @@ -115,14 +135,18 @@ PyObject *_tmp_1 = stack_pointer[-1]; { PyObject *value = _tmp_1; + #line 121 "Python/bytecodes.c" SETLOCAL(oparg, value); + #line 141 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value; + #line 110 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 150 "Python/generated_cases.c.h" _tmp_1 = value; } stack_pointer[-1] = _tmp_1; @@ -134,12 +158,16 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; + #line 121 "Python/bytecodes.c" SETLOCAL(oparg, value); + #line 164 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value = _tmp_2; + #line 121 "Python/bytecodes.c" SETLOCAL(oparg, value); + #line 171 "Python/generated_cases.c.h" } STACK_SHRINK(2); DISPATCH(); @@ -150,16 +178,20 @@ PyObject *_tmp_2; { PyObject *value; + #line 116 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); + #line 185 "Python/generated_cases.c.h" _tmp_2 = value; } oparg = (next_instr++)->op.arg; { PyObject *value; + #line 110 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 195 "Python/generated_cases.c.h" _tmp_1 = value; } STACK_GROW(2); @@ -170,6 +202,8 @@ TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; + #line 131 "Python/bytecodes.c" + #line 207 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); DISPATCH(); @@ -177,7 +211,9 @@ TARGET(PUSH_NULL) { PyObject *res; + #line 135 "Python/bytecodes.c" res = NULL; + #line 217 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -188,10 +224,14 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; + #line 131 "Python/bytecodes.c" + #line 229 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; + #line 131 "Python/bytecodes.c" + #line 235 "Python/generated_cases.c.h" Py_DECREF(value); } STACK_SHRINK(2); @@ -201,9 +241,13 @@ TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 141 "Python/bytecodes.c" res = PyNumber_Negative(value); + #line 247 "Python/generated_cases.c.h" Py_DECREF(value); + #line 143 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; + #line 251 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -211,8 +255,11 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 147 "Python/bytecodes.c" int err = PyObject_IsTrue(value); + #line 261 "Python/generated_cases.c.h" Py_DECREF(value); + #line 149 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -221,6 +268,7 @@ res = Py_False; } Py_INCREF(res); + #line 272 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -228,9 +276,13 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 160 "Python/bytecodes.c" res = PyNumber_Invert(value); + #line 282 "Python/generated_cases.c.h" Py_DECREF(value); + #line 162 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; + #line 286 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -239,6 +291,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; + #line 179 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); @@ -247,6 +300,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (prod == NULL) goto pop_2_error; + #line 304 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = prod; next_instr += 1; @@ -257,6 +311,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; + #line 190 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); @@ -264,6 +319,7 @@ double dprod = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dprod, prod); + #line 323 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = prod; next_instr += 1; @@ -274,6 +330,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; + #line 200 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); @@ -282,6 +339,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (sub == NULL) goto pop_2_error; + #line 343 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sub; next_instr += 1; @@ -292,12 +350,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; + #line 211 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsub, sub); + #line 361 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sub; next_instr += 1; @@ -308,6 +368,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 220 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -316,6 +377,7 @@ _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; + #line 381 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -325,6 +387,7 @@ TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 237 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -352,6 +415,7 @@ if (*target_local == NULL) goto pop_2_error; // The STORE_FAST is already done. JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); + #line 419 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -360,6 +424,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; + #line 267 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -367,6 +432,7 @@ double dsum = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum); + #line 436 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sum; next_instr += 1; @@ -377,6 +443,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; + #line 277 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -385,6 +452,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (sum == NULL) goto pop_2_error; + #line 456 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sum; next_instr += 1; @@ -397,6 +465,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; + #line 296 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -409,9 +478,12 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); + #line 482 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); + #line 309 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; + #line 487 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 4; @@ -423,6 +495,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; + #line 313 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -435,6 +508,7 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; + #line 512 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; DISPATCH(); @@ -445,6 +519,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; + #line 328 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -457,6 +532,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; + #line 536 "Python/generated_cases.c.h" STACK_SHRINK(4); DISPATCH(); } @@ -465,6 +541,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; + #line 343 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -480,6 +557,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); + #line 561 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 4; @@ -490,6 +568,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; + #line 361 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -505,6 +584,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); + #line 588 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 4; @@ -515,6 +595,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; + #line 379 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -523,11 +604,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } + #line 608 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); + #line 388 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub + #line 615 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -541,6 +625,7 @@ PyObject *container = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t func_version = read_u16(&next_instr[3].cache); + #line 395 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(tp->tp_version_tag != type_version, BINARY_SUBSCR); assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); @@ -559,12 +644,15 @@ new_frame->localsplus[1] = sub; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); DISPATCH_INLINED(new_frame); + #line 648 "Python/generated_cases.c.h" } TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; + #line 416 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; + #line 656 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -573,9 +661,13 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; + #line 421 "Python/bytecodes.c" int err = PySet_Add(set, v); + #line 667 "Python/generated_cases.c.h" Py_DECREF(v); + #line 423 "Python/bytecodes.c" if (err) goto pop_1_error; + #line 671 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -588,6 +680,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); + #line 434 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); @@ -603,10 +696,13 @@ #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); + #line 700 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); + #line 450 "Python/bytecodes.c" if (err) goto pop_3_error; + #line 706 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -616,6 +712,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; + #line 454 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -633,6 +730,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); + #line 734 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -642,12 +740,14 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; + #line 474 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; + #line 751 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -656,11 +756,15 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; + #line 483 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); + #line 763 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); + #line 486 "Python/bytecodes.c" if (err) goto pop_2_error; + #line 768 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -668,10 +772,14 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 490 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); + #line 779 "Python/generated_cases.c.h" Py_DECREF(value); + #line 493 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; + #line 783 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -680,11 +788,15 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; + #line 497 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); + #line 795 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); + #line 500 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; + #line 800 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -692,6 +804,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); + #line 504 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -709,10 +822,12 @@ break; } if (true) { STACK_SHRINK(oparg); goto error; } + #line 826 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; + #line 524 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -724,10 +839,12 @@ assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; + #line 843 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; + #line 538 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -741,9 +858,11 @@ _PyEvalFrameClearAndPop(tstate, dying); _PyFrame_StackPush(frame, retval); goto resume_frame; + #line 862 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { + #line 554 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -758,11 +877,13 @@ _PyEvalFrameClearAndPop(tstate, dying); _PyFrame_StackPush(frame, retval); goto resume_frame; + #line 881 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; + #line 571 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -775,12 +896,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); + #line 900 "Python/generated_cases.c.h" Py_DECREF(obj); + #line 584 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); + #line 907 "Python/generated_cases.c.h" Py_DECREF(obj); + #line 589 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -793,6 +918,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } + #line 922 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -800,6 +926,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; + #line 604 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -843,6 +970,7 @@ } } + #line 974 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; PREDICT(LOAD_CONST); @@ -853,13 +981,16 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; + #line 651 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } + #line 992 "Python/generated_cases.c.h" Py_DECREF(iterable); + #line 658 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -877,6 +1008,7 @@ if (iter == NULL) goto pop_1_error; + #line 1012 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -887,6 +1019,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; + #line 684 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -922,6 +1055,7 @@ assert(retval != NULL); } Py_DECREF(v); + #line 1059 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -930,6 +1064,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; + #line 722 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -945,10 +1080,12 @@ tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg); DISPATCH_INLINED(gen_frame); + #line 1084 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; + #line 740 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -967,12 +1104,15 @@ frame->prev_instr -= frame->yield_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; + #line 1108 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; + #line 761 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); + #line 1116 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -980,6 +1120,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); + #line 766 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -995,27 +1136,28 @@ } assert(exc && PyExceptionInstance_Check(exc)); Py_INCREF(exc); - PyObject *typ = Py_NewRef(PyExceptionInstance_Class(exc)); - PyObject *tb = PyException_GetTraceback(exc); - _PyErr_Restore(tstate, typ, exc, tb); + _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; + #line 1142 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; + #line 786 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { + #line 1151 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); + #line 789 "Python/bytecodes.c" } else { Py_INCREF(exc); - PyObject *typ = Py_NewRef(PyExceptionInstance_Class(exc)); - PyObject *tb = PyException_GetTraceback(exc); - _PyErr_Restore(tstate, typ, exc, tb); + _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } + #line 1161 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1026,19 +1168,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; + #line 798 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); + #line 1177 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); + #line 803 "Python/bytecodes.c" none = Py_NewRef(Py_None); } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } + #line 1188 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1047,7 +1193,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; + #line 812 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); + #line 1199 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1055,6 +1203,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; + #line 816 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1076,6 +1225,7 @@ if (true) goto error; } } + #line 1229 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1083,26 +1233,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; + #line 840 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); + #line 1244 "Python/generated_cases.c.h" Py_DECREF(v); + #line 847 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); + #line 1253 "Python/generated_cases.c.h" Py_DECREF(v); + #line 854 "Python/bytecodes.c" if (err) goto pop_1_error; + #line 1257 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { + #line 858 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1119,6 +1276,7 @@ name); goto error; } + #line 1280 "Python/generated_cases.c.h" DISPATCH(); } @@ -1126,6 +1284,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; + #line 884 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1139,8 +1298,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); + #line 1302 "Python/generated_cases.c.h" Py_DECREF(seq); + #line 898 "Python/bytecodes.c" if (res == 0) goto pop_1_error; + #line 1306 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1150,12 +1312,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); + #line 902 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); + #line 1323 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1166,6 +1330,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); + #line 912 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1173,6 +1338,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } + #line 1342 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1183,6 +1349,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); + #line 923 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1190,6 +1357,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } + #line 1361 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1199,11 +1367,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; + #line 934 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); + #line 1375 "Python/generated_cases.c.h" Py_DECREF(seq); + #line 938 "Python/bytecodes.c" if (res == 0) goto pop_1_error; + #line 1379 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1214,6 +1386,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); + #line 949 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); @@ -1230,9 +1403,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); + #line 1407 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); + #line 966 "Python/bytecodes.c" if (err) goto pop_2_error; + #line 1412 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1240,25 +1416,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; + #line 970 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); + #line 1423 "Python/generated_cases.c.h" Py_DECREF(owner); + #line 973 "Python/bytecodes.c" if (err) goto pop_1_error; + #line 1427 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; + #line 977 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); + #line 1437 "Python/generated_cases.c.h" Py_DECREF(v); + #line 980 "Python/bytecodes.c" if (err) goto pop_1_error; + #line 1441 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { + #line 984 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1270,11 +1455,13 @@ } goto error; } + #line 1459 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_NAME) { PyObject *v; + #line 998 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { @@ -1333,6 +1520,7 @@ } } } + #line 1524 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = v; DISPATCH(); @@ -1343,6 +1531,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; + #line 1065 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1395,6 +1584,7 @@ } } null = NULL; + #line 1588 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1408,6 +1598,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); + #line 1120 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); @@ -1419,6 +1610,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; + #line 1614 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1433,6 +1625,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); + #line 1134 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); @@ -1447,6 +1640,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; + #line 1644 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1456,13 +1650,16 @@ } TARGET(DELETE_FAST) { + #line 1151 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); + #line 1658 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { + #line 1157 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1471,10 +1668,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); + #line 1672 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { + #line 1168 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1485,11 +1684,13 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); + #line 1688 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_CLASSDEREF) { PyObject *value; + #line 1181 "Python/bytecodes.c" PyObject *name, *locals = LOCALS(); assert(locals); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1521,6 +1722,7 @@ } Py_INCREF(value); } + #line 1726 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1528,6 +1730,7 @@ TARGET(LOAD_DEREF) { PyObject *value; + #line 1215 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1535,6 +1738,7 @@ if (true) goto error; } Py_INCREF(value); + #line 1742 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1542,15 +1746,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; + #line 1225 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); + #line 1755 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { + #line 1232 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -1561,17 +1768,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } + #line 1772 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; + #line 1245 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); + #line 1781 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } + #line 1247 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } + #line 1787 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1581,8 +1793,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; + #line 1251 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } + #line 1800 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1592,8 +1806,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; + #line 1256 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } + #line 1813 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1603,6 +1819,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; + #line 1261 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1613,10 +1830,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } + #line 1834 "Python/generated_cases.c.h" Py_DECREF(iterable); + #line 1272 "Python/bytecodes.c" if (true) goto pop_1_error; } Py_DECREF(none_val); + #line 1840 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -1625,9 +1845,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; + #line 1279 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); + #line 1851 "Python/generated_cases.c.h" Py_DECREF(iterable); + #line 1281 "Python/bytecodes.c" if (err < 0) goto pop_1_error; + #line 1855 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1635,6 +1859,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; + #line 1285 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1649,6 +1874,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } + #line 1878 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -1658,6 +1884,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; + #line 1302 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1665,10 +1892,13 @@ if (map == NULL) goto error; + #line 1896 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } + #line 1310 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } + #line 1902 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1676,6 +1906,7 @@ } TARGET(SETUP_ANNOTATIONS) { + #line 1314 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1715,6 +1946,7 @@ Py_DECREF(ann_dict); } } + #line 1950 "Python/generated_cases.c.h" DISPATCH(); } @@ -1722,6 +1954,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; + #line 1356 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1731,11 +1964,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); + #line 1968 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); + #line 1366 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } + #line 1975 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -1743,6 +1979,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; + #line 1370 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1750,9 +1987,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } + #line 1991 "Python/generated_cases.c.h" Py_DECREF(update); + #line 1378 "Python/bytecodes.c" if (true) goto pop_1_error; } + #line 1996 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -1760,13 +2000,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; + #line 1384 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); + #line 2009 "Python/generated_cases.c.h" Py_DECREF(update); + #line 1389 "Python/bytecodes.c" if (true) goto pop_1_error; } + #line 2014 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -1776,11 +2020,13 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; + #line 1396 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; + #line 2030 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -1792,6 +2038,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; + #line 1419 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1826,7 +2073,9 @@ NULL | meth | arg1 | ... | argN */ + #line 2077 "Python/generated_cases.c.h" Py_DECREF(owner); + #line 1454 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -1835,9 +2084,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); + #line 2088 "Python/generated_cases.c.h" Py_DECREF(owner); + #line 1463 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } + #line 2093 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -1851,6 +2103,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); + #line 1468 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -1864,6 +2117,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; + #line 2121 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1878,6 +2132,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); + #line 1485 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; @@ -1891,6 +2146,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; + #line 2150 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1905,6 +2161,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); + #line 1502 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -1932,6 +2189,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; + #line 2193 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1946,6 +2204,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); + #line 1533 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -1956,6 +2215,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; + #line 2219 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1970,6 +2230,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); + #line 1547 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); @@ -1982,6 +2243,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); + #line 2247 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1995,6 +2257,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); + #line 1563 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); @@ -2018,6 +2281,7 @@ new_frame->localsplus[0] = owner; JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH_INLINED(new_frame); + #line 2285 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2025,6 +2289,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); + #line 1589 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2050,6 +2315,7 @@ new_frame->localsplus[1] = Py_NewRef(name); JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH_INLINED(new_frame); + #line 2319 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2057,6 +2323,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); + #line 1617 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2075,6 +2342,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); + #line 2346 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2085,6 +2353,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); + #line 1638 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2124,6 +2393,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); + #line 2397 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2134,6 +2404,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); + #line 1680 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2144,6 +2415,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); + #line 2419 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2153,12 +2425,16 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 1693 "Python/bytecodes.c" STAT_INC(COMPARE_OP, deferred); assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); + #line 2433 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); + #line 1697 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; + #line 2438 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2169,6 +2445,7 @@ PREDICTED(COMPARE_AND_BRANCH); PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 1709 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2182,8 +2459,10 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); + #line 2463 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); + #line 1723 "Python/bytecodes.c" if (cond == NULL) goto pop_2_error; assert(next_instr[1].op.code == POP_JUMP_IF_FALSE || next_instr[1].op.code == POP_JUMP_IF_TRUE); @@ -2195,6 +2474,7 @@ if (jump_on_true == (err != 0)) { JUMPBY(offset); } + #line 2478 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2203,6 +2483,7 @@ TARGET(COMPARE_AND_BRANCH_FLOAT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 1737 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); @@ -2217,6 +2498,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } + #line 2502 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2225,6 +2507,7 @@ TARGET(COMPARE_AND_BRANCH_INT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 1755 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); @@ -2242,6 +2525,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } + #line 2529 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2250,6 +2534,7 @@ TARGET(COMPARE_AND_BRANCH_STR) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 1776 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); @@ -2265,6 +2550,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } + #line 2554 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2274,10 +2560,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; + #line 1794 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; + #line 2566 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); + #line 1796 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); + #line 2571 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2287,11 +2577,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; + #line 1800 "Python/bytecodes.c" int res = PySequence_Contains(right, left); + #line 2583 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); + #line 1802 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); + #line 2589 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2302,9 +2596,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; + #line 1807 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { + #line 2602 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); + #line 1809 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2312,8 +2609,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); + #line 2613 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); + #line 1817 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2322,6 +2621,7 @@ if (!Py_IsNone(match)) { PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL); } + #line 2625 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2331,15 +2631,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; + #line 1828 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { + #line 2638 "Python/generated_cases.c.h" Py_DECREF(right); + #line 1831 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); + #line 2645 "Python/generated_cases.c.h" Py_DECREF(right); + #line 1836 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); + #line 2649 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2348,11 +2654,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; + #line 1840 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); + #line 2661 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); + #line 1843 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; + #line 2666 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2361,23 +2671,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; + #line 1847 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; + #line 2679 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { + #line 1853 "Python/bytecodes.c" JUMPBY(oparg); + #line 2688 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); + #line 1857 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); + #line 2697 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2385,6 +2701,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; + #line 1863 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2394,7 +2711,9 @@ } else { int err = PyObject_IsTrue(cond); + #line 2715 "Python/generated_cases.c.h" Py_DECREF(cond); + #line 1873 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2402,12 +2721,14 @@ if (err < 0) goto pop_1_error; } } + #line 2725 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; + #line 1883 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2417,7 +2738,9 @@ } else { int err = PyObject_IsTrue(cond); + #line 2742 "Python/generated_cases.c.h" Py_DECREF(cond); + #line 1893 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2425,38 +2748,48 @@ if (err < 0) goto pop_1_error; } } + #line 2752 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; + #line 1903 "Python/bytecodes.c" if (!Py_IsNone(value)) { + #line 2761 "Python/generated_cases.c.h" Py_DECREF(value); + #line 1905 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } + #line 2769 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; + #line 1913 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { + #line 2782 "Python/generated_cases.c.h" Py_DECREF(value); + #line 1919 "Python/bytecodes.c" } + #line 2786 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_IF_FALSE_OR_POP) { PyObject *cond = stack_pointer[-1]; + #line 1923 "Python/bytecodes.c" bool jump = false; int err; if (Py_IsTrue(cond)) { @@ -2479,6 +2812,7 @@ goto error; } } + #line 2816 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW((jump ? 1 : 0)); DISPATCH(); @@ -2486,6 +2820,7 @@ TARGET(JUMP_IF_TRUE_OR_POP) { PyObject *cond = stack_pointer[-1]; + #line 1948 "Python/bytecodes.c" bool jump = false; int err; if (Py_IsFalse(cond)) { @@ -2508,29 +2843,34 @@ goto error; } } + #line 2847 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW((jump ? 1 : 0)); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { + #line 1973 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); + #line 2861 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; + #line 1982 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; + #line 2874 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -2541,13 +2881,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; + #line 1990 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); + #line 2890 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); + #line 1995 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -2555,6 +2898,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } + #line 2902 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -2563,8 +2907,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; + #line 2005 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); + #line 2914 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2574,8 +2920,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; + #line 2011 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); + #line 2927 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2586,9 +2934,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; + #line 2017 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; + #line 2942 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -2597,10 +2947,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; + #line 2023 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); + #line 2954 "Python/generated_cases.c.h" Py_DECREF(iterable); + #line 2026 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; + #line 2958 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -2608,6 +2962,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; + #line 2030 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2630,8 +2985,11 @@ if (iter == NULL) { goto error; } + #line 2989 "Python/generated_cases.c.h" Py_DECREF(iterable); + #line 2053 "Python/bytecodes.c" } + #line 2993 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -2642,6 +3000,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; + #line 2072 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2674,6 +3033,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator + #line 3037 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -2683,6 +3043,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; + #line 2107 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; @@ -2703,6 +3064,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator + #line 3068 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -2712,6 +3074,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; + #line 2130 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); @@ -2732,6 +3095,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator + #line 3099 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -2741,6 +3105,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; + #line 2153 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); @@ -2759,6 +3124,7 @@ if (next == NULL) { goto error; } + #line 3128 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -2767,6 +3133,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; + #line 2174 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -2781,12 +3148,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); assert(next_instr->op.code == END_FOR); DISPATCH_INLINED(gen_frame); + #line 3152 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; + #line 2191 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -2809,13 +3178,16 @@ Py_DECREF(enter); goto error; } + #line 3182 "Python/generated_cases.c.h" Py_DECREF(mgr); + #line 2214 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } + #line 3191 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -2827,6 +3199,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; + #line 2224 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -2852,13 +3225,16 @@ Py_DECREF(enter); goto error; } + #line 3229 "Python/generated_cases.c.h" Py_DECREF(mgr); + #line 2250 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } + #line 3238 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -2870,6 +3246,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; + #line 2259 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -2890,6 +3267,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; + #line 3271 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -2898,6 +3276,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; + #line 2282 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -2907,6 +3286,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); + #line 3290 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -2920,6 +3300,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); + #line 2294 "Python/bytecodes.c" /* Cached method object */ assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); @@ -2937,6 +3318,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); + #line 3322 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2950,6 +3332,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); + #line 2314 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2960,6 +3343,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); + #line 3347 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2973,6 +3357,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); + #line 2327 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2987,6 +3372,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); + #line 3376 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2995,9 +3381,11 @@ } TARGET(KW_NAMES) { + #line 2344 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); + #line 3389 "Python/generated_cases.c.h" DISPATCH(); } @@ -3008,6 +3396,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2380 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3079,6 +3468,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3472 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3090,6 +3480,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; + #line 2458 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3099,6 +3490,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); + #line 3494 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3107,6 +3499,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); + #line 2470 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3131,6 +3524,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); + #line 3528 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3139,6 +3533,7 @@ PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); uint16_t min_args = read_u16(&next_instr[3].cache); + #line 2497 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3168,6 +3563,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); + #line 3567 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3175,6 +3571,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2529 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3185,6 +3582,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable + #line 3586 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3197,6 +3595,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2542 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3208,6 +3607,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3611 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3221,6 +3621,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2557 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3231,6 +3632,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3636 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3244,6 +3646,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2571 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3265,6 +3668,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3672 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3278,6 +3682,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2596 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_O functions */ assert(kwnames == NULL); @@ -3306,6 +3711,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3715 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3319,6 +3725,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2628 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); @@ -3351,6 +3758,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ + #line 3762 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3364,6 +3772,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2664 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; @@ -3396,6 +3805,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3809 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3409,6 +3819,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2700 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* len(o) */ @@ -3434,6 +3845,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3849 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3446,6 +3858,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2728 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* isinstance(o, o2) */ @@ -3473,6 +3886,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3890 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3484,6 +3898,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; + #line 2759 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); assert(oparg == 1); @@ -3502,12 +3917,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); + #line 3921 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2780 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3538,6 +3955,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3959 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3550,6 +3968,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2814 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3578,6 +3997,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 4001 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3590,6 +4010,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2846 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -3618,6 +4039,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 4043 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3630,6 +4052,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2878 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3657,6 +4080,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 4084 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3671,6 +4095,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; + #line 2909 "Python/bytecodes.c" if (oparg & 1) { // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. @@ -3689,12 +4114,15 @@ assert(PyTuple_CheckExact(callargs)); result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); + #line 4118 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); + #line 2928 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } + #line 4126 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -3709,6 +4137,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; + #line 2939 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -3737,12 +4166,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; + #line 4170 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { + #line 2970 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -3763,6 +4194,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; + #line 4198 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -3770,11 +4202,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; + #line 2993 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); + #line 4208 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); + #line 2995 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } + #line 4214 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -3785,6 +4221,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; + #line 2999 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -3815,21 +4252,11 @@ value = result; } - /* If value is a unicode object, and there's no fmt_spec, - then we know the result of format(value) is value - itself. In that case, skip calling format(). I plan to - move this optimization in to PyObject_Format() - itself. */ - if (PyUnicode_CheckExact(value) && fmt_spec == NULL) { - /* Do nothing, just transfer ownership to result. */ - result = value; - } else { - /* Actually call format(). */ - result = PyObject_Format(value, fmt_spec); - Py_DECREF(value); - Py_XDECREF(fmt_spec); - if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - } + result = PyObject_Format(value, fmt_spec); + Py_DECREF(value); + Py_XDECREF(fmt_spec); + if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } + #line 4260 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -3838,8 +4265,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; + #line 3036 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); + #line 4272 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -3851,6 +4280,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; + #line 3041 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3866,9 +4296,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); + #line 4300 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); + #line 3057 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; + #line 4305 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -3878,21 +4311,27 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; + #line 3062 "Python/bytecodes.c" assert(oparg >= 2); + #line 4317 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(EXTENDED_ARG) { + #line 3066 "Python/bytecodes.c" assert(oparg); assert(cframe.use_tracing == 0); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); + #line 4331 "Python/generated_cases.c.h" } TARGET(CACHE) { + #line 3075 "Python/bytecodes.c" Py_UNREACHABLE(); + #line 4337 "Python/generated_cases.c.h" } diff --git a/Python/import.c b/Python/import.c index 1bf4199e125aa5..c68bd1f7db420d 100644 --- a/Python/import.c +++ b/Python/import.c @@ -389,8 +389,7 @@ PyImport_AddModule(const char *name) static void remove_module(PyThreadState *tstate, PyObject *name) { - PyObject *type, *value, *traceback; - _PyErr_Fetch(tstate, &type, &value, &traceback); + PyObject *exc = _PyErr_GetRaisedException(tstate); PyObject *modules = MODULES(tstate->interp); if (PyDict_CheckExact(modules)) { @@ -403,7 +402,7 @@ remove_module(PyThreadState *tstate, PyObject *name) } } - _PyErr_ChainExceptions(type, value, traceback); + _PyErr_ChainExceptions1(exc); } @@ -978,6 +977,31 @@ _PyImport_CheckSubinterpIncompatibleExtensionAllowed(const char *name) return 0; } +static PyObject * +get_core_module_dict(PyInterpreterState *interp, + PyObject *name, PyObject *filename) +{ + /* Only builtin modules are core. */ + if (filename == name) { + assert(!PyErr_Occurred()); + if (PyUnicode_CompareWithASCIIString(name, "sys") == 0) { + return interp->sysdict_copy; + } + assert(!PyErr_Occurred()); + if (PyUnicode_CompareWithASCIIString(name, "builtins") == 0) { + return interp->builtins_copy; + } + assert(!PyErr_Occurred()); + } + return NULL; +} + +static inline int +is_core_module(PyInterpreterState *interp, PyObject *name, PyObject *filename) +{ + return get_core_module_dict(interp, name, filename) != NULL; +} + static int fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) { @@ -999,9 +1023,8 @@ fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) // bpo-44050: Extensions and def->m_base.m_copy can be updated // when the extension module doesn't support sub-interpreters. - // XXX Why special-case the main interpreter? - if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) { - if (def->m_size == -1) { + if (def->m_size == -1) { + if (!is_core_module(tstate->interp, name, filename)) { if (def->m_base.m_copy) { /* Somebody already imported the module, likely under a different name. @@ -1017,7 +1040,10 @@ fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) return -1; } } + } + // XXX Why special-case the main interpreter? + if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) { if (_extensions_cache_set(filename, name, def) < 0) { return -1; } @@ -1055,18 +1081,24 @@ import_find_extension(PyThreadState *tstate, PyObject *name, PyObject *modules = MODULES(tstate->interp); if (def->m_size == -1) { + PyObject *m_copy = def->m_base.m_copy; /* Module does not support repeated initialization */ - if (def->m_base.m_copy == NULL) - return NULL; + if (m_copy == NULL) { + m_copy = get_core_module_dict(tstate->interp, name, filename); + if (m_copy == NULL) { + return NULL; + } + } mod = import_add_module(tstate, name); - if (mod == NULL) + if (mod == NULL) { return NULL; + } mdict = PyModule_GetDict(mod); if (mdict == NULL) { Py_DECREF(mod); return NULL; } - if (PyDict_Update(mdict, def->m_base.m_copy)) { + if (PyDict_Update(mdict, m_copy)) { Py_DECREF(mod); return NULL; } @@ -2291,32 +2323,34 @@ remove_importlib_frames(PyThreadState *tstate) const char *remove_frames = "_call_with_frames_removed"; int always_trim = 0; int in_importlib = 0; - PyObject *exception, *value, *base_tb, *tb; PyObject **prev_link, **outer_link = NULL; + PyObject *base_tb = NULL; /* Synopsis: if it's an ImportError, we trim all importlib chunks from the traceback. We always trim chunks which end with a call to "_call_with_frames_removed". */ - _PyErr_Fetch(tstate, &exception, &value, &base_tb); - if (!exception || _PyInterpreterState_GetConfig(tstate->interp)->verbose) { + PyObject *exc = _PyErr_GetRaisedException(tstate); + if (exc == NULL || _PyInterpreterState_GetConfig(tstate->interp)->verbose) { goto done; } - if (PyType_IsSubtype((PyTypeObject *) exception, - (PyTypeObject *) PyExc_ImportError)) + if (PyType_IsSubtype(Py_TYPE(exc), (PyTypeObject *) PyExc_ImportError)) { always_trim = 1; + } + assert(PyExceptionInstance_Check(exc)); + base_tb = PyException_GetTraceback(exc); prev_link = &base_tb; - tb = base_tb; + PyObject *tb = base_tb; while (tb != NULL) { + assert(PyTraceBack_Check(tb)); PyTracebackObject *traceback = (PyTracebackObject *)tb; PyObject *next = (PyObject *) traceback->tb_next; PyFrameObject *frame = traceback->tb_frame; PyCodeObject *code = PyFrame_GetCode(frame); int now_in_importlib; - assert(PyTraceBack_Check(tb)); now_in_importlib = _PyUnicode_EqualToASCIIString(code->co_filename, importlib_filename) || _PyUnicode_EqualToASCIIString(code->co_filename, external_filename); if (now_in_importlib && !in_importlib) { @@ -2337,15 +2371,14 @@ remove_importlib_frames(PyThreadState *tstate) Py_DECREF(code); tb = next; } - assert(PyExceptionInstance_Check(value)); - assert((PyObject *)Py_TYPE(value) == exception); if (base_tb == NULL) { base_tb = Py_None; Py_INCREF(Py_None); } - PyException_SetTraceback(value, base_tb); + PyException_SetTraceback(exc, base_tb); done: - _PyErr_Restore(tstate, exception, value, base_tb); + Py_XDECREF(base_tb); + _PyErr_SetRaisedException(tstate, exc); } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 93f3c76c5b8240..ee760ab78af217 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -707,12 +707,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { } #endif -enum Direction { DIR_NONE, DIR_READ, DIR_WRITE }; enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; struct opcode_metadata { - enum Direction dir_op1; - enum Direction dir_op2; - enum Direction dir_op3; bool valid_entry; enum InstructionFormat instr_format; }; @@ -721,175 +717,175 @@ struct opcode_metadata { extern const struct opcode_metadata _PyOpcode_opcode_metadata[256]; #else const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { - [NOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RESUME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_CLOSURE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [LOAD_FAST__LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [STORE_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [STORE_FAST__STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [LOAD_CONST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [POP_TOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [PUSH_NULL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [END_FOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNARY_NEGATIVE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [UNARY_NOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [UNARY_INVERT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_OP_MULTIPLY_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_MULTIPLY_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_SUBTRACT_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_SUBTRACT_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_INPLACE_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_OP_ADD_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_ADD_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [STORE_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_SUBSCR_LIST_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_TUPLE_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_GETITEM] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [LIST_APPEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SET_ADD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [STORE_SUBSCR_LIST_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [STORE_SUBSCR_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [DELETE_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CALL_INTRINSIC_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_INTRINSIC_2] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [RAISE_VARARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [INTERPRETER_EXIT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RETURN_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RETURN_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [GET_AITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_ANEXT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_AWAITABLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [SEND_GEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [YIELD_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [POP_EXCEPT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RERAISE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [END_ASYNC_FOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CLEANUP_THROW] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_ASSERTION_ERROR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_BUILD_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [STORE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNPACK_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [UNPACK_SEQUENCE_TWO_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [UNPACK_SEQUENCE_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [UNPACK_SEQUENCE_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [UNPACK_EX] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [DELETE_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [LOAD_GLOBAL_MODULE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [LOAD_GLOBAL_BUILTIN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [DELETE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MAKE_CELL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_CLASSDEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [COPY_FREE_VARS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_STRING] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LIST_EXTEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SET_UPDATE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_SET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_MAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SETUP_ANNOTATIONS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BUILD_CONST_KEY_MAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DICT_UPDATE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DICT_MERGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MAP_ADD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_INSTANCE_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_MODULE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_WITH_HINT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_SLOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_PROPERTY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [STORE_ATTR_INSTANCE_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [STORE_ATTR_WITH_HINT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [STORE_ATTR_SLOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [COMPARE_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [COMPARE_AND_BRANCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_STR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [IS_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CONTAINS_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CHECK_EG_MATCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CHECK_EXC_MATCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [IMPORT_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [IMPORT_FROM] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_FORWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_BACKWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_FALSE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_TRUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_NOT_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_IF_FALSE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_IF_TRUE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_BACKWARD_NO_INTERRUPT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [GET_LEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [MATCH_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MATCH_MAPPING] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [MATCH_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [MATCH_KEYS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_YIELD_FROM_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [FOR_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [FOR_ITER_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [FOR_ITER_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [FOR_ITER_RANGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [FOR_ITER_GEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [BEFORE_ASYNC_WITH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BEFORE_WITH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [WITH_EXCEPT_START] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [PUSH_EXC_INFO] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_ATTR_METHOD_WITH_VALUES] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_METHOD_NO_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_METHOD_LAZY_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [KW_NAMES] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_BOUND_METHOD_EXACT_ARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_PY_EXACT_ARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_PY_WITH_DEFAULTS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_TYPE_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_STR_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_TUPLE_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_BUILTIN_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_BUILTIN_O] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_BUILTIN_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_LEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_ISINSTANCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_LIST_APPEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_FUNCTION_EX] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MAKE_FUNCTION] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [RETURN_GENERATOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BUILD_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [FORMAT_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [COPY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BINARY_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [SWAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [EXTENDED_ARG] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CACHE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [NOP] = { true, INSTR_FMT_IX }, + [RESUME] = { true, INSTR_FMT_IB }, + [LOAD_CLOSURE] = { true, INSTR_FMT_IB }, + [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB }, + [LOAD_FAST] = { true, INSTR_FMT_IB }, + [LOAD_CONST] = { true, INSTR_FMT_IB }, + [STORE_FAST] = { true, INSTR_FMT_IB }, + [LOAD_FAST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, + [LOAD_FAST__LOAD_CONST] = { true, INSTR_FMT_IBIB }, + [STORE_FAST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, + [STORE_FAST__STORE_FAST] = { true, INSTR_FMT_IBIB }, + [LOAD_CONST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, + [POP_TOP] = { true, INSTR_FMT_IX }, + [PUSH_NULL] = { true, INSTR_FMT_IX }, + [END_FOR] = { true, INSTR_FMT_IB }, + [UNARY_NEGATIVE] = { true, INSTR_FMT_IX }, + [UNARY_NOT] = { true, INSTR_FMT_IX }, + [UNARY_INVERT] = { true, INSTR_FMT_IX }, + [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC }, + [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IX }, + [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC }, + [BINARY_SUBSCR] = { true, INSTR_FMT_IXC000 }, + [BINARY_SLICE] = { true, INSTR_FMT_IX }, + [STORE_SLICE] = { true, INSTR_FMT_IX }, + [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC000 }, + [LIST_APPEND] = { true, INSTR_FMT_IB }, + [SET_ADD] = { true, INSTR_FMT_IB }, + [STORE_SUBSCR] = { true, INSTR_FMT_IXC }, + [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC }, + [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC }, + [DELETE_SUBSCR] = { true, INSTR_FMT_IX }, + [CALL_INTRINSIC_1] = { true, INSTR_FMT_IB }, + [CALL_INTRINSIC_2] = { true, INSTR_FMT_IB }, + [RAISE_VARARGS] = { true, INSTR_FMT_IB }, + [INTERPRETER_EXIT] = { true, INSTR_FMT_IX }, + [RETURN_VALUE] = { true, INSTR_FMT_IX }, + [RETURN_CONST] = { true, INSTR_FMT_IB }, + [GET_AITER] = { true, INSTR_FMT_IX }, + [GET_ANEXT] = { true, INSTR_FMT_IX }, + [GET_AWAITABLE] = { true, INSTR_FMT_IB }, + [SEND] = { true, INSTR_FMT_IBC }, + [SEND_GEN] = { true, INSTR_FMT_IBC }, + [YIELD_VALUE] = { true, INSTR_FMT_IX }, + [POP_EXCEPT] = { true, INSTR_FMT_IX }, + [RERAISE] = { true, INSTR_FMT_IB }, + [END_ASYNC_FOR] = { true, INSTR_FMT_IX }, + [CLEANUP_THROW] = { true, INSTR_FMT_IX }, + [LOAD_ASSERTION_ERROR] = { true, INSTR_FMT_IX }, + [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX }, + [STORE_NAME] = { true, INSTR_FMT_IB }, + [DELETE_NAME] = { true, INSTR_FMT_IB }, + [UNPACK_SEQUENCE] = { true, INSTR_FMT_IBC }, + [UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC }, + [UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC }, + [UNPACK_SEQUENCE_LIST] = { true, INSTR_FMT_IBC }, + [UNPACK_EX] = { true, INSTR_FMT_IB }, + [STORE_ATTR] = { true, INSTR_FMT_IBC000 }, + [DELETE_ATTR] = { true, INSTR_FMT_IB }, + [STORE_GLOBAL] = { true, INSTR_FMT_IB }, + [DELETE_GLOBAL] = { true, INSTR_FMT_IB }, + [LOAD_NAME] = { true, INSTR_FMT_IB }, + [LOAD_GLOBAL] = { true, INSTR_FMT_IBC000 }, + [LOAD_GLOBAL_MODULE] = { true, INSTR_FMT_IBC000 }, + [LOAD_GLOBAL_BUILTIN] = { true, INSTR_FMT_IBC000 }, + [DELETE_FAST] = { true, INSTR_FMT_IB }, + [MAKE_CELL] = { true, INSTR_FMT_IB }, + [DELETE_DEREF] = { true, INSTR_FMT_IB }, + [LOAD_CLASSDEREF] = { true, INSTR_FMT_IB }, + [LOAD_DEREF] = { true, INSTR_FMT_IB }, + [STORE_DEREF] = { true, INSTR_FMT_IB }, + [COPY_FREE_VARS] = { true, INSTR_FMT_IB }, + [BUILD_STRING] = { true, INSTR_FMT_IB }, + [BUILD_TUPLE] = { true, INSTR_FMT_IB }, + [BUILD_LIST] = { true, INSTR_FMT_IB }, + [LIST_EXTEND] = { true, INSTR_FMT_IB }, + [SET_UPDATE] = { true, INSTR_FMT_IB }, + [BUILD_SET] = { true, INSTR_FMT_IB }, + [BUILD_MAP] = { true, INSTR_FMT_IB }, + [SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX }, + [BUILD_CONST_KEY_MAP] = { true, INSTR_FMT_IB }, + [DICT_UPDATE] = { true, INSTR_FMT_IB }, + [DICT_MERGE] = { true, INSTR_FMT_IB }, + [MAP_ADD] = { true, INSTR_FMT_IB }, + [LOAD_ATTR] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000 }, + [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000 }, + [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000 }, + [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000 }, + [COMPARE_OP] = { true, INSTR_FMT_IBC }, + [COMPARE_AND_BRANCH] = { true, INSTR_FMT_IBC0 }, + [COMPARE_AND_BRANCH_FLOAT] = { true, INSTR_FMT_IBC0 }, + [COMPARE_AND_BRANCH_INT] = { true, INSTR_FMT_IBC0 }, + [COMPARE_AND_BRANCH_STR] = { true, INSTR_FMT_IBC0 }, + [IS_OP] = { true, INSTR_FMT_IB }, + [CONTAINS_OP] = { true, INSTR_FMT_IB }, + [CHECK_EG_MATCH] = { true, INSTR_FMT_IX }, + [CHECK_EXC_MATCH] = { true, INSTR_FMT_IX }, + [IMPORT_NAME] = { true, INSTR_FMT_IB }, + [IMPORT_FROM] = { true, INSTR_FMT_IB }, + [JUMP_FORWARD] = { true, INSTR_FMT_IB }, + [JUMP_BACKWARD] = { true, INSTR_FMT_IB }, + [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB }, + [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB }, + [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB }, + [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB }, + [JUMP_IF_FALSE_OR_POP] = { true, INSTR_FMT_IB }, + [JUMP_IF_TRUE_OR_POP] = { true, INSTR_FMT_IB }, + [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB }, + [GET_LEN] = { true, INSTR_FMT_IX }, + [MATCH_CLASS] = { true, INSTR_FMT_IB }, + [MATCH_MAPPING] = { true, INSTR_FMT_IX }, + [MATCH_SEQUENCE] = { true, INSTR_FMT_IX }, + [MATCH_KEYS] = { true, INSTR_FMT_IX }, + [GET_ITER] = { true, INSTR_FMT_IX }, + [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX }, + [FOR_ITER] = { true, INSTR_FMT_IBC }, + [FOR_ITER_LIST] = { true, INSTR_FMT_IBC }, + [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC }, + [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC }, + [FOR_ITER_GEN] = { true, INSTR_FMT_IBC }, + [BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX }, + [BEFORE_WITH] = { true, INSTR_FMT_IX }, + [WITH_EXCEPT_START] = { true, INSTR_FMT_IX }, + [PUSH_EXC_INFO] = { true, INSTR_FMT_IX }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000 }, + [KW_NAMES] = { true, INSTR_FMT_IB }, + [CALL] = { true, INSTR_FMT_IBC000 }, + [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC000 }, + [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC000 }, + [CALL_PY_WITH_DEFAULTS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_TYPE_1] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_STR_1] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_TUPLE_1] = { true, INSTR_FMT_IBC000 }, + [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_BUILTIN_O] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_BUILTIN_FAST] = { true, INSTR_FMT_IBC000 }, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_LEN] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_ISINSTANCE] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_LIST_APPEND] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC000 }, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC000 }, + [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB }, + [MAKE_FUNCTION] = { true, INSTR_FMT_IB }, + [RETURN_GENERATOR] = { true, INSTR_FMT_IX }, + [BUILD_SLICE] = { true, INSTR_FMT_IB }, + [FORMAT_VALUE] = { true, INSTR_FMT_IB }, + [COPY] = { true, INSTR_FMT_IB }, + [BINARY_OP] = { true, INSTR_FMT_IBC }, + [SWAP] = { true, INSTR_FMT_IB }, + [EXTENDED_ARG] = { true, INSTR_FMT_IB }, + [CACHE] = { true, INSTR_FMT_IX }, }; #endif diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 82e94090a6027a..8110d94ba17526 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -31,7 +31,8 @@ #include "pycore_unicodeobject.h" // _PyUnicode_InitTypes() #include "opcode.h" -extern void _PyIO_Fini(void); +extern PyStatus _PyIO_InitTypes(PyInterpreterState *interp); +extern void _PyIO_FiniTypes(PyInterpreterState *interp); #include // setlocale() #include // getenv() @@ -697,6 +698,11 @@ pycore_init_types(PyInterpreterState *interp) return _PyStatus_ERR("failed to initialize an exception type"); } + status = _PyIO_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + status = _PyExc_InitGlobalObjects(interp); if (_PyStatus_EXCEPTION(status)) { return status; @@ -802,6 +808,11 @@ pycore_interp_init(PyThreadState *tstate) PyStatus status; PyObject *sysmod = NULL; + // This is a temporary fix until we have immortal objects. + // (See _PyType_InitCache() in typeobject.c.) + extern void _PyType_FixCacheRefcounts(void); + _PyType_FixCacheRefcounts(); + // Create singletons before the first PyType_Ready() call, since // PyType_Ready() uses singletons like the Unicode empty string (tp_doc) // and the empty tuple singletons (tp_bases). @@ -1304,7 +1315,7 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose) { // List of names to clear in sys static const char * const sys_deletes[] = { - "path", "argv", "ps1", "ps2", + "path", "argv", "ps1", "ps2", "last_exc", "last_type", "last_value", "last_traceback", "__interactivehook__", // path_hooks and path_importer_cache are cleared @@ -1695,9 +1706,7 @@ finalize_interp_clear(PyThreadState *tstate) /* Clear interpreter state and all thread states */ _PyInterpreterState_Clear(tstate); - if (is_main_interp) { - _PyIO_Fini(); - } + _PyIO_FiniTypes(tstate->interp); /* Clear all loghooks */ /* Both _PySys_Audit function and users still need PyObject, such as tuple. @@ -1930,6 +1939,7 @@ Py_FinalizeEx(void) if (show_ref_count) { _PyDebug_PrintTotalRefs(); } + _Py_FinalizeRefTotal(runtime); #endif #ifdef Py_TRACE_REFS @@ -2056,30 +2066,31 @@ new_interpreter(PyThreadState **tstate_p, const _PyInterpreterConfig *config) /* Oops, it didn't work. Undo it all. */ PyErr_PrintEx(0); + PyThreadState_Swap(save_tstate); PyThreadState_Clear(tstate); PyThreadState_Delete(tstate); PyInterpreterState_Delete(interp); - PyThreadState_Swap(save_tstate); return status; } -PyThreadState * -_Py_NewInterpreterFromConfig(const _PyInterpreterConfig *config) +PyStatus +_Py_NewInterpreterFromConfig(PyThreadState **tstate_p, + const _PyInterpreterConfig *config) { - PyThreadState *tstate = NULL; - PyStatus status = new_interpreter(&tstate, config); - if (_PyStatus_EXCEPTION(status)) { - Py_ExitStatusException(status); - } - return tstate; + return new_interpreter(tstate_p, config); } PyThreadState * Py_NewInterpreter(void) { + PyThreadState *tstate = NULL; const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; - return _Py_NewInterpreterFromConfig(&config); + PyStatus status = _Py_NewInterpreterFromConfig(&tstate, &config); + if (_PyStatus_EXCEPTION(status)) { + Py_ExitStatusException(status); + } + return tstate; } /* Delete an interpreter and its last thread. This requires that the @@ -2537,41 +2548,29 @@ _Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp, static int _Py_FatalError_PrintExc(PyThreadState *tstate) { - PyObject *ferr, *res; - PyObject *exception, *v, *tb; - int has_tb; - - _PyErr_Fetch(tstate, &exception, &v, &tb); - if (exception == NULL) { + PyObject *exc = _PyErr_GetRaisedException(tstate); + if (exc == NULL) { /* No current exception */ return 0; } - ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); + PyObject *ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); if (ferr == NULL || ferr == Py_None) { /* sys.stderr is not set yet or set to None, no need to try to display the exception */ + Py_DECREF(exc); return 0; } - _PyErr_NormalizeException(tstate, &exception, &v, &tb); - if (tb == NULL) { - tb = Py_NewRef(Py_None); - } - PyException_SetTraceback(v, tb); - if (exception == NULL) { - /* PyErr_NormalizeException() failed */ - return 0; - } + PyErr_DisplayException(exc); - has_tb = (tb != Py_None); - PyErr_Display(exception, v, tb); - Py_XDECREF(exception); - Py_XDECREF(v); + PyObject *tb = PyException_GetTraceback(exc); + int has_tb = (tb != NULL) && (tb != Py_None); Py_XDECREF(tb); + Py_DECREF(exc); /* sys.stderr may be buffered: call sys.stderr.flush() */ - res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush)); + PyObject *res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush)); if (res == NULL) { _PyErr_Clear(tstate); } diff --git a/Python/pystate.c b/Python/pystate.c index 28606e4f32f71c..b17efdbefd124c 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -482,6 +482,11 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) void _PyRuntimeState_Fini(_PyRuntimeState *runtime) { +#ifdef Py_REF_DEBUG + /* The count is cleared by _Py_FinalizeRefTotal(). */ + assert(runtime->object_state.interpreter_leaks == 0); +#endif + if (gilstate_tss_initialized(runtime)) { gilstate_tss_fini(runtime); } @@ -805,6 +810,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) assert(interp->imports.importlib == NULL); assert(interp->imports.import_func == NULL); + Py_CLEAR(interp->sysdict_copy); Py_CLEAR(interp->builtins_copy); Py_CLEAR(interp->dict); #ifdef HAVE_FORK @@ -898,6 +904,12 @@ PyInterpreterState_Delete(PyInterpreterState *interp) _PyEval_FiniState(&interp->ceval); +#ifdef Py_REF_DEBUG + // XXX This call should be done at the end of clear_interpreter(), + // but currently some objects get decref'ed after that. + _PyInterpreterState_FinalizeRefTotal(interp); +#endif + HEAD_LOCK(runtime); PyInterpreterState **p; for (p = &interpreters->head; ; p = &(*p)->next) { diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 34a44dd92847ba..b16d3f53f89fb9 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -18,7 +18,7 @@ #include "pycore_interp.h" // PyInterpreterState.importlib #include "pycore_object.h" // _PyDebug_PrintTotalRefs() #include "pycore_parser.h" // _PyParser_ASTFromString() -#include "pycore_pyerrors.h" // _PyErr_Fetch, _Py_Offer_Suggestions +#include "pycore_pyerrors.h" // _PyErr_GetRaisedException, _Py_Offer_Suggestions #include "pycore_pylifecycle.h" // _Py_UnhandledKeyboardInterrupt #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_sysmodule.h" // _PySys_Audit() @@ -698,30 +698,30 @@ _Py_HandleSystemExit(int *exitcode_p) return 0; } - PyObject *exception, *value, *tb; - PyErr_Fetch(&exception, &value, &tb); - fflush(stdout); int exitcode = 0; - if (value == NULL || value == Py_None) { + + PyObject *exc = PyErr_GetRaisedException(); + if (exc == NULL) { goto done; } + assert(PyExceptionInstance_Check(exc)); - if (PyExceptionInstance_Check(value)) { - /* The error code should be in the `code' attribute. */ - PyObject *code = PyObject_GetAttr(value, &_Py_ID(code)); - if (code) { - Py_SETREF(value, code); - if (value == Py_None) - goto done; + /* The error code should be in the `code' attribute. */ + PyObject *code = PyObject_GetAttr(exc, &_Py_ID(code)); + if (code) { + Py_SETREF(exc, code); + if (exc == Py_None) { + goto done; } - /* If we failed to dig out the 'code' attribute, - just let the else clause below print the error. */ } + /* If we failed to dig out the 'code' attribute, + * just let the else clause below print the error. + */ - if (PyLong_Check(value)) { - exitcode = (int)PyLong_AsLong(value); + if (PyLong_Check(exc)) { + exitcode = (int)PyLong_AsLong(exc); } else { PyThreadState *tstate = _PyThreadState_GET(); @@ -732,20 +732,17 @@ _Py_HandleSystemExit(int *exitcode_p) */ PyErr_Clear(); if (sys_stderr != NULL && sys_stderr != Py_None) { - PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW); + PyFile_WriteObject(exc, sys_stderr, Py_PRINT_RAW); } else { - PyObject_Print(value, stderr, Py_PRINT_RAW); + PyObject_Print(exc, stderr, Py_PRINT_RAW); fflush(stderr); } PySys_WriteStderr("\n"); exitcode = 1; } - done: - /* Cleanup the exception */ - Py_CLEAR(exception); - Py_CLEAR(value); - Py_CLEAR(tb); +done: + Py_CLEAR(exc); *exitcode_p = exitcode; return 1; } @@ -764,39 +761,38 @@ handle_system_exit(void) static void _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) { - PyObject *exception, *v, *tb, *hook; - + PyObject *typ = NULL, *tb = NULL; handle_system_exit(); - _PyErr_Fetch(tstate, &exception, &v, &tb); - if (exception == NULL) { + PyObject *exc = _PyErr_GetRaisedException(tstate); + if (exc == NULL) { goto done; } - - _PyErr_NormalizeException(tstate, &exception, &v, &tb); + assert(PyExceptionInstance_Check(exc)); + typ = Py_NewRef(Py_TYPE(exc)); + tb = PyException_GetTraceback(exc); if (tb == NULL) { tb = Py_NewRef(Py_None); } - PyException_SetTraceback(v, tb); - if (exception == NULL) { - goto done; - } - /* Now we know v != NULL too */ if (set_sys_last_vars) { - if (_PySys_SetAttr(&_Py_ID(last_type), exception) < 0) { + if (_PySys_SetAttr(&_Py_ID(last_exc), exc) < 0) { + _PyErr_Clear(tstate); + } + /* Legacy version: */ + if (_PySys_SetAttr(&_Py_ID(last_type), typ) < 0) { _PyErr_Clear(tstate); } - if (_PySys_SetAttr(&_Py_ID(last_value), v) < 0) { + if (_PySys_SetAttr(&_Py_ID(last_value), exc) < 0) { _PyErr_Clear(tstate); } if (_PySys_SetAttr(&_Py_ID(last_traceback), tb) < 0) { _PyErr_Clear(tstate); } } - hook = _PySys_GetAttr(tstate, &_Py_ID(excepthook)); + PyObject *hook = _PySys_GetAttr(tstate, &_Py_ID(excepthook)); if (_PySys_Audit(tstate, "sys.excepthook", "OOOO", hook ? hook : Py_None, - exception, v, tb) < 0) { + typ, exc, tb) < 0) { if (PyErr_ExceptionMatches(PyExc_RuntimeError)) { PyErr_Clear(); goto done; @@ -805,46 +801,34 @@ _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) } if (hook) { PyObject* stack[3]; - PyObject *result; - - stack[0] = exception; - stack[1] = v; + stack[0] = typ; + stack[1] = exc; stack[2] = tb; - result = _PyObject_FastCall(hook, stack, 3); + PyObject *result = _PyObject_FastCall(hook, stack, 3); if (result == NULL) { handle_system_exit(); - PyObject *exception2, *v2, *tb2; - _PyErr_Fetch(tstate, &exception2, &v2, &tb2); - _PyErr_NormalizeException(tstate, &exception2, &v2, &tb2); - /* It should not be possible for exception2 or v2 - to be NULL. However PyErr_Display() can't - tolerate NULLs, so just be safe. */ - if (exception2 == NULL) { - exception2 = Py_NewRef(Py_None); - } - if (v2 == NULL) { - v2 = Py_NewRef(Py_None); - } + PyObject *exc2 = _PyErr_GetRaisedException(tstate); + assert(exc2 && PyExceptionInstance_Check(exc2)); fflush(stdout); PySys_WriteStderr("Error in sys.excepthook:\n"); - PyErr_Display(exception2, v2, tb2); + PyErr_DisplayException(exc2); PySys_WriteStderr("\nOriginal exception was:\n"); - PyErr_Display(exception, v, tb); - Py_DECREF(exception2); - Py_DECREF(v2); - Py_XDECREF(tb2); + PyErr_DisplayException(exc); + Py_DECREF(exc2); + } + else { + Py_DECREF(result); } - Py_XDECREF(result); } else { PySys_WriteStderr("sys.excepthook is missing\n"); - PyErr_Display(exception, v, tb); + PyErr_DisplayException(exc); } done: - Py_XDECREF(exception); - Py_XDECREF(v); + Py_XDECREF(typ); + Py_XDECREF(exc); Py_XDECREF(tb); } @@ -1508,7 +1492,7 @@ print_exception_recursive(struct exception_print_context *ctx, PyObject *value) #define PyErr_MAX_GROUP_DEPTH 10 void -_PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *tb) +_PyErr_Display(PyObject *file, PyObject *unused, PyObject *value, PyObject *tb) { assert(file != NULL && file != Py_None); if (PyExceptionInstance_Check(value) @@ -1516,10 +1500,12 @@ _PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *t /* Put the traceback on the exception, otherwise it won't get displayed. See issue #18776. */ PyObject *cur_tb = PyException_GetTraceback(value); - if (cur_tb == NULL) + if (cur_tb == NULL) { PyException_SetTraceback(value, tb); - else + } + else { Py_DECREF(cur_tb); + } } struct exception_print_context ctx; @@ -1555,7 +1541,7 @@ _PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *t } void -PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb) +PyErr_Display(PyObject *unused, PyObject *value, PyObject *tb) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *file = _PySys_GetAttr(tstate, &_Py_ID(stderr)); @@ -1568,10 +1554,20 @@ PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb) return; } Py_INCREF(file); - _PyErr_Display(file, exception, value, tb); + _PyErr_Display(file, NULL, value, tb); Py_DECREF(file); } +void _PyErr_DisplayException(PyObject *file, PyObject *exc) +{ + _PyErr_Display(file, NULL, exc, NULL); +} + +void PyErr_DisplayException(PyObject *exc) +{ + PyErr_Display(NULL, exc, NULL); +} + PyObject * PyRun_StringFlags(const char *str, int start, PyObject *globals, PyObject *locals, PyCompilerFlags *flags) @@ -1641,35 +1637,29 @@ PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals, } - static void -flush_io(void) +flush_io_stream(PyThreadState *tstate, PyObject *name) { - PyObject *f, *r; - PyObject *type, *value, *traceback; - - /* Save the current exception */ - PyErr_Fetch(&type, &value, &traceback); - - PyThreadState *tstate = _PyThreadState_GET(); - f = _PySys_GetAttr(tstate, &_Py_ID(stderr)); + PyObject *f = _PySys_GetAttr(tstate, name); if (f != NULL) { - r = _PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); - if (r) + PyObject *r = _PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); + if (r) { Py_DECREF(r); - else - PyErr_Clear(); - } - f = _PySys_GetAttr(tstate, &_Py_ID(stdout)); - if (f != NULL) { - r = _PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); - if (r) - Py_DECREF(r); - else + } + else { PyErr_Clear(); + } } +} - PyErr_Restore(type, value, traceback); +static void +flush_io(void) +{ + PyThreadState *tstate = _PyThreadState_GET(); + PyObject *exc = _PyErr_GetRaisedException(tstate); + flush_io_stream(tstate, &_Py_ID(stderr)); + flush_io_stream(tstate, &_Py_ID(stdout)); + _PyErr_SetRaisedException(tstate, exc); } static PyObject * diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 764fb70bae6c38..4afb0f1d0b5ed2 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -742,7 +742,7 @@ sys_excepthook_impl(PyObject *module, PyObject *exctype, PyObject *value, PyObject *traceback) /*[clinic end generated code: output=18d99fdda21b6b5e input=ecf606fa826f19d9]*/ { - PyErr_Display(exctype, value, traceback); + PyErr_Display(NULL, value, traceback); Py_RETURN_NONE; } @@ -1854,7 +1854,9 @@ static Py_ssize_t sys_gettotalrefcount_impl(PyObject *module) /*[clinic end generated code: output=4103886cf17c25bc input=53b744faa5d2e4f6]*/ { - return _Py_GetRefTotal(); + /* It may make sense to return the total for the current interpreter + or have a second function that does so. */ + return _Py_GetGlobalRefTotal(); } #endif /* Py_REF_DEBUG */ @@ -2670,11 +2672,13 @@ stderr -- standard error object; used for error messages\n\ By assigning other file objects (or objects that behave like files)\n\ to these, it is possible to redirect all of the interpreter's I/O.\n\ \n\ +last_exc - the last uncaught exception\n\ + Only available in an interactive session after a\n\ + traceback has been printed.\n\ last_type -- type of last uncaught exception\n\ last_value -- value of last uncaught exception\n\ last_traceback -- traceback of last uncaught exception\n\ - These three are only available in an interactive session after a\n\ - traceback has been printed.\n\ + These three are the (deprecated) legacy representation of last_exc.\n\ " ) /* concatenating string here */ @@ -3431,6 +3435,11 @@ _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p) } interp->sysdict = Py_NewRef(sysdict); + interp->sysdict_copy = PyDict_Copy(sysdict); + if (interp->sysdict_copy == NULL) { + goto error; + } + if (PyDict_SetItemString(sysdict, "modules", modules) < 0) { goto error; } diff --git a/Python/traceback.c b/Python/traceback.c index 31b85e77575efa..097f69c76abfe1 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -11,7 +11,7 @@ #include "pycore_interp.h" // PyInterpreterState.gc #include "pycore_parser.h" // _PyParser_ASTFromString #include "pycore_pyarena.h" // _PyArena_Free() -#include "pycore_pyerrors.h" // _PyErr_Fetch() +#include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_traceback.h" // EXCEPTION_TB_HEADER @@ -242,17 +242,18 @@ _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame) int PyTraceBack_Here(PyFrameObject *frame) { - PyObject *exc, *val, *tb, *newtb; - PyErr_Fetch(&exc, &val, &tb); - newtb = _PyTraceBack_FromFrame(tb, frame); + PyObject *exc = PyErr_GetRaisedException(); + assert(PyExceptionInstance_Check(exc)); + PyObject *tb = PyException_GetTraceback(exc); + PyObject *newtb = _PyTraceBack_FromFrame(tb, frame); + Py_XDECREF(tb); if (newtb == NULL) { - _PyErr_ChainExceptions(exc, val, tb); + _PyErr_ChainExceptions1(exc); return -1; } - assert(PyExceptionInstance_Check(val)); - PyException_SetTraceback(val, newtb); - PyErr_Restore(exc, val, newtb); - Py_XDECREF(tb); + PyException_SetTraceback(exc, newtb); + Py_XDECREF(newtb); + PyErr_SetRaisedException(exc); return 0; } diff --git a/Tools/build/generate_global_objects.py b/Tools/build/generate_global_objects.py index 9ceae89878cda8..1f53f02d41ef39 100644 --- a/Tools/build/generate_global_objects.py +++ b/Tools/build/generate_global_objects.py @@ -360,6 +360,7 @@ def generate_static_strings_initializer(identifiers, strings): # This use of _Py_ID() is ignored by iter_global_strings() # since iter_files() ignores .h files. printer.write(f'string = &_Py_ID({i});') + printer.write(f'assert(_PyUnicode_CheckConsistency(string, 1));') printer.write(f'PyUnicode_InternInPlace(&string);') # XXX What about "strings"? printer.write(END) diff --git a/Tools/c-analyzer/c_parser/preprocessor/common.py b/Tools/c-analyzer/c_parser/preprocessor/common.py index 4291a066337545..dbe1edeef38527 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/common.py +++ b/Tools/c-analyzer/c_parser/preprocessor/common.py @@ -115,15 +115,15 @@ def converted_error(tool, argv, filename): def convert_error(tool, argv, filename, stderr, rc): error = (stderr.splitlines()[0], rc) if (_expected := is_os_mismatch(filename, stderr)): - logger.debug(stderr.strip()) + logger.info(stderr.strip()) raise OSMismatchError(filename, _expected, argv, error, tool) elif (_missing := is_missing_dep(stderr)): - logger.debug(stderr.strip()) + logger.info(stderr.strip()) raise MissingDependenciesError(filename, (_missing,), argv, error, tool) elif '#error' in stderr: # XXX Ignore incompatible files. error = (stderr.splitlines()[1], rc) - logger.debug(stderr.strip()) + logger.info(stderr.strip()) raise ErrorDirectiveError(filename, argv, error, tool) else: # Try one more time, with stderr written to the terminal. diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index 7ef1a8afc3b135..c680f351f22416 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -6,6 +6,11 @@ TOOL = 'gcc' +META_FILES = { + '', + '', +} + # https://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html # flags: # 1 start of a new file @@ -75,11 +80,15 @@ def _iter_lines(text, reqfile, samefiles, cwd, raw=False): # The first line is special. # The next two lines are consistent. - for expected in [ - f'# 1 "{reqfile}"', - '# 1 ""', - '# 1 ""', - ]: + firstlines = [ + f'# 0 "{reqfile}"', + '# 0 ""', + '# 0 ""', + ] + if text.startswith('# 1 '): + # Some preprocessors emit a lineno of 1 for line-less entries. + firstlines = [l.replace('# 0 ', '# 1 ') for l in firstlines] + for expected in firstlines: line = next(lines) if line != expected: raise NotImplementedError((line, expected)) @@ -121,7 +130,7 @@ def _iter_top_include_lines(lines, topfile, cwd, # _parse_marker_line() that the preprocessor reported lno as 1. lno = 1 for line in lines: - if line == '# 1 "" 2': + if line == '# 0 "" 2' or line == '# 1 "" 2': # We're done with this top-level include. return @@ -144,9 +153,13 @@ def _iter_top_include_lines(lines, topfile, cwd, # XXX How can a file return to line 1? #assert lno > 1, (line, lno) else: - # It's the next line from the file. - assert included == files[-1], (line, files) - assert lno > 1, (line, lno) + if included == files[-1]: + # It's the next line from the file. + assert lno > 1, (line, lno) + else: + # We ran into a user-added #LINE directive, + # which we promptly ignore. + pass elif not files: raise NotImplementedError((line,)) elif filter_reqfile(files[-1]): @@ -174,8 +187,8 @@ def _parse_marker_line(line, reqfile=None): return None, None, None lno, origfile, flags = m.groups() lno = int(lno) + assert origfile not in META_FILES, (line,) assert lno > 0, (line, lno) - assert origfile not in ('', ''), (line,) flags = set(int(f) for f in flags.split()) if flags else () if 1 in flags: diff --git a/Tools/c-analyzer/cpython/__main__.py b/Tools/c-analyzer/cpython/__main__.py index 2b9e4233b95ac4..fe7a16726f45a9 100644 --- a/Tools/c-analyzer/cpython/__main__.py +++ b/Tools/c-analyzer/cpython/__main__.py @@ -1,5 +1,6 @@ import logging import sys +import textwrap from c_common.fsutil import expand_filenames, iter_files_by_suffix from c_common.scriptutil import ( @@ -26,6 +27,39 @@ logger = logging.getLogger(__name__) +CHECK_EXPLANATION = textwrap.dedent(''' + ------------------------- + + Non-constant global variables are generally not supported + in the CPython repo. We use a tool to analyze the C code + and report if any unsupported globals are found. The tool + may be run manually with: + + ./python Tools/c-analyzer/check-c-globals.py --format summary [FILE] + + Occasionally the tool is unable to parse updated code. + If this happens then add the file to the "EXCLUDED" list + in Tools/c-analyzer/cpython/_parser.py and create a new + issue for fixing the tool (and CC ericsnowcurrently + on the issue). + + If the tool reports an unsupported global variable and + it is actually const (and thus supported) then first try + fixing the declaration appropriately in the code. If that + doesn't work then add the variable to the "should be const" + section of Tools/c-analyzer/cpython/ignored.tsv. + + If the tool otherwise reports an unsupported global variable + then first try to make it non-global, possibly adding to + PyInterpreterState (for core code) or module state (for + extension modules). In an emergency, you can add the + variable to Tools/c-analyzer/cpython/globals-to-fix.tsv + to get CI passing, but doing so should be avoided. If + this course it taken, be sure to create an issue for + eliminating the global (and CC ericsnowcurrently). +''') + + def _resolve_filenames(filenames): if filenames: resolved = (_files.resolve_filename(f) for f in filenames) @@ -123,14 +157,26 @@ def _cli_check(parser, **kwargs): def cmd_check(filenames=None, **kwargs): filenames = _resolve_filenames(filenames) kwargs['get_file_preprocessor'] = _parser.get_preprocessor(log_err=print) - c_analyzer.cmd_check( - filenames, - relroot=REPO_ROOT, - _analyze=_analyzer.analyze, - _CHECKS=CHECKS, - file_maxsizes=_parser.MAX_SIZES, - **kwargs - ) + try: + c_analyzer.cmd_check( + filenames, + relroot=REPO_ROOT, + _analyze=_analyzer.analyze, + _CHECKS=CHECKS, + file_maxsizes=_parser.MAX_SIZES, + **kwargs + ) + except SystemExit as exc: + num_failed = exc.args[0] if getattr(exc, 'args', None) else None + if isinstance(num_failed, int): + if num_failed > 0: + sys.stderr.flush() + print(CHECK_EXPLANATION, flush=True) + raise # re-raise + except Exception: + sys.stderr.flush() + print(CHECK_EXPLANATION, flush=True) + raise # re-raise def cmd_analyze(filenames=None, **kwargs): diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index e7764165d36c4c..acf30e2c4020b3 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -91,6 +91,7 @@ def clean_lines(text): # XXX Fix the parser. EXCLUDED += clean_lines(''' # The tool should be able to parse these... + # The problem with xmlparse.c is that something # has gone wrong where # we handle "maybe inline actual" # in Tools/c-analyzer/c_parser/parser/_global.py. @@ -106,15 +107,20 @@ def clean_lines(text): * ./Include/internal Modules/_decimal/**/*.c Modules/_decimal/libmpdec +Modules/_elementtree.c Modules/expat Modules/_hacl/*.c Modules/_hacl/include Modules/_hacl/*.h Modules/_hacl/include -Modules/_tkinter.c /usr/include/tcl8.6 Modules/md5module.c Modules/_hacl/include Modules/sha1module.c Modules/_hacl/include Modules/sha2module.c Modules/_hacl/include -Modules/tkappinit.c /usr/include/tcl Objects/stringlib/*.h Objects +# possible system-installed headers, just in case +Modules/_tkinter.c /usr/include/tcl8.6 +Modules/_uuidmodule.c /usr/include/uuid +Modules/nismodule.c /usr/include/tirpc +Modules/tkappinit.c /usr/include/tcl + # @end=tsv@ ''')[1:] diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 700ddf2851839e..14fc32a07b4309 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -141,7 +141,6 @@ Modules/syslogmodule.c - S_log_open - ##----------------------- ## kept for stable ABI compatibility -# XXX should be per-interpreter, without impacting stable ABI extensions Objects/object.c - _Py_RefTotal - ##----------------------- @@ -228,6 +227,7 @@ Modules/_xxinterpchannelsmodule.c - _channelid_end_recv - Modules/_xxinterpchannelsmodule.c - _channelid_end_send - Modules/_zoneinfo.c - DAYS_BEFORE_MONTH - Modules/_zoneinfo.c - DAYS_IN_MONTH - +Modules/_xxsubinterpretersmodule.c - no_exception - Modules/arraymodule.c - descriptors - Modules/arraymodule.c - emptybuf - Modules/cjkcodecs/_codecs_cn.c - _mapping_list - @@ -300,6 +300,7 @@ Objects/genobject.c - NON_INIT_CORO_MSG - Objects/longobject.c - _PyLong_DigitValue - Objects/object.c - _Py_SwappedOp - Objects/object.c - _Py_abstract_hack - +Objects/object.c - last_final_reftotal - Objects/object.c - static_types - Objects/obmalloc.c - _PyMem - Objects/obmalloc.c - _PyMem_Debug - diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 25cf75e4c1c490..a0bba65545d4f8 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -13,6 +13,7 @@ import sys import typing +import lexer as lx import parser from parser import StackEffect @@ -43,6 +44,9 @@ arg_parser.add_argument( "-m", "--metadata", type=str, help="Generated metadata", default=DEFAULT_METADATA_OUTPUT ) +arg_parser.add_argument( + "-l", "--emit-line-directives", help="Emit #line directives", action="store_true" +) arg_parser.add_argument( "input", nargs=argparse.REMAINDER, help="Instruction definition file(s)" ) @@ -105,13 +109,35 @@ class Formatter: stream: typing.TextIO prefix: str - - def __init__(self, stream: typing.TextIO, indent: int) -> None: + emit_line_directives: bool = False + lineno: int # Next line number, 1-based + filename: str # Slightly improved stream.filename + nominal_lineno: int + nominal_filename: str + + def __init__( + self, stream: typing.TextIO, indent: int, emit_line_directives: bool = False + ) -> None: self.stream = stream self.prefix = " " * indent + self.emit_line_directives = emit_line_directives + self.lineno = 1 + filename = os.path.relpath(self.stream.name, ROOT) + # Make filename more user-friendly and less platform-specific + filename = filename.replace("\\", "/") + if filename.startswith("./"): + filename = filename[2:] + if filename.endswith(".new"): + filename = filename[:-4] + self.filename = filename + self.nominal_lineno = 1 + self.nominal_filename = filename def write_raw(self, s: str) -> None: self.stream.write(s) + newlines = s.count("\n") + self.lineno += newlines + self.nominal_lineno += newlines def emit(self, arg: str) -> None: if arg: @@ -119,6 +145,17 @@ def emit(self, arg: str) -> None: else: self.write_raw("\n") + def set_lineno(self, lineno: int, filename: str) -> None: + if self.emit_line_directives: + if lineno != self.nominal_lineno or filename != self.nominal_filename: + self.emit(f'#line {lineno} "{filename}"') + self.nominal_lineno = lineno + self.nominal_filename = filename + + def reset_lineno(self) -> None: + if self.lineno != self.nominal_lineno or self.filename != self.nominal_filename: + self.set_lineno(self.lineno + 1, self.filename) + @contextlib.contextmanager def indent(self): self.prefix += " " @@ -193,12 +230,12 @@ class Instruction: # Parts of the underlying instruction definition inst: parser.InstDef - register: bool kind: typing.Literal["inst", "op", "legacy"] # Legacy means no (input -- output) name: str block: parser.Block block_text: list[str] # Block.text, less curlies, less PREDICT() calls predictions: list[str] # Prediction targets (instruction names) + block_line: int # First line of block in original code # Computed by constructor always_exits: bool @@ -209,21 +246,16 @@ class Instruction: unmoved_names: frozenset[str] instr_fmt: str - # Parallel to input_effects; set later - input_registers: list[str] = dataclasses.field(repr=False) - output_registers: list[str] = dataclasses.field(repr=False) - # Set later family: parser.Family | None = None predicted: bool = False def __init__(self, inst: parser.InstDef): self.inst = inst - self.register = inst.register self.kind = inst.kind self.name = inst.name self.block = inst.block - self.block_text, self.check_eval_breaker, self.predictions = \ + self.block_text, self.check_eval_breaker, self.predictions, self.block_line = \ extract_block_text(self.block) self.always_exits = always_exits(self.block_text) self.cache_effects = [ @@ -241,15 +273,10 @@ def __init__(self, inst: parser.InstDef): else: break self.unmoved_names = frozenset(unmoved_names) - if self.register: - num_regs = len(self.input_effects) + len(self.output_effects) - num_dummies = (num_regs // 2) * 2 + 1 - num_regs - fmt = "I" + "B" * num_regs + "X" * num_dummies + if variable_used(inst, "oparg"): + fmt = "IB" else: - if variable_used(inst, "oparg"): - fmt = "IB" - else: - fmt = "IX" + fmt = "IX" cache = "C" for ce in self.cache_effects: for _ in range(ce.size): @@ -257,20 +284,6 @@ def __init__(self, inst: parser.InstDef): cache = "0" self.instr_fmt = fmt - def analyze_registers(self, a: "Analyzer") -> None: - regs = iter(("REG(oparg1)", "REG(oparg2)", "REG(oparg3)")) - try: - self.input_registers = [ - next(regs) for ieff in self.input_effects if ieff.name != UNUSED - ] - self.output_registers = [ - next(regs) for oeff in self.output_effects if oeff.name != UNUSED - ] - except StopIteration: # Running out of registers - a.error( - f"Instruction {self.name} has too many register effects", node=self.inst - ) - def write(self, out: Formatter) -> None: """Write one instruction, sans prologue and epilogue.""" # Write a static assertion that a family's cache size is correct @@ -282,25 +295,19 @@ def write(self, out: Formatter) -> None: f'{self.cache_offset}, "incorrect cache size");' ) - if not self.register: - # Write input stack effect variable declarations and initializations - ieffects = list(reversed(self.input_effects)) - for i, ieffect in enumerate(ieffects): - isize = string_effect_size( - list_effect_size([ieff for ieff in ieffects[: i + 1]]) - ) - if ieffect.size: - src = StackEffect(f"(stack_pointer - {maybe_parenthesize(isize)})", "PyObject **") - elif ieffect.cond: - src = StackEffect(f"({ieffect.cond}) ? stack_pointer[-{maybe_parenthesize(isize)}] : NULL", "") - else: - src = StackEffect(f"stack_pointer[-{maybe_parenthesize(isize)}]", "") - out.declare(ieffect, src) - else: - # Write input register variable declarations and initializations - for ieffect, reg in zip(self.input_effects, self.input_registers): - src = StackEffect(reg, "") - out.declare(ieffect, src) + # Write input stack effect variable declarations and initializations + ieffects = list(reversed(self.input_effects)) + for i, ieffect in enumerate(ieffects): + isize = string_effect_size( + list_effect_size([ieff for ieff in ieffects[: i + 1]]) + ) + if ieffect.size: + src = StackEffect(f"(stack_pointer - {maybe_parenthesize(isize)})", "PyObject **") + elif ieffect.cond: + src = StackEffect(f"({ieffect.cond}) ? stack_pointer[-{maybe_parenthesize(isize)}] : NULL", "") + else: + src = StackEffect(f"stack_pointer[-{maybe_parenthesize(isize)}]", "") + out.declare(ieffect, src) # Write output stack effect variable declarations isize = string_effect_size(list_effect_size(self.input_effects)) @@ -330,32 +337,26 @@ def write(self, out: Formatter) -> None: if self.always_exits: return - if not self.register: - # Write net stack growth/shrinkage - out.stack_adjust( - 0, - [ieff for ieff in self.input_effects], - [oeff for oeff in self.output_effects], - ) + # Write net stack growth/shrinkage + out.stack_adjust( + 0, + [ieff for ieff in self.input_effects], + [oeff for oeff in self.output_effects], + ) - # Write output stack effect assignments - oeffects = list(reversed(self.output_effects)) - for i, oeffect in enumerate(oeffects): - if oeffect.name in self.unmoved_names: - continue - osize = string_effect_size( - list_effect_size([oeff for oeff in oeffects[: i + 1]]) - ) - if oeffect.size: - dst = StackEffect(f"stack_pointer - {maybe_parenthesize(osize)}", "PyObject **") - else: - dst = StackEffect(f"stack_pointer[-{maybe_parenthesize(osize)}]", "") - out.assign(dst, oeffect) - else: - # Write output register assignments - for oeffect, reg in zip(self.output_effects, self.output_registers): - dst = StackEffect(reg, "") - out.assign(dst, oeffect) + # Write output stack effect assignments + oeffects = list(reversed(self.output_effects)) + for i, oeffect in enumerate(oeffects): + if oeffect.name in self.unmoved_names: + continue + osize = string_effect_size( + list_effect_size([oeff for oeff in oeffects[: i + 1]]) + ) + if oeffect.size: + dst = StackEffect(f"stack_pointer - {maybe_parenthesize(osize)}", "PyObject **") + else: + dst = StackEffect(f"stack_pointer[-{maybe_parenthesize(osize)}]", "") + out.assign(dst, oeffect) # Write cache effect if self.cache_offset: @@ -388,26 +389,30 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None assert dedent <= 0 extra = " " * -dedent names_to_skip = self.unmoved_names | frozenset({UNUSED, "null"}) + offset = 0 + context = self.block.context + assert context != None + filename = context.owner.filename for line in self.block_text: + out.set_lineno(self.block_line + offset, filename) + offset += 1 if m := re.match(r"(\s*)ERROR_IF\((.+), (\w+)\);\s*(?://.*)?$", line): space, cond, label = m.groups() space = extra + space # ERROR_IF() must pop the inputs from the stack. # The code block is responsible for DECREF()ing them. # NOTE: If the label doesn't exist, just add it to ceval.c. - if not self.register: - # Don't pop common input/output effects at the bottom! - # These aren't DECREF'ed so they can stay. - ieffs = list(self.input_effects) - oeffs = list(self.output_effects) - while ieffs and oeffs and ieffs[0] == oeffs[0]: - ieffs.pop(0) - oeffs.pop(0) - ninputs, symbolic = list_effect_size(ieffs) - if ninputs: - label = f"pop_{ninputs}_{label}" - else: - symbolic = "" + + # Don't pop common input/output effects at the bottom! + # These aren't DECREF'ed so they can stay. + ieffs = list(self.input_effects) + oeffs = list(self.output_effects) + while ieffs and oeffs and ieffs[0] == oeffs[0]: + ieffs.pop(0) + oeffs.pop(0) + ninputs, symbolic = list_effect_size(ieffs) + if ninputs: + label = f"pop_{ninputs}_{label}" if symbolic: out.write_raw( f"{space}if ({cond}) {{ STACK_SHRINK({symbolic}); goto {label}; }}\n" @@ -415,22 +420,23 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None else: out.write_raw(f"{space}if ({cond}) goto {label};\n") elif m := re.match(r"(\s*)DECREF_INPUTS\(\);\s*(?://.*)?$", line): - if not self.register: - space = extra + m.group(1) - for ieff in self.input_effects: - if ieff.name in names_to_skip: - continue - if ieff.size: - out.write_raw( - f"{space}for (int _i = {ieff.size}; --_i >= 0;) {{\n" - ) - out.write_raw(f"{space} Py_DECREF({ieff.name}[_i]);\n") - out.write_raw(f"{space}}}\n") - else: - decref = "XDECREF" if ieff.cond else "DECREF" - out.write_raw(f"{space}Py_{decref}({ieff.name});\n") + out.reset_lineno() + space = extra + m.group(1) + for ieff in self.input_effects: + if ieff.name in names_to_skip: + continue + if ieff.size: + out.write_raw( + f"{space}for (int _i = {ieff.size}; --_i >= 0;) {{\n" + ) + out.write_raw(f"{space} Py_DECREF({ieff.name}[_i]);\n") + out.write_raw(f"{space}}}\n") + else: + decref = "XDECREF" if ieff.cond else "DECREF" + out.write_raw(f"{space}Py_{decref}({ieff.name});\n") else: out.write_raw(extra + line) + out.reset_lineno() InstructionOrCacheEffect = Instruction | parser.CacheEffect @@ -501,6 +507,7 @@ class Analyzer: output_filename: str metadata_filename: str errors: int = 0 + emit_line_directives: bool = False def __init__(self, input_filenames: list[str], output_filename: str, metadata_filename: str): """Read the input file.""" @@ -561,6 +568,11 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None: with open(filename) as file: src = file.read() + filename = os.path.relpath(filename, ROOT) + # Make filename more user-friendly and less platform-specific + filename = filename.replace("\\", "/") + if filename.startswith("./"): + filename = filename[2:] psr = parser.Parser(src, filename=filename) # Skip until begin marker @@ -622,7 +634,6 @@ def analyze(self) -> None: Raises SystemExit if there is an error. """ self.find_predictions() - self.analyze_register_instrs() self.analyze_supers_and_macros() self.map_families() self.check_families() @@ -732,11 +743,6 @@ def effect_counts(self, name: str) -> tuple[int, int, int]: assert False, f"Unknown instruction {name!r}" return cache, input, output - def analyze_register_instrs(self) -> None: - for instr in self.instrs.values(): - if instr.register: - instr.analyze_registers(self) - def analyze_supers_and_macros(self) -> None: """Analyze each super- and macro instruction.""" self.super_instrs = {} @@ -766,7 +772,7 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction: stack, initial_sp = self.stack_analysis(components) sp = initial_sp parts: list[Component | parser.CacheEffect] = [] - format = "IB" # Macros don't support register instructions yet + format = "IB" cache = "C" for component in components: match component: @@ -972,24 +978,21 @@ def write_metadata(self) -> None: format_enums = [INSTR_FMT_PREFIX + format for format in sorted(all_formats)] with open(self.metadata_filename, "w") as f: + # Create formatter + self.out = Formatter(f, 0) + # Write provenance header - f.write(f"// This file is generated by {THIS}\n") - f.write(self.from_source_files()) - f.write(f"// Do not edit!\n") + self.out.write_raw(f"// This file is generated by {THIS}\n") + self.out.write_raw(self.from_source_files()) + self.out.write_raw(f"// Do not edit!\n") - # Create formatter; the rest of the code uses this - self.out = Formatter(f, 0) self.write_stack_effect_functions() # Write type definitions - self.out.emit("enum Direction { DIR_NONE, DIR_READ, DIR_WRITE };") self.out.emit(f"enum InstructionFormat {{ {', '.join(format_enums)} }};") self.out.emit("struct opcode_metadata {") with self.out.indent(): - self.out.emit("enum Direction dir_op1;") - self.out.emit("enum Direction dir_op2;") - self.out.emit("enum Direction dir_op3;") self.out.emit("bool valid_entry;") self.out.emit("enum InstructionFormat instr_format;") self.out.emit("};") @@ -1022,44 +1025,32 @@ def write_metadata(self) -> None: def write_metadata_for_inst(self, instr: Instruction) -> None: """Write metadata for a single instruction.""" - dir_op1 = dir_op2 = dir_op3 = "DIR_NONE" - if instr.kind == "legacy": - assert not instr.register - else: - if instr.register: - directions: list[str] = [] - directions.extend("DIR_READ" for _ in instr.input_effects) - directions.extend("DIR_WRITE" for _ in instr.output_effects) - directions.extend("DIR_NONE" for _ in range(3)) - dir_op1, dir_op2, dir_op3 = directions[:3] self.out.emit( - f" [{instr.name}] = {{ {dir_op1}, {dir_op2}, {dir_op3}, true, {INSTR_FMT_PREFIX}{instr.instr_fmt} }}," + f" [{instr.name}] = {{ true, {INSTR_FMT_PREFIX}{instr.instr_fmt} }}," ) def write_metadata_for_super(self, sup: SuperInstruction) -> None: """Write metadata for a super-instruction.""" - dir_op1 = dir_op2 = dir_op3 = "DIR_NONE" self.out.emit( - f" [{sup.name}] = {{ {dir_op1}, {dir_op2}, {dir_op3}, true, {INSTR_FMT_PREFIX}{sup.instr_fmt} }}," + f" [{sup.name}] = {{ true, {INSTR_FMT_PREFIX}{sup.instr_fmt} }}," ) def write_metadata_for_macro(self, mac: MacroInstruction) -> None: """Write metadata for a macro-instruction.""" - dir_op1 = dir_op2 = dir_op3 = "DIR_NONE" self.out.emit( - f" [{mac.name}] = {{ {dir_op1}, {dir_op2}, {dir_op3}, true, {INSTR_FMT_PREFIX}{mac.instr_fmt} }}," + f" [{mac.name}] = {{ true, {INSTR_FMT_PREFIX}{mac.instr_fmt} }}," ) def write_instructions(self) -> None: """Write instructions to output file.""" with open(self.output_filename, "w") as f: - # Write provenance header - f.write(f"// This file is generated by {THIS}\n") - f.write(self.from_source_files()) - f.write(f"// Do not edit!\n") + # Create formatter + self.out = Formatter(f, 8, self.emit_line_directives) - # Create formatter; the rest of the code uses this - self.out = Formatter(f, 8) + # Write provenance header + self.out.write_raw(f"// This file is generated by {THIS}\n") + self.out.write_raw(self.from_source_files()) + self.out.write_raw(f"// Do not edit!\n") # Write and count instructions of all kinds n_instrs = 0 @@ -1179,13 +1170,16 @@ def wrap_super_or_macro(self, up: SuperOrMacroInstruction): self.out.emit(f"DISPATCH();") -def extract_block_text(block: parser.Block) -> tuple[list[str], bool, list[str]]: +def extract_block_text(block: parser.Block) -> tuple[list[str], bool, list[str], int]: # Get lines of text with proper dedent blocklines = block.text.splitlines(True) + first_token: lx.Token = block.tokens[0] # IndexError means the context is broken + block_line = first_token.begin[0] # Remove blank lines from both ends while blocklines and not blocklines[0].strip(): blocklines.pop(0) + block_line += 1 while blocklines and not blocklines[-1].strip(): blocklines.pop() @@ -1194,6 +1188,7 @@ def extract_block_text(block: parser.Block) -> tuple[list[str], bool, list[str]] assert blocklines and blocklines[-1].strip() == "}" blocklines.pop() blocklines.pop(0) + block_line += 1 # Remove trailing blank lines while blocklines and not blocklines[-1].strip(): @@ -1213,7 +1208,7 @@ def extract_block_text(block: parser.Block) -> tuple[list[str], bool, list[str]] predictions.insert(0, m.group(1)) blocklines.pop() - return blocklines, check_eval_breaker, predictions + return blocklines, check_eval_breaker, predictions, block_line def always_exits(lines: list[str]) -> bool: @@ -1250,6 +1245,8 @@ def main(): if len(args.input) == 0: args.input.append(DEFAULT_INPUT) a = Analyzer(args.input, args.output, args.metadata) # Raises OSError if input unreadable + if args.emit_line_directives: + a.emit_line_directives = True a.parse() # Raises SyntaxError on failure a.analyze() # Prints messages and sets a.errors on failure if a.errors: