Imported Upstream version 3.9.12 upstream/3.9.12
authorJinWang An <jinwang.an@samsung.com>
Wed, 18 Jan 2023 06:01:26 +0000 (15:01 +0900)
committerJinWang An <jinwang.an@samsung.com>
Wed, 18 Jan 2023 06:01:26 +0000 (15:01 +0900)
76 files changed:
Doc/library/aifc.rst
Doc/library/asynchat.rst
Doc/library/asyncore.rst
Doc/library/audioop.rst
Doc/library/binascii.rst
Doc/library/cgi.rst
Doc/library/cgitb.rst
Doc/library/chunk.rst
Doc/library/configparser.rst
Doc/library/crypt.rst
Doc/library/fileformats.rst
Doc/library/imghdr.rst
Doc/library/internet.rst
Doc/library/ipc.rst
Doc/library/mm.rst
Doc/library/msilib.rst
Doc/library/netdata.rst
Doc/library/nis.rst
Doc/library/nntplib.rst
Doc/library/ossaudiodev.rst
Doc/library/pathlib.rst
Doc/library/pipes.rst
Doc/library/smtpd.rst
Doc/library/sndhdr.rst
Doc/library/spwd.rst
Doc/library/sunau.rst
Doc/library/superseded.rst
Doc/library/telnetlib.rst
Doc/library/textwrap.rst
Doc/library/typing.rst
Doc/library/unix.rst
Doc/library/uu.rst
Doc/library/windows.rst
Doc/library/xdrlib.rst
Doc/library/zlib.rst
Doc/reference/compound_stmts.rst
Doc/reference/datamodel.rst
Doc/reference/executionmodel.rst
Doc/tools/susp-ignored.csv
Include/patchlevel.h
Lib/argparse.py
Lib/asyncio/locks.py
Lib/doctest.py
Lib/pydoc.py
Lib/pydoc_data/topics.py
Lib/sre_parse.py
Lib/test/libregrtest/main.py
Lib/test/libregrtest/win_utils.py
Lib/test/pydoc_mod.py
Lib/test/test_argparse.py
Lib/test/test_asyncio/test_asyncio_waitfor.py [deleted file]
Lib/test/test_asyncio/test_locks.py
Lib/test/test_asyncio/test_tasks.py
Lib/test/test_asyncio/test_waitfor.py [new file with mode: 0644]
Lib/test/test_binascii.py
Lib/test/test_cmd_line.py
Lib/test/test_doctest.py
Lib/test/test_hashlib.py
Lib/test/test_pydoc.py
Lib/test/test_re.py
Lib/test/test_shutil.py
Lib/tkinter/test/test_tkinter/test_widgets.py
Lib/tkinter/test/test_ttk/test_style.py
Lib/unittest/main.py
Lib/zipfile.py
Misc/ACKS
Misc/NEWS
Modules/_hashopenssl.c
Modules/_sre.c
Modules/binascii.c
Modules/faulthandler.c
Modules/sre.h
README.rst
configure
configure.ac
pyconfig.h.in

index 2e917cf7321b857bb7a0bcb317e93d2ab88ba443..edb4bf86e5a0aae57c83db8e2d9d14fcfa6cc681 100644 (file)
@@ -3,6 +3,7 @@
 
 .. module:: aifc
    :synopsis: Read and write audio files in AIFF or AIFC format.
+   :deprecated:
 
 **Source code:** :source:`Lib/aifc.py`
 
    single: AIFF
    single: AIFF-C
 
+
+.. deprecated:: 3.11
+   The :mod:`aifc` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 This module provides support for reading and writing AIFF and AIFF-C files.
index 9e51416b83a570b45964431e85ef8b07070b27f5..4354444a1d3314a57d63dd5c38f15034143bd378 100644 (file)
@@ -3,6 +3,7 @@
 
 .. module:: asynchat
    :synopsis: Support for asynchronous command/response protocols.
+   :deprecated:
 
 .. moduleauthor:: Sam Rushing <rushing@nightmare.com>
 .. sectionauthor:: Steve Holden <sholden@holdenweb.com>
@@ -10,6 +11,7 @@
 **Source code:** :source:`Lib/asynchat.py`
 
 .. deprecated:: 3.6
+   :mod:`asynchat` will be removed in Python 3.12 (:pep:`594`).
    Please use :mod:`asyncio` instead.
 
 --------------
index a86518ebff2777eb12e75fb361950392145a2699..e481e13db76f70204b0990839170d9050bce22d1 100644 (file)
@@ -4,6 +4,7 @@
 .. module:: asyncore
    :synopsis: A base class for developing asynchronous socket handling
               services.
+   :deprecated:
 
 .. moduleauthor:: Sam Rushing <rushing@nightmare.com>
 .. sectionauthor:: Christopher Petrilli <petrilli@amber.org>
@@ -13,6 +14,7 @@
 **Source code:** :source:`Lib/asyncore.py`
 
 .. deprecated:: 3.6
+   :mod:`asyncore` will be removed in Python 3.12 (:pep:`594`).
    Please use :mod:`asyncio` instead.
 
 --------------
index bad9da2ec62e565d50bfdd0ed45519251f07ae35..eae206084f09004ffb7cf888ca48efb09437082d 100644 (file)
@@ -3,6 +3,10 @@
 
 .. module:: audioop
    :synopsis: Manipulate raw audio data.
+   :deprecated:
+
+.. deprecated:: 3.11
+   The :mod:`audioop` module is deprecated (see :pep:`594` for details).
 
 --------------
 
index 2c0c1bce5d7f8f9a0f18f0be815a0c4c5605b6df..5cd058c0b6d74f97cd85f2917783e4de14d964d3 100644 (file)
@@ -135,7 +135,7 @@ The :mod:`binascii` module defines the following functions:
 
 .. function:: crc32(data[, value])
 
-   Compute CRC-32, the 32-bit checksum of *data*, starting with an
+   Compute CRC-32, the unsigned 32-bit checksum of *data*, starting with an
    initial CRC of *value*.  The default initial CRC is zero.  The algorithm
    is consistent with the ZIP file checksum.  Since the algorithm is designed for
    use as a checksum algorithm, it is not suitable for use as a general hash
@@ -149,9 +149,8 @@ The :mod:`binascii` module defines the following functions:
 
    .. versionchanged:: 3.0
       The result is always unsigned.
-      To generate the same numeric value across all Python versions and
-      platforms, use ``crc32(data) & 0xffffffff``.
-
+      To generate the same numeric value when using Python 2 or earlier,
+      use ``crc32(data) & 0xffffffff``.
 
 .. function:: b2a_hex(data[, sep[, bytes_per_sep=1]])
               hexlify(data[, sep[, bytes_per_sep=1]])
index 3ec919e9ccd000e9ea1026fbbc59a439b1914ec5..80c4d8033130c45418848e1b4449aee17b50a611 100644 (file)
@@ -3,6 +3,7 @@
 
 .. module:: cgi
    :synopsis: Helpers for running Python scripts via the Common Gateway Interface.
+   :deprecated:
 
 **Source code:** :source:`Lib/cgi.py`
 
@@ -14,6 +15,9 @@
    single: URL
    single: Common Gateway Interface
 
+.. deprecated:: 3.11
+   The :mod:`cgi` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 Support module for Common Gateway Interface (CGI) scripts.
index 5f3a6476dd8cdcf5431425576ea14f3b0c638fd5..349414610bd40a7375b5c4b5436660f3688f8f97 100644 (file)
@@ -3,6 +3,7 @@
 
 .. module:: cgitb
    :synopsis: Configurable traceback handler for CGI scripts.
+   :deprecated:
 
 .. moduleauthor:: Ka-Ping Yee <ping@lfw.org>
 .. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
@@ -15,6 +16,9 @@
    single: exceptions; in CGI scripts
    single: tracebacks; in CGI scripts
 
+.. deprecated:: 3.11
+   The :mod:`cgitb` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 The :mod:`cgitb` module provides a special exception handler for Python scripts.
index 5e24df923ed21024f986d8597921f1ac6938b344..7999420f536d762becefbb06a39589ec0379b1a4 100644 (file)
@@ -3,6 +3,7 @@
 
 .. module:: chunk
    :synopsis: Module to read IFF chunks.
+   :deprecated:
 
 .. moduleauthor:: Sjoerd Mullender <sjoerd@acm.org>
 .. sectionauthor:: Sjoerd Mullender <sjoerd@acm.org>
@@ -16,6 +17,9 @@
    single: Real Media File Format
    single: RMFF
 
+.. deprecated:: 3.11
+   The :mod:`chunk` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 This module provides an interface for reading files that use EA IFF 85 chunks.
index e5c78246881f1926908e1b5f4ed8bf8da94e32bc..c98ffe718e50af6be787e02e5e4402fa0dcc6ccd 100644 (file)
@@ -323,7 +323,8 @@ from ``get()`` calls.
       my_pictures: %(my_dir)s/Pictures
 
       [Escape]
-      gain: 80%%  # use a %% to escape the % sign (% is the only character that needs to be escaped)
+      # use a %% to escape the % sign (% is the only character that needs to be escaped):
+      gain: 80%%
 
    In the example above, :class:`ConfigParser` with *interpolation* set to
    ``BasicInterpolation()`` would resolve ``%(home_dir)s`` to the value of
@@ -358,7 +359,8 @@ from ``get()`` calls.
       my_pictures: ${my_dir}/Pictures
 
       [Escape]
-      cost: $$80  # use a $$ to escape the $ sign ($ is the only character that needs to be escaped)
+      # use a $$ to escape the $ sign ($ is the only character that needs to be escaped):
+      cost: $$80
 
    Values from other sections can be fetched as well:
 
index d25c626a175854ac5edca4c2f5d30a30bdb60e94..73df87ca0db8d183702102d61568a0037f5f3fe5 100644 (file)
@@ -4,6 +4,7 @@
 .. module:: crypt
    :platform: Unix
    :synopsis: The crypt() function used to check Unix passwords.
+   :deprecated:
 
 .. moduleauthor:: Steven D. Majewski <sdm7g@virginia.edu>
 .. sectionauthor:: Steven D. Majewski <sdm7g@virginia.edu>
@@ -15,6 +16,9 @@
    single: crypt(3)
    pair: cipher; DES
 
+.. deprecated:: 3.11
+   The :mod:`crypt` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 This module implements an interface to the :manpage:`crypt(3)` routine, which is
index e9c2e1fbbdf3e8975400c8f1bb67f36e11f822df..7b33b3364572d92ce02ae1a40b4eac1945e3bfe9 100644 (file)
@@ -13,5 +13,4 @@ that aren't markup languages and are not related to e-mail.
    csv.rst
    configparser.rst
    netrc.rst
-   xdrlib.rst
    plistlib.rst
index 800e919599d9cbf6a15bff1b862b67a8ca25ab59..f63a0fa56fd26c3dc07dd94dbf011c153f2939e2 100644 (file)
@@ -3,9 +3,13 @@
 
 .. module:: imghdr
    :synopsis: Determine the type of image contained in a file or byte stream.
+   :deprecated:
 
 **Source code:** :source:`Lib/imghdr.py`
 
+.. deprecated:: 3.11
+   The :mod:`imghdr` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 The :mod:`imghdr` module determines the type of image contained in a file or
index b8950bb6cb8c2dc29327d7666a66ea3a8ab214bd..c8bab2a5836ade2b2016ee3f02e2eb2b416bfa42 100644 (file)
@@ -20,8 +20,6 @@ is currently supported on most popular platforms.  Here is an overview:
 .. toctree::
 
    webbrowser.rst
-   cgi.rst
-   cgitb.rst
    wsgiref.rst
    urllib.rst
    urllib.request.rst
@@ -33,10 +31,7 @@ is currently supported on most popular platforms.  Here is an overview:
    ftplib.rst
    poplib.rst
    imaplib.rst
-   nntplib.rst
    smtplib.rst
-   smtpd.rst
-   telnetlib.rst
    uuid.rst
    socketserver.rst
    http.server.rst
index b88a174eb97f15c0067664902b6aca8cb0185f8b..4849c82f317d97ec704e72f3da037081abaa9cb4 100644 (file)
@@ -22,7 +22,5 @@ The list of modules described in this chapter is:
    ssl.rst
    select.rst
    selectors.rst
-   asyncore.rst
-   asynchat.rst
    signal.rst
    mmap.rst
index c8f79c4de1cdf258d00f4c546b13ea57ade708fa..cd06e9385a26124ed93ee002db8c317182e3b9e7 100644 (file)
@@ -11,12 +11,5 @@ discretion of the installation.  Here's an overview:
 
 .. toctree::
 
-   audioop.rst
-   aifc.rst
-   sunau.rst
    wave.rst
-   chunk.rst
    colorsys.rst
-   imghdr.rst
-   sndhdr.rst
-   ossaudiodev.rst
index 83b3d4973bf0d96dc4880c2ff3581eced2f91c6d..5ce18a1f75fc21a29eca8ba009ce83a0747aeae3 100644 (file)
@@ -4,6 +4,7 @@
 .. module:: msilib
    :platform: Windows
    :synopsis: Creation of Microsoft Installer files, and CAB files.
+   :deprecated:
 
 .. moduleauthor:: Martin v. Löwis <martin@v.loewis.de>
 .. sectionauthor:: Martin v. Löwis <martin@v.loewis.de>
@@ -12,6 +13,9 @@
 
 .. index:: single: msi
 
+.. deprecated:: 3.11
+   The :mod:`msilib` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 The :mod:`msilib` supports the creation of Microsoft Installer (``.msi``) files.
index 491501665e3d716e81dba69c794b70ab72974408..8a3ad68753a535d20419c3ffb366b53c5c678827 100644 (file)
@@ -20,4 +20,3 @@ on the Internet.
    binhex.rst
    binascii.rst
    quopri.rst
-   uu.rst
index 10c67cbb81b2f057470ff6f039f37da10336f3a2..f6b6ea83946b0ed496abbea6b4e3cb981bf9435e 100644 (file)
@@ -5,10 +5,14 @@
 .. module:: nis
    :platform: Unix
    :synopsis: Interface to Sun's NIS (Yellow Pages) library.
+   :deprecated:
 
 .. moduleauthor:: Fred Gansevles <Fred.Gansevles@cs.utwente.nl>
 .. sectionauthor:: Moshe Zadka <moshez@zadka.site.co.il>
 
+.. deprecated:: 3.11
+   The :mod:`nis` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 The :mod:`nis` module gives a thin wrapper around the NIS library, useful for
index e7ec9047e015e6cd66f07ad09160cdb72bad8b4e..2a996e451bf7c535c81f17b05c571e754f3ccc08 100644 (file)
@@ -3,6 +3,7 @@
 
 .. module:: nntplib
    :synopsis: NNTP protocol client (requires sockets).
