git-updates
authorMatthias Klose <doko@debian.org>
Mon, 19 Oct 2020 09:51:18 +0000 (10:51 +0100)
committerMatthias Klose <doko@debian.org>
Mon, 19 Oct 2020 09:51:18 +0000 (10:51 +0100)
# DP: updates from the 3.9 branch (until 2020-10-19).

# DP: updates from the 3.9 branch (until 2020-10-19).

# git diff --no-renames 9cf6752276e6fcfd0c23fdb064ad27f448aaaf75 7c949020ef2520d7a7cbc978f0b34423e6c2a94c | filterdiff -x ?/.hgignore -x ?/.hgeol -x ?/.hgtags -x ?/.hgtouch -x ?/.gitignore -x ?/.gitattributes -x '?/.github/*' -x '?/.git*' -x ?/.codecov.yml -x ?/.travis.yml -x ?/configure --remove-timestamps

Gbp-Pq: Name git-updates.diff

69 files changed:
Doc/faq/programming.rst
Doc/library/idle.rst
Doc/library/math.rst
Doc/library/random.rst
Doc/library/shutil.rst
Doc/library/site.rst
Doc/library/typing.rst
Doc/library/unittest.rst
Doc/library/xml.etree.elementtree.rst
Doc/reference/datamodel.rst
Doc/tools/extensions/pyspecific.py
Doc/whatsnew/3.8.rst
Doc/whatsnew/3.9.rst
Grammar/python.gram
Include/cpython/fileobject.h
Include/fileobject.h
Include/patchlevel.h
Lib/cProfile.py
Lib/ctypes/test/test_find.py
Lib/ctypes/util.py
Lib/datetime.py
Lib/graphlib.py
Lib/idlelib/NEWS.txt
Lib/idlelib/calltip.py
Lib/idlelib/help.html
Lib/idlelib/idle_test/test_calltip.py
Lib/idlelib/pyshell.py
Lib/logging/__init__.py
Lib/profile.py
Lib/pstats.py
Lib/symtable.py
Lib/test/datetimetester.py
Lib/test/multibytecodec_support.py
Lib/test/test_codecs.py
Lib/test/test_finalization.py
Lib/test/test_gc.py
Lib/test/test_genericalias.py
Lib/test/test_isinstance.py
Lib/test/test_lib2to3.py
Lib/test/test_logging.py
Lib/test/test_profile.py
Lib/test/test_pstats.py
Lib/test/test_site.py
Lib/test/test_symtable.py
Lib/test/test_with.py
Lib/test/test_xml_etree.py
Lib/test/test_zipfile.py
Lib/test/test_zoneinfo/test_zoneinfo.py
Lib/tkinter/__init__.py
Lib/tkinter/test/test_tkinter/test_misc.py
Lib/tkinter/test/test_tkinter/test_widgets.py
Lib/xml/etree/ElementTree.py
Lib/zipfile.py
Mac/BuildScript/build-installer.py
Misc/ACKS
Modules/_testcapimodule.c
Modules/_tracemalloc.c
Objects/abstract.c
Objects/genericaliasobject.c
Objects/methodobject.c
Objects/typeobject.c
Objects/unicodeobject.c
Parser/pegen/parse.c
Python/dynload_aix.c
Python/dynload_hpux.c
Python/dynload_shlib.c
Python/import.c
Tools/c-analyzer/c_analyzer/common/files.py
setup.py

index 66d210a55fac7e9f06a83c6771dd20a8ab0ccd61..106450fb786709ab9b9b0f20dcaf8820d38547f5 100644 (file)
@@ -942,7 +942,7 @@ There are various techniques.
      f()
 
 
-* Use :func:`locals` or :func:`eval` to resolve the function name::
+* Use :func:`locals` to resolve the function name::
 
      def myFunc():
          print("hello")
@@ -952,12 +952,6 @@ There are various techniques.
      f = locals()[fname]
      f()
 
-     f = eval(fname)
-     f()
-
-  Note: Using :func:`eval` is slow and dangerous.  If you don't have absolute
-  control over the contents of the string, someone could pass a string that
-  resulted in an arbitrary function being executed.
 
 Is there an equivalent to Perl's chomp() for removing trailing newlines from strings?
 -------------------------------------------------------------------------------------
@@ -1164,6 +1158,21 @@ This converts the list into a set, thereby removing duplicates, and then back
 into a list.
 
 
+How do you remove multiple items from a list
+--------------------------------------------
+
+As with removing duplicates, explicitly iterating in reverse with a
+delete condition is one possibility.  However, it is easier and faster
+to use slice replacement with an implicit or explicit forward iteration.
+Here are three variations.::
+
+   mylist[:] = filter(keep_function, mylist)
+   mylist[:] = (x for x in mylist if keep_condition)
+   mylist[:] = [x for x in mylist if keep_condition]
+
+The list comprehension may be fastest.
+
+
 How do you make an array in Python?
 -----------------------------------
 
@@ -1366,20 +1375,6 @@ out the element you want. ::
    ['else', 'sort', 'to', 'something']
 
 
-An alternative for the last step is::
-
-   >>> result = []
-   >>> for p in pairs: result.append(p[1])
-
-If you find this more legible, you might prefer to use this instead of the final
-list comprehension.  However, it is almost twice as slow for long lists.  Why?
-First, the ``append()`` operation has to reallocate memory, and while it uses
-some tricks to avoid doing that each time, it still has to do it occasionally,
-and that costs quite a bit.  Second, the expression "result.append" requires an
-extra attribute lookup, and third, there's a speed reduction from having to make
-all those function calls.
-
-
 Objects
 =======
 
index 43096b014fed349eabe5438dc2b073bcdcf3ac4f..a59a5d3a465703c1a09c3e518626e903e47bc8fd 100644 (file)
@@ -527,30 +527,33 @@ by typing '_' after '.', either before or after the box is opened.
 Calltips
 ^^^^^^^^
 
-A calltip is shown when one types :kbd:`(` after the name of an *accessible*
-function.  A name expression may include dots and subscripts.  A calltip
-remains until it is clicked, the cursor is moved out of the argument area,
-or :kbd:`)` is typed.  When the cursor is in the argument part of a definition,
-the menu or shortcut display a calltip.
-
-A calltip consists of the function signature and the first line of the
-docstring.  For builtins without an accessible signature, the calltip
-consists of all lines up the fifth line or the first blank line.  These
-details may change.
-
-The set of *accessible* functions depends on what modules have been imported
-into the user process, including those imported by Idle itself,
-and what definitions have been run, all since the last restart.
+A calltip is shown automatically when one types :kbd:`(` after the name
+of an *accessible* function.  A function name expression may include
+dots and subscripts.  A calltip remains until it is clicked, the cursor
+is moved out of the argument area, or :kbd:`)` is typed.  Whenever the
+cursor is in the argument part of a definition, select Edit and "Show
+Call Tip" on the menu or enter its shortcut to display a calltip.
+
+The calltip consists of the function's signature and docstring up to
+the latter's first blank line or the fifth non-blank line.  (Some builtin
+functions lack an accessible signature.)  A '/' or '*' in the signature
+indicates that the preceding or following arguments are passed by
+position or name (keyword) only.  Details are subject to change.
+
+In Shell, the accessible functions depends on what modules have been
+imported into the user process, including those imported by Idle itself,
+and which definitions have been run, all since the last restart.
 
 For example, restart the Shell and enter ``itertools.count(``.  A calltip
-appears because Idle imports itertools into the user process for its own use.
-(This could change.)  Enter ``turtle.write(`` and nothing appears.  Idle does
-not import turtle.  The menu or shortcut do nothing either.  Enter
-``import turtle`` and then ``turtle.write(`` will work.
-
-In an editor, import statements have no effect until one runs the file.  One
-might want to run a file after writing the import statements at the top,
-or immediately run an existing file before editing.
+appears because Idle imports itertools into the user process for its own
+use.  (This could change.)  Enter ``turtle.write(`` and nothing appears.
+Idle does not itself import turtle.  The menu entry and shortcut also do
+nothing.  Enter ``import turtle``.  Thereafter, ``turtle.write(``
+will display a calltip.
+
+In an editor, import statements have no effect until one runs the file.
+One might want to run a file after writing import statements, after
+adding function definitions, or after opening an existing file.
 
 .. _code-context:
 
index 6ec1feee35a6dc7151c5fd981f7e6db9a96703a3..b20e557b5c6109b514db9acf833f246a1ad0803a 100644 (file)
@@ -130,7 +130,7 @@ Number-theoretic and representation functions
 
    Return the greatest common divisor of the specified integer arguments.
    If any of the arguments is nonzero, then the returned value is the largest
-   positive integer that is a divisor af all arguments.  If all arguments
+   positive integer that is a divisor of all arguments.  If all arguments
    are zero, then the returned value is ``0``.  ``gcd()`` without arguments
    returns ``0``.
 
index 90366f499cae6a2a3ddb8c220bc4d0c559067e0c..f9535d7d1b9a224f7d3b6a68dcfdf2827d110d9b 100644 (file)
@@ -253,6 +253,8 @@ Functions for sequences
       order so that the sample is reproducible.
 
 
+.. _real-valued-distributions:
+
 Real-valued distributions
 -------------------------
 
@@ -391,8 +393,8 @@ change across Python versions, but two aspects are guaranteed not to change:
 
 .. _random-examples:
 
-Examples and Recipes
---------------------
+Examples
+--------
 
 Basic examples::
 
@@ -536,3 +538,58 @@ Simulation of arrival times and service deliveries for a multiserver queue::
    a tutorial by `Peter Norvig <http://norvig.com/bio.html>`_ covering
    the basics of probability theory, how to write simulations, and
    how to perform data analysis using Python.
+
+
+Recipes
+-------
+
+The default :func:`.random` returns multiples of 2⁻⁵³ in the range
+*0.0 ≤ x < 1.0*.  All such numbers are evenly spaced and are exactly
+representable as Python floats.  However, many other representable
+floats in that interval are not possible selections.  For example,
+``0.05954861408025609`` isn't an integer multiple of 2⁻⁵³.
+
+The following recipe takes a different approach.  All floats in the
+interval are possible selections.  The mantissa comes from a uniform
+distribution of integers in the range *2⁵² ≤ mantissa < 2⁵³*.  The
+exponent comes from a geometric distribution where exponents smaller
+than *-53* occur half as often as the next larger exponent.
+
+::
+
+    from random import Random
+    from math import ldexp
+
+    class FullRandom(Random):
+
+        def random(self):
+            mantissa = 0x10_0000_0000_0000 | self.getrandbits(52)
+            exponent = -53
+            x = 0
+            while not x:
+                x = self.getrandbits(32)
+                exponent += x.bit_length() - 32
+            return ldexp(mantissa, exponent)
+
+All :ref:`real valued distributions <real-valued-distributions>`
+in the class will use the new method::
+
+    >>> fr = FullRandom()
+    >>> fr.random()
+    0.05954861408025609
+    >>> fr.expovariate(0.25)
+    8.87925541791544
+
+The recipe is conceptually equivalent to an algorithm that chooses from
+all the multiples of 2⁻¹⁰⁷⁴ in the range *0.0 ≤ x < 1.0*.  All such
+numbers are evenly spaced, but most have to be rounded down to the
+nearest representable Python float.  (The value 2⁻¹⁰⁷⁴ is the smallest
+positive unnormalized float and is equal to ``math.ulp(0.0)``.)
+
+
+.. seealso::
+
+   `Generating Pseudo-random Floating-Point Values
+   <https://allendowney.com/research/rand/downey07randfloat.pdf>`_ a
+   paper by Allen B. Downey describing ways to generate more
+   fine-grained floats than normally generated by :func:`.random`.
index 1b094aeb9ca3d80ab5cc41bcb117d86e3f65f06e..fd3ce7445b5111f498a0169a1aa334a72347d834 100644 (file)
@@ -349,7 +349,7 @@ Directory and files operations
    will be created in or as *dst* and *src* will be removed.
 
    If *copy_function* is given, it must be a callable that takes two arguments
-   *src* and *dst*, and will be used to copy *src* to *dest* if
+   *src* and *dst*, and will be used to copy *src* to *dst* if
    :func:`os.rename` cannot be used.  If the source is a directory,
    :func:`copytree` is called, passing it the :func:`copy_function`. The
    default *copy_function* is :func:`copy2`.  Using :func:`~shutil.copy` as the
index b424e1ba348d870a7534d54cec06a29fcb9cec88..2e3646f6a74f80ce19d9aa7725a7388a1980a3b2 100644 (file)
@@ -231,7 +231,9 @@ Module contents
 
    Return the path of the user-specific site-packages directory,
    :data:`USER_SITE`.  If it is not initialized yet, this function will also set
-   it, respecting :envvar:`PYTHONNOUSERSITE` and :data:`USER_BASE`.
+   it, respecting :data:`USER_BASE`.  To determine if the user-specific
+   site-packages was added to ``sys.path`` :data:`ENABLE_USER_SITE` should be
+   used.
 
    .. versionadded:: 3.2
 
index 3900e49679a3847d2e94c27362ab920a760c3d54..e8f34e44a0c0ecedcdc637c393b13a8c9c8c6bed 100644 (file)
@@ -1461,7 +1461,7 @@ Context manager types
    .. versionadded:: 3.6.0
 
    .. deprecated:: 3.9
-      :class:`collections.contextlib.AbstractContextManager` now supports ``[]``. See :pep:`585`.
+      :class:`contextlib.AbstractContextManager` now supports ``[]``. See :pep:`585`.
 
 .. class:: AsyncContextManager(Generic[T_co])
 
@@ -1471,7 +1471,7 @@ Context manager types
    .. versionadded:: 3.6.2
 
    .. deprecated:: 3.9
-      :class:`collections.contextlib.AbstractAsyncContextManager` now supports ``[]``. See :pep:`585`.
+      :class:`contextlib.AbstractAsyncContextManager` now supports ``[]``. See :pep:`585`.
 
 Protocols
 ---------
@@ -1691,7 +1691,7 @@ Constant
 
       If ``from __future__ import annotations`` is used in Python 3.7 or later,
       annotations are not evaluated at function definition time.
-      Instead, the are stored as strings in ``__annotations__``,
+      Instead, they are stored as strings in ``__annotations__``,
       This makes it unnecessary to use quotes around the annotation.
       (see :pep:`563`).
 
index 285bb9e8cbe626d1d5a943cfc4c499f3773039d3..8a4fd25322e33f8c4332adf132a4c6a276e93c8d 100644 (file)
@@ -1088,7 +1088,8 @@ Test cases
 
       If given, *logger* should be a :class:`logging.Logger` object or a
       :class:`str` giving the name of a logger.  The default is the root
-      logger, which will catch all messages.
+      logger, which will catch all messages that were not blocked by a
+      non-propagating descendent logger.
 
       If given, *level* should be either a numeric logging level or
       its string equivalent (for example either ``"ERROR"`` or
index 7725e4d158d429e90be266ef91450bec628f2f11..f4bccf6609810ee05814d0ce5a0eac1654f197f5 100644 (file)
@@ -251,12 +251,18 @@ We can remove elements using :meth:`Element.remove`.  Let's say we want to
 remove all countries with a rank higher than 50::
 
    >>> for country in root.findall('country'):
+   ...     # using root.findall() to avoid removal during traversal
    ...     rank = int(country.find('rank').text)
    ...     if rank > 50:
    ...         root.remove(country)
    ...
    >>> tree.write('output.xml')
 
+Note that concurrent modification while iterating can lead to problems,
+just like when iterating and modifying Python lists or dicts.
+Therefore, the example first collects all matching elements with
+``root.findall()``, and only then iterates over the list of matches.
+
 Our XML now looks like this:
 
 .. code-block:: xml
index fc304a191a3149ba3bb6d30ca12671c5896d9121..354c6ce53f76f03cee6a83c077a84aeb790ac173 100644 (file)
@@ -2376,10 +2376,11 @@ left undefined.
 
    .. note::
 
-      If the right operand's type is a subclass of the left operand's type and that
-      subclass provides the reflected method for the operation, this method will be
-      called before the left operand's non-reflected method.  This behavior allows
-      subclasses to override their ancestors' operations.
+      If the right operand's type is a subclass of the left operand's type and
+      that subclass provides a different implementation of the reflected method
+      for the operation, this method will be called before the left operand's
+      non-reflected method. This behavior allows subclasses to override their
+      ancestors' operations.
 
 
 .. method:: object.__iadd__(self, other)
@@ -2778,6 +2779,6 @@ An example of an asynchronous context manager class::
    method—that will instead have the opposite effect of explicitly
    *blocking* such fallback.
 
-.. [#] For operands of the same type, it is assumed that if the non-reflected method
-   (such as :meth:`__add__`) fails the operation is not supported, which is why the
-   reflected method is not called.
+.. [#] For operands of the same type, it is assumed that if the non-reflected
+   method -- such as :meth:`__add__` -- fails then the overall operation is not
+   supported, which is why the reflected method is not called.
index f08f4abbfa0f15c07e01c6f3ff2ebb527464ede0..2fad9ec00cd568b0025d1ce4caa45f25465e1a47 100644 (file)
@@ -31,7 +31,12 @@ from sphinx.util import status_iterator, logging
 from sphinx.util.nodes import split_explicit_title
 from sphinx.writers.text import TextWriter, TextTranslator
 from sphinx.writers.latex import LaTeXTranslator
-from sphinx.domains.python import PyModulelevel, PyClassmember
+
+try:
+    from sphinx.domains.python import PyFunction, PyMethod
+except ImportError:
+    from sphinx.domains.python import PyClassmember as PyMethod
+    from sphinx.domains.python import PyModulelevel as PyFunction
 
 # Support for checking for suspicious markup
 
@@ -238,17 +243,18 @@ class PyDecoratorMixin(object):
         return False
 
 
-class PyDecoratorFunction(PyDecoratorMixin, PyModulelevel):
+class PyDecoratorFunction(PyDecoratorMixin, PyFunction):
     def run(self):
         # a decorator function is a function after all
         self.name = 'py:function'
-        return PyModulelevel.run(self)
+        return PyFunction.run(self)
 
 
-class PyDecoratorMethod(PyDecoratorMixin, PyClassmember):
+# TODO: Use sphinx.domains.python.PyDecoratorMethod when possible
+class PyDecoratorMethod(PyDecoratorMixin, PyMethod):
     def run(self):
         self.name = 'py:method'
-        return PyClassmember.run(self)
+        return PyMethod.run(self)
 
 
 class PyCoroutineMixin(object):
@@ -265,31 +271,31 @@ class PyAwaitableMixin(object):
         return ret
 
 
-class PyCoroutineFunction(PyCoroutineMixin, PyModulelevel):
+class PyCoroutineFunction(PyCoroutineMixin, PyFunction):
     def run(self):
         self.name = 'py:function'
-        return PyModulelevel.run(self)
+        return PyFunction.run(self)
 
 
-class PyCoroutineMethod(PyCoroutineMixin, PyClassmember):
+class PyCoroutineMethod(PyCoroutineMixin, PyMethod):
     def run(self):
         self.name = 'py:method'
-        return PyClassmember.run(self)
+        return PyMethod.run(self)
 
 
-class PyAwaitableFunction(PyAwaitableMixin, PyClassmember):
+class PyAwaitableFunction(PyAwaitableMixin, PyFunction):
     def run(self):
         self.name = 'py:function'
-        return PyClassmember.run(self)
+        return PyFunction.run(self)
 
 
-class PyAwaitableMethod(PyAwaitableMixin, PyClassmember):
+class PyAwaitableMethod(PyAwaitableMixin, PyMethod):
     def run(self):
         self.name = 'py:method'
-        return PyClassmember.run(self)
+        return PyMethod.run(self)
 
 
-class PyAbstractMethod(PyClassmember):
+class PyAbstractMethod(PyMethod):
 
     def handle_signature(self, sig, signode):
         ret = super(PyAbstractMethod, self).handle_signature(sig, signode)
@@ -299,7 +305,7 @@ class PyAbstractMethod(PyClassmember):
 
     def run(self):
         self.name = 'py:method'
-        return PyClassmember.run(self)
+        return PyMethod.run(self)
 
 
 # Support for documenting version of removal in deprecations
index a2fa17811b3fc8999177b61eef2ea923f79fed41..6a9fa3415694654cb1a61aafc31c382df6e66a75 100644 (file)
@@ -870,8 +870,18 @@ clipboard.  Converting strings from Tcl to Python and back now never fails.
 (Many people worked on this for eight years but the problem was finally
 solved by Serhiy Storchaka in :issue:`13153`.)
 
+New in 3.8.1:
+
+Add option to toggle cursor blink off.  (Contributed by Zackery Spytz
+in :issue:`4603`.)
+
+Escape key now closes IDLE completion windows.  (Contributed by Johnny
+Najera in :issue:`38944`.)
+
 The changes above have been backported to 3.7 maintenance releases.
 
+Add keywords to module name completion list.  (Contributed by Terry J.
+Reedy in :issue:`37765`.)
 
 inspect
 -------
index 9a09e710a3d2e1fcc8575ad72809b721bc07fb18..da0718561537b1c12b2664a894cba6740ce5da88 100644 (file)
@@ -781,41 +781,41 @@ Here's a summary of performance improvements from Python 3.4 through Python 3.9:
     --------------                       ---     ---     ---     ---     ---    ---
 
     Variable and attribute read access:
-        read_local                       7.1     7.1     5.4     5.1     3.9    4.0
-        read_nonlocal                    7.1     8.1     5.8     5.4     4.4    4.8
-        read_global                     15.5    19.0    14.3    13.6     7.6    7.7
-        read_builtin                    21.1    21.6    18.5    19.0     7.5    7.7
-        read_classvar_from_class        25.6    26.5    20.7    19.5    18.4   18.6
-        read_classvar_from_instance     22.8    23.5    18.8    17.1    16.4   20.1
-        read_instancevar                32.4    33.1    28.0    26.3    25.4   27.7
-        read_instancevar_slots          27.8    31.3    20.8    20.8    20.2   24.5
-        read_namedtuple                 73.8    57.5    45.0    46.8    18.4   23.2
-        read_boundmethod                37.6    37.9    29.6    26.9    27.7   45.9
+        read_local                       7.1     7.1     5.4     5.1     3.9    3.9
+        read_nonlocal                    7.1     8.1     5.8     5.4     4.4    4.5
+        read_global                     15.5    19.0    14.3    13.6     7.6    7.8
+        read_builtin                    21.1    21.6    18.5    19.0     7.5    7.8
+        read_classvar_from_class        25.6    26.5    20.7    19.5    18.4   17.9
+        read_classvar_from_instance     22.8    23.5    18.8    17.1    16.4   16.9
+        read_instancevar                32.4    33.1    28.0    26.3    25.4   25.3
+        read_instancevar_slots          27.8    31.3    20.8    20.8    20.2   20.5
+        read_namedtuple                 73.8    57.5    45.0    46.8    18.4   18.7
+        read_boundmethod                37.6    37.9    29.6    26.9    27.7   41.1
 
     Variable and attribute write access:
-        write_local                      8.7     9.3     5.5     5.3     4.3    4.2
-        write_nonlocal                  10.5    11.1     5.6     5.5     4.7    4.9
-        write_global                    19.7    21.2    18.0    18.0    15.8   17.2
-        write_classvar                  92.9    96.0   104.6   102.1    39.2   43.2
-        write_instancevar               44.6    45.8    40.0    38.9    35.5   40.7
-        write_instancevar_slots         35.6    36.1    27.3    26.6    25.7   27.7
+        write_local                      8.7     9.3     5.5     5.3     4.3    4.3
+        write_nonlocal                  10.5    11.1     5.6     5.5     4.7    4.8
+        write_global                    19.7    21.2    18.0    18.0    15.8   16.7
+        write_classvar                  92.9    96.0   104.6   102.1    39.2   39.8
+        write_instancevar               44.6    45.8    40.0    38.9    35.5   37.4
+        write_instancevar_slots         35.6    36.1    27.3    26.6    25.7   25.8
 
     Data structure read access:
-        read_list                       24.2    24.5    20.8    20.8    19.0   21.1
-        read_deque                      24.7    25.5    20.2    20.6    19.8   21.6
-        read_dict                       24.3    25.7    22.3    23.0    21.0   22.5
-        read_strdict                    22.6    24.3    19.5    21.2    18.9   21.6
+        read_list                       24.2    24.5    20.8    20.8    19.0   19.5
+        read_deque                      24.7    25.5    20.2    20.6    19.8   20.2
+        read_dict                       24.3    25.7    22.3    23.0    21.0   22.4
+        read_strdict                    22.6    24.3    19.5    21.2    18.9   21.5
 
     Data structure write access:
-        write_list                      27.1    28.5    22.5    21.6    20.0   21.6
-        write_deque                     28.7    30.1    22.7    21.8    23.5   23.2
-        write_dict                      31.4    33.3    29.3    29.2    24.7   27.8
-        write_strdict                   28.4    29.9    27.5    25.2    23.1   29.8
+        write_list                      27.1    28.5    22.5    21.6    20.0   20.0
+        write_deque                     28.7    30.1    22.7    21.8    23.5   21.7
+        write_dict                      31.4    33.3    29.3    29.2    24.7   25.4
+        write_strdict                   28.4    29.9    27.5    25.2    23.1   24.5
 
     Stack (or queue) operations:
-        list_append_pop                 93.4   112.7    75.4    74.2    50.8   53.9
-        deque_append_pop                43.5    57.0    49.4    49.2    42.5   45.5
-        deque_append_popleft            43.7    57.3    49.7    49.7    42.8   45.5
+        list_append_pop                 93.4   112.7    75.4    74.2    50.8   50.6
+        deque_append_pop                43.5    57.0    49.4    49.2    42.5   44.2
+        deque_append_popleft            43.7    57.3    49.7    49.7    42.8   46.4
 
     Timing loop:
         loop_overhead                    0.5     0.6     0.4     0.3     0.3    0.3
@@ -891,7 +891,7 @@ Deprecated
   and will be removed in future Python versions.  ``value`` itself should be
   used instead of ``Index(value)``.  ``Tuple(slices, Load())`` should be
   used instead of ``ExtSlice(slices)``.
-  (Contributed by Serhiy Storchaka in :issue:`32892`.)
+  (Contributed by Serhiy Storchaka in :issue:`34822`.)
 
 * :mod:`ast` classes ``Suite``, ``Param``, ``AugLoad`` and ``AugStore``
   are considered deprecated and will be removed in future Python versions.
index 334a7f56f01070ae914b3b38a66f361012d98c23..8f4d250dc3ae4d7b4d582568de12f5d42b08fd7d 100644 (file)
@@ -182,7 +182,7 @@ with_stmt[stmt_ty]:
     | ASYNC 'with' a=','.with_item+ ':' tc=[TYPE_COMMENT] b=block {
        CHECK_VERSION(5, "Async with statements are", _Py_AsyncWith(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA)) }
 with_item[withitem_ty]:
-    | e=expression 'as' t=target &(',' | ')' | ':') { _Py_withitem(e, t, p->arena) }
+    | e=expression 'as' t=star_target &(',' | ')' | ':') { _Py_withitem(e, t, p->arena) }
     | invalid_with_item
     | e=expression { _Py_withitem(e, NULL, p->arena) }
 
index 57eac13c064c2e8905bd8c1d57c93405b7c00842..3005ce1f00f9d5b7644fde56fb064ade7abbff5f 100644 (file)
@@ -8,14 +8,6 @@ extern "C" {
 
 PyAPI_FUNC(char *) Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *);
 
-#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000
-PyAPI_DATA(const char *) Py_FileSystemDefaultEncodeErrors;
-#endif
-
-#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000
-PyAPI_DATA(int) Py_UTF8Mode;
-#endif
-
 /* The std printer acts as a preliminary sys.stderr until the new io
    infrastructure is in place. */
 PyAPI_FUNC(PyObject *) PyFile_NewStdPrinter(int);
index 456887ef9d045da0e5fa3147554164cd01a70522..6ec2994aa859b6fbcd71d12fd283733ea1d049ab 100644 (file)
@@ -20,8 +20,15 @@ PyAPI_FUNC(int) PyObject_AsFileDescriptor(PyObject *);
    If non-NULL, this is different than the default encoding for strings
 */
 PyAPI_DATA(const char *) Py_FileSystemDefaultEncoding;
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000
+PyAPI_DATA(const char *) Py_FileSystemDefaultEncodeErrors;
+#endif
 PyAPI_DATA(int) Py_HasFileSystemDefaultEncoding;
 
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000
+PyAPI_DATA(int) Py_UTF8Mode;
+#endif
+
 /* A routine to check if a file descriptor can be select()-ed. */
 #ifdef _MSC_VER
     /* On Windows, any socket fd can be select()-ed, no matter how high */
index a9e8ef19e9cbc75db08ffdc9d541455e4c08e1a3..2243329744ced02f12444e079fb81920769307d5 100644 (file)
@@ -23,7 +23,7 @@
 #define PY_RELEASE_SERIAL       0
 
 /* Version as a string */
-#define PY_VERSION              "3.9.0"
+#define PY_VERSION              "3.9.0+"
 /*--end constants--*/
 
 /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
index 4f202038d61260a250138c08d319c1cd499bf00e..59b4699feb5062aef3fef5110be0acf8d7ae4e61 100755 (executable)
@@ -152,6 +152,11 @@ def main():
     (options, args) = parser.parse_args()
     sys.argv[:] = args
 
+    # The script that we're profiling may chdir, so capture the absolute path
+    # to the output file at startup.
+    if options.outfile is not None:
+        options.outfile = os.path.abspath(options.outfile)
+
     if len(args) > 0:
         if options.module:
             code = "run_module(modname, run_name='__main__')"
index b99fdcba7b28fc2b248c17d4aef8e449a3e21f3d..92ac1840ad7d435e72d47c89e6e175a48e321630 100644 (file)
@@ -1,4 +1,5 @@
 import unittest
+import unittest.mock
 import os.path
 import sys
 import test.support
@@ -72,7 +73,7 @@ class Test_OpenGL_libs(unittest.TestCase):
 
 @unittest.skipUnless(sys.platform.startswith('linux'),
                      'Test only valid for Linux')
-class LibPathFindTest(unittest.TestCase):
+class FindLibraryLinux(unittest.TestCase):
     def test_find_on_libpath(self):
         import subprocess
         import tempfile
@@ -111,6 +112,15 @@ class LibPathFindTest(unittest.TestCase):
                 # LD_LIBRARY_PATH)
                 self.assertEqual(find_library(libname), 'lib%s.so' % libname)
 
+    def test_find_library_with_gcc(self):
+        with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None):
+            self.assertNotEqual(find_library('c'), None)
+
+    def test_find_library_with_ld(self):
+        with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None), \
+             unittest.mock.patch("ctypes.util._findLib_gcc", lambda *args: None):
+            self.assertNotEqual(find_library('c'), None)
+
 
 if __name__ == "__main__":
     unittest.main()
index 01176bf9696577008ffdb6f06bc2bdf2f15752c1..0c2510e1619c8ed33f49aeacfbc72b118ad9d27a 100644 (file)
@@ -93,6 +93,12 @@ elif os.name == "posix":
     # Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
     import re, tempfile
 
+    def _is_elf(filename):
+        "Return True if the given file is an ELF file"
+        elf_header = b'\x7fELF'
+        with open(filename, 'br') as thefile:
+            return thefile.read(4) == elf_header
+
     def _findLib_gcc(name):
         # Run GCC's linker with the -t (aka --trace) option and examine the
         # library name it prints out. The GCC command will fail because we
@@ -130,10 +136,17 @@ elif os.name == "posix":
                 # Raised if the file was already removed, which is the normal
                 # behaviour of GCC if linking fails
                 pass
-        res = re.search(expr, trace)
+        res = re.findall(expr, trace)
         if not res:
             return None
-        return os.fsdecode(res.group(0))
+
+        for file in res:
+            # Check if the given file is an elf file: gcc can report
+            # some files that are linker scripts and not actual
+            # shared objects. See bpo-41976 for more details
+            if not _is_elf(file):
+                continue
+            return os.fsdecode(file)
 
 
     if sys.platform == "sunos5":
@@ -299,9 +312,14 @@ elif os.name == "posix":
                                      stderr=subprocess.PIPE,
                                      universal_newlines=True)
                 out, _ = p.communicate()
-                res = re.search(expr, os.fsdecode(out))
-                if res:
-                    result = res.group(0)
+                res = re.findall(expr, os.fsdecode(out))
+                for file in res:
+                    # Check if the given file is an elf file: gcc can report
+                    # some files that are linker scripts and not actual
+                    # shared objects. See bpo-41976 for more details
+                    if not _is_elf(file):
+                        continue
+                    return os.fsdecode(file)
             except Exception:
                 pass  # result will be None
             return result
@@ -309,7 +327,7 @@ elif os.name == "posix":
         def find_library(name):
             # See issue #9998
             return _findSoname_ldconfig(name) or \
-                   _get_soname(_findLib_gcc(name) or _findLib_ld(name))
+                   _get_soname(_findLib_gcc(name)) or _get_soname(_findLib_ld(name))
 
 ################################################################
 # test code
index 2294ac2b6873a55eedac8a503747f47399671158..e508d996fb1ed199ed638eaf6990aa696efec481 100644 (file)
@@ -1579,7 +1579,7 @@ class time:
         self._tzinfo = tzinfo
 
     def __reduce_ex__(self, protocol):
-        return (time, self._getstate(protocol))
+        return (self.__class__, self._getstate(protocol))
 
     def __reduce__(self):
         return self.__reduce_ex__(2)
index 948f62f1dc3034082b5f25a3399e9dfd6ba276ef..d0e7a4814c565dc8cd0ccba81c25fa439978c478 100644 (file)
@@ -22,7 +22,8 @@ class _NodeInfo:
 
 
 class CycleError(ValueError):
-    """Subclass of ValueError raised by TopologicalSorterif cycles exist in the graph
+    """Subclass of ValueError raised by TopologicalSorter.prepare if cycles
+    exist in the working graph.
 
     If multiple cycles exist, only one undefined choice among them will be reported
     and included in the exception. The detected cycle can be accessed via the second
@@ -129,7 +130,7 @@ class TopologicalSorter:
         return result
 
     def is_active(self):
-        """Return True if more progress can be made and ``False`` otherwise.
+        """Return ``True`` if more progress can be made and ``False`` otherwise.
 
         Progress can be made if cycles do not block the resolution and either there
         are still nodes ready that haven't yet been returned by "get_ready" or the
@@ -149,7 +150,7 @@ class TopologicalSorter:
         """Marks a set of nodes returned by "get_ready" as processed.
 
         This method unblocks any successor of each node in *nodes* for being returned
-        in the future by a a call to "get_ready"
+        in the future by a call to "get_ready".
 
         Raises :exec:`ValueError` if any node in *nodes* has already been marked as
         processed by a previous call to this method, if a node was not added to the
index fd762077b1b3cf9f790c67ab9a4237fa661762f3..5ea33226cc0c3a23dcbdf25202fd7dbdc3c4c493 100644 (file)
@@ -1,8 +1,20 @@
+What's New in IDLE 3.9.1
+Released on 2020-12-07?
+======================================
+
+
+bpo-41775: Make 'IDLE Shell' the shell title.
+
+bpo-35764: Rewrite the Calltips doc section.
+
+bpo-40181: In calltips, stop reminding that '/' marks the end of
+positional-only arguments.
+
+
 What's New in IDLE 3.9.0 (since 3.8.0)
 Released on 2020-10-05?
 ======================================
 
-
 bpo-41468: Improve IDLE run crash error message (which users should
 never see).
 
index d4092c7847186bf6317fe0cdc97e5bd1d00ec520..b02f87207d8db18a228ce0b0468f5faadacb3efd 100644 (file)
@@ -118,7 +118,6 @@ _INDENT = ' '*4  # for wrapped signatures
 _first_param = re.compile(r'(?<=\()\w*\,?\s*')
 _default_callable_argspec = "See source or doc"
 _invalid_method = "invalid method signature"
-_argument_positional = "  # '/' marks preceding args as positional-only."
 
 def get_argspec(ob):
     '''Return a string describing the signature of a callable object, or ''.
@@ -146,9 +145,6 @@ def get_argspec(ob):
         else:
             argspec = ''
 
-    if '/' in argspec and len(argspec) < _MAX_COLS - len(_argument_positional):
-        # Add explanation TODO remove after 3.7, before 3.9.
-        argspec += _argument_positional
     if isinstance(fob, type) and argspec == '()':
         # If fob has no argument, use default callable argspec.
         argspec = _default_callable_argspec
index b2853cffe0c26d66e144595534770b66d0aea0fb..0edd3917e1ffa5c75c88b974ce36012c99a68f00 100644 (file)
@@ -509,26 +509,29 @@ by typing ‘_’ after ‘.’, either before or after the box is opened.</p>
 </div>
 <div class="section" id="calltips">
 <span id="id4"></span><h3>Calltips<a class="headerlink" href="#calltips" title="Permalink to this headline">¶</a></h3>
-<p>A calltip is shown when one types <kbd class="kbd docutils literal notranslate">(</kbd> after the name of an <em>accessible</em>
-function.  A name expression may include dots and subscripts.  A calltip
-remains until it is clicked, the cursor is moved out of the argument area,
-or <kbd class="kbd docutils literal notranslate">)</kbd> is typed.  When the cursor is in the argument part of a definition,
-the menu or shortcut display a calltip.</p>
-<p>A calltip consists of the function signature and the first line of the
-docstring.  For builtins without an accessible signature, the calltip
-consists of all lines up the fifth line or the first blank line.  These
-details may change.</p>
-<p>The set of <em>accessible</em> functions depends on what modules have been imported
-into the user process, including those imported by Idle itself,
-and what definitions have been run, all since the last restart.</p>
+<p>A calltip is shown automatically when one types <kbd class="kbd docutils literal notranslate">(</kbd> after the name
+of an <em>accessible</em> function.  A function name expression may include
+dots and subscripts.  A calltip remains until it is clicked, the cursor
+is moved out of the argument area, or <kbd class="kbd docutils literal notranslate">)</kbd> is typed.  Whenever the
+cursor is in the argument part of a definition, select Edit and “Show
+Call Tip” on the menu or enter its shortcut to display a calltip.</p>
+<p>The calltip consists of the function’s signature and docstring up to
+the latter’s first blank line or the fifth non-blank line.  (Some builtin
+functions lack an accessible signature.)  A ‘/’ or ‘*’ in the signature
+indicates that the preceding or following arguments are passed by
+position or name (keyword) only.  Details are subject to change.</p>
+<p>In Shell, the accessible functions depends on what modules have been
+imported into the user process, including those imported by Idle itself,
+and which definitions have been run, all since the last restart.</p>
 <p>For example, restart the Shell and enter <code class="docutils literal notranslate"><span class="pre">itertools.count(</span></code>.  A calltip
-appears because Idle imports itertools into the user process for its own use.
-(This could change.)  Enter <code class="docutils literal notranslate"><span class="pre">turtle.write(</span></code> and nothing appears.  Idle does
-not import turtle.  The menu or shortcut do nothing either.  Enter
-<code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">turtle</span></code> and then <code class="docutils literal notranslate"><span class="pre">turtle.write(</span></code> will work.</p>
-<p>In an editor, import statements have no effect until one runs the file.  One
-might want to run a file after writing the import statements at the top,
-or immediately run an existing file before editing.</p>
+appears because Idle imports itertools into the user process for its own
+use.  (This could change.)  Enter <code class="docutils literal notranslate"><span class="pre">turtle.write(</span></code> and nothing appears.
+Idle does not itself import turtle.  The menu entry and shortcut also do
+nothing.  Enter <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">turtle</span></code>.  Thereafter, <code class="docutils literal notranslate"><span class="pre">turtle.write(</span></code>
+will display a calltip.</p>
+<p>In an editor, import statements have no effect until one runs the file.
+One might want to run a file after writing import statements, after
+adding function definitions, or after opening an existing file.</p>
 </div>
 <div class="section" id="code-context">
 <span id="id5"></span><h3>Code Context<a class="headerlink" href="#code-context" title="Permalink to this headline">¶</a></h3>
@@ -975,7 +978,7 @@ also used for testing.</p>
 <br />
     <br />
 
-    Last updated on Sep 09, 2020.
+    Last updated on Sep 22, 2020.
     <a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
     <br />
 
index d386b5cd8132124bc9c8f3b3fe38bb209baa6955..4d53df17d8cc7c79188fe6a7f034bbada56068a2 100644 (file)
@@ -61,18 +61,16 @@ class Get_argspecTest(unittest.TestCase):
 
         if List.__doc__ is not None:
             tiptest(List,
-                    f'(iterable=(), /){calltip._argument_positional}'
+                    f'(iterable=(), /)'
                     f'\n{List.__doc__}')
         tiptest(list.__new__,
               '(*args, **kwargs)\n'
               'Create and return a new object.  '
               'See help(type) for accurate signature.')
         tiptest(list.__init__,
-              '(self, /, *args, **kwargs)'
-              + calltip._argument_positional + '\n' +
+              '(self, /, *args, **kwargs)\n'
               'Initialize self.  See help(type(self)) for accurate signature.')
-        append_doc = (calltip._argument_positional
-                      + "\nAppend object to the end of the list.")
+        append_doc = "\nAppend object to the end of the list."
         tiptest(list.append, '(self, object, /)' + append_doc)
         tiptest(List.append, '(self, object, /)' + append_doc)
         tiptest([].append, '(object, /)' + append_doc)
index 66ae0f7435daba7df06a2d37bc9d4ff66ac382b7..b69916dbe876cae7afce2d6f6aac3850f54def8f 100755 (executable)
@@ -833,7 +833,7 @@ class ModifiedInterpreter(InteractiveInterpreter):
 
 class PyShell(OutputWindow):
 
-    shell_title = "Python " + python_version() + " Shell"
+    shell_title = "IDLE Shell " + python_version()
 
     # Override classes
     ColorDelegator = ModifiedColorDelegator
index 403dc81b13ef4e235b8300a6d867b8e941ef6325..7b169a16fbb70f7bb53287360bcf31413a0aad45 100644 (file)
@@ -509,7 +509,7 @@ class Formatter(object):
     responsible for converting a LogRecord to (usually) a string which can
     be interpreted by either a human or an external system. The base Formatter
     allows a formatting string to be specified. If none is supplied, the
-    the style-dependent default value, "%(message)s", "{message}", or
+    style-dependent default value, "%(message)s", "{message}", or
     "${message}", is used.
 
     The Formatter can be initialized with a format string which makes use of
@@ -748,8 +748,8 @@ class Filter(object):
         """
         Determine if the specified record is to be logged.
 
-        Is the specified record to be logged? Returns 0 for no, nonzero for
-        yes. If deemed appropriate, the record may be modified in-place.
+        Returns True if the record should be logged, or False otherwise.
+        If deemed appropriate, the record may be modified in-place.
         """
         if self.nlen == 0:
             return True
index aad458dc951f4113c723cfb1dbd678f59817ee32..5cb017ed8300993ad9767db967e105926e2f0159 100755 (executable)
@@ -571,6 +571,11 @@ def main():
     (options, args) = parser.parse_args()
     sys.argv[:] = args
 
+    # The script that we're profiling may chdir, so capture the absolute path
+    # to the output file at startup.
+    if options.outfile is not None:
+        options.outfile = os.path.abspath(options.outfile)
+
     if len(args) > 0:
         if options.module:
             import runpy
index e781b91c6052cfdae924f547140cfc36cecffe14..0f93ae02c95074dfd6bddff780474d11c28a654c 100644 (file)
@@ -45,9 +45,9 @@ class SortKey(str, Enum):
     TIME = 'time', 'tottime'
 
     def __new__(cls, *values):
-        obj = str.__new__(cls)
-
-        obj._value_ = values[0]
+        value = values[0]
+        obj = str.__new__(cls, value)
+        obj._value_ = value
         for other_value in values[1:]:
             cls._value2member_map_[other_value] = obj
         obj._all_values = values
index a711676582f649f52d370367a1978742d94b7d1a..521540fe9eeec6849252221e729e5e6d671b398a 100644 (file)
@@ -34,7 +34,7 @@ class SymbolTableFactory:
 _newSymbolTable = SymbolTableFactory()
 
 
-class SymbolTable(object):
+class SymbolTable:
 
     def __init__(self, raw_table, filename):
         self._table = raw_table
@@ -47,7 +47,7 @@ class SymbolTable(object):
         else:
             kind = "%s " % self.__class__.__name__
 
-        if self._table.name == "global":
+        if self._table.name == "top":
             return "<{0}SymbolTable for module {1}>".format(kind, self._filename)
         else:
             return "<{0}SymbolTable for {1} in {2}>".format(kind,
@@ -90,7 +90,9 @@ class SymbolTable(object):
         if sym is None:
             flags = self._table.symbols[name]
             namespaces = self.__check_children(name)
-            sym = self._symbols[name] = Symbol(name, flags, namespaces)
+            module_scope = (self._table.name == "top")
+            sym = self._symbols[name] = Symbol(name, flags, namespaces,
+                                               module_scope=module_scope)
         return sym
 
     def get_symbols(self):
@@ -163,13 +165,14 @@ class Class(SymbolTable):
         return self.__methods
 
 
-class Symbol(object):
+class Symbol:
 
-    def __init__(self, name, flags, namespaces=None):
+    def __init__(self, name, flags, namespaces=None, *, module_scope=False):
         self.__name = name
         self.__flags = flags
         self.__scope = (flags >> SCOPE_OFF) & SCOPE_MASK # like PyST_GetScope()
         self.__namespaces = namespaces or ()
+        self.__module_scope = module_scope
 
     def __repr__(self):
         return "<symbol {0!r}>".format(self.__name)
@@ -184,7 +187,10 @@ class Symbol(object):
         return bool(self.__flags & DEF_PARAM)
 
     def is_global(self):
-        return bool(self.__scope in (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT))
+        """Return *True* if the sysmbol is global.
+        """
+        return bool(self.__scope in (GLOBAL_IMPLICIT, GLOBAL_EXPLICIT)
+                    or (self.__module_scope and self.__flags & DEF_BOUND))
 
     def is_nonlocal(self):
         return bool(self.__flags & DEF_NONLOCAL)
@@ -193,7 +199,10 @@ class Symbol(object):
         return bool(self.__scope == GLOBAL_EXPLICIT)
 
     def is_local(self):
-        return bool(self.__scope in (LOCAL, CELL))
+        """Return *True* if the symbol is local.
+        """
+        return bool(self.__scope in (LOCAL, CELL)
+                    or (self.__module_scope and self.__flags & DEF_BOUND))
 
     def is_annotated(self):
         return bool(self.__flags & DEF_ANNOT)
index a9741d6d4062f497b10342bd3f57e681c1276c2d..b37ef9170787237f64fa67f6df4c54aa1af32818 100644 (file)
@@ -1781,6 +1781,7 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase):
             green = pickler.dumps(orig, proto)
             derived = unpickler.loads(green)
             self.assertEqual(orig, derived)
+            self.assertTrue(isinstance(derived, SubclassDate))
 
     def test_backdoor_resistance(self):
         # For fast unpickling, the constructor accepts a pickle byte string.
@@ -2308,6 +2309,7 @@ class TestDateTime(TestDate):
             green = pickler.dumps(orig, proto)
             derived = unpickler.loads(green)
             self.assertEqual(orig, derived)
+            self.assertTrue(isinstance(derived, SubclassDatetime))
 
     def test_compat_unpickle(self):
         tests = [
@@ -3357,6 +3359,7 @@ class TestTime(HarmlessMixedComparison, unittest.TestCase):
             green = pickler.dumps(orig, proto)
             derived = unpickler.loads(green)
             self.assertEqual(orig, derived)
+            self.assertTrue(isinstance(derived, SubclassTime))
 
     def test_compat_unpickle(self):
         tests = [
index cca8af67d6d1d6cc65f586517981b3a04aaf865d..f76c0153f5ecf7295c2536586f87cc72d5e12342 100644 (file)
@@ -305,29 +305,23 @@ class TestBase_Mapping(unittest.TestCase):
             self._test_mapping_file_plain()
 
     def _test_mapping_file_plain(self):
-        unichrs = lambda s: ''.join(map(chr, map(eval, s.split('+'))))
+        def unichrs(s):
+            return ''.join(chr(int(x, 16)) for x in s.split('+'))
+
         urt_wa = {}
 
         with self.open_mapping_file() as f:
             for line in f:
                 if not line:
                     break
-                data = line.split('#')[0].strip().split()
+                data = line.split('#')[0].split()
                 if len(data) != 2:
                     continue
 
-                csetval = eval(data[0])
-                if csetval <= 0x7F:
-                    csetch = bytes([csetval & 0xff])
-                elif csetval >= 0x1000000:
-                    csetch = bytes([(csetval >> 24), ((csetval >> 16) & 0xff),
-                                    ((csetval >> 8) & 0xff), (csetval & 0xff)])
-                elif csetval >= 0x10000:
-                    csetch = bytes([(csetval >> 16), ((csetval >> 8) & 0xff),
-                                    (csetval & 0xff)])
-                elif csetval >= 0x100:
-                    csetch = bytes([(csetval >> 8), (csetval & 0xff)])
-                else:
+                if data[0][:2] != '0x':
+                    self.fail(f"Invalid line: {line!r}")
+                csetch = bytes.fromhex(data[0][2:])
+                if len(csetch) == 1 and 0x80 <= csetch[0]:
                     continue
 
                 unich = unichrs(data[1])
index 54a3520802a4f317ccdb792765c4427689710d9a..8d112a171d7c4ef5f2138ff398d2b5270b3cccee 100644 (file)
@@ -2183,6 +2183,18 @@ class CharmapTest(unittest.TestCase):
             ("", len(allbytes))
         )
 
+        self.assertRaisesRegex(TypeError,
+            "character mapping must be in range\\(0x110000\\)",
+            codecs.charmap_decode,
+            b"\x00\x01\x02", "strict", {0: "A", 1: 'Bb', 2: -2}
+        )
+
+        self.assertRaisesRegex(TypeError,
+            "character mapping must be in range\\(0x110000\\)",
+            codecs.charmap_decode,
+            b"\x00\x01\x02", "strict", {0: "A", 1: 'Bb', 2: 999999999}
+        )
+
     def test_decode_with_int2int_map(self):
         a = ord('a')
         b = ord('b')
index 35d7913e5b89b52d90494da41bdee6fc92de4607..1d134430909d8487b5beb939515bce61e82a6093 100644 (file)
@@ -16,6 +16,15 @@ except ImportError:
                 raise TypeError('requires _testcapi.with_tp_del')
         return C
 
+try:
+    from _testcapi import without_gc
+except ImportError:
+    def without_gc(cls):
+        class C:
+            def __new__(cls, *args, **kwargs):
+                raise TypeError('requires _testcapi.without_gc')
+        return C
+
 from test import support
 
 
@@ -94,9 +103,11 @@ class SimpleBase(NonGCSimpleBase):
         assert self.id_ == id(self)
 
 
+@without_gc
 class NonGC(NonGCSimpleBase):
     __slots__ = ()
 
+@without_gc
 class NonGCResurrector(NonGCSimpleBase):
     __slots__ = ()
 
@@ -109,8 +120,14 @@ class NonGCResurrector(NonGCSimpleBase):
 class Simple(SimpleBase):
     pass
 
-class SimpleResurrector(NonGCResurrector, SimpleBase):
-    pass
+# Can't inherit from NonGCResurrector, in case importing without_gc fails.
+class SimpleResurrector(SimpleBase):
+
+    def side_effect(self):
+        """
+        Resurrect self by storing self in a class-wide list.
+        """
+        self.survivors.append(self)
 
 
 class TestBase:
@@ -178,6 +195,7 @@ class SimpleFinalizationTest(TestBase, unittest.TestCase):
             self.assert_survivors([])
         self.assertIs(wr(), None)
 
+    @support.cpython_only
     def test_non_gc(self):
         with SimpleBase.test():
             s = NonGC()
@@ -191,6 +209,7 @@ class SimpleFinalizationTest(TestBase, unittest.TestCase):
             self.assert_del_calls(ids)
             self.assert_survivors([])
 
+    @support.cpython_only
     def test_non_gc_resurrect(self):
         with SimpleBase.test():
             s = NonGCResurrector()
index acb6391944bc0b2a90594f44a09cec6277d40559..38c9cb7123311b618a85921a72a12c61a22cc078 100644 (file)
@@ -581,9 +581,9 @@ class GCTests(unittest.TestCase):
         self.assertTrue(gc.is_tracked(UserInt()))
         self.assertTrue(gc.is_tracked([]))
         self.assertTrue(gc.is_tracked(set()))
-        self.assertFalse(gc.is_tracked(UserClassSlots()))
-        self.assertFalse(gc.is_tracked(UserFloatSlots()))
-        self.assertFalse(gc.is_tracked(UserIntSlots()))
+        self.assertTrue(gc.is_tracked(UserClassSlots()))
+        self.assertTrue(gc.is_tracked(UserFloatSlots()))
+        self.assertTrue(gc.is_tracked(UserIntSlots()))
 
     def test_is_finalized(self):
         # Objects not tracked by the always gc return false
index ec1acd475ce5a2a8d120b2780d1c090e11d6e53f..240aad02518ff6c6ad81d64cdc0fc5103bf24160 100644 (file)
@@ -26,7 +26,7 @@ try:
 except ImportError:
     # multiprocessing.shared_memory is not available on e.g. Android
     ShareableList = None
-from multiprocessing.queues import SimpleQueue
+from multiprocessing.queues import SimpleQueue as MPSimpleQueue
 from os import DirEntry
 from re import Pattern, Match
 from types import GenericAlias, MappingProxyType, AsyncGeneratorType
@@ -79,7 +79,7 @@ class BaseTest(unittest.TestCase):
                   SplitResult, ParseResult,
                   ValueProxy, ApplyResult,
                   WeakSet, ReferenceType, ref,
-                  ShareableList, SimpleQueue,
+                  ShareableList, MPSimpleQueue,
                   Future, _WorkItem,
                   Morsel,
                   ):
index 53639e984e48a784cff38339c725ee1b9711be4e..31b38996930cc4e5d45f5ff5d39ee802fea4594f 100644 (file)
@@ -271,6 +271,16 @@ class TestIsInstanceIsSubclass(unittest.TestCase):
 
         self.assertEqual(True, issubclass(B(), int))
 
+    def test_infinite_recursion_in_bases(self):
+        class X:
+            @property
+            def __bases__(self):
+                return self.__bases__
+
+        self.assertRaises(RecursionError, issubclass, X(), int)
+        self.assertRaises(RecursionError, issubclass, int, X())
+        self.assertRaises(RecursionError, isinstance, 1, X())
+
 
 def blowstack(fxn, arg, compare_to):
     # Make sure that calling isinstance with a deeply nested tuple for its
index 15c317e957bc05e612d09cb15fa5a3f6de739423..e939d47336e365739faa942061ead06a7eaa67a9 100644 (file)
@@ -1,8 +1,8 @@
 import unittest
-from test.support import check_warnings
+from test.support import check_warnings, import_fresh_module
 
 with check_warnings(("", PendingDeprecationWarning)):
-    from lib2to3.tests import load_tests
+    load_tests = import_fresh_module('lib2to3.tests', fresh=['lib2to3']).load_tests
 
 if __name__ == '__main__':
     unittest.main()
index 62759c07017a34a45251f8f7bc9762403b219cd1..410eae2208688435aaa7251b81314850c0161471 100644 (file)
@@ -1161,22 +1161,27 @@ class MemoryHandlerTest(BaseTest):
         class MockRaceConditionHandler:
             def __init__(self, mem_hdlr):
                 self.mem_hdlr = mem_hdlr
+                self.threads = []
 
             def removeTarget(self):
                 self.mem_hdlr.setTarget(None)
 
             def handle(self, msg):
-                t = threading.Thread(target=self.removeTarget)
-                t.daemon = True
-                t.start()
+                thread = threading.Thread(target=self.removeTarget)
+                self.threads.append(thread)
+                thread.start()
 
         target = MockRaceConditionHandler(self.mem_hdlr)
-        self.mem_hdlr.setTarget(target)
+        try:
+            self.mem_hdlr.setTarget(target)
 
-        for _ in range(10):
-            time.sleep(0.005)
-            self.mem_logger.info("not flushed")
-            self.mem_logger.warning("flushed")
+            for _ in range(10):
+                time.sleep(0.005)
+                self.mem_logger.info("not flushed")
+                self.mem_logger.warning("flushed")
+        finally:
+            for thread in target.threads:
+                support.join_thread(thread)
 
 
 class ExceptionFormatter(logging.Formatter):
index 01a8a6eaf5a23cc9e95e821b1cc044d0dbbfa290..233649899ec20c0cf1a25fc4d4b1c9eff6d9f86e 100644 (file)
@@ -6,7 +6,7 @@ import unittest
 import os
 from difflib import unified_diff
 from io import StringIO
-from test.support import TESTFN, run_unittest, unlink
+from test.support import TESTFN, run_unittest, unlink, temp_dir, change_cwd
 from contextlib import contextmanager
 
 import profile
@@ -111,6 +111,20 @@ class ProfileTest(unittest.TestCase):
         assert_python_ok('-m', self.profilermodule.__name__,
                          '-m', 'timeit', '-n', '1')
 
+    def test_output_file_when_changing_directory(self):
+        with temp_dir() as tmpdir, change_cwd(tmpdir):
+            os.mkdir('dest')
+            with open('demo.py', 'w') as f:
+                f.write('import os; os.chdir("dest")')
+
+            assert_python_ok(
+                '-m', self.profilermodule.__name__,
+                '-o', 'out.pstats',
+                'demo.py',
+            )
+
+            self.assertTrue(os.path.exists('out.pstats'))
+
 
 def regenerate_expected_output(filename, cls):
     filename = filename.rstrip('co')
index 10559deb6bcb23a91b5cc690e06337910b79cd71..4f78b99fd1cae79a3fa5c9b37de0a71a25c09abd 100644 (file)
@@ -95,5 +95,9 @@ class StatsTestCase(unittest.TestCase):
         self.assertIn('pass2', funcs_called)
         self.assertIn('pass3', funcs_called)
 
+    def test_SortKey_enum(self):
+        self.assertEqual(SortKey.FILENAME, 'filename')
+        self.assertNotEqual(SortKey.FILENAME, SortKey.CALLS)
+
 if __name__ == "__main__":
     unittest.main()
index 923f35efe2ede6a36162b7007a6838b8b2156902..ffba139dbeade3443d069335e8895c580dd9cf43 100644 (file)
@@ -500,8 +500,6 @@ class ImportSideEffectTests(unittest.TestCase):
 
     @test.support.requires_resource('network')
     @test.support.system_must_validate_cert
-    @unittest.skipUnless(sys.version_info[3] == 'final',
-                         'only for released versions')
     @unittest.skipUnless(hasattr(urllib.request, "HTTPSHandler"),
                          'need SSL support to download license')
     def test_license_exists_at_url(self):
@@ -509,6 +507,8 @@ class ImportSideEffectTests(unittest.TestCase):
         # string displayed by license in the absence of a LICENSE file.
         url = license._Printer__data.split()[1]
         req = urllib.request.Request(url, method='HEAD')
+        # Reset global urllib.request._opener
+        self.addCleanup(urllib.request.urlcleanup)
         try:
             with socket_helper.transient_internet(url):
                 with urllib.request.urlopen(req) as data:
index d19355888e4b347140ea30158377ed5258f7647c..6585071912a0d0bca4ddb14f6af4b1c839eb97d1 100644 (file)
@@ -11,6 +11,8 @@ import sys
 
 glob = 42
 some_var = 12
+some_non_assigned_global_var = 11
+some_assigned_global_var = 11
 
 class Mine:
     instance_var = 24
@@ -19,6 +21,8 @@ class Mine:
 
 def spam(a, b, *var, **kw):
     global bar
+    global some_assigned_global_var
+    some_assigned_global_var = 12
     bar = 47
     some_var = 10
     x = 23
@@ -81,14 +85,14 @@ class SymtableTest(unittest.TestCase):
 
     def test_lineno(self):
         self.assertEqual(self.top.get_lineno(), 0)
-        self.assertEqual(self.spam.get_lineno(), 12)
+        self.assertEqual(self.spam.get_lineno(), 14)
 
     def test_function_info(self):
         func = self.spam
         self.assertEqual(sorted(func.get_parameters()), ["a", "b", "kw", "var"])
         expected = ['a', 'b', 'internal', 'kw', 'other_internal', 'some_var', 'var', 'x']
         self.assertEqual(sorted(func.get_locals()), expected)
-        self.assertEqual(sorted(func.get_globals()), ["bar", "glob"])
+        self.assertEqual(sorted(func.get_globals()), ["bar", "glob", "some_assigned_global_var"])
         self.assertEqual(self.internal.get_frees(), ("x",))
 
     def test_globals(self):
@@ -99,6 +103,9 @@ class SymtableTest(unittest.TestCase):
         self.assertFalse(self.internal.lookup("x").is_global())
         self.assertFalse(self.Mine.lookup("instance_var").is_global())
         self.assertTrue(self.spam.lookup("bar").is_global())
+        # Module-scope globals are both global and local
+        self.assertTrue(self.top.lookup("some_non_assigned_global_var").is_global())
+        self.assertTrue(self.top.lookup("some_assigned_global_var").is_global())
 
     def test_nonlocal(self):
         self.assertFalse(self.spam.lookup("some_var").is_nonlocal())
@@ -109,6 +116,9 @@ class SymtableTest(unittest.TestCase):
     def test_local(self):
         self.assertTrue(self.spam.lookup("x").is_local())
         self.assertFalse(self.spam.lookup("bar").is_local())
+        # Module-scope globals are both global and local
+        self.assertTrue(self.top.lookup("some_non_assigned_global_var").is_local())
+        self.assertTrue(self.top.lookup("some_assigned_global_var").is_local())
 
     def test_free(self):
         self.assertTrue(self.internal.lookup("x").is_free())
@@ -227,6 +237,10 @@ class SymtableTest(unittest.TestCase):
         top = symtable.symtable(code, "?", "exec")
         self.assertIsNotNone(find_block(top, "\u017d"))
 
+    def test_symtable_repr(self):
+        self.assertEqual(str(self.top), "<SymbolTable for module ?>")
+        self.assertEqual(str(self.spam), "<Function SymbolTable for spam in ?>")
+
 
 if __name__ == '__main__':
     unittest.main()
index b1d7a15b5e4ee3ae9083d846fcbb57c6d1e9e999..f21bf65fed8499d52b523b2814ba4744bdbf924d 100644 (file)
@@ -7,7 +7,7 @@ __email__ = "mbland at acm dot org"
 import sys
 import unittest
 from collections import deque
-from contextlib import _GeneratorContextManager, contextmanager
+from contextlib import _GeneratorContextManager, contextmanager, nullcontext
 
 
 class MockContextManager(_GeneratorContextManager):
@@ -641,6 +641,12 @@ class AssignmentTargetTestCase(unittest.TestCase):
             self.assertEqual(blah.two, 2)
             self.assertEqual(blah.three, 3)
 
+    def testWithExtendedTargets(self):
+        with nullcontext(range(1, 5)) as (a, *b, c):
+            self.assertEqual(a, 1)
+            self.assertEqual(b, [2, 3])
+            self.assertEqual(c, 4)
+
 
 class ExitSwallowsExceptionTestCase(unittest.TestCase):
 
index d01649d1c31b261c61c792ad64fcfa2f92c7e235..5632b8b503cf3f9d92c80223da0362ff431a466a 100644 (file)
@@ -3894,6 +3894,14 @@ class C14NTest(unittest.TestCase):
         #self.assertEqual(c14n_roundtrip("<doc xmlns:x='http://example.com/x' xmlns='http://example.com/default'><b y:a1='1' xmlns='http://example.com/default' a3='3' xmlns:y='http://example.com/y' y:a2='2'/></doc>"),
         #'<doc xmlns:x="http://example.com/x"><b xmlns:y="http://example.com/y" a3="3" y:a1="1" y:a2="2"></b></doc>')
 
+        # Namespace issues
+        xml = '<X xmlns="http://nps/a"><Y targets="abc,xyz"></Y></X>'
+        self.assertEqual(c14n_roundtrip(xml), xml)
+        xml = '<X xmlns="http://nps/a"><Y xmlns="http://nsp/b" targets="abc,xyz"></Y></X>'
+        self.assertEqual(c14n_roundtrip(xml), xml)
+        xml = '<X xmlns="http://nps/a"><Y xmlns:b="http://nsp/b" b:targets="abc,xyz"></Y></X>'
+        self.assertEqual(c14n_roundtrip(xml), xml)
+
     def test_c14n_exclusion(self):
         xml = textwrap.dedent("""\
         <root xmlns:x="http://example.com/x">
index b7bc218d17a3d966171cdd98c5750720b4f78fed..999197a0e32dcc10770247a80f0dd0455f96912b 100644 (file)
@@ -1855,11 +1855,14 @@ class OtherTests(unittest.TestCase):
             self.assertEqual(zipf.comment, b"an updated comment")
 
         # check that comments are correctly shortened in append mode
+        # and the file is indeed truncated
         with zipfile.ZipFile(TESTFN,mode="w") as zipf:
             zipf.comment = b"original comment that's longer"
             zipf.writestr("foo.txt", "O, for a Muse of Fire!")
+        original_zip_size = os.path.getsize(TESTFN)
         with zipfile.ZipFile(TESTFN,mode="a") as zipf:
             zipf.comment = b"shorter comment"
+        self.assertTrue(original_zip_size > os.path.getsize(TESTFN))
         with zipfile.ZipFile(TESTFN,mode="r") as zipf:
             self.assertEqual(zipf.comment, b"shorter comment")
 
index 85703269a1336e6005344d32c2fc58f0c9433771..d4704b75d389dfc92083a0d87630b9044f26c286 100644 (file)
@@ -6,7 +6,6 @@ import dataclasses
 import importlib.metadata
 import io
 import json
-import lzma
 import os
 import pathlib
 import pickle
@@ -20,7 +19,9 @@ from functools import cached_property
 
 from . import _support as test_support
 from ._support import OS_ENV_LOCK, TZPATH_TEST_LOCK, ZoneInfoTestBase
+from test.support import import_module
 
+lzma = import_module('lzma')
 py_zoneinfo, c_zoneinfo = test_support.get_modules()
 
 try:
index 1067ab6a8b8a1d9b730a354ad38c41e435e7cdd8..2175afcffa435ad4f85375eb593a2a29fc5a136f 100644 (file)
@@ -146,10 +146,10 @@ def _splitdict(tk, v, cut_minus=True, conv=None):
 
 class EventType(str, enum.Enum):
     KeyPress = '2'
-    Key = KeyPress,
+    Key = KeyPress
     KeyRelease = '3'
     ButtonPress = '4'
-    Button = ButtonPress,
+    Button = ButtonPress
     ButtonRelease = '5'
     Motion = '6'
     Enter = '7'
@@ -180,13 +180,12 @@ class EventType(str, enum.Enum):
     Colormap = '32'
     ClientMessage = '33'    # undocumented
     Mapping = '34'          # undocumented
-    VirtualEvent = '35',    # undocumented
-    Activate = '36',
-    Deactivate = '37',
-    MouseWheel = '38',
+    VirtualEvent = '35'     # undocumented
+    Activate = '36'
+    Deactivate = '37'
+    MouseWheel = '38'
 
-    def __str__(self):
-        return self.name
+    __str__ = str.__str__
 
 
 class Event:
@@ -266,7 +265,7 @@ class Event:
                 'num', 'delta', 'focus',
                 'x', 'y', 'width', 'height')
         return '<%s event%s>' % (
-            self.type,
+            getattr(self.type, 'name', self.type),
             ''.join(' %s=%s' % (k, attrs[k]) for k in keys if k in attrs)
         )
 
index 1e089747a91ee5ddddb1cdd7f4aefc1a87443066..b8eea2544f5228e2b45225929c8d5d4826526952 100644 (file)
@@ -192,6 +192,54 @@ class MiscTest(AbstractTkTest, unittest.TestCase):
         with self.assertRaises(tkinter.TclError):
             root.clipboard_get()
 
+    def test_event_repr_defaults(self):
+        e = tkinter.Event()
+        e.serial = 12345
+        e.num = '??'
+        e.height = '??'
+        e.keycode = '??'
+        e.state = 0
+        e.time = 123456789
+        e.width = '??'
+        e.x = '??'
+        e.y = '??'
+        e.char = ''
+        e.keysym = '??'
+        e.keysym_num = '??'
+        e.type = '100'
+        e.widget = '??'
+        e.x_root = '??'
+        e.y_root = '??'
+        e.delta = 0
+        self.assertEqual(repr(e), '<100 event>')
+
+    def test_event_repr(self):
+        e = tkinter.Event()
+        e.serial = 12345
+        e.num = 3
+        e.focus = True
+        e.height = 200
+        e.keycode = 65
+        e.state = 0x30405
+        e.time = 123456789
+        e.width = 300
+        e.x = 10
+        e.y = 20
+        e.char = 'A'
+        e.send_event = True
+        e.keysym = 'Key-A'
+        e.keysym_num = ord('A')
+        e.type = tkinter.EventType.Configure
+        e.widget = '.text'
+        e.x_root = 1010
+        e.y_root = 1020
+        e.delta = -1
+        self.assertEqual(repr(e),
+                         "<Configure event send_event=True"
+                         " state=Shift|Control|Button3|0x30000"
+                         " keysym=Key-A keycode=65 char='A'"
+                         " num=3 delta=-1 focus=True"
+                         " x=10 y=20 width=300 height=200>")
 
 tests_gui = (MiscTest, )
 
index 721e81369a8d5b726368f68dad7cfb68b5a5a81f..b6f792d6c2cf8566085c244d990aeec13dbd1a4e 100644 (file)
@@ -940,7 +940,8 @@ class ScaleTest(AbstractWidgetTest, unittest.TestCase):
 
     def test_from(self):
         widget = self.create()
-        self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=float_round)
+        conv = False if get_tk_patchlevel() >= (8, 6, 10) else float_round
+        self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv)
 
     def test_label(self):
         widget = self.create()
index da2bcad0b4d629880c9ced468927975df45def32..7a269001d6e18f60790f5565d69b301622139469 100644 (file)
@@ -1876,6 +1876,11 @@ class C14NWriterTarget:
                 self._declared_ns_stack[-1].append((uri, prefix))
                 return f'{prefix}:{tag}' if prefix else tag, tag, uri
 
+        if not uri:
+            # As soon as a default namespace is defined,
+            # anything that has no namespace (and thus, no prefix) goes there.
+            return tag, tag, uri
+
         raise ValueError(f'Namespace "{uri}" is not declared in scope')
 
     def data(self, data):
index 915698f9e0588936f7adb1b0394860819fad8f73..816f8582bbf6d5949537f1e42e1173b67bc4c19a 100644 (file)
@@ -1918,6 +1918,8 @@ class ZipFile:
                              centDirSize, centDirOffset, len(self._comment))
         self.fp.write(endrec)
         self.fp.write(self._comment)
+        if self.mode == "a":
+            self.fp.truncate()
         self.fp.flush()
 
     def _fpclose(self, fp):
index a58b922ce30b8363f208241ea6d1bb97d5f16112..2548b212d9ea424bac9e80f896c01eca9de9ca77 100755 (executable)
@@ -307,9 +307,9 @@ def library_recipes():
                   ),
           ),
           dict(
-              name="SQLite 3.32.3",
-              url="https://sqlite.org/2020/sqlite-autoconf-3320300.tar.gz",
-              checksum='2e3911a3c15e85c2f2d040154bbe5ce3',
+              name="SQLite 3.33.0",
+              url="https://sqlite.org/2020/sqlite-autoconf-3330000.tar.gz",
+              checksum='842a8a100d7b01b09e543deb2b7951dd',
               extra_cflags=('-Os '
                             '-DSQLITE_ENABLE_FTS5 '
                             '-DSQLITE_ENABLE_FTS4 '
index a16f15a74ebdcf0294ab25c69df05372f4c3bdf9..3125600284daf4435ff743744fe4fe5840aae0f8 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -781,6 +781,7 @@ Meador Inge
 Peter Ingebretson
 Tony Ingraldi
 John Interrante
+Dean Inwood
 Bob Ippolito
 Roger Irwin
 Atsuo Ishimoto
index b2d070cffaca00e388906291e2587945c01abfc7..54c1e62a282414d60c7b78c465fb67a9f29db873 100644 (file)
@@ -3629,6 +3629,25 @@ with_tp_del(PyObject *self, PyObject *args)
     return obj;
 }
 
+static PyObject *
+without_gc(PyObject *Py_UNUSED(self), PyObject *obj)
+{
+    PyTypeObject *tp = (PyTypeObject*)obj;
+    if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
+        return PyErr_Format(PyExc_TypeError, "heap type expected, got %R", obj);
+    }
+    if (PyType_IS_GC(tp)) {
+        // Don't try this at home, kids:
+        tp->tp_flags -= Py_TPFLAGS_HAVE_GC;
+        tp->tp_free = PyObject_Del;
+        tp->tp_traverse = NULL;
+        tp->tp_clear = NULL;
+    }
+    assert(!PyType_IS_GC(tp));
+    Py_INCREF(obj);
+    return obj;
+}
+
 static PyMethodDef ml;
 
 static PyObject *