+   :deprecated:
 
 **Source code:** :source:`Lib/nntplib.py`
 
@@ -10,6 +11,9 @@
    pair: NNTP; protocol
    single: Network News Transfer Protocol
 
+.. deprecated:: 3.11
+   The :mod:`nntplib` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 This module defines the class :class:`NNTP` which implements the client side of
index a7d3dac363cdf24ae0f65e11a05eca9d444fd324..e0f0a6b8259e4f4deb19214e091213a9f53d90d0 100644 (file)
@@ -4,6 +4,10 @@
 .. module:: ossaudiodev
    :platform: Linux, FreeBSD
    :synopsis: Access to OSS-compatible audio devices.
+   :deprecated:
+
+.. deprecated:: 3.11
+   The :mod:`ossaudiodev` module is deprecated (see :pep:`594` for details).
 
 --------------
 
index 88e8756cf84a53a9af5aad903f44de0a714d55af..3a41b5454b86448b2c12d3bb44f275698167890d 100644 (file)
@@ -900,7 +900,7 @@ call fails (for example because the path doesn't exist).
 
    The children are yielded in arbitrary order, and the special entries
    ``'.'`` and ``'..'`` are not included.  If a file is removed from or added
-   to the directory after creating the iterator, whether an path object for
+   to the directory after creating the iterator, whether a path object for
    that file be included is unspecified.
 
 .. method:: Path.lchmod(mode)
index 0a22da1f555bc285906f54250954f11ebf3af95d..25f808566ecf963d88004e4621f63076686fd9f0 100644 (file)
@@ -4,11 +4,15 @@
 .. module:: pipes
    :platform: Unix
    :synopsis: A Python interface to Unix shell pipelines.
+   :deprecated:
 
 .. sectionauthor:: Moshe Zadka <moshez@zadka.site.co.il>
 
 **Source code:** :source:`Lib/pipes.py`
 
+.. deprecated:: 3.11
+   The :mod:`pipes` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 The :mod:`pipes` module defines a class to abstract the concept of a *pipeline*
index d84e74a8ceaaff506cfcfcc62f6985be3cf80915..a39bc024047fd34681e17b17e747dc874d1d35a0 100644 (file)
@@ -3,6 +3,7 @@
 
 .. module:: smtpd
    :synopsis: A SMTP server implementation in Python.
+   :deprecated:
 
 .. moduleauthor:: Barry Warsaw <barry@python.org>
 .. sectionauthor:: Moshe Zadka <moshez@moshez.org>
 
 This module offers several classes to implement SMTP (email) servers.
 
-.. seealso::
-
-    The `aiosmtpd <http://aiosmtpd.readthedocs.io/>`_ package is a recommended
-    replacement for this module.  It is based on :mod:`asyncio` and provides a
-    more straightforward API.  :mod:`smtpd` should be considered deprecated.
+.. deprecated:: 3.6
+   :mod:`smtpd` will be removed in Python 3.12 (:pep:`594`).
+   The `aiosmtpd <https://aiosmtpd.readthedocs.io/>`_ package is a recommended
+   replacement for this module.  It is based on :mod:`asyncio` and provides a
+   more straightforward API.
 
 Several server implementations are present; one is a generic
 do-nothing implementation, which can be overridden, while the other two offer
index 6bfa9a9fd210bef3fee5aaffa7c2054853d7175c..41bce18b9cd849a4fb85630aec5e390033e946a7 100644 (file)
@@ -3,6 +3,7 @@
 
 .. module:: sndhdr
    :synopsis: Determine type of a sound file.
+   :deprecated:
 
 .. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
 .. Based on comments in the module source file.
@@ -13,6 +14,9 @@
    single: A-LAW
    single: u-LAW
 
+.. deprecated:: 3.11
+   The :mod:`sndhdr` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 The :mod:`sndhdr` provides utility functions which attempt to determine the type
index c6cad2a3c32849fba0aef2c63d0c242809e06ae7..cb31a10a52e0017a850be468b1dd8197fef9ef74 100644 (file)
@@ -4,6 +4,10 @@
 .. module:: spwd
    :platform: Unix
    :synopsis: The shadow password database (getspnam() and friends).
+   :deprecated:
+
+.. deprecated:: 3.11
+   The :mod:`spwd` module is deprecated (see :pep:`594` for details).
 
 --------------
 
index aad6f93b6bff18ebc2f431481fd4d7631ccbbbe1..cfb1257f585484b91a09b95488b9a11650e50254 100644 (file)
@@ -3,11 +3,15 @@
 
 .. module:: sunau
    :synopsis: Provide an interface to the Sun AU sound format.
+   :deprecated:
 
 .. sectionauthor:: Moshe Zadka <moshez@zadka.site.co.il>
 
 **Source code:** :source:`Lib/sunau.py`
 
+.. deprecated:: 3.11
+   The :mod:`sunau` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 The :mod:`sunau` module provides a convenient interface to the Sun AU sound
index 50a5983236e76ae605e2399383c2f8f83ff66a2b..e3f9b0d37fe10bdbd9acf86a8f74d6a923108ad9 100644 (file)
@@ -10,5 +10,26 @@ backwards compatibility. They have been superseded by other modules.
 
 .. toctree::
 
-   optparse.rst
+   aifc.rst
+   asynchat.rst
+   asyncore.rst
+   audioop.rst
+   cgi.rst
+   cgitb.rst
+   chunk.rst
+   crypt.rst
+   imghdr.rst
    imp.rst
+   msilib.rst
+   nntplib.rst
+   nis.rst
+   optparse.rst
+   ossaudiodev.rst
+   pipes.rst
+   smtpd.rst
+   sndhdr.rst
+   spwd.rst
+   sunau.rst
+   telnetlib.rst
+   uu.rst
+   xdrlib.rst
index 48a9aea50dddd1aecdfc102ca99c9fad131aa03b..97b0a713e442238d1e73301112d48aa999acb15a 100644 (file)
@@ -3,6 +3,7 @@
 
 .. module:: telnetlib
    :synopsis: Telnet client class.
+   :deprecated:
 
 .. sectionauthor:: Skip Montanaro <skip@pobox.com>
 
@@ -10,6 +11,9 @@
 
 .. index:: single: protocol; Telnet
 
+.. deprecated:: 3.11
+   The :mod:`telnetlib` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 The :mod:`telnetlib` module provides a :class:`Telnet` class that implements the
index 7780e241769657e5d79b9804bf0ebb7859de043e..1a9d5f98f78a7e89e01e696c972b912d403ee520 100644 (file)
@@ -21,7 +21,8 @@ functions should be good enough; otherwise, you should use an instance of
                    subsequent_indent="", expand_tabs=True, \
                    replace_whitespace=True, fix_sentence_endings=False, \
                    break_long_words=True, drop_whitespace=True, \
-                   break_on_hyphens=True, tabsize=8, max_lines=None)
+                   break_on_hyphens=True, tabsize=8, max_lines=None, \
+                   placeholder=' [...]')
 
    Wraps the single paragraph in *text* (a string) so every line is at most
    *width* characters long.  Returns a list of output lines, without final
@@ -39,7 +40,7 @@ functions should be good enough; otherwise, you should use an instance of
                    replace_whitespace=True, fix_sentence_endings=False, \
                    break_long_words=True, drop_whitespace=True, \
                    break_on_hyphens=True, tabsize=8, \
-                   max_lines=None)
+                   max_lines=None, placeholder=' [...]')
 
    Wraps the single paragraph in *text*, and returns a single string containing the
    wrapped paragraph.  :func:`fill` is shorthand for  ::
index 13fc418e9274b46eaafbd9c5af17600893d77da3..2689c7f2938716326c55fd1542534e0910ec728f 100644 (file)
@@ -214,7 +214,7 @@ subscription to denote expected types for container elements.
    def notify_by_email(employees: Sequence[Employee],
                        overrides: Mapping[str, str]) -> None: ...
 
-Generics can be parameterized by using a new factory available in typing
+Generics can be parameterized by using a factory available in typing
 called :class:`TypeVar`.
 
 ::
@@ -271,16 +271,16 @@ that ``LoggedVar[t]`` is valid as a type::
        for var in vars:
            var.set(0)
 
-A generic type can have any number of type variables, and type variables may
-be constrained::
+A generic type can have any number of type variables. All varieties of
+:class:`TypeVar` are permissible as parameters for a generic type::
 
-   from typing import TypeVar, Generic
-   ...
+   from typing import TypeVar, Generic, Sequence
 
-   T = TypeVar('T')
+   T = TypeVar('T', contravariant=True)
+   B = TypeVar('B', bound=Sequence[bytes], covariant=True)
    S = TypeVar('S', int, str)
 
-   class StrangePair(Generic[T, S]):
+   class WeirdTrio(Generic[T, B, S]):
        ...
 
 Each type variable argument to :class:`Generic` must be distinct.
@@ -856,7 +856,8 @@ These are not used in annotations. They are building blocks for creating generic
     Usage::
 
       T = TypeVar('T')  # Can be anything
-      A = TypeVar('A', str, bytes)  # Must be str or bytes
+      S = TypeVar('S', bound=str)  # Can be any subtype of str
+      A = TypeVar('A', str, bytes)  # Must be exactly str or bytes
 
     Type variables exist primarily for the benefit of static type
     checkers.  They serve as the parameters for generic types as well
@@ -867,29 +868,95 @@ These are not used in annotations. They are building blocks for creating generic
            """Return a list containing n references to x."""
            return [x]*n
 
-       def longest(x: A, y: A) -> A:
-           """Return the longest of two strings."""
-           return x if len(x) >= len(y) else y
 
-    The latter example's signature is essentially the overloading
-    of ``(str, str) -> str`` and ``(bytes, bytes) -> bytes``.  Also note
-    that if the arguments are instances of some subclass of :class:`str`,
-    the return type is still plain :class:`str`.
+       def print_capitalized(x: S) -> S:
+           """Print x capitalized, and return x."""
+           print(x.capitalize())
+           return x
+
+
+       def concatenate(x: A, y: A) -> A:
+           """Add two strings or bytes objects together."""
+           return x + y
+
+    Note that type variables can be *bound*, *constrained*, or neither, but
+    cannot be both bound *and* constrained.
+
+    Constrained type variables and bound type variables have different
+    semantics in several important ways. Using a *constrained* type variable
+    means that the ``TypeVar`` can only ever be solved as being exactly one of
+    the constraints given::
+
+       a = concatenate('one', 'two')  # Ok, variable 'a' has type 'str'
+       b = concatenate(StringSubclass('one'), StringSubclass('two'))  # Inferred type of variable 'b' is 'str',
+                                                                      # despite 'StringSubclass' being passed in
+       c = concatenate('one', b'two')  # error: type variable 'A' can be either 'str' or 'bytes' in a function call, but not both
+
+    Using a *bound* type variable, however, means that the ``TypeVar`` will be
+    solved using the most specific type possible::
+
+       print_capitalized('a string')  # Ok, output has type 'str'
+
+       class StringSubclass(str):
+           pass
+
+       print_capitalized(StringSubclass('another string'))  # Ok, output has type 'StringSubclass'
+       print_capitalized(45)  # error: int is not a subtype of str
+
+    Type variables can be bound to concrete types, abstract types (ABCs or
+    protocols), and even unions of types::
+
+       U = TypeVar('U', bound=str|bytes)  # Can be any subtype of the union str|bytes
+       V = TypeVar('V', bound=SupportsAbs)  # Can be anything with an __abs__ method
+
+    Bound type variables are particularly useful for annotating
+    :func:`classmethods <classmethod>` that serve as alternative constructors.
+    In the following example (©
+    `Raymond Hettinger <https://www.youtube.com/watch?v=HTLu2DFOdTg>`_), the
+    type variable ``C`` is bound to the ``Circle`` class through the use of a
+    forward reference. Using this type variable to annotate the
+    ``with_circumference`` classmethod, rather than hardcoding the return type
+    as ``Circle``, means that a type checker can correctly infer the return
+    type even if the method is called on a subclass::
+
+       import math
+
+       C = TypeVar('C', bound='Circle')
+
+       class Circle:
+           """An abstract circle"""
+
+           def __init__(self, radius: float) -> None:
+               self.radius = radius
+
+           # Use a type variable to show that the return type
+           # will always be an instance of whatever `cls` is
+           @classmethod
+           def with_circumference(cls: type[C], circumference: float) -> C:
+               """Create a circle with the specified circumference"""
+               radius = circumference / (math.pi * 2)
+               return cls(radius)
+
+
+       class Tire(Circle):
+           """A specialised circle (made out of rubber)"""
+
+           MATERIAL = 'rubber'
+
+
+       c = Circle.with_circumference(3)  # Ok, variable 'c' has type 'Circle'
+       t = Tire.with_circumference(4)  # Ok, variable 't' has type 'Tire' (not 'Circle')
 
     At runtime, ``isinstance(x, T)`` will raise :exc:`TypeError`.  In general,
     :func:`isinstance` and :func:`issubclass` should not be used with types.
 
     Type variables may be marked covariant or contravariant by passing
     ``covariant=True`` or ``contravariant=True``.  See :pep:`484` for more
-    details.  By default type variables are invariant.  Alternatively,
-    a type variable may specify an upper bound using ``bound=<type>``.
-    This means that an actual type substituted (explicitly or implicitly)
-    for the type variable must be a subclass of the boundary type,
-    see :pep:`484`.
+    details.  By default, type variables are invariant.
 
 .. data:: AnyStr
 
-   ``AnyStr`` is a type variable defined as
+   ``AnyStr`` is a :class:`constrained type variable <TypeVar>` defined as
    ``AnyStr = TypeVar('AnyStr', str, bytes)``.
 
    It is meant to be used for functions that may accept any kind of string
index 04d4081f4a0736ed658a1c51ac9f0bca9d62b11e..4553a104d15a24d16921b856f2ae368e076e28ff 100644 (file)
@@ -13,14 +13,10 @@ of it.  Here's an overview:
 
    posix.rst
    pwd.rst
-   spwd.rst
    grp.rst
-   crypt.rst
    termios.rst
    tty.rst
    pty.rst
    fcntl.rst
-   pipes.rst
    resource.rst
-   nis.rst
    syslog.rst
index 0bc8021e1bdfc7445aaf4a5ac662ef57f90e7e63..c341bc83dcfed0aca91303c15f6728ffd6961771 100644 (file)
@@ -3,11 +3,15 @@
 
 .. module:: uu
    :synopsis: Encode and decode files in uuencode format.
+   :deprecated:
 
 .. moduleauthor:: Lance Ellinghouse
 
 **Source code:** :source:`Lib/uu.py`
 
+.. deprecated:: 3.11
+   The :mod:`uu` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 This module encodes and decodes files in uuencode format, allowing arbitrary
index b60d4e4ccf51d9c2a8a192ebb061842ce1bc6883..4d72ead12aadc7f3f6f0a6ccc8144b1715e16d52 100644 (file)
@@ -9,7 +9,6 @@ This chapter describes modules that are only available on MS Windows platforms.
 
 .. toctree::
 
-   msilib.rst
    msvcrt.rst
    winreg.rst
    winsound.rst
index 42a03a46754d03f0012f1660226eca4ffb863f5f..060b2e2c60df6d6cba3225f1f47dd8577e35cf58 100644 (file)
@@ -3,6 +3,7 @@
 
 .. module:: xdrlib
    :synopsis: Encoders and decoders for the External Data Representation (XDR).
+   :deprecated:
 
 **Source code:** :source:`Lib/xdrlib.py`
 
@@ -10,6 +11,9 @@
    single: XDR
    single: External Data Representation
 
+.. deprecated:: 3.11
+   The :mod:`xdrlib` module is deprecated (see :pep:`594` for details).
+
 --------------
 
 The :mod:`xdrlib` module supports the External Data Representation Standard as
index ec60ea24db662709f0745715e91cf3c738885164..6758c615d74db8242a65fd7f352b5495bd156107 100644 (file)
@@ -42,10 +42,9 @@ The available exception and functions in this module are:
    for use as a general hash algorithm.
 
    .. versionchanged:: 3.0
-      Always returns an unsigned value.
-      To generate the same numeric value across all Python versions and
-      platforms, use ``adler32(data) & 0xffffffff``.
-
+      The result is always unsigned.
+      To generate the same numeric value when using Python 2 or earlier,
+      use ``adler32(data) & 0xffffffff``.
 
 .. function:: compress(data, /, level=-1)
 
@@ -127,10 +126,9 @@ The available exception and functions in this module are:
    for use as a general hash algorithm.
 
    .. versionchanged:: 3.0
-      Always returns an unsigned value.
-      To generate the same numeric value across all Python versions and
-      platforms, use ``crc32(data) & 0xffffffff``.
-
+      The result is always unsigned.
+      To generate the same numeric value when using Python 2 or earlier,
+      use ``crc32(data) & 0xffffffff``.
 
 .. function:: decompress(data, /, wbits=MAX_WBITS, bufsize=DEF_BUF_SIZE)
 
index 0bc1e24437100d42fd1a3a791a348011ac65ac3a..493fd707164bd01feb43b2344c35d207e6226d64 100644 (file)
@@ -253,9 +253,10 @@ is found that matches the exception.  An expression-less except clause, if
 present, must be last; it matches any exception.  For an except clause with an
 expression, that expression is evaluated, and the clause matches the exception
 if the resulting object is "compatible" with the exception.  An object is
-compatible with an exception if it is the class or a base class of the exception
-object, or a tuple containing an item that is the class or a base class of
-the exception object.
+compatible with an exception if the object is the class or a
+:term:`non-virtual base class <abstract base class>` of the exception object,
+or a tuple containing an item that is the class or a non-virtual base class
+of the exception object.
 
 If no except clause matches the exception, the search for an exception handler
 continues in the surrounding code and on the invocation stack.  [#]_
index f4320db60c92ad70d7ca557a106712656b3302b7..84320f41f6caebf0b1495e532506fff23a400ce2 100644 (file)
@@ -1435,7 +1435,7 @@ Basic customization
 
    Called by built-in function :func:`hash` and for operations on members of
    hashed collections including :class:`set`, :class:`frozenset`, and
-   :class:`dict`.  :meth:`__hash__` should return an integer. The only required
+   :class:`dict`.  The ``__hash__()`` method should return an integer. The only required
    property is that objects which compare equal have the same hash value; it is
    advised to mix together the hash values of the components of the object that
    also play a part in comparison of objects by packing them into a tuple and
index 5c85dd7052d673f0e8df9bac0c5b3f8c6bb2b241..5eed24e6ee4a596ec5d92130ca7e61066c5dadb1 100644 (file)
@@ -249,8 +249,9 @@ a stack traceback, except when the exception is :exc:`SystemExit`.
 
 Exceptions are identified by class instances.  The :keyword:`except` clause is
 selected depending on the class of the instance: it must reference the class of
-the instance or a base class thereof.  The instance can be received by the
-handler and can carry additional information about the exceptional condition.
+the instance or a :term:`non-virtual base class <abstract base class>` thereof.
+The instance can be received by the handler and can carry additional information
+about the exceptional condition.
 
 .. note::
 
index 48480ed567713a24a4b6c4b09e5e8c5f6a152956..67e449316e4a21d5b1b07fbf3342d716f35ea110 100644 (file)
@@ -370,3 +370,4 @@ whatsnew/changelog,,::,default::DeprecationWarning
 library/importlib.metadata,,:main,"EntryPoint(name='wheel', value='wheel.cli:main', group='console_scripts')"
 library/importlib.metadata,,`,loading the metadata for packages for the indicated ``context``.
 library/re,,`,"`"
+library/typing,,`,    # will always be an instance of whatever `cls` is
index bf343ad960b8cc22d4ac73ae5165eb2dd7aac87c..a4418b0a6c69156a1d8a79a68ffae167d436d51a 100644 (file)
 /*--start constants--*/
 #define PY_MAJOR_VERSION        3
 #define PY_MINOR_VERSION        9
-#define PY_MICRO_VERSION        11
+#define PY_MICRO_VERSION        12
 #define PY_RELEASE_LEVEL        PY_RELEASE_LEVEL_FINAL
 #define PY_RELEASE_SERIAL       0
 
 /* Version as a string */
-#define PY_VERSION              "3.9.11"
+#define PY_VERSION              "3.9.12"
 /*--end constants--*/
 
 /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
index fbdfd5172fb35b6ae0f6903829e352eda954ba45..c46bb302711fc5c9eca3c8c7b667f4d600fe3ae7 100644 (file)
@@ -726,7 +726,7 @@ def _get_action_name(argument):
     if argument is None:
         return None
     elif argument.option_strings:
-        return  '/'.join(argument.option_strings)
+        return '/'.join(argument.option_strings)
     elif argument.metavar not in (None, SUPPRESS):
         return argument.metavar
     elif argument.dest not in (None, SUPPRESS):
@@ -1256,9 +1256,9 @@ class FileType(object):
         # the special argument "-" means sys.std{in,out}
         if string == '-':
             if 'r' in self._mode:
-                return _sys.stdin
-            elif 'w' in self._mode:
-                return _sys.stdout
+                return _sys.stdin.buffer if 'b' in self._mode else _sys.stdin
+            elif any(c in self._mode for c in 'wax'):
+                return _sys.stdout.buffer if 'b' in self._mode else _sys.stdout
             else:
                 msg = _('argument "-" with mode %r') % self._mode
                 raise ValueError(msg)
index f1ce7324785ba983b8ba12f3283a70757ad0cc86..d17d7ccd813d2a32554d37557af23b73bfac5841 100644 (file)
@@ -378,6 +378,7 @@ class Semaphore(_ContextManagerMixin):
             warnings.warn("The loop argument is deprecated since Python 3.8, "
                           "and scheduled for removal in Python 3.10.",
                           DeprecationWarning, stacklevel=2)
+        self._wakeup_scheduled = False
 
     def __repr__(self):
         res = super().__repr__()
@@ -391,6 +392,7 @@ class Semaphore(_ContextManagerMixin):
             waiter = self._waiters.popleft()
             if not waiter.done():
                 waiter.set_result(None)
+                self._wakeup_scheduled = True
                 return
 
     def locked(self):
@@ -406,16 +408,17 @@ class Semaphore(_ContextManagerMixin):
         called release() to make it larger than 0, and then return
         True.
         """
-        while self._value <= 0:
+        # _wakeup_scheduled is set if *another* task is scheduled to wakeup
+        # but its acquire() is not resumed yet
+        while self._wakeup_scheduled or self._value <= 0:
             fut = self._loop.create_future()
             self._waiters.append(fut)
             try:
                 await fut
-            except:
-                # See the similar code in Queue.get.
-                fut.cancel()
-                if self._value > 0 and not fut.cancelled():
-                    self._wake_up_next()
+                # reset _wakeup_scheduled *after* waiting for a future
+                self._wakeup_scheduled = False
+            except exceptions.CancelledError:
+                self._wake_up_next()
                 raise
         self._value -= 1
         return True
index d2c8828e5ed978b52a0a43f4724e503e4850fea1..3caf4d9949e7b9c057e716135407a0334d268e58 100644 (file)
@@ -2159,6 +2159,7 @@ class DocTestCase(unittest.TestCase):
         unittest.TestCase.__init__(self)
         self._dt_optionflags = optionflags
         self._dt_checker = checker
+        self._dt_globs = test.globs.copy()
         self._dt_test = test
         self._dt_setUp = setUp
         self._dt_tearDown = tearDown
@@ -2175,7 +2176,9 @@ class DocTestCase(unittest.TestCase):
         if self._dt_tearDown is not None:
             self._dt_tearDown(test)
 
+        # restore the original globs
         test.globs.clear()
+        test.globs.update(self._dt_globs)
 
     def runTest(self):
         test = self._dt_test
index 4f9d227ff4603a32add7f79d5992c4a8bb73c4a3..ead678530768f0ad6c45d3141a988755809c2321 100755 (executable)
@@ -69,6 +69,7 @@ import sys
 import sysconfig
 import time
 import tokenize
+import types
 import urllib.parse
 import warnings
 from collections import deque
@@ -90,13 +91,16 @@ def pathdirs():
             normdirs.append(normdir)
     return dirs
 
+def _isclass(object):
+    return inspect.isclass(object) and not isinstance(object, types.GenericAlias)
+
 def _findclass(func):
     cls = sys.modules.get(func.__module__)
     if cls is None:
         return None
     for name in func.__qualname__.split('.')[:-1]:
         cls = getattr(cls, name)
-    if not inspect.isclass(cls):
+    if not _isclass(cls):
         return None
     return cls
 
@@ -104,7 +108,7 @@ def _finddoc(obj):
     if inspect.ismethod(obj):
         name = obj.__func__.__name__
         self = obj.__self__
-        if (inspect.isclass(self) and
+        if (_isclass(self) and
             getattr(getattr(self, name, None), '__func__') is obj.__func__):
             # classmethod
             cls = self
@@ -118,7 +122,7 @@ def _finddoc(obj):
     elif inspect.isbuiltin(obj):
         name = obj.__name__
         self = obj.__self__
-        if (inspect.isclass(self) and
+        if (_isclass(self) and
             self.__qualname__ + '.' + name == obj.__qualname__):
             # classmethod
             cls = self
@@ -205,7 +209,7 @@ def classname(object, modname):
 
 def isdata(object):
     """Check if an object is of a type that probably means it's data."""
-    return not (inspect.ismodule(object) or inspect.isclass(object) or
+    return not (inspect.ismodule(object) or _isclass(object) or
                 inspect.isroutine(object) or inspect.isframe(object) or
                 inspect.istraceback(object) or inspect.iscode(object))
 
@@ -470,7 +474,7 @@ class Doc:
         # by lacking a __name__ attribute) and an instance.
         try:
             if inspect.ismodule(object): return self.docmodule(*args)
-            if inspect.isclass(object): return self.docclass(*args)
+            if _isclass(object): return self.docclass(*args)
             if inspect.isroutine(object): return self.docroutine(*args)
         except AttributeError:
             pass
@@ -775,7 +779,7 @@ class HTMLDoc(Doc):
         modules = inspect.getmembers(object, inspect.ismodule)
 
         classes, cdict = [], {}
-        for key, value in inspect.getmembers(object, inspect.isclass):
+        for key, value in inspect.getmembers(object, _isclass):
             # if __all__ exists, believe it.  Otherwise use old heuristic.
             if (all is not None or
                 (inspect.getmodule(value) or object) is object):
@@ -1217,7 +1221,7 @@ location listed above.
             result = result + self.section('DESCRIPTION', desc)
 
         classes = []
-        for key, value in inspect.getmembers(object, inspect.isclass):
+        for key, value in inspect.getmembers(object, _isclass):
             # if __all__ exists, believe it.  Otherwise use old heuristic.
             if (all is not None
                 or (inspect.getmodule(value) or object) is object):
@@ -1698,7 +1702,7 @@ def describe(thing):
         return 'member descriptor %s.%s.%s' % (
             thing.__objclass__.__module__, thing.__objclass__.__name__,
             thing.__name__)
-    if inspect.isclass(thing):
+    if _isclass(thing):
         return 'class ' + thing.__name__
     if inspect.isfunction(thing):
         return 'function ' + thing.__name__
@@ -1759,7 +1763,7 @@ def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
         desc += ' in module ' + module.__name__
 
     if not (inspect.ismodule(object) or
-              inspect.isclass(object) or
+              _isclass(object) or
               inspect.isroutine(object) or
               inspect.isdatadescriptor(object) or
               _getdoc(object)):
index 0e63c31f1b4fe4493619e08d57783a169f27259f..2546eb933bcbdb3183a8c3ac60424cd440696a53 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Autogenerated by Sphinx on Tue Mar 15 21:44:32 2022
+# Autogenerated by Sphinx on Wed Mar 23 22:08:02 2022
 topics = {'assert': 'The "assert" statement\n'
            '**********************\n'
            '\n'
@@ -2416,11 +2416,11 @@ topics = {'assert': 'The "assert" statement\n'
              'resulting\n'
              'object is “compatible” with the exception.  An object is '
              'compatible\n'
-             'with an exception if it is the class or a base class of the '
-             'exception\n'
-             'object, or a tuple containing an item that is the class or a '
+             'with an exception if the object is the class or a *non-virtual '
              'base\n'
-             'class of the exception object.\n'
+             'class* of the exception object, or a tuple containing an item '
+             'that is\n'
+             'the class or a non-virtual base class of the exception object.\n'
              '\n'
              'If no except clause matches the exception, the search for an '
              'exception\n'
@@ -3567,15 +3567,17 @@ topics = {'assert': 'The "assert" statement\n'
                   'on members\n'
                   '   of hashed collections including "set", "frozenset", and '
                   '"dict".\n'
-                  '   "__hash__()" should return an integer. The only required '
-                  'property\n'
-                  '   is that objects which compare equal have the same hash '
-                  'value; it is\n'
-                  '   advised to mix together the hash values of the '
-                  'components of the\n'
-                  '   object that also play a part in comparison of objects by '
-                  'packing\n'
-                  '   them into a tuple and hashing the tuple. Example:\n'
+                  '   The "__hash__()" method should return an integer. The '
+                  'only required\n'
+                  '   property is that objects which compare equal have the '
+                  'same hash\n'
+                  '   value; it is advised to mix together the hash values of '
+                  'the\n'
+                  '   components of the object that also play a part in '
+                  'comparison of\n'
+                  '   objects by packing them into a tuple and hashing the '
+                  'tuple.\n'
+                  '   Example:\n'
                   '\n'
                   '      def __hash__(self):\n'
                   '          return hash((self.name, self.nick, self.color))\n'
@@ -4559,11 +4561,11 @@ topics = {'assert': 'The "assert" statement\n'
                'clause is\n'
                'selected depending on the class of the instance: it must '
                'reference the\n'
-               'class of the instance or a base class thereof.  The instance '
-               'can be\n'
-               'received by the handler and can carry additional information '
-               'about the\n'
-               'exceptional condition.\n'
+               'class of the instance or a *non-virtual base class* thereof. '
+               'The\n'
+               'instance can be received by the handler and can carry '
+               'additional\n'
+               'information about the exceptional condition.\n'
                '\n'
                'Note:\n'
                '\n'
@@ -4886,11 +4888,11 @@ topics = {'assert': 'The "assert" statement\n'
               'clause is\n'
               'selected depending on the class of the instance: it must '
               'reference the\n'
-              'class of the instance or a base class thereof.  The instance '
-              'can be\n'
-              'received by the handler and can carry additional information '
-              'about the\n'
-              'exceptional condition.\n'
+              'class of the instance or a *non-virtual base class* thereof. '
+              'The\n'
+              'instance can be received by the handler and can carry '
+              'additional\n'
+              'information about the exceptional condition.\n'
               '\n'
               'Note:\n'
               '\n'
@@ -8440,15 +8442,17 @@ topics = {'assert': 'The "assert" statement\n'
                  'on members\n'
                  '   of hashed collections including "set", "frozenset", and '
                  '"dict".\n'
-                 '   "__hash__()" should return an integer. The only required '
-                 'property\n'
-                 '   is that objects which compare equal have the same hash '
-                 'value; it is\n'
-                 '   advised to mix together the hash values of the components '
-                 'of the\n'
-                 '   object that also play a part in comparison of objects by '
-                 'packing\n'
-                 '   them into a tuple and hashing the tuple. Example:\n'
+                 '   The "__hash__()" method should return an integer. The '
+                 'only required\n'
+                 '   property is that objects which compare equal have the '
+                 'same hash\n'
+                 '   value; it is advised to mix together the hash values of '
+                 'the\n'
+                 '   components of the object that also play a part in '
+                 'comparison of\n'
+                 '   objects by packing them into a tuple and hashing the '
+                 'tuple.\n'
+                 '   Example:\n'
                  '\n'
                  '      def __hash__(self):\n'
                  '          return hash((self.name, self.nick, self.color))\n'
@@ -11531,10 +11535,10 @@ topics = {'assert': 'The "assert" statement\n'
         'exception.  For an except clause with an expression, that expression\n'
         'is evaluated, and the clause matches the exception if the resulting\n'
         'object is “compatible” with the exception.  An object is compatible\n'
-        'with an exception if it is the class or a base class of the '
-        'exception\n'
-        'object, or a tuple containing an item that is the class or a base\n'
-        'class of the exception object.\n'
+        'with an exception if the object is the class or a *non-virtual base\n'
+        'class* of the exception object, or a tuple containing an item that '
+        'is\n'
+        'the class or a non-virtual base class of the exception object.\n'
         '\n'
         'If no except clause matches the exception, the search for an '
         'exception\n'
index 83119168e6376ee83bb41f7b75d2c9a0cd3058d7..53706676e9f7b8ae2dff7ebce28e226d328fd37b 100644 (file)
@@ -807,9 +807,11 @@ def _parse(source, state, verbose, nested, first=False):
                         if not first or subpattern:
                             import warnings
                             warnings.warn(
-                                'Flags not at the start of the expression %r%s' % (
+                                'Flags not at the start of the expression %r%s'
+                                ' but at position %d' % (
                                     source.string[:20],  # truncate long regexes
                                     ' (truncated)' if len(source.string) > 20 else '',
+                                    start,
                                 ),
                                 DeprecationWarning, stacklevel=nested + 6
                             )
index 56458afd290bb26bfa7fc16554b910d81bb00d6f..6e7abdc322d837f050dd3b80f1e142059d164038 100644 (file)
@@ -530,7 +530,24 @@ class Regrtest:
 
         if self.ns.use_mp:
             from test.libregrtest.runtest_mp import run_tests_multiprocess
-            run_tests_multiprocess(self)
+            # If we're on windows and this is the parent runner (not a worker),
+            # track the load average.
+            if sys.platform == 'win32' and self.worker_test_name is None:
+                from test.libregrtest.win_utils import WindowsLoadTracker
+
+                try:
+                    self.win_load_tracker = WindowsLoadTracker()
+                except PermissionError as error:
+                    # Standard accounts may not have access to the performance
+                    # counters.
+                    print(f'Failed to create WindowsLoadTracker: {error}')
+
+            try:
+                run_tests_multiprocess(self)
+            finally:
+                if self.win_load_tracker is not None:
+                    self.win_load_tracker.close()
+                    self.win_load_tracker = None
         else:
             self.run_tests_sequential()
 
@@ -692,28 +709,11 @@ class Regrtest:
             self.list_cases()
             sys.exit(0)
 
-        # If we're on windows and this is the parent runner (not a worker),
-        # track the load average.
-        if sys.platform == 'win32' and self.worker_test_name is None:
-            from test.libregrtest.win_utils import WindowsLoadTracker
-
-            try:
-                self.win_load_tracker = WindowsLoadTracker()
-            except FileNotFoundError as error:
-                # Windows IoT Core and Windows Nano Server do not provide
-                # typeperf.exe for x64, x86 or ARM
-                print(f'Failed to create WindowsLoadTracker: {error}')
+        self.run_tests()
+        self.display_result()
 
-        try:
-            self.run_tests()
-            self.display_result()
-
-            if self.ns.verbose2 and self.bad:
-                self.rerun_failed_tests()
-        finally:
-            if self.win_load_tracker is not None:
-                self.win_load_tracker.close()
-                self.win_load_tracker = None
+        if self.ns.verbose2 and self.bad:
+            self.rerun_failed_tests()
 
         self.finalize()
 
index 028c01106dee08ed53af2178591584b43dafd510..5736cdfd3c72926630acfa5c465a83fe5392c757 100644 (file)
@@ -1,16 +1,11 @@
+import _overlapped
+import _thread
 import _winapi
 import math
-import msvcrt
-import os
-import subprocess
-import uuid
+import struct
 import winreg
-from test import support
-from test.libregrtest.utils import print_warning
 
 
-# Max size of asynchronous reads
-BUFSIZE = 8192
 # Seconds per measurement
 SAMPLING_INTERVAL = 1
 # Exponential damping factor to compute exponentially weighted moving average
@@ -19,172 +14,111 @@ LOAD_FACTOR_1 = 1 / math.exp(SAMPLING_INTERVAL / 60)
 # Initialize the load using the arithmetic mean of the first NVALUE values
 # of the Processor Queue Length
 NVALUE = 5
-# Windows registry subkey of HKEY_LOCAL_MACHINE where the counter names
-# of typeperf are registered
-COUNTER_REGISTRY_KEY = (r"SOFTWARE\Microsoft\Windows NT\CurrentVersion"
-                        r"\Perflib\CurrentLanguage")
 
 
 class WindowsLoadTracker():
     """
-    This class asynchronously interacts with the `typeperf` command to read
-    the system load on Windows. Multiprocessing and threads can't be used
-    here because they interfere with the test suite's cases for those
-    modules.
+    This class asynchronously reads the performance counters to calculate
+    the system load on Windows.  A "raw" thread is used here to prevent
+    interference with the test suite's cases for the threading module.
     """
 
     def __init__(self):
+        # Pre-flight test for access to the performance data;
+        # `PermissionError` will be raised if not allowed
+        winreg.QueryInfoKey(winreg.HKEY_PERFORMANCE_DATA)
+
         self._values = []
         self._load = None
-        self._buffer = ''
-        self._popen = None
-        self.start()
-
-    def start(self):
-        # Create a named pipe which allows for asynchronous IO in Windows
-        pipe_name =  r'\\.\pipe\typeperf_output_' + str(uuid.uuid4())
-
-        open_mode =  _winapi.PIPE_ACCESS_INBOUND
-        open_mode |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE
-        open_mode |= _winapi.FILE_FLAG_OVERLAPPED
-
-        # This is the read end of the pipe, where we will be grabbing output
-        self.pipe = _winapi.CreateNamedPipe(
-            pipe_name, open_mode, _winapi.PIPE_WAIT,
-            1, BUFSIZE, BUFSIZE, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL
-        )
-        # The write end of the pipe which is passed to the created process
-        pipe_write_end = _winapi.CreateFile(
-            pipe_name, _winapi.GENERIC_WRITE, 0, _winapi.NULL,
-            _winapi.OPEN_EXISTING, 0, _winapi.NULL
-        )
-        # Open up the handle as a python file object so we can pass it to
-        # subprocess
-        command_stdout = msvcrt.open_osfhandle(pipe_write_end, 0)
-
-        # Connect to the read end of the pipe in overlap/async mode
-        overlap = _winapi.ConnectNamedPipe(self.pipe, overlapped=True)
-        overlap.GetOverlappedResult(True)
-
-        # Spawn off the load monitor
-        counter_name = self._get_counter_name()
-        command = ['typeperf', counter_name, '-si', str(SAMPLING_INTERVAL)]
-        self._popen = subprocess.Popen(' '.join(command), stdout=command_stdout, cwd=support.SAVEDCWD)
-
-        # Close our copy of the write end of the pipe
-        os.close(command_stdout)
-
-    def _get_counter_name(self):
-        # accessing the registry to get the counter localization name
-        with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, COUNTER_REGISTRY_KEY) as perfkey:
-            counters = winreg.QueryValueEx(perfkey, 'Counter')[0]
-
-        # Convert [key1, value1, key2, value2, ...] list
-        # to {key1: value1, key2: value2, ...} dict
-        counters = iter(counters)
-        counters_dict = dict(zip(counters, counters))
-
-        # System counter has key '2' and Processor Queue Length has key '44'
-        system = counters_dict['2']
-        process_queue_length = counters_dict['44']
-        return f'"\\{system}\\{process_queue_length}"'
-
-    def close(self, kill=True):
-        if self._popen is None:
+        self._running = _overlapped.CreateEvent(None, True, False, None)
+        self._stopped = _overlapped.CreateEvent(None, True, False, None)
+
+        _thread.start_new_thread(self._update_load, (), {})
+
+    def _update_load(self,
+                    # localize module access to prevent shutdown errors
+                     _wait=_winapi.WaitForSingleObject,
+                     _signal=_overlapped.SetEvent):
+        # run until signaled to stop
+        while _wait(self._running, 1000):
+            self._calculate_load()
+        # notify stopped
+        _signal(self._stopped)
+
+    def _calculate_load(self,
+                        # localize module access to prevent shutdown errors
+                        _query=winreg.QueryValueEx,
+                        _hkey=winreg.HKEY_PERFORMANCE_DATA,
+                        _unpack=struct.unpack_from):
+        # get the 'System' object
+        data, _ = _query(_hkey, '2')
+        # PERF_DATA_BLOCK {
+        #   WCHAR Signature[4]      8 +
+        #   DWOWD LittleEndian      4 +
+        #   DWORD Version           4 +
+        #   DWORD Revision          4 +
+        #   DWORD TotalByteLength   4 +
+        #   DWORD HeaderLength      = 24 byte offset
+        #   ...
+        # }
+        obj_start, = _unpack('L', data, 24)
+        # PERF_OBJECT_TYPE {
+        #   DWORD TotalByteLength
+        #   DWORD DefinitionLength
+        #   DWORD HeaderLength
+        #   ...
+        # }
+        data_start, defn_start = _unpack('4xLL', data, obj_start)
+        data_base = obj_start + data_start
+        defn_base = obj_start + defn_start
+        # find the 'Processor Queue Length' counter (index=44)
+        while defn_base < data_base:
+            # PERF_COUNTER_DEFINITION {
+            #   DWORD ByteLength
+            #   DWORD CounterNameTitleIndex
+            #   ... [7 DWORDs/28 bytes]
+            #   DWORD CounterOffset
+            # }
+            size, idx, offset = _unpack('LL28xL', data, defn_base)
+            defn_base += size
+            if idx == 44:
+                counter_offset = data_base + offset
+                # the counter is known to be PERF_COUNTER_RAWCOUNT (DWORD)
+                processor_queue_length, = _unpack('L', data, counter_offset)
+                break
+        else:
             return
 
-        self._load = None
-
-        if kill:
-            self._popen.kill()
-        self._popen.wait()
-        self._popen = None
-
-    def __del__(self):
-        self.close()
-
-    def _parse_line(self, line):
-        # typeperf outputs in a CSV format like this:
-        # "07/19/2018 01:32:26.605","3.000000"
-        # (date, process queue length)
-        tokens = line.split(',')
-        if len(tokens) != 2:
-            raise ValueError
-
-        value = tokens[1]
-        if not value.startswith('"') or not value.endswith('"'):
-            raise ValueError
-        value = value[1:-1]
-        return float(value)
-
-    def _read_lines(self):
-        overlapped, _ = _winapi.ReadFile(self.pipe, BUFSIZE, True)
-        bytes_read, res = overlapped.GetOverlappedResult(False)
-        if res != 0:
-            return ()
-
-        output = overlapped.getbuffer()
-        output = output.decode('oem', 'replace')
-        output = self._buffer + output
-        lines = output.splitlines(True)
-
-        # bpo-36670: typeperf only writes a newline *before* writing a value,
-        # not after. Sometimes, the written line in incomplete (ex: only
-        # timestamp, without the process queue length). Only pass the last line
-        # to the parser if it's a valid value, otherwise store it in
-        # self._buffer.
-        try:
-            self._parse_line(lines[-1])
-        except ValueError:
-            self._buffer = lines.pop(-1)
+        # We use an exponentially weighted moving average, imitating the
+        # load calculation on Unix systems.
+        # https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation
+        # https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
+        if self._load is not None:
+            self._load = (self._load * LOAD_FACTOR_1
+                            + processor_queue_length  * (1.0 - LOAD_FACTOR_1))
+        elif len(self._values) < NVALUE:
+            self._values.append(processor_queue_length)
         else:
-            self._buffer = ''
+            self._load = sum(self._values) / len(self._values)
 
-        return lines
+    def close(self, kill=True):
+        self.__del__()
+        return
+
+    def __del__(self,
+                # localize module access to prevent shutdown errors
+                _wait=_winapi.WaitForSingleObject,
+                _close=_winapi.CloseHandle,
+                _signal=_overlapped.SetEvent):
+        if self._running is not None:
+            # tell the update thread to quit
+            _signal(self._running)
+            # wait for the update thread to signal done
+            _wait(self._stopped, -1)
+            # cleanup events
+            _close(self._running)
+            _close(self._stopped)
+            self._running = self._stopped = None
 
     def getloadavg(self):
-        if self._popen is None:
-            return None
-
-        returncode = self._popen.poll()
-        if returncode is not None:
-            self.close(kill=False)
-            return None
-
-        try:
-            lines = self._read_lines()
-        except BrokenPipeError:
-            self.close()
-            return None
-
-        for line in lines:
-            line = line.rstrip()
-
-            # Ignore the initial header:
-            # "(PDH-CSV 4.0)","\\\\WIN\\System\\Processor Queue Length"
-            if 'PDH-CSV' in line:
-                continue
-
-            # Ignore blank lines
-            if not line:
-                continue
-
-            try:
-                processor_queue_length = self._parse_line(line)
-            except ValueError:
-                print_warning("Failed to parse typeperf output: %a" % line)
-                continue
-
-            # We use an exponentially weighted moving average, imitating the
-            # load calculation on Unix systems.
-            # https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation
-            # https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
-            if self._load is not None:
-                self._load = (self._load * LOAD_FACTOR_1
-                              + processor_queue_length  * (1.0 - LOAD_FACTOR_1))
-            elif len(self._values) < NVALUE:
-                self._values.append(processor_queue_length)
-            else:
-                self._load = sum(self._values) / len(self._values)
-
         return self._load
index 9c1fff5c2f2c1491d676e7ce75c2752497a64b71..bc3677b7e0548831670f68140ac11f9c6db1e939 100644 (file)
@@ -1,5 +1,8 @@
 """This is a test module for test_pydoc"""
 
+import types
+import typing
+
 __author__ = "Benjamin Peterson"
 __credits__ = "Nobody"
 __version__ = "1.2.3.4"
@@ -24,6 +27,8 @@ class C(object):
     def is_it_true(self):
         """ Return self.get_answer() """
         return self.get_answer()
+    def __class_getitem__(self, item):
+        return types.GenericAlias(self, item)
 
 def doc_func():
     """
@@ -35,3 +40,9 @@ def doc_func():
 
 def nodoc_func():
     pass
+
+
+list_alias1 = typing.List[int]
+list_alias2 = list[int]
+c_alias = C[int]
+type_union1 = typing.Union[int, str]
index 5c86583ce10a41c18026878709b165d757c39082..dcc392faf231093684f6fa5d466da6acfde2936c 100644 (file)
@@ -1,6 +1,8 @@
 # Author: Steven J. Bethard <steven.bethard@gmail.com>.
 
 import inspect
+import io
+import operator
 import os
 import shutil
 import stat
@@ -10,12 +12,27 @@ import tempfile
 import unittest
 import argparse
 
-from io import StringIO
-
 from test import support
 from unittest import mock
-class StdIOBuffer(StringIO):
-    pass
+
+
+class StdIOBuffer(io.TextIOWrapper):
+    '''Replacement for writable io.StringIO that behaves more like real file
+
+    Unlike StringIO, provides a buffer attribute that holds the underlying
+    binary data, allowing it to replace sys.stdout/sys.stderr in more
+    contexts.
+    '''
+
+    def __init__(self, initial_value='', newline='\n'):
+        initial_value = initial_value.encode('utf-8')
+        super().__init__(io.BufferedWriter(io.BytesIO(initial_value)),
+                         'utf-8', newline=newline)
+
+    def getvalue(self):
+        self.flush()
+        return self.buffer.raw.getvalue().decode('utf-8')
+
 
 class TestCase(unittest.TestCase):
 
@@ -42,11 +59,14 @@ class TempDirMixin(object):
                 os.chmod(os.path.join(self.temp_dir, name), stat.S_IWRITE)
         shutil.rmtree(self.temp_dir, True)
 
-    def create_readonly_file(self, filename):
+    def create_writable_file(self, filename):
         file_path = os.path.join(self.temp_dir, filename)
         with open(file_path, 'w') as file:
             file.write(filename)
-        os.chmod(file_path, stat.S_IREAD)
+        return file_path
+
+    def create_readonly_file(self, filename):
+        os.chmod(self.create_writable_file(filename), stat.S_IREAD)
 
 class Sig(object):
 
@@ -96,10 +116,15 @@ def stderr_to_parser_error(parse_args, *args, **kwargs):
         try:
             result = parse_args(*args, **kwargs)
             for key in list(vars(result)):
-                if getattr(result, key) is sys.stdout:
+                attr = getattr(result, key)
+                if attr is sys.stdout:
                     setattr(result, key, old_stdout)
-                if getattr(result, key) is sys.stderr:
+                elif attr is sys.stdout.buffer:
+                    setattr(result, key, getattr(old_stdout, 'buffer', BIN_STDOUT_SENTINEL))
+                elif attr is sys.stderr:
                     setattr(result, key, old_stderr)
+                elif attr is sys.stderr.buffer:
+                    setattr(result, key, getattr(old_stderr, 'buffer', BIN_STDERR_SENTINEL))
             return result
         except SystemExit as e:
             code = e.code
@@ -1545,16 +1570,40 @@ class TestFileTypeRepr(TestCase):
         type = argparse.FileType('r', 1, errors='replace')
         self.assertEqual("FileType('r', 1, errors='replace')", repr(type))
 
+
+BIN_STDOUT_SENTINEL = object()
+BIN_STDERR_SENTINEL = object()
+
+
 class StdStreamComparer:
     def __init__(self, attr):
-        self.attr = attr
+        # We try to use the actual stdXXX.buffer attribute as our
+        # marker, but but under some test environments,
+        # sys.stdout/err are replaced by io.StringIO which won't have .buffer,
+        # so we use a sentinel simply to show that the tests do the right thing
+        # for any buffer supporting object
+        self.getattr = operator.attrgetter(attr)
+        if attr == 'stdout.buffer':
+            self.backupattr = BIN_STDOUT_SENTINEL
+        elif attr == 'stderr.buffer':
+            self.backupattr = BIN_STDERR_SENTINEL
+        else:
+            self.backupattr = object() # Not equal to anything
 
     def __eq__(self, other):
-        return other == getattr(sys, self.attr)
+        try:
+            return other == self.getattr(sys)
+        except AttributeError:
+            return other == self.backupattr
+
 
 eq_stdin = StdStreamComparer('stdin')
 eq_stdout = StdStreamComparer('stdout')
 eq_stderr = StdStreamComparer('stderr')
+eq_bstdin = StdStreamComparer('stdin.buffer')
+eq_bstdout = StdStreamComparer('stdout.buffer')
+eq_bstderr = StdStreamComparer('stderr.buffer')
+
 
 class RFile(object):
     seen = {}
@@ -1631,7 +1680,7 @@ class TestFileTypeRB(TempDirMixin, ParserTestCase):
         ('foo', NS(x=None, spam=RFile('foo'))),
         ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
         ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
-        ('-x - -', NS(x=eq_stdin, spam=eq_stdin)),
+        ('-x - -', NS(x=eq_bstdin, spam=eq_bstdin)),
     ]
 
 
@@ -1658,8 +1707,9 @@ class TestFileTypeW(TempDirMixin, ParserTestCase):
     """Test the FileType option/argument type for writing files"""
 
     def setUp(self):
-        super(TestFileTypeW, self).setUp()
+        super().setUp()
         self.create_readonly_file('readonly')
+        self.create_writable_file('writable')
 
     argument_signatures = [
         Sig('-x', type=argparse.FileType('w')),
@@ -1668,13 +1718,37 @@ class TestFileTypeW(TempDirMixin, ParserTestCase):
     failures = ['-x', '', 'readonly']
     successes = [
         ('foo', NS(x=None, spam=WFile('foo'))),
+        ('writable', NS(x=None, spam=WFile('writable'))),
         ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
         ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
         ('-x - -', NS(x=eq_stdout, spam=eq_stdout)),
     ]
 
+@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
+                 "non-root user required")
+class TestFileTypeX(TempDirMixin, ParserTestCase):
+    """Test the FileType option/argument type for writing new files only"""
+
+    def setUp(self):
+        super().setUp()
+        self.create_readonly_file('readonly')
+        self.create_writable_file('writable')
+
+    argument_signatures = [
+        Sig('-x', type=argparse.FileType('x')),
+        Sig('spam', type=argparse.FileType('x')),
+    ]
+    failures = ['-x', '', 'readonly', 'writable']
+    successes = [
+        ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
+        ('-x - -', NS(x=eq_stdout, spam=eq_stdout)),
+    ]
+
 
+@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
+                 "non-root user required")
 class TestFileTypeWB(TempDirMixin, ParserTestCase):
+    """Test the FileType option/argument type for writing binary files"""
 
     argument_signatures = [
         Sig('-x', type=argparse.FileType('wb')),
@@ -1685,7 +1759,22 @@ class TestFileTypeWB(TempDirMixin, ParserTestCase):
         ('foo', NS(x=None, spam=WFile('foo'))),
         ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
         ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
-        ('-x - -', NS(x=eq_stdout, spam=eq_stdout)),
+        ('-x - -', NS(x=eq_bstdout, spam=eq_bstdout)),
+    ]
+
+
+@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
+                 "non-root user required")
+class TestFileTypeXB(TestFileTypeX):
+    "Test the FileType option/argument type for writing new binary files only"
+
+    argument_signatures = [
+        Sig('-x', type=argparse.FileType('xb')),
+        Sig('spam', type=argparse.FileType('xb')),
+    ]
+    successes = [
+        ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
+        ('-x - -', NS(x=eq_bstdout, spam=eq_bstdout)),
     ]
 
 
diff --git a/Lib/test/test_asyncio/test_asyncio_waitfor.py b/Lib/test/test_asyncio/test_asyncio_waitfor.py
deleted file mode 100644 (file)
index 2ca64ab..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-import asyncio
-import unittest
-import time
-
-def tearDownModule():
-    asyncio.set_event_loop_policy(None)
-
-
-class SlowTask:
-    """ Task will run for this defined time, ignoring cancel requests """
-    TASK_TIMEOUT = 0.2
-
-    def __init__(self):
-        self.exited = False
-
-    async def run(self):
-        exitat = time.monotonic() + self.TASK_TIMEOUT
-
-        while True:
-            tosleep = exitat - time.monotonic()
-            if tosleep <= 0:
-                break
-
-            try:
-                await asyncio.sleep(tosleep)
-            except asyncio.CancelledError:
-                pass
-
-        self.exited = True
-
-class AsyncioWaitForTest(unittest.TestCase):
-
-    async def atest_asyncio_wait_for_cancelled(self):
-        t  = SlowTask()
-
-        waitfortask = asyncio.create_task(asyncio.wait_for(t.run(), t.TASK_TIMEOUT * 2))
-        await asyncio.sleep(0)
-        waitfortask.cancel()
-        await asyncio.wait({waitfortask})
-
-        self.assertTrue(t.exited)
-
-    def test_asyncio_wait_for_cancelled(self):
-        asyncio.run(self.atest_asyncio_wait_for_cancelled())
-
-    async def atest_asyncio_wait_for_timeout(self):
-        t  = SlowTask()
-
-        try:
-            await asyncio.wait_for(t.run(), t.TASK_TIMEOUT / 2)
-        except asyncio.TimeoutError:
-            pass
-
-        self.assertTrue(t.exited)
-
-    def test_asyncio_wait_for_timeout(self):
-        asyncio.run(self.atest_asyncio_wait_for_timeout())
-
-
-if __name__ == '__main__':
-    unittest.main()
index b9aae360384eaf4f01fdd44ad692a5e09fedca80..79ebbd26804a541015143e8d171ca97d091b3cd0 100644 (file)
@@ -961,6 +961,32 @@ class SemaphoreTests(unittest.IsolatedAsyncioTestCase):
         sem.release()
         self.assertFalse(sem.locked())
 
+    async def test_acquire_fifo_order(self):
+        sem = asyncio.Semaphore(1)
+        result = []
+
+        async def coro(tag):
+            await sem.acquire()
+            result.append(f'{tag}_1')
+            await asyncio.sleep(0.01)
+            sem.release()
+
+            await sem.acquire()
+            result.append(f'{tag}_2')
+            await asyncio.sleep(0.01)
+            sem.release()
+
+        t1 = asyncio.create_task(coro('c1'))
+        t2 = asyncio.create_task(coro('c2'))
+        t3 = asyncio.create_task(coro('c3'))
+
+        await asyncio.gather(t1, t2, t3)
+
+        self.assertEqual(
+            ['c1_1', 'c2_1', 'c3_1', 'c1_2', 'c2_2', 'c3_2'],
+            result
+        )
+
 
 if __name__ == '__main__':
     unittest.main()
index 0e538edcd9678e73d076f9b4f0759304abf27b15..f311876acdeb3cd09cf748547850f28442d9d614 100644 (file)
@@ -98,12 +98,6 @@ class CoroLikeObject:
         return self
 
 
-# The following value can be used as a very small timeout:
-# it passes check "timeout > 0", but has almost
-# no effect on the test performance
-_EPSILON = 0.0001
-
-
 class BaseTaskTests:
 
     Task = None
@@ -121,7 +115,6 @@ class BaseTaskTests:
         self.loop.set_task_factory(self.new_task)
         self.loop.create_future = lambda: self.new_future(self.loop)
 
-
     def test_generic_alias(self):
         task = self.__class__.Task[str]
         self.assertEqual(task.__args__, (str,))
@@ -977,278 +970,6 @@ class BaseTaskTests:
             task._log_traceback = True
         self.loop.run_until_complete(task)
 
-    def test_wait_for_timeout_less_then_0_or_0_future_done(self):
-        def gen():
-            when = yield
-            self.assertAlmostEqual(0, when)
-
-        loop = self.new_test_loop(gen)
-
-        fut = self.new_future(loop)
-        fut.set_result('done')
-
-        ret = loop.run_until_complete(asyncio.wait_for(fut, 0))
-
-        self.assertEqual(ret, 'done')
-        self.assertTrue(fut.done())
-        self.assertAlmostEqual(0, loop.time())
-
-    def test_wait_for_timeout_less_then_0_or_0_coroutine_do_not_started(self):
-        def gen():
-            when = yield
-            self.assertAlmostEqual(0, when)
-
-        loop = self.new_test_loop(gen)
-
-        foo_started = False
-
-        async def foo():
-            nonlocal foo_started
-            foo_started = True
-
-        with self.assertRaises(asyncio.TimeoutError):
-            loop.run_until_complete(asyncio.wait_for(foo(), 0))
-
-        self.assertAlmostEqual(0, loop.time())
-        self.assertEqual(foo_started, False)
-
-    def test_wait_for_timeout_less_then_0_or_0(self):
-        def gen():
-            when = yield
-            self.assertAlmostEqual(0.2, when)
-            when = yield 0
-            self.assertAlmostEqual(0, when)
-
-        for timeout in [0, -1]:
-            with self.subTest(timeout=timeout):
-                loop = self.new_test_loop(gen)
-
-                foo_running = None
-
-                async def foo():
-                    nonlocal foo_running
-                    foo_running = True
-                    try:
-                        await asyncio.sleep(0.2)
-                    finally:
-                        foo_running = False
-                    return 'done'
-
-                fut = self.new_task(loop, foo())
-
-                with self.assertRaises(asyncio.TimeoutError):
-                    loop.run_until_complete(asyncio.wait_for(fut, timeout))
-                self.assertTrue(fut.done())
-                # it should have been cancelled due to the timeout
-                self.assertTrue(fut.cancelled())
-                self.assertAlmostEqual(0, loop.time())
-                self.assertEqual(foo_running, False)
-
-    def test_wait_for(self):
-
-        def gen():
-            when = yield
-            self.assertAlmostEqual(0.2, when)
-            when = yield 0
-            self.assertAlmostEqual(0.1, when)
-            when = yield 0.1
-
-        loop = self.new_test_loop(gen)
-
-        foo_running = None
-
-        async def foo():
-            nonlocal foo_running
-            foo_running = True
-            try:
-                await asyncio.sleep(0.2)
-            finally:
-                foo_running = False
-            return 'done'
-
-        fut = self.new_task(loop, foo())
-
-        with self.assertRaises(asyncio.TimeoutError):
-            loop.run_until_complete(asyncio.wait_for(fut, 0.1))
-        self.assertTrue(fut.done())
-        # it should have been cancelled due to the timeout
-        self.assertTrue(fut.cancelled())
-        self.assertAlmostEqual(0.1, loop.time())
-        self.assertEqual(foo_running, False)
-
-    def test_wait_for_blocking(self):
-        loop = self.new_test_loop()
-
-        async def coro():
-            return 'done'
-
-        res = loop.run_until_complete(asyncio.wait_for(coro(), timeout=None))
-        self.assertEqual(res, 'done')
-
-    def test_wait_for_with_global_loop(self):
-
-        def gen():
-            when = yield
-            self.assertAlmostEqual(0.2, when)
-            when = yield 0
-            self.assertAlmostEqual(0.01, when)
-            yield 0.01
-
-        loop = self.new_test_loop(gen)
-
-        async def foo():
-            await asyncio.sleep(0.2)
-            return 'done'
-
-        asyncio.set_event_loop(loop)
-        try:
-            fut = self.new_task(loop, foo())
-            with self.assertRaises(asyncio.TimeoutError):
-                loop.run_until_complete(asyncio.wait_for(fut, 0.01))
-        finally:
-            asyncio.set_event_loop(None)
-
-        self.assertAlmostEqual(0.01, loop.time())
-        self.assertTrue(fut.done())
-        self.assertTrue(fut.cancelled())
-
-    def test_wait_for_race_condition(self):
-
-        def gen():
-            yield 0.1
-            yield 0.1
-            yield 0.1
-
-        loop = self.new_test_loop(gen)
-
-        fut = self.new_future(loop)
-        task = asyncio.wait_for(fut, timeout=0.2)
-        loop.call_later(0.1, fut.set_result, "ok")
-        res = loop.run_until_complete(task)
-        self.assertEqual(res, "ok")
-
-    def test_wait_for_cancellation_race_condition(self):
-        async def inner():
-            with contextlib.suppress(asyncio.CancelledError):
-                await asyncio.sleep(1)
-            return 1
-
-        async def main():
-            result = await asyncio.wait_for(inner(), timeout=.01)
-            assert result == 1
-
-        asyncio.run(main())
-
-    def test_wait_for_waits_for_task_cancellation(self):
-        loop = asyncio.new_event_loop()
-        self.addCleanup(loop.close)
-
-        task_done = False
-
-        async def foo():
-            async def inner():
-                nonlocal task_done
-                try:
-                    await asyncio.sleep(0.2)
-                except asyncio.CancelledError:
-                    await asyncio.sleep(_EPSILON)
-                    raise
-                finally:
-                    task_done = True
-
-            inner_task = self.new_task(loop, inner())
-
-            await asyncio.wait_for(inner_task, timeout=_EPSILON)
-
-        with self.assertRaises(asyncio.TimeoutError) as cm:
-            loop.run_until_complete(foo())
-
-        self.assertTrue(task_done)
-        chained = cm.exception.__context__
-        self.assertEqual(type(chained), asyncio.CancelledError)
-
-    def test_wait_for_waits_for_task_cancellation_w_timeout_0(self):
-        loop = asyncio.new_event_loop()
-        self.addCleanup(loop.close)
-
-        task_done = False
-
-        async def foo():
-            async def inner():
-                nonlocal task_done
-                try:
-                    await asyncio.sleep(10)
-                except asyncio.CancelledError:
-                    await asyncio.sleep(_EPSILON)
-                    raise
-                finally:
-                    task_done = True
-
-            inner_task = self.new_task(loop, inner())
-            await asyncio.sleep(_EPSILON)
-            await asyncio.wait_for(inner_task, timeout=0)
-
-        with self.assertRaises(asyncio.TimeoutError) as cm:
-            loop.run_until_complete(foo())
-
-        self.assertTrue(task_done)
-        chained = cm.exception.__context__
-        self.assertEqual(type(chained), asyncio.CancelledError)
-
-    def test_wait_for_reraises_exception_during_cancellation(self):
-        loop = asyncio.new_event_loop()
-        self.addCleanup(loop.close)
-
-        class FooException(Exception):
-            pass
-
-        async def foo():
-            async def inner():
-                try:
-                    await asyncio.sleep(0.2)
-                finally:
-                    raise FooException
-
-            inner_task = self.new_task(loop, inner())
-
-            await asyncio.wait_for(inner_task, timeout=_EPSILON)
-
-        with self.assertRaises(FooException):
-            loop.run_until_complete(foo())
-
-    def test_wait_for_self_cancellation(self):
-        loop = asyncio.new_event_loop()
-        self.addCleanup(loop.close)
-
-        async def foo():
-            async def inner():
-                try:
-                    await asyncio.sleep(0.3)
-                except asyncio.CancelledError:
-                    try:
-                        await asyncio.sleep(0.3)
-                    except asyncio.CancelledError:
-                        await asyncio.sleep(0.3)
-
-                return 42
-
-            inner_task = self.new_task(loop, inner())
-
-            wait = asyncio.wait_for(inner_task, timeout=0.1)
-
-            # Test that wait_for itself is properly cancellable
-            # even when the initial task holds up the initial cancellation.
-            task = self.new_task(loop, wait)
-            await asyncio.sleep(0.2)
-            task.cancel()
-
-            with self.assertRaises(asyncio.CancelledError):
-                await task
-
-            self.assertEqual(await inner_task, 42)
-
-        loop.run_until_complete(foo())
-
     def test_wait(self):
 
         def gen():
@@ -2467,32 +2188,6 @@ class BaseTaskTests:
                           'test_task_source_traceback'))
         self.loop.run_until_complete(task)
 
-    def _test_cancel_wait_for(self, timeout):
-        loop = asyncio.new_event_loop()
-        self.addCleanup(loop.close)
-
-        async def blocking_coroutine():
-            fut = self.new_future(loop)
-            # Block: fut result is never set
-            await fut
-
-        task = loop.create_task(blocking_coroutine())
-
-        wait = loop.create_task(asyncio.wait_for(task, timeout))
-        loop.call_soon(wait.cancel)
-
-        self.assertRaises(asyncio.CancelledError,
-                          loop.run_until_complete, wait)
-
-        # Python issue #23219: cancelling the wait must also cancel the task
-        self.assertTrue(task.cancelled())
-
-    def test_cancel_blocking_wait_for(self):
-        self._test_cancel_wait_for(None)
-
-    def test_cancel_wait_for(self):
-        self._test_cancel_wait_for(60.0)
-
     def test_cancel_gather_1(self):
         """Ensure that a gathering future refuses to be cancelled once all
         children are done"""
diff --git a/Lib/test/test_asyncio/test_waitfor.py b/Lib/test/test_asyncio/test_waitfor.py
new file mode 100644 (file)
index 0000000..45498fa
--- /dev/null
@@ -0,0 +1,294 @@
+import asyncio
+import unittest
+import time
+
+
+def tearDownModule():
+    asyncio.set_event_loop_policy(None)
+
+
+# The following value can be used as a very small timeout:
+# it passes check "timeout > 0", but has almost
+# no effect on the test performance
+_EPSILON = 0.0001
+
+
+class SlowTask:
+    """ Task will run for this defined time, ignoring cancel requests """
+    TASK_TIMEOUT = 0.2
+
+    def __init__(self):
+        self.exited = False
+
+    async def run(self):
+        exitat = time.monotonic() + self.TASK_TIMEOUT
+
+        while True:
+            tosleep = exitat - time.monotonic()
+            if tosleep <= 0:
+                break
+
+            try:
+                await asyncio.sleep(tosleep)
+            except asyncio.CancelledError:
+                pass
+
+        self.exited = True
+
+
+class AsyncioWaitForTest(unittest.IsolatedAsyncioTestCase):
+
+    async def test_asyncio_wait_for_cancelled(self):
+        t = SlowTask()
+
+        waitfortask = asyncio.create_task(
+            asyncio.wait_for(t.run(), t.TASK_TIMEOUT * 2))
+        await asyncio.sleep(0)
+        waitfortask.cancel()
+        await asyncio.wait({waitfortask})
+
+        self.assertTrue(t.exited)
+
+    async def test_asyncio_wait_for_timeout(self):
+        t = SlowTask()
+
+        try:
+            await asyncio.wait_for(t.run(), t.TASK_TIMEOUT / 2)
+        except asyncio.TimeoutError:
+            pass
+
+        self.assertTrue(t.exited)
+
+    async def test_wait_for_timeout_less_then_0_or_0_future_done(self):
+        loop = asyncio.get_running_loop()
+
+        fut = loop.create_future()
+        fut.set_result('done')
+
+        t0 = loop.time()
+        ret = await asyncio.wait_for(fut, 0)
+        t1 = loop.time()
+
+        self.assertEqual(ret, 'done')
+        self.assertTrue(fut.done())
+        self.assertLess(t1 - t0, 0.1)
+
+    async def test_wait_for_timeout_less_then_0_or_0_coroutine_do_not_started(self):
+        loop = asyncio.get_running_loop()
+
+        foo_started = False
+
+        async def foo():
+            nonlocal foo_started
+            foo_started = True
+
+        with self.assertRaises(asyncio.TimeoutError):
+            t0 = loop.time()
+            await asyncio.wait_for(foo(), 0)
+        t1 = loop.time()
+
+        self.assertEqual(foo_started, False)
+        self.assertLess(t1 - t0, 0.1)
+
+    async def test_wait_for_timeout_less_then_0_or_0(self):
+        loop = asyncio.get_running_loop()
+
+        for timeout in [0, -1]:
+            with self.subTest(timeout=timeout):
+                foo_running = None
+                started = loop.create_future()
+
+                async def foo():
+                    nonlocal foo_running
+                    foo_running = True
+                    started.set_result(None)
+                    try:
+                        await asyncio.sleep(10)
+                    finally:
+                        foo_running = False
+                    return 'done'
+
+                fut = asyncio.create_task(foo())
+                await started
+
+                with self.assertRaises(asyncio.TimeoutError):
+                    t0 = loop.time()
+                    await asyncio.wait_for(fut, timeout)
+                t1 = loop.time()
+
+                self.assertTrue(fut.done())
+                # it should have been cancelled due to the timeout
+                self.assertTrue(fut.cancelled())
+                self.assertEqual(foo_running, False)
+                self.assertLess(t1 - t0, 0.1)
+
+    async def test_wait_for(self):
+        loop = asyncio.get_running_loop()
+        foo_running = None
+
+        async def foo():
+            nonlocal foo_running
+            foo_running = True
+            try:
+                await asyncio.sleep(10)
+            finally:
+                foo_running = False
+            return 'done'
+
+        fut = asyncio.create_task(foo())
+
+        with self.assertRaises(asyncio.TimeoutError):
+            t0 = loop.time()
+            await asyncio.wait_for(fut, 0.1)
+        t1 = loop.time()
+        self.assertTrue(fut.done())
+        # it should have been cancelled due to the timeout
+        self.assertTrue(fut.cancelled())
+        self.assertLess(t1 - t0, 0.5)
+        self.assertEqual(foo_running, False)
+
+    async def test_wait_for_blocking(self):
+        async def coro():
+            return 'done'
+
+        res = await asyncio.wait_for(coro(), timeout=None)
+        self.assertEqual(res, 'done')
+
+    async def test_wait_for_race_condition(self):
+        loop = asyncio.get_running_loop()
+
+        fut = loop.create_future()
+        task = asyncio.wait_for(fut, timeout=0.2)
+        loop.call_later(0.1, fut.set_result, "ok")
+        res = await task
+        self.assertEqual(res, "ok")
+
+    async def test_wait_for_cancellation_race_condition(self):
+        async def inner():
+            with self.assertRaises(asyncio.CancelledError):
+                await asyncio.sleep(1)
+            return 1
+
+        result = await asyncio.wait_for(inner(), timeout=.01)
+        self.assertEqual(result, 1)
+
+    async def test_wait_for_waits_for_task_cancellation(self):
+        task_done = False
+
+        async def inner():
+            nonlocal task_done
+            try:
+                await asyncio.sleep(10)
+            except asyncio.CancelledError:
+                await asyncio.sleep(_EPSILON)
+                raise
+            finally:
+                task_done = True
+
+        inner_task = asyncio.create_task(inner())
+
+        with self.assertRaises(asyncio.TimeoutError) as cm:
+            await asyncio.wait_for(inner_task, timeout=_EPSILON)
+
+        self.assertTrue(task_done)
+        chained = cm.exception.__context__
+        self.assertEqual(type(chained), asyncio.CancelledError)
+
+    async def test_wait_for_waits_for_task_cancellation_w_timeout_0(self):
+        task_done = False
+
+        async def foo():
+            async def inner():
+                nonlocal task_done
+                try:
+                    await asyncio.sleep(10)
+                except asyncio.CancelledError:
+                    await asyncio.sleep(_EPSILON)
+                    raise
+                finally:
+                    task_done = True
+
+            inner_task = asyncio.create_task(inner())
+            await asyncio.sleep(_EPSILON)
+            await asyncio.wait_for(inner_task, timeout=0)
+
+        with self.assertRaises(asyncio.TimeoutError) as cm:
+            await foo()
+
+        self.assertTrue(task_done)
+        chained = cm.exception.__context__
+        self.assertEqual(type(chained), asyncio.CancelledError)
+
+    async def test_wait_for_reraises_exception_during_cancellation(self):
+        class FooException(Exception):
+            pass
+
+        async def foo():
+            async def inner():
+                try:
+                    await asyncio.sleep(0.2)
+                finally:
+                    raise FooException
+
+            inner_task = asyncio.create_task(inner())
+
+            await asyncio.wait_for(inner_task, timeout=_EPSILON)
+
+        with self.assertRaises(FooException):
+            await foo()
+
+    async def test_wait_for_self_cancellation(self):
+        async def inner():
+            try:
+                await asyncio.sleep(0.3)
+            except asyncio.CancelledError:
+                try:
+                    await asyncio.sleep(0.3)
+                except asyncio.CancelledError:
+                    await asyncio.sleep(0.3)
+
+            return 42
+
+        inner_task = asyncio.create_task(inner())
+
+        wait = asyncio.wait_for(inner_task, timeout=0.1)
+
+        # Test that wait_for itself is properly cancellable
+        # even when the initial task holds up the initial cancellation.
+        task = asyncio.create_task(wait)
+        await asyncio.sleep(0.2)
+        task.cancel()
+
+        with self.assertRaises(asyncio.CancelledError):
+            await task
+
+        self.assertEqual(await inner_task, 42)
+
+    async def _test_cancel_wait_for(self, timeout):
+        loop = asyncio.get_running_loop()
+
+        async def blocking_coroutine():
+            fut = loop.create_future()
+            # Block: fut result is never set
+            await fut
+
+        task = asyncio.create_task(blocking_coroutine())
+
+        wait = asyncio.create_task(asyncio.wait_for(task, timeout))
+        loop.call_soon(wait.cancel)
+
+        with self.assertRaises(asyncio.CancelledError):
+            await wait
+
+        # Python issue #23219: cancelling the wait must also cancel the task
+        self.assertTrue(task.cancelled())
+
+    async def test_cancel_blocking_wait_for(self):
+        await self._test_cancel_wait_for(None)
+
+    async def test_cancel_wait_for(self):
+        await self._test_cancel_wait_for(60.0)
+
+
+if __name__ == '__main__':
+    unittest.main()
index 45327953a7701ad1741f54a7cd54b62527528d0f..745329102f77bb4fc753976689378da89e259fee 100644 (file)
@@ -5,6 +5,8 @@ import binascii
 import array
 import re
 from test import support
+from test.support import bigmemtest, _1G, _4G, warnings_helper
+
 
 # Note: "*_hex" functions are aliases for "(un)hexlify"
 b2a_functions = ['b2a_base64', 'b2a_hex', 'b2a_hqx', 'b2a_qp', 'b2a_uu',
@@ -448,6 +450,14 @@ class BytearrayBinASCIITest(BinASCIITest):
 class MemoryviewBinASCIITest(BinASCIITest):
     type2test = memoryview
 
+class ChecksumBigBufferTestCase(unittest.TestCase):
+    """bpo-38256 - check that inputs >=4 GiB are handled correctly."""
+
+    @bigmemtest(size=_4G + 4, memuse=1, dry_run=False)
+    def test_big_buffer(self, size):
+        data = b"nyan" * (_1G + 1)
+        self.assertEqual(binascii.crc32(data), 1044521549)
+
 
 if __name__ == "__main__":
     unittest.main()
index 712d861c4d5a3f95fedfe8836c3e5dfb302d0656..4b3e33c4fd3544b32dafbea134b923b64220f14c 100644 (file)
@@ -136,6 +136,17 @@ class CmdLineTest(unittest.TestCase):
         self.assertTrue(data.find(b'1 loop') != -1)
         self.assertTrue(data.find(b'__main__.Timer') != -1)
 
+    def test_relativedir_bug46421(self):
+        # Test `python -m unittest` with a relative directory beginning with ./
+        # Note: We have to switch to the project's top module's directory, as per
+        # the python unittest wiki. We will switch back when we are done.
+        defaultwd = os.getcwd()
+        projectlibpath = os.path.dirname(__file__).removesuffix("test")
+        with support.change_cwd(projectlibpath):
+            # Testing with and without ./
+            assert_python_ok('-m', 'unittest', "test/test_longexp.py")
+            assert_python_ok('-m', 'unittest', "./test/test_longexp.py")
+
     def test_run_code(self):
         # Test expected operation of the '-c' switch
         # Switch needs an argument
index 47b8575cec563378c6b5971bebaceec69984bf84..dba19103e80d138e3f1c03944942842ab837a970 100644 (file)
@@ -3107,6 +3107,22 @@ def test_no_trailing_whitespace_stripping():
     """
 
 
+def test_run_doctestsuite_multiple_times():
+    """
+    It was not possible to run the same DocTestSuite multiple times
+    http://bugs.python.org/issue2604
+    http://bugs.python.org/issue9736
+
+    >>> import unittest
+    >>> import test.sample_doctest
+    >>> suite = doctest.DocTestSuite(test.sample_doctest)
+    >>> suite.run(unittest.TestResult())
+    <unittest.result.TestResult run=9 errors=0 failures=4>
+    >>> suite.run(unittest.TestResult())
+    <unittest.result.TestResult run=9 errors=0 failures=4>
+    """
+
+
 def load_tests(loader, tests, pattern):
     tests.addTest(doctest.DocTestSuite(doctest))
     tests.addTest(doctest.DocTestSuite())
index 214bc3cb2b187c29ada863636543e6ec89b61978..f845c7a76e7cb91f7d29247f31c1f763a4c51a58 100644 (file)
@@ -223,6 +223,10 @@ class HashLibTestCase(unittest.TestCase):
     def test_algorithms_available(self):
         self.assertTrue(set(hashlib.algorithms_guaranteed).
                             issubset(hashlib.algorithms_available))
+        # all available algorithms must be loadable, bpo-47101
+        self.assertNotIn("undefined", hashlib.algorithms_available)
+        for name in hashlib.algorithms_available:
+            digest = hashlib.new(name, usedforsecurity=False)
 
     def test_usedforsecurity_true(self):
         hashlib.new("sha256", usedforsecurity=True)
index 9b0e94de49d60cd0b18188f5b95cd372c9e9a897..34188a158d179372a42836e07f705f938a5ddee5 100644 (file)
@@ -95,6 +95,11 @@ CLASSES
      |  say_no(self)
      |\x20\x20
      |  ----------------------------------------------------------------------
+     |  Class methods defined here:
+     |\x20\x20
+     |  __class_getitem__(item) from builtins.type
+     |\x20\x20
+     |  ----------------------------------------------------------------------
      |  Data descriptors defined here:
      |\x20\x20
      |  __dict__
@@ -114,6 +119,10 @@ FUNCTIONS
 
 DATA
     __xyz__ = 'X, Y and Z'
+    c_alias = test.pydoc_mod.C[int]
+    list_alias1 = typing.List[int]
+    list_alias2 = list[int]
+    type_union1 = typing.Union[int, str]
 
 VERSION
     1.2.3.4
@@ -141,6 +150,15 @@ expected_html_pattern = """
     <p><tt>This&nbsp;is&nbsp;a&nbsp;test&nbsp;module&nbsp;for&nbsp;test_pydoc</tt></p>
 <p>
 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
+<tr bgcolor="#aa55cc">
+<td colspan=3 valign=bottom>&nbsp;<br>
+<font color="#ffffff" face="helvetica, arial"><big><strong>Modules</strong></big></font></td></tr>
+\x20\x20\x20\x20
+<tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
+<td width="100%%"><table width="100%%" summary="list"><tr><td width="25%%" valign=top><a href="types.html">types</a><br>
+</td><td width="25%%" valign=top><a href="typing.html">typing</a><br>
+</td><td width="25%%" valign=top></td><td width="25%%" valign=top></td></tr></table></td></tr></table><p>
+<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
 <tr bgcolor="#ee77aa">
 <td colspan=3 valign=bottom>&nbsp;<br>
 <font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr>
@@ -210,6 +228,10 @@ Data and other attributes defined here:<br>
 
 <dl><dt><a name="C-say_no"><strong>say_no</strong></a>(self)</dt></dl>
 
+<hr>
+Class methods defined here:<br>
+<dl><dt><a name="C-__class_getitem__"><strong>__class_getitem__</strong></a>(item)<font color="#909090"><font face="helvetica, arial"> from <a href="builtins.html#type">builtins.type</a></font></font></dt></dl>
+
 <hr>
 Data descriptors defined here:<br>
 <dl><dt><strong>__dict__</strong></dt>
@@ -237,7 +259,11 @@ war</tt></dd></dl>
 <font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
 \x20\x20\x20\x20
 <tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
-<td width="100%%"><strong>__xyz__</strong> = 'X, Y and Z'</td></tr></table><p>
+<td width="100%%"><strong>__xyz__</strong> = 'X, Y and Z'<br>
+<strong>c_alias</strong> = test.pydoc_mod.C[int]<br>
+<strong>list_alias1</strong> = typing.List[int]<br>
+<strong>list_alias2</strong> = list[int]<br>
+<strong>type_union1</strong> = typing.Union[int, str]</td></tr></table><p>
 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
 <tr bgcolor="#7799ee">
 <td colspan=3 valign=bottom>&nbsp;<br>
@@ -1048,6 +1074,37 @@ class TestDescriptions(unittest.TestCase):
         expected = 'C in module %s object' % __name__
         self.assertIn(expected, pydoc.render_doc(c))
 
+    def test_generic_alias(self):
+        self.assertEqual(pydoc.describe(typing.List[int]), '_GenericAlias')
+        doc = pydoc.render_doc(typing.List[int], renderer=pydoc.plaintext)
+        self.assertIn('_GenericAlias in module typing', doc)
+        self.assertIn('\nclass list(object)', doc)
+        self.assertIn(list.__doc__.strip().splitlines()[0], doc)
+
+        self.assertEqual(pydoc.describe(list[int]), 'GenericAlias')
+        doc = pydoc.render_doc(list[int], renderer=pydoc.plaintext)
+        self.assertIn('GenericAlias in module builtins', doc)
+        self.assertIn('\nclass list(object)', doc)
+        self.assertIn(list.__doc__.strip().splitlines()[0], doc)
+
+    def test_union_type(self):
+        self.assertEqual(pydoc.describe(typing.Union[int, str]), '_UnionGenericAlias')
+        doc = pydoc.render_doc(typing.Union[int, str], renderer=pydoc.plaintext)
+        self.assertIn('_UnionGenericAlias in module typing', doc)
+        self.assertIn('\ntyping.Union', doc)
+        if typing.Union.__doc__:
+            self.assertIn(typing.Union.__doc__.strip().splitlines()[0], doc)
+
+    def test_special_form(self):
+        self.assertEqual(pydoc.describe(typing.Any), '_SpecialForm')
+        doc = pydoc.render_doc(typing.Any, renderer=pydoc.plaintext)
+        self.assertIn('_SpecialForm in module typing', doc)
+        if typing.Any.__doc__:
+            self.assertIn('\ntyping.Any', doc)
+            self.assertIn(typing.Any.__doc__.strip().splitlines()[0], doc)
+        else:
+            self.assertIn('\nclass _SpecialForm(_Final)', doc)
+
     def test_typing_pydoc(self):
         def foo(data: typing.List[typing.Any],
                 x: int) -> typing.Iterator[typing.Tuple[int, typing.Any]]:
index 1bfbcb853c4ed1a8b79fc963ffed4e375c52faa9..48a609b5a00317bfd9b7dc1e8981c198787d6b6d 100644 (file)
@@ -1443,7 +1443,8 @@ class ReTests(unittest.TestCase):
             self.assertTrue(re.match(p, lower_char))
         self.assertEqual(
             str(warns.warnings[0].message),
-            'Flags not at the start of the expression %r' % p
+            'Flags not at the start of the expression %r'
+            ' but at position 1' % p
         )
         self.assertEqual(warns.warnings[0].filename, __file__)
 
@@ -1452,7 +1453,8 @@ class ReTests(unittest.TestCase):
             self.assertTrue(re.match(p, lower_char))
         self.assertEqual(
             str(warns.warnings[0].message),
-            'Flags not at the start of the expression %r (truncated)' % p[:20]
+            'Flags not at the start of the expression %r (truncated)'
+            ' but at position 1' % p[:20]
         )
         self.assertEqual(warns.warnings[0].filename, __file__)
 
@@ -1464,7 +1466,8 @@ class ReTests(unittest.TestCase):
                 self.assertTrue(re.match(p, b'a'))
             self.assertEqual(
                 str(warns.warnings[0].message),
-                'Flags not at the start of the expression %r' % p
+                'Flags not at the start of the expression %r'
+                ' but at position 1' % p
             )
             self.assertEqual(warns.warnings[0].filename, __file__)
 
index 85cac94dfec78daf08de7f6b02e3913999fb86c5..3890df93bbccdc85e35b6b366595776a19f64694 100644 (file)
@@ -2154,7 +2154,7 @@ class TestMove(BaseTest, unittest.TestCase):
 
             # Create a file and keep the directory immutable
             os.lchflags(TESTFN_SRC, stat.UF_OPAQUE)
-            os_helper.create_empty_file(os.path.join(TESTFN_SRC, 'child'))
+            support.create_empty_file(os.path.join(TESTFN_SRC, 'child'))
             os.lchflags(TESTFN_SRC, stat.SF_IMMUTABLE)
 
             # Testing on a non-empty immutable directory
@@ -2164,10 +2164,10 @@ class TestMove(BaseTest, unittest.TestCase):
         finally:
             if os.path.exists(TESTFN_SRC):
                 os.lchflags(TESTFN_SRC, stat.UF_OPAQUE)
-                os_helper.rmtree(TESTFN_SRC)
+                support.rmtree(TESTFN_SRC)
             if os.path.exists(TESTFN_DST):
                 os.lchflags(TESTFN_DST, stat.UF_OPAQUE)
-                os_helper.rmtree(TESTFN_DST)
+                support.rmtree(TESTFN_DST)
 
 
 class TestCopyFile(unittest.TestCase):
index cc227e579679b739d7a8c14167c64b57427021ae..c0b92bf3b1921b0373debc93ebe4abd8666bebb8 100644 (file)
@@ -800,7 +800,7 @@ class ListboxTest(AbstractWidgetTest, unittest.TestCase):
         self.checkEnumParam(widget, 'activestyle',
                             'dotbox', 'none', 'underline')
 
-    test_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_configure_justify)
+    test_configure_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_configure_justify)
 
     def test_configure_listvariable(self):
         widget = self.create()
@@ -939,7 +939,7 @@ class ScaleTest(AbstractWidgetTest, unittest.TestCase):
 
     def test_configure_from(self):
         widget = self.create()
-        conv = False if get_tk_patchlevel() >= (8, 6, 10) else float_round
+        conv = float if get_tk_patchlevel() >= (8, 6, 10) else float_round
         self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv)
 
     def test_configure_label(self):
index a33c24ac55beefab7f50c18740abb32b15099a0f..54ad3437168fe1195e70f6b05746072248d79786 100644 (file)
@@ -4,7 +4,7 @@ import tkinter
 from tkinter import ttk
 from test import support
 from test.support import requires
-from tkinter.test.support import AbstractTkTest
+from tkinter.test.support import AbstractTkTest, get_tk_patchlevel
 
 requires('gui')
 
@@ -170,6 +170,8 @@ class StyleTest(AbstractTkTest, unittest.TestCase):
                     newname = f'C.{name}'
                     self.assertEqual(style.map(newname), {})
                     style.map(newname, **default)
+                    if theme == 'alt' and name == '.' and get_tk_patchlevel() < (8, 6, 1):
+                        default['embossed'] = [('disabled', '1')]
                     self.assertEqual(style.map(newname), default)
                     for key, value in default.items():
                         self.assertEqual(style.map(newname, key), value)
index e62469aa2a170f2bc1894adc232cf46cdeb2b4d9..88a188c545cd073acef54789fe07ca9875c5cf27 100644 (file)
@@ -39,7 +39,7 @@ def _convert_name(name):
             name = rel_path
         # on Windows both '\' and '/' are used as path
         # separators. Better to replace both than rely on os.path.sep
-        return name[:-3].replace('\\', '.').replace('/', '.')
+        return os.path.normpath(name)[:-3].replace('\\', '.').replace('/', '.')
     return name
 
 def _convert_names(names):
index f72c6a4e0c25397651cfa6ffd566d94b400550f8..1e942a503e8ee12186fdd3dfef3c60cb09153fbf 100644 (file)
@@ -720,7 +720,9 @@ class _SharedFile:
         self._lock = lock
         self._writing = writing
         self.seekable = file.seekable
-        self.tell = file.tell
+
+    def tell(self):
+        return self._pos
 
     def seek(self, offset, whence=0):
         with self._lock:
index 2a26fdcd16b439d47944d2f481d59c33d1e2d862..d043195a7b550ac1ec52a2c211880f9844f036a0 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1947,6 +1947,7 @@ Masazumi Yoshikawa
 Arnaud Ysmal
 Bernard Yue
 Moshe Zadka
+Bader Zaidan
 Elias Zamaria
 Milan Zamazal
 Artur Zaprzala
index b8efb8fb9f013c70923d23e865e2c5d87cd9c393..7d815048ccba37ebd2b074cd2147ce11da53e775 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -2,6 +2,68 @@
 Python News
 +++++++++++
 
+What's New in Python 3.9.12 final?
+==================================
+
+*Release date: 2022-03-23*
+
+Core and Builtins
+-----------------
+
+- bpo-46968: Check for the existence of the "sys/auxv.h" header in
+  :mod:`faulthandler` to avoid compilation problems in systems where this
+  header doesn't exist. Patch by Pablo Galindo
+
+Library
+-------
+
+- bpo-47101: :const:`hashlib.algorithms_available` now lists only algorithms
+  that are provided by activated crypto providers on OpenSSL 3.0. Legacy
+  algorithms are not listed unless the legacy provider has been loaded into
+  the default OSSL context.
+
+- bpo-23691: Protect the :func:`re.finditer` iterator from re-entering.
+
+- bpo-42369: Fix thread safety of :meth:`zipfile._SharedFile.tell` to avoid
+  a "zipfile.BadZipFile: Bad CRC-32 for file" exception when reading a
+  :class:`ZipFile` from multiple threads.
+
+- bpo-38256: Fix :func:`binascii.crc32` when it is compiled to use zlib'c
+  crc32 to work properly on inputs 4+GiB in length instead of returning the
+  wrong result. The workaround prior to this was to always feed the function
+  data in increments smaller than 4GiB or to just call the zlib module
+  function.
+
+- bpo-39394: A warning about inline flags not at the start of the regular
+  expression now contains the position of the flag.
+
+- bpo-47061: Deprecate the various modules listed by :pep:`594`:
+
+  aifc, asynchat, asyncore, audioop, cgi, cgitb, chunk, crypt, imghdr,
+  msilib, nntplib, nis, ossaudiodev, pipes, smtpd, sndhdr, spwd, sunau,
+  telnetlib, uu, xdrlib
+
+- bpo-2604: Fix bug where doctests using globals would fail when run
+  multiple times.
+
+- bpo-45997: Fix :class:`asyncio.Semaphore` re-aquiring FIFO order.
+
+- bpo-47022: The :mod:`asynchat`, :mod:`asyncore` and  :mod:`smtpd` modules
+  have been deprecated since at least Python 3.6. Their documentation has
+  now been updated to note they will removed in Python 3.12 (:pep:`594`).
+
+- bpo-46421: Fix a unittest issue where if the command was invoked as
+  ``python -m unittest`` and the filename(s) began with a dot (.), a
+  ``ValueError`` is returned.
+
+- bpo-40296: Fix supporting generic aliases in :mod:`pydoc`.
+
+- bpo-14156: argparse.FileType now supports an argument of '-' in binary
+  mode, returning the .buffer attribute of sys.stdin/sys.stdout as
+  appropriate. Modes including 'x' and 'a' are treated equivalently to 'w'
+  when argument is '-'. Patch contributed by Josh Rosenberg
+
+
 What's New in Python 3.9.11 final?
 ==================================
 
index 4873bb11aa0cd677e8d1b42e4d8d277b6cea1b3b..4db058c06275ff1ca346169e63b8bbdda37c6215 100644 (file)
@@ -1860,15 +1860,21 @@ typedef struct _internal_name_mapper_state {
 
 /* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */
 static void
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+_openssl_hash_name_mapper(EVP_MD *md, void *arg)
+#else
 _openssl_hash_name_mapper(const EVP_MD *md, const char *from,
                           const char *to, void *arg)
+#endif
 {
     _InternalNameMapperState *state = (_InternalNameMapperState *)arg;
     PyObject *py_name;
 
     assert(state != NULL);
-    if (md == NULL)
+    // ignore all undefined providers
+    if ((md == NULL) || (EVP_MD_nid(md) == NID_undef)) {
         return;
+    }
 
     py_name = py_digest_name(md);
     if (py_name == NULL) {
@@ -1894,7 +1900,12 @@ hashlib_md_meth_names(PyObject *module)
         return -1;
     }
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+    // get algorithms from all activated providers in default context
+    EVP_MD_do_all_provided(NULL, &_openssl_hash_name_mapper, &state);
+#else
     EVP_MD_do_all(&_openssl_hash_name_mapper, &state);
+#endif
 
     if (state.error) {
         Py_DECREF(state.set);
index 8225c36da1a38968708c169ec31b391b8fe76354..338530e2dc9936d4adfc79e7f9ada47a61a9c51f 100644 (file)
@@ -2391,6 +2391,25 @@ scanner_dealloc(ScannerObject* self)
     PyObject_DEL(self);
 }
 
+static int
+scanner_begin(ScannerObject* self)
+{
+    if (self->executing) {
+        PyErr_SetString(PyExc_ValueError,
+                        "regular expression scanner already executing");
+        return 0;
+    }
+    self->executing = 1;
+    return 1;
+}
+
+static void
+scanner_end(ScannerObject* self)
+{
+    assert(self->executing);
+    self->executing = 0;
+}
+
 /*[clinic input]
 _sre.SRE_Scanner.match
 
@@ -2404,16 +2423,23 @@ _sre_SRE_Scanner_match_impl(ScannerObject *self)
     PyObject* match;
     Py_ssize_t status;
 
-    if (state->start == NULL)
+    if (!scanner_begin(self)) {
+        return NULL;
+    }
+    if (state->start == NULL) {
+        scanner_end(self);
         Py_RETURN_NONE;
+    }
 
     state_reset(state);
 
     state->ptr = state->start;
 
     status = sre_match(state, PatternObject_GetCode(self->pattern));
-    if (PyErr_Occurred())
+    if (PyErr_Occurred()) {
+        scanner_end(self);
         return NULL;
+    }
 
     match = pattern_new_match((PatternObject*) self->pattern,
                                state, status);
@@ -2425,6 +2451,7 @@ _sre_SRE_Scanner_match_impl(ScannerObject *self)
         state->start = state->ptr;
     }
 
+    scanner_end(self);
     return match;
 }
 
@@ -2442,16 +2469,23 @@ _sre_SRE_Scanner_search_impl(ScannerObject *self)
     PyObject* match;
     Py_ssize_t status;
 
-    if (state->start == NULL)
+    if (!scanner_begin(self)) {
+        return NULL;
+    }
+    if (state->start == NULL) {
+        scanner_end(self);
         Py_RETURN_NONE;
+    }
 
     state_reset(state);
 
     state->ptr = state->start;
 
     status = sre_search(state, PatternObject_GetCode(self->pattern));
-    if (PyErr_Occurred())
+    if (PyErr_Occurred()) {
+        scanner_end(self);
         return NULL;
+    }
 
     match = pattern_new_match((PatternObject*) self->pattern,
                                state, status);
@@ -2463,6 +2497,7 @@ _sre_SRE_Scanner_search_impl(ScannerObject *self)
         state->start = state->ptr;
     }
 
+    scanner_end(self);
     return match;
 }
 
@@ -2476,6 +2511,7 @@ pattern_scanner(PatternObject *self, PyObject *string, Py_ssize_t pos, Py_ssize_
     if (!scanner)
         return NULL;
     scanner->pattern = NULL;
+    scanner->executing = 0;
 
     /* create search state object */
     if (!state_init(&scanner->state, self, string, pos, endpos)) {
index 1f3248b6049b31e98328e8962d21b95b33c98e22..3777580a79f2a92d7a94c43fc0e29f0d1ba2bf9a 100644 (file)
@@ -1120,16 +1120,20 @@ binascii_crc32_impl(PyObject *module, Py_buffer *data, unsigned int crc)
 /*[clinic end generated code: output=52cf59056a78593b input=bbe340bc99d25aa8]*/
 
 #ifdef USE_ZLIB_CRC32
-/* This was taken from zlibmodule.c PyZlib_crc32 (but is PY_SSIZE_T_CLEAN) */
+/* The same core as zlibmodule.c zlib_crc32_impl. */
 {
-    const Byte *buf;
-    Py_ssize_t len;
-    int signed_val;
-
-    buf = (Byte*)data->buf;
-    len = data->len;
-    signed_val = crc32(crc, buf, len);
-    return (unsigned int)signed_val & 0xffffffffU;
+    unsigned char *buf = data->buf;
+    Py_ssize_t len = data->len;
+
+    /* Avoid truncation of length for very large buffers. crc32() takes
+       length as an unsigned int, which may be narrower than Py_ssize_t. */
+    while ((size_t)len > UINT_MAX) {
+        crc = crc32(crc, buf, UINT_MAX);
+        buf += (size_t) UINT_MAX;
+        len -= (size_t) UINT_MAX;
+    }
+    crc = crc32(crc, buf, (unsigned int)len);
+    return crc & 0xffffffff;
 }
 #else  /* USE_ZLIB_CRC32 */
 { /* By Jim Ahlstrom; All rights transferred to CNRI */
index 764ff439d77d95347a5cd10f3b8636113cb61d05..16f98ace3bb05b59f8b4008ed2e1c098aaf957c7 100644 (file)
@@ -21,9 +21,9 @@
 #  define FAULTHANDLER_USE_ALT_STACK
 #endif
 
-#if defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_LINUX_AUXVEC_H)
-#  include <linux/auxvec.h>
-#  include <sys/auxv.h>
+#if defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_LINUX_AUXVEC_H) && defined(HAVE_SYS_AUXV_H)
+#  include <linux/auxvec.h>       // AT_MINSIGSTKSZ
+#  include <sys/auxv.h>           // getauxval()
 #endif
 
 /* Allocate at maximum 100 MiB of the stack to raise the stack overflow */
index 9b0d8b190426acf96d431de8ee9c6bd94e5a352c..785adbd003e7fd93d3f445e446992310ed194d54 100644 (file)
@@ -89,6 +89,7 @@ typedef struct {
     PyObject_HEAD
     PyObject* pattern;
     SRE_STATE state;
+    int executing;
 } ScannerObject;
 
 #endif
index 8856328f9d0bf9d31940062a55559a380a5a21f5..d3b2521a875a03c4c16f9cd5752f36f4ff9e480a 100644 (file)
@@ -1,4 +1,4 @@
-This is Python version 3.9.11
+This is Python version 3.9.12
 =============================
 
 .. image:: https://travis-ci.org/python/cpython.svg?branch=3.9
index 7f9749091dc011fa5d8ae00dc0dae2f6cf620363..b7be60eaa37ddbe4850fa54e11e45106d24c3ae1 100755 (executable)
--- a/configure
+++ b/configure
@@ -8042,7 +8042,7 @@ sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
 sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
 libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
 linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \
-sys/endian.h sys/sysmacros.h linux/auxvec.h linux/memfd.h linux/wait.h sys/memfd.h sys/mman.h
+sys/endian.h sys/sysmacros.h linux/auxvec.h sys/auxv.h linux/memfd.h linux/wait.h sys/memfd.h sys/mman.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
index 1354cc0a8dd68b473c9a0a309556c3e87f0c1aa3..aa515da46553a2c8aa254ed3d82dd92b6cdc0668 100644 (file)
@@ -2228,7 +2228,7 @@ sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
 sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
 libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
 linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \
-sys/endian.h sys/sysmacros.h linux/auxvec.h linux/memfd.h linux/wait.h sys/memfd.h sys/mman.h)
+sys/endian.h sys/sysmacros.h linux/auxvec.h sys/auxv.h linux/memfd.h linux/wait.h sys/memfd.h sys/mman.h)
 AC_HEADER_DIRENT
 AC_HEADER_MAJOR
 
index ce850fcad8280a115ebdbb8cb4138b7436e5f60b..bf695e9e58200b6e76967813b984ee2229c3feee 100644 (file)
 /* Define to 1 if you have the <sys/audioio.h> header file. */
 #undef HAVE_SYS_AUDIOIO_H
 
+/* Define to 1 if you have the <sys/auxv.h> header file. */
+#undef HAVE_SYS_AUXV_H
+
 /* Define to 1 if you have the <sys/bsdtty.h> header file. */
 #undef HAVE_SYS_BSDTTY_H