@@ -5535,6 +5554,7 @@ static PyMethodDef TestMethods[] = {
     {"meth_fastcall", (PyCFunction)(void(*)(void))meth_fastcall, METH_FASTCALL},
     {"meth_fastcall_keywords", (PyCFunction)(void(*)(void))meth_fastcall_keywords, METH_FASTCALL|METH_KEYWORDS},
     {"pynumber_tobase", pynumber_tobase, METH_VARARGS},
+    {"without_gc", without_gc, METH_O},
     {NULL, NULL} /* sentinel */
 };
 
index fc91622d3925b8424880b48bdd8f0f3a411fad9c..04f6c243b5ca4d1fdb539ffadb4ba8244846f875 100644 (file)
@@ -1199,7 +1199,7 @@ tracemalloc_copy_trace(_Py_hashtable_t *traces,
     trace_t *trace = (trace_t *)value;
 
     trace_t *trace2 = raw_malloc(sizeof(trace_t));
-    if (traces2 == NULL) {
+    if (trace2 == NULL) {
         return -1;
     }
     *trace2 = *trace;
index 1d671c9e3334a59d868aefc0ee313e31b2acfc09..1922619ad85db051d22d8e0560fd75f3ac46584f 100644 (file)
@@ -2375,9 +2375,7 @@ abstract_get_bases(PyObject *cls)
     _Py_IDENTIFIER(__bases__);
     PyObject *bases;
 
-    Py_ALLOW_RECURSION
     (void)_PyObject_LookupAttrId(cls, &PyId___bases__, &bases);
-    Py_END_ALLOW_RECURSION
     if (bases != NULL && !PyTuple_Check(bases)) {
         Py_DECREF(bases);
         return NULL;
index 4f952162ec93098d2f3acb9a23fbcc7aecaf95d5..3e850b51092cc74207e5bdbf4934ec9be210fad7 100644 (file)
@@ -582,7 +582,7 @@ PyTypeObject Py_GenericAliasType = {
     .tp_name = "types.GenericAlias",
     .tp_doc = "Represent a PEP 585 generic type\n"
               "\n"
-              "E.g. for t = list[int], t.origin is list and t.args is (int,).",
+              "E.g. for t = list[int], t.__origin__ is list and t.__args__ is (int,).",
     .tp_basicsize = sizeof(gaobject),
     .tp_dealloc = ga_dealloc,
     .tp_repr = ga_repr,
index 5659f2143d1823396d7be2d1e115cde21ee5e0a2..7b430416c5a048715c1e8e91b4128c46ca25f828 100644 (file)
@@ -164,9 +164,11 @@ meth_dealloc(PyCFunctionObject *m)
     if (m->m_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject*) m);
     }
+    // Dereference class before m_self: PyCFunction_GET_CLASS accesses
+    // PyMethodDef m_ml, which could be kept alive by m_self
+    Py_XDECREF(PyCFunction_GET_CLASS(m));
     Py_XDECREF(m->m_self);
     Py_XDECREF(m->m_module);
-    Py_XDECREF(PyCFunction_GET_CLASS(m));
     PyObject_GC_Del(m);
 }
 
@@ -243,9 +245,9 @@ meth_get__qualname__(PyCFunctionObject *m, void *closure)
 static int
 meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
 {
+    Py_VISIT(PyCFunction_GET_CLASS(m));
     Py_VISIT(m->m_self);
     Py_VISIT(m->m_module);
-    Py_VISIT(PyCFunction_GET_CLASS(m));
     return 0;
 }
 
index f65434fdb7a757aeaf883d628fa7d149d65b9822..1a12b0ce07fcff9f1fe3a5abf0f06df25532dae3 100644 (file)
@@ -2605,10 +2605,10 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
     slots = NULL;
 
     /* Initialize tp_flags */
+    // All heap types need GC, since we can create a reference cycle by storing
+    // an instance on one of its parents:
     type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE |
-        Py_TPFLAGS_BASETYPE;
-    if (base->tp_flags & Py_TPFLAGS_HAVE_GC)
-        type->tp_flags |= Py_TPFLAGS_HAVE_GC;
+        Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC;
 
     /* Initialize essential fields */
     type->tp_as_async = &et->as_async;
@@ -2808,21 +2808,11 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
     }
     type->tp_dealloc = subtype_dealloc;
 
-    /* Enable GC unless this class is not adding new instance variables and
-       the base class did not use GC. */
-    if ((base->tp_flags & Py_TPFLAGS_HAVE_GC) ||
-        type->tp_basicsize > base->tp_basicsize)
-        type->tp_flags |= Py_TPFLAGS_HAVE_GC;
-
     /* Always override allocation strategy to use regular heap */
     type->tp_alloc = PyType_GenericAlloc;
-    if (type->tp_flags & Py_TPFLAGS_HAVE_GC) {
-        type->tp_free = PyObject_GC_Del;
-        type->tp_traverse = subtype_traverse;
-        type->tp_clear = subtype_clear;
-    }
-    else
-        type->tp_free = PyObject_Del;
+    type->tp_free = PyObject_GC_Del;
+    type->tp_traverse = subtype_traverse;
+    type->tp_clear = subtype_clear;
 
     /* store type in class' cell if one is supplied */
     cell = _PyDict_GetItemIdWithError(dict, &PyId___classcell__);
index 4c8c880657974f682c455e47e644581937c43e29..d5fbf158d50b429e97919135490632380e9091f1 100644 (file)
@@ -8160,7 +8160,7 @@ charmap_decode_mapping(const char *s,
                 goto Undefined;
             if (value < 0 || value > MAX_UNICODE) {
                 PyErr_Format(PyExc_TypeError,
-                             "character mapping must be in range(0x%lx)",
+                             "character mapping must be in range(0x%x)",
                              (unsigned long)MAX_UNICODE + 1);
                 goto onError;
             }
@@ -15602,9 +15602,7 @@ PyUnicode_InternInPlace(PyObject **p)
     }
 
     PyObject *t;
-    Py_ALLOW_RECURSION
     t = PyDict_SetDefault(interned, s, s);
-    Py_END_ALLOW_RECURSION
 
     if (t == NULL) {
         PyErr_Clear();
index f74b6f297b0403bcaaf2e9d0745548171ef1b5f4..1a4df757eae33815b4d45e1feed042a671ba9ad3 100644 (file)
@@ -4289,7 +4289,10 @@ with_stmt_rule(Parser *p)
     return _res;
 }
 
-// with_item: expression 'as' target &(',' | ')' | ':') | invalid_with_item | expression
+// with_item:
+//     | expression 'as' star_target &(',' | ')' | ':')
+//     | invalid_with_item
+//     | expression
 static withitem_ty
 with_item_rule(Parser *p)
 {
@@ -4300,12 +4303,12 @@ with_item_rule(Parser *p)
     }
     withitem_ty _res = NULL;
     int _mark = p->mark;
-    { // expression 'as' target &(',' | ')' | ':')
+    { // expression 'as' star_target &(',' | ')' | ':')
         if (p->error_indicator) {
             D(p->level--);
             return NULL;
         }
-        D(fprintf(stderr, "%*c> with_item[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression 'as' target &(',' | ')' | ':')"));
+        D(fprintf(stderr, "%*c> with_item[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')"));
         Token * _keyword;
         expr_ty e;
         expr_ty t;
@@ -4314,12 +4317,12 @@ with_item_rule(Parser *p)
             &&
             (_keyword = _PyPegen_expect_token(p, 520))  // token='as'
             &&
-            (t = target_rule(p))  // target
+            (t = star_target_rule(p))  // star_target
             &&
             _PyPegen_lookahead(1, _tmp_47_rule, p)
         )
         {
-            D(fprintf(stderr, "%*c+ with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' target &(',' | ')' | ':')"));
+            D(fprintf(stderr, "%*c+ with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')"));
             _res = _Py_withitem ( e , t , p -> arena );
             if (_res == NULL && PyErr_Occurred()) {
                 p->error_indicator = 1;
@@ -4330,7 +4333,7 @@ with_item_rule(Parser *p)
         }
         p->mark = _mark;
         D(fprintf(stderr, "%*c%s with_item[%d-%d]: %s failed!\n", p->level, ' ',
-                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression 'as' target &(',' | ')' | ':')"));
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')"));
     }
     { // invalid_with_item
         if (p->error_indicator) {
index 684f10a8b919363bc337f6fff033ee49b48301d8..97f7698ef4b2d94540f10f1b3ba3e497e4699c92 100644 (file)
@@ -144,10 +144,16 @@ aix_loaderror(const char *pathname)
         ERRBUF_APPEND(message[i]);
         ERRBUF_APPEND("\n");
     }
-    errbuf[strlen(errbuf)-1] = '\0';            /* trim off last newline */
-    pathname_ob = PyUnicode_FromString(pathname);
-    errbuf_ob = PyUnicode_FromString(errbuf);
-    PyErr_SetImportError(errbuf_ob, NULL, pathname);
+    /* Subtract 1 from the length to trim off trailing newline */
+    errbuf_ob = PyUnicode_DecodeLocaleAndSize(errbuf, strlen(errbuf)-1, "surrogateescape");
+    if (errbuf_ob == NULL)
+        return;
+    pathname_ob = PyUnicode_DecodeFSDefault(pathname);
+    if (pathname_ob == NULL) {
+        Py_DECREF(errbuf_ob);
+        return;
+    }
+    PyErr_SetImportError(errbuf_ob, NULL, pathname_ob);
     Py_DECREF(pathname_ob);
     Py_DECREF(errbuf_ob);
     return;
index 4b964a69d3bde6cc2906062e721ee1e042d3cbfa..e36d608c6dca4481ff1d97b55b079b1c9c207693 100644 (file)
@@ -36,9 +36,20 @@ dl_funcptr _PyImport_FindSharedFuncptr(const char *prefix,
         char buf[256];
         PyOS_snprintf(buf, sizeof(buf), "Failed to load %.200s",
                       pathname);
-        PyObject *buf_ob = PyUnicode_FromString(buf);
+        PyObject *buf_ob = PyUnicode_DecodeFSDefault(buf);
+        if (buf_ob == NULL)
+            return NULL;
         PyObject *shortname_ob = PyUnicode_FromString(shortname);
-        PyObject *pathname_ob = PyUnicode_FromString(pathname);
+        if (shortname_ob == NULL) {
+            Py_DECREF(buf_ob);
+            return NULL;
+        }
+        PyObject *pathname_ob = PyUnicode_DecodeFSDefault(pathname);
+        if (pathname_ob == NULL) {
+            Py_DECREF(buf_ob);
+            Py_DECREF(shortname_ob);
+            return NULL;
+        }
         PyErr_SetImportError(buf_ob, shortname_ob, pathname_ob);
         Py_DECREF(buf_ob);
         Py_DECREF(shortname_ob);
index 082154dd91b1fc87d8810ba9ecd46657a3aa0b9e..23828898d35a5d50df3ca09b4a2283a0fa54a3ee 100644 (file)
@@ -106,7 +106,7 @@ _PyImport_FindSharedFuncptr(const char *prefix,
         const char *error = dlerror();
         if (error == NULL)
             error = "unknown dlopen() error";
-        error_ob = PyUnicode_FromString(error);
+        error_ob = PyUnicode_DecodeLocale(error, "surrogateescape");
         if (error_ob == NULL)
             return NULL;
         mod_name = PyUnicode_FromString(shortname);
@@ -114,7 +114,7 @@ _PyImport_FindSharedFuncptr(const char *prefix,
             Py_DECREF(error_ob);
             return NULL;
         }
-        path = PyUnicode_FromString(pathname);
+        path = PyUnicode_DecodeFSDefault(pathname);
         if (path == NULL) {
             Py_DECREF(error_ob);
             Py_DECREF(mod_name);
index 0e2e7c370868fa13bb3cff2d18b3eae4bb31c818..5e39a2fb9a02e587fcdaf21d3d61feda105be67d 100644 (file)
@@ -905,7 +905,11 @@ PyImport_AddModule(const char *name)
 }
 
 
-/* Remove name from sys.modules, if it's there. */
+/* Remove name from sys.modules, if it's there.
+ * Can be called with an exception raised.
+ * If fail to remove name a new exception will be chained with the old
+ * exception, otherwise the old exception is preserved.
+ */
 static void
 remove_module(PyThreadState *tstate, PyObject *name)
 {
@@ -913,18 +917,17 @@ remove_module(PyThreadState *tstate, PyObject *name)
     _PyErr_Fetch(tstate, &type, &value, &traceback);
 
     PyObject *modules = tstate->interp->modules;
-    if (!PyMapping_HasKey(modules, name)) {
-        goto out;
+    if (PyDict_CheckExact(modules)) {
+        PyObject *mod = _PyDict_Pop(modules, name, Py_None);
+        Py_XDECREF(mod);
     }
-    if (PyMapping_DelItem(modules, name) < 0) {
-        _PyErr_SetString(tstate, PyExc_RuntimeError,
-                         "deleting key in sys.modules failed");
-        _PyErr_ChainExceptions(type, value, traceback);
-        return;
+    else if (PyMapping_DelItem(modules, name) < 0) {
+        if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
+            _PyErr_Clear(tstate);
+        }
     }
 
-out:
-    _PyErr_Restore(tstate, type, value, traceback);
+    _PyErr_ChainExceptions(type, value, traceback);
 }
 
 
index f630afe62592424f43d899768e578ecdb233ebb3..a8a044757d00b2bf86693e922a9a6a51cfde0394 100644 (file)
@@ -60,7 +60,7 @@ def glob_tree(root, *,
 
 
 def iter_files(root, suffix=None, relparent=None, *,
-               get_files=os.walk,
+               get_files=None,
                _glob=glob_tree,
                _walk=walk_tree,
                ):
@@ -75,6 +75,8 @@ def iter_files(root, suffix=None, relparent=None, *,
     if "relparent" is provided then it is used to resolve each
     filename as a relative path.
     """
+    if get_files is None:
+        get_files = os.walk
     if not isinstance(root, str):
         roots = root
         for root in roots:
index 770866bca76b3264777baf3a1a8844d4d7b355ab..0a6cd8ca2e9acb17504769d93fa889b6f1f210d1 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -1882,9 +1882,9 @@ class PyBuildExt(build_ext):
         # you want to build and link with a framework build of Tcl and Tk
         # that is not in /Library/Frameworks, say, in your private
         # $HOME/Library/Frameworks directory or elsewhere. It turns
-        # out to be difficult to make that work automtically here
+        # out to be difficult to make that work automatically here
         # without bringing into play more tools and magic. That case
-        # can be hamdled using a recipe with the right arguments
+        # can be handled using a recipe with the right arguments
         # to detect_tkinter_explicitly().
         #
         # Note also that the fallback case here is to try to use the
@@ -1892,7 +1892,7 @@ class PyBuildExt(build_ext):
         # be forewarned that they are deprecated by Apple and typically
         # out-of-date and buggy; their use should be avoided if at
         # all possible by installing a newer version of Tcl and Tk in
-        # /Library/Frameworks before bwfore building Python without
+        # /Library/Frameworks before building Python without
         # an explicit SDK or by configuring build arguments explicitly.
 
         from os.path import join, exists
@@ -1909,7 +1909,7 @@ class PyBuildExt(build_ext):
         else:
             # Use case #1: no explicit SDK selected.
             # Search the local system-wide /Library/Frameworks,
-            # not the one in the default SDK, othewise fall back to
+            # not the one in the default SDK, otherwise fall back to
             # /System/Library/Frameworks whose header files may be in
             # the default SDK or, on older systems, actually installed.
             framework_dirs = [
@@ -1925,7 +1925,7 @@ class PyBuildExt(build_ext):
                 if not exists(join(F, fw + '.framework')):
                     break
             else:
-                # ok, F is now directory with both frameworks. Continure
+                # ok, F is now directory with both frameworks. Continue
                 # building
                 break
         else: