Imported Upstream version 3.6.8
authorHyunjee Kim <hj0426.kim@samsung.com>
Wed, 20 Mar 2019 02:00:31 +0000 (11:00 +0900)
committerHyunjee Kim <hj0426.kim@samsung.com>
Wed, 20 Mar 2019 02:00:31 +0000 (11:00 +0900)
392 files changed:
.azure-pipelines/docs-steps.yml
Doc/c-api/buffer.rst
Doc/c-api/codec.rst
Doc/c-api/dict.rst
Doc/c-api/gcsupport.rst
Doc/c-api/mapping.rst
Doc/c-api/number.rst
Doc/c-api/objbuffer.rst
Doc/c-api/object.rst
Doc/c-api/structures.rst
Doc/c-api/tuple.rst
Doc/c-api/type.rst
Doc/c-api/unicode.rst
Doc/c-api/veryhigh.rst
Doc/data/refcounts.dat
Doc/distutils/apiref.rst
Doc/distutils/builtdist.rst
Doc/distutils/configfile.rst
Doc/extending/extending.rst
Doc/faq/extending.rst
Doc/faq/general.rst
Doc/faq/windows.rst
Doc/glossary.rst
Doc/howto/logging.rst
Doc/install/index.rst
Doc/library/abc.rst
Doc/library/argparse.rst
Doc/library/ast.rst
Doc/library/cmd.rst
Doc/library/codecs.rst
Doc/library/concurrent.futures.rst
Doc/library/configparser.rst
Doc/library/constants.rst
Doc/library/copy.rst
Doc/library/crypt.rst
Doc/library/curses.ascii.rst
Doc/library/datetime.rst
Doc/library/difflib.rst
Doc/library/doctest.rst
Doc/library/email.compat32-message.rst
Doc/library/email.message.rst
Doc/library/email.parser.rst
Doc/library/email.rst
Doc/library/email.utils.rst [moved from Doc/library/email.util.rst with 100% similarity]
Doc/library/exceptions.rst
Doc/library/fnmatch.rst
Doc/library/functions.rst
Doc/library/functools.rst
Doc/library/gettext.rst
Doc/library/glob.rst
Doc/library/heapq.rst
Doc/library/http.server.rst
Doc/library/idle.rst
Doc/library/importlib.rst
Doc/library/inspect.rst
Doc/library/io.rst
Doc/library/json.rst
Doc/library/locale.rst
Doc/library/logging.rst
Doc/library/mmap.rst
Doc/library/optparse.rst
Doc/library/os.path.rst
Doc/library/os.rst
Doc/library/ossaudiodev.rst
Doc/library/pickle.rst
Doc/library/pprint.rst
Doc/library/re.rst
Doc/library/reprlib.rst
Doc/library/shutil.rst
Doc/library/site.rst
Doc/library/smtplib.rst
Doc/library/sqlite3.rst
Doc/library/stat.rst
Doc/library/stdtypes.rst
Doc/library/string.rst
Doc/library/struct.rst
Doc/library/sys.rst
Doc/library/sysconfig.rst
Doc/library/termios.rst
Doc/library/textwrap.rst
Doc/library/time.rst
Doc/library/tkinter.rst
Doc/library/traceback.rst
Doc/library/turtle.rst
Doc/library/typing.rst
Doc/library/unittest.mock-examples.rst
Doc/library/unittest.mock.rst
Doc/library/unittest.rst
Doc/library/urllib.parse.rst
Doc/library/urllib.request.rst
Doc/library/winreg.rst
Doc/library/xml.dom.minidom.rst
Doc/library/xml.sax.rst
Doc/library/zipfile.rst
Doc/make.bat
Doc/reference/compound_stmts.rst
Doc/reference/datamodel.rst
Doc/reference/executionmodel.rst
Doc/reference/expressions.rst
Doc/reference/import.rst
Doc/reference/lexical_analysis.rst
Doc/reference/simple_stmts.rst
Doc/tools/extensions/escape4chm.py
Doc/tools/extensions/pyspecific.py
Doc/tools/static/switchers.js
Doc/tools/susp-ignored.csv
Doc/tools/templates/indexsidebar.html
Doc/tutorial/classes.rst
Doc/tutorial/controlflow.rst
Doc/tutorial/errors.rst
Doc/tutorial/introduction.rst
Doc/using/unix.rst
Doc/using/venv-create.inc
Doc/using/windows.rst
Doc/whatsnew/2.2.rst
Doc/whatsnew/2.3.rst
Doc/whatsnew/2.5.rst
Doc/whatsnew/3.4.rst
Doc/whatsnew/3.6.rst
Include/Python.h
Include/ceval.h
Include/fileutils.h
Include/object.h
Include/patchlevel.h
Include/pyerrors.h
Include/pylifecycle.h
Include/pymem.h
Include/unicodeobject.h
Lib/_osx_support.py
Lib/_pydecimal.py
Lib/asyncio/base_events.py
Lib/asyncio/proactor_events.py
Lib/asyncio/selector_events.py
Lib/asyncio/test_utils.py
Lib/cProfile.py
Lib/cgi.py
Lib/compileall.py
Lib/ctypes/test/test_bytes.py
Lib/datetime.py
Lib/distutils/archive_util.py
Lib/distutils/command/bdist_dumb.py
Lib/distutils/command/bdist_msi.py
Lib/distutils/command/bdist_rpm.py
Lib/distutils/command/bdist_wininst.py
Lib/distutils/command/build_ext.py
Lib/distutils/tests/test_archive_util.py
Lib/distutils/tests/test_bdist_dumb.py
Lib/distutils/tests/test_sdist.py
Lib/email/_header_value_parser.py
Lib/ensurepip/__init__.py
Lib/ensurepip/_bundled/pip-10.0.1-py2.py3-none-any.whl [deleted file]
Lib/ensurepip/_bundled/pip-18.1-py2.py3-none-any.whl [new file with mode: 0644]
Lib/ensurepip/_bundled/setuptools-40.6.2-py2.py3-none-any.whl [moved from Lib/ensurepip/_bundled/setuptools-39.0.1-py2.py3-none-any.whl with 54% similarity]
Lib/ftplib.py
Lib/idlelib/NEWS.txt
Lib/idlelib/codecontext.py
Lib/idlelib/config.py
Lib/idlelib/debugger_r.py
Lib/idlelib/filelist.py
Lib/idlelib/help.html
Lib/idlelib/help.py
Lib/idlelib/hyperparser.py
Lib/idlelib/idle_test/htest.py
Lib/idlelib/idle_test/mock_tk.py
Lib/idlelib/idle_test/test_browser.py
Lib/idlelib/idle_test/test_config.py
Lib/idlelib/idle_test/test_config_key.py
Lib/idlelib/idle_test/test_configdialog.py
Lib/idlelib/idle_test/test_rpc.py
Lib/idlelib/idle_test/test_zoomheight.py
Lib/idlelib/iomenu.py
Lib/idlelib/macosx.py
Lib/idlelib/outwin.py
Lib/idlelib/pyparse.py
Lib/idlelib/pyshell.py
Lib/imaplib.py
Lib/inspect.py
Lib/lib2to3/fixes/fix_execfile.py
Lib/lib2to3/tests/test_fixers.py
Lib/mimetypes.py
Lib/multiprocessing/pool.py
Lib/ntpath.py
Lib/platform.py
Lib/poplib.py
Lib/posixpath.py
Lib/pydoc.py
Lib/pydoc_data/topics.py
Lib/shutil.py
Lib/smtplib.py
Lib/socketserver.py
Lib/sqlite3/test/regression.py
Lib/ssl.py
Lib/subprocess.py
Lib/test/_test_multiprocessing.py
Lib/test/datetimetester.py
Lib/test/eintrdata/eintr_tester.py
Lib/test/libregrtest/cmdline.py
Lib/test/libregrtest/main.py
Lib/test/libregrtest/runtest.py
Lib/test/libregrtest/runtest_mp.py
Lib/test/pythoninfo.py
Lib/test/signalinterproctester.py
Lib/test/support/__init__.py
Lib/test/support/testresult.py
Lib/test/test__osx_support.py
Lib/test/test_asyncio/keycert3.pem [deleted file]
Lib/test/test_asyncio/pycacert.pem [deleted file]
Lib/test/test_asyncio/ssl_cert.pem [deleted file]
Lib/test/test_asyncio/ssl_key.pem [deleted file]
Lib/test/test_asyncio/test_base_events.py
Lib/test/test_asyncio/test_events.py
Lib/test/test_asyncio/test_selector_events.py
Lib/test/test_bdb.py
Lib/test/test_bytes.py
Lib/test/test_capi.py
Lib/test/test_cgi.py
Lib/test/test_codecs.py
Lib/test/test_compile.py
Lib/test/test_compileall.py
Lib/test/test_cprofile.py
Lib/test/test_decimal.py
Lib/test/test_eintr.py
Lib/test/test_email/test_utils.py
Lib/test/test_gdb.py
Lib/test/test_http_cookiejar.py
Lib/test/test_io.py
Lib/test/test_largefile.py
Lib/test/test_minidom.py
Lib/test/test_multiprocessing_fork.py
Lib/test/test_multiprocessing_forkserver.py
Lib/test/test_ntpath.py
Lib/test/test_ordered_dict.py
Lib/test/test_os.py
Lib/test/test_posixpath.py
Lib/test/test_pydoc.py
Lib/test/test_range.py
Lib/test/test_regrtest.py
Lib/test/test_site.py
Lib/test/test_smtplib.py
Lib/test/test_socket.py
Lib/test/test_ssl.py
Lib/test/test_strptime.py
Lib/test/test_support.py
Lib/test/test_threading.py
Lib/test/test_urllib2net.py
Lib/test/test_urlparse.py
Lib/test/test_venv.py
Lib/test/test_xml_etree.py
Lib/test/test_xml_etree_c.py
Lib/tkinter/__init__.py
Lib/tkinter/test/support.py
Lib/tkinter/test/test_tkinter/test_widgets.py
Lib/trace.py
Lib/turtle.py
Lib/unittest/case.py
Lib/unittest/mock.py
Lib/unittest/test/test_case.py
Lib/unittest/test/testmock/testcallable.py
Lib/unittest/test/testmock/testhelpers.py
Lib/unittest/test/testmock/testmock.py
Lib/unittest/test/testmock/testpatch.py
Lib/urllib/parse.py
Lib/urllib/request.py
Lib/xml/dom/domreg.py
Lib/xml/dom/minidom.py
Lib/xml/sax/__init__.py
Lib/zipfile.py
Mac/BuildScript/build-installer.py
Mac/BuildScript/resources/ReadMe.rtf
Mac/BuildScript/resources/Welcome.rtf
Mac/BuildScript/tk868_on_10_8_10_9.patch [deleted file]
Makefile.pre.in
Misc/ACKS
Misc/NEWS
Modules/Setup.dist
Modules/_asynciomodule.c
Modules/_bz2module.c
Modules/_collectionsmodule.c
Modules/_csv.c
Modules/_ctypes/_ctypes.c
Modules/_ctypes/callbacks.c
Modules/_ctypes/callproc.c
Modules/_cursesmodule.c
Modules/_datetimemodule.c
Modules/_decimal/libmpdec/mpdecimal.h
Modules/_elementtree.c
Modules/_hashopenssl.c
Modules/_io/bytesio.c
Modules/_io/fileio.c
Modules/_io/textio.c
Modules/_io/winconsoleio.c
Modules/_localemodule.c
Modules/_lzmamodule.c
Modules/_multiprocessing/semaphore.c
Modules/_operator.c
Modules/_pickle.c
Modules/_posixsubprocess.c
Modules/_sqlite/connection.c
Modules/_sqlite/row.c
Modules/_sre.c
Modules/_ssl.c
Modules/_testbuffer.c
Modules/_testcapimodule.c
Modules/_threadmodule.c
Modules/_tkinter.c
Modules/_tracemalloc.c
Modules/arraymodule.c
Modules/cjkcodecs/_codecs_jp.c
Modules/cjkcodecs/multibytecodec.c
Modules/clinic/md5module.c.h
Modules/clinic/posixmodule.c.h
Modules/clinic/sha1module.c.h
Modules/clinic/sha256module.c.h
Modules/clinic/sha512module.c.h
Modules/expat/expat_external.h
Modules/expat/xmltok.c
Modules/faulthandler.c
Modules/fcntlmodule.c
Modules/grpmodule.c
Modules/md5module.c
Modules/mmapmodule.c
Modules/nismodule.c
Modules/posixmodule.c
Modules/pwdmodule.c
Modules/pyexpat.c
Modules/readline.c
Modules/selectmodule.c
Modules/sha1module.c
Modules/sha256module.c
Modules/sha512module.c
Modules/socketmodule.c
Modules/termios.c
Modules/timemodule.c
Modules/xxsubtype.c
Modules/zlibmodule.c
Objects/bytearrayobject.c
Objects/bytesobject.c
Objects/capsule.c
Objects/classobject.c
Objects/descrobject.c
Objects/exceptions.c
Objects/fileobject.c
Objects/frameobject.c
Objects/funcobject.c
Objects/genobject.c
Objects/memoryobject.c
Objects/methodobject.c
Objects/namespaceobject.c
Objects/object.c
Objects/obmalloc.c
Objects/odictobject.c
Objects/rangeobject.c
Objects/setobject.c
Objects/stringlib/localeutil.h
Objects/typeobject.c
Objects/unicodeobject.c
PC/getpathp.c
PC/winreg.c
PCbuild/build.bat
PCbuild/get_externals.bat
PCbuild/libeay.vcxproj
PCbuild/pyproject.props
PCbuild/python.props
Parser/myreadline.c
Parser/tokenizer.c
Python/_warnings.c
Python/ast.c
Python/ceval.c
Python/codecs.c
Python/compile.c
Python/fileutils.c
Python/formatter_unicode.c
Python/import.c
Python/marshal.c
Python/peephole.c
Python/pylifecycle.c
Python/pymath.c
Python/pystate.c
Python/pystrtod.c
Python/random.c
Python/symtable.c
Python/sysmodule.c
Python/thread_pthread.h
Python/traceback.c
README.rst
Tools/gdb/libpython.py
Tools/scripts/patchcheck.py
Tools/scripts/texi2html.py
aclocal.m4
configure
configure.ac
setup.py

index c0404ae..492e4e3 100644 (file)
@@ -12,7 +12,7 @@ steps:
   inputs:
     versionSpec: '>=3.6'
 
-- script: python -m pip install sphinx~=1.6.1 blurb python-docs-theme
+- script: python -m pip install sphinx==1.8.2 blurb python-docs-theme
   displayName: 'Install build dependencies'
 
 - ${{ if ne(parameters.latex, 'true') }}:
index 5a9a46f..c7c1e3c 100644 (file)
@@ -198,7 +198,7 @@ a buffer, see :c:func:`PyObject_GetBuffer`.
       indicates that no de-referencing should occur (striding in a contiguous
       memory block).
 
-      If all suboffsets are negative (i.e. no de-referencing is needed, then
+      If all suboffsets are negative (i.e. no de-referencing is needed), then
       this field must be NULL (the default value).
 
       This type of array representation is used by the Python Imaging Library
@@ -429,7 +429,7 @@ Buffer-related functions
 
    Return ``1`` if *obj* supports the buffer interface otherwise ``0``.  When ``1`` is
    returned, it doesn't guarantee that :c:func:`PyObject_GetBuffer` will
-   succeed.
+   succeed.  This function always succeeds.
 
 
 .. c:function:: int PyObject_GetBuffer(PyObject *exporter, Py_buffer *view, int flags)
@@ -470,7 +470,7 @@ Buffer-related functions
 
    Return ``1`` if the memory defined by the *view* is C-style (*order* is
    ``'C'``) or Fortran-style (*order* is ``'F'``) :term:`contiguous` or either one
-   (*order* is ``'A'``).  Return ``0`` otherwise.
+   (*order* is ``'A'``).  Return ``0`` otherwise.  This function always succeeds.
 
 
 .. c:function:: int PyBuffer_ToContiguous(void *buf, Py_buffer *src, Py_ssize_t len, char order)
index dfe3d43..c55f199 100644 (file)
@@ -13,7 +13,7 @@ Codec registry and support functions
 .. c:function:: int PyCodec_KnownEncoding(const char *encoding)
 
    Return ``1`` or ``0`` depending on whether there is a registered codec for
-   the given *encoding*.
+   the given *encoding*.  This function always succeeds.
 
 .. c:function:: PyObject* PyCodec_Encode(PyObject *object, const char *encoding, const char *errors)
 
index cfa5e13..68ca25c 100644 (file)
@@ -95,6 +95,10 @@ Dictionary Objects
    Return the object from dictionary *p* which has a key *key*.  Return *NULL*
    if the key *key* is not present, but *without* setting an exception.
 
+   Note that exceptions which occur while calling :meth:`__hash__` and
+   :meth:`__eq__` methods will get suppressed.
+   To get error reporting use :c:func:`PyDict_GetItemWithError()` instead.
+
 
 .. c:function:: PyObject* PyDict_GetItemWithError(PyObject *p, PyObject *key)
 
@@ -109,6 +113,11 @@ Dictionary Objects
    This is the same as :c:func:`PyDict_GetItem`, but *key* is specified as a
    :c:type:`char\*`, rather than a :c:type:`PyObject\*`.
 
+   Note that exceptions which occur while calling :meth:`__hash__` and
+   :meth:`__eq__` methods and creating a temporary string object
+   will get suppressed.
+   To get error reporting use :c:func:`PyDict_GetItemWithError()` instead.
+
 
 .. c:function:: PyObject* PyDict_SetDefault(PyObject *p, PyObject *key, PyObject *default)
 
index 7f54b6a..472cd93 100644 (file)
@@ -66,6 +66,9 @@ Constructors for container types must conform to two rules:
    A macro version of :c:func:`PyObject_GC_Track`.  It should not be used for
    extension modules.
 
+   .. deprecated:: 3.6
+      This macro is removed from Python 3.8.
+
 Similarly, the deallocator for the object must conform to a similar pair of
 rules:
 
@@ -95,6 +98,9 @@ rules:
    A macro version of :c:func:`PyObject_GC_UnTrack`.  It should not be used for
    extension modules.
 
+   .. deprecated:: 3.6
+      This macro is removed from Python 3.8.
+
 The :c:member:`~PyTypeObject.tp_traverse` handler accepts a function parameter of this type:
 
 
index c16fcf4..cb68ef8 100644 (file)
@@ -60,6 +60,10 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and
    This is equivalent to the Python expression ``key in o``.
    This function always succeeds.
 
+   Note that exceptions which occur while calling the :meth:`__getitem__`
+   method will get suppressed.
+   To get error reporting use :c:func:`PyObject_GetItem()` instead.
+
 
 .. c:function:: int PyMapping_HasKeyString(PyObject *o, const char *key)
 
@@ -67,6 +71,10 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and
    This is equivalent to the Python expression ``key in o``.
    This function always succeeds.
 
+   Note that exceptions which occur while calling the :meth:`__getitem__`
+   method and creating a temporary string object will get suppressed.
+   To get error reporting use :c:func:`PyMapping_GetItemString()` instead.
+
 
 .. c:function:: PyObject* PyMapping_Keys(PyObject *o)
 
index 3c7605a..296b21c 100644 (file)
@@ -280,3 +280,4 @@ Number Protocol
 
    Returns ``1`` if *o* is an index integer (has the nb_index slot of  the
    tp_as_number structure filled in), and ``0`` otherwise.
+   This function always succeeds.
index e7f4fde..9ad7c57 100644 (file)
@@ -39,7 +39,11 @@ an object, and :c:func:`PyBuffer_Release` when the buffer view can be released.
 .. c:function:: int PyObject_CheckReadBuffer(PyObject *o)
 
    Returns ``1`` if *o* supports the single-segment readable buffer interface.
-   Otherwise returns ``0``.
+   Otherwise returns ``0``.  This function always succeeds.
+
+   Note that this function tries to get and release a buffer, and exceptions
+   which occur while calling correspoding functions will get suppressed.
+   To get error reporting use :c:func:`PyObject_GetBuffer()` instead.
 
 
 .. c:function:: int PyObject_AsWriteBuffer(PyObject *obj, void **buffer, Py_ssize_t *buffer_len)
index 8692a2c..ea0aa8d 100644 (file)
@@ -33,6 +33,10 @@ Object Protocol
    is equivalent to the Python expression ``hasattr(o, attr_name)``.  This function
    always succeeds.
 
+   Note that exceptions which occur while calling :meth:`__getattr__` and
+   :meth:`__getattribute__` methods will get suppressed.
+   To get error reporting use :c:func:`PyObject_GetAttr()` instead.
+
 
 .. c:function:: int PyObject_HasAttrString(PyObject *o, const char *attr_name)
 
@@ -40,6 +44,11 @@ Object Protocol
    is equivalent to the Python expression ``hasattr(o, attr_name)``.  This function
    always succeeds.
 
+   Note that exceptions which occur while calling :meth:`__getattr__` and
+   :meth:`__getattribute__` methods and creating a temporary string object
+   will get suppressed.
+   To get error reporting use :c:func:`PyObject_GetAttrString()` instead.
+
 
 .. c:function:: PyObject* PyObject_GetAttr(PyObject *o, PyObject *attr_name)
 
index 675f6f2..c493f64 100644 (file)
@@ -292,7 +292,8 @@ definition with the same method name.
 
    :attr:`flags` can be ``0`` for write and read access or :c:macro:`READONLY` for
    read-only access.  Using :c:macro:`T_STRING` for :attr:`type` implies
-   :c:macro:`READONLY`.  Only :c:macro:`T_OBJECT` and :c:macro:`T_OBJECT_EX`
+   :c:macro:`READONLY`.  :c:macro:`T_STRING` data is interpreted as UTF-8.
+   Only :c:macro:`T_OBJECT` and :c:macro:`T_OBJECT_EX`
    members can be deleted.  (They are set to *NULL*).
 
 
index 3922d50..ab8ee9a 100644 (file)
@@ -209,7 +209,7 @@ type.
       This function "steals" a reference to *o*.
 
 
-.. c:function:: PyObject* PyStructSequence_SET_ITEM(PyObject *p, Py_ssize_t *pos, PyObject *o)
+.. c:function:: void PyStructSequence_SET_ITEM(PyObject *p, Py_ssize_t *pos, PyObject *o)
 
    Macro equivalent of :c:func:`PyStructSequence_SetItem`.
 
index 60c5e73..4dfd53f 100644 (file)
@@ -35,7 +35,7 @@ Type Objects
 
    Clear the internal lookup cache. Return the current version tag.
 
-.. c:function:: long PyType_GetFlags(PyTypeObject* type)
+.. c:function:: unsigned long PyType_GetFlags(PyTypeObject* type)
 
    Return the :c:member:`~PyTypeObject.tp_flags` member of *type*. This function is primarily
    meant for use with `Py_LIMITED_API`; the individual flag bits are
@@ -44,6 +44,9 @@ Type Objects
 
    .. versionadded:: 3.2
 
+   .. versionchanged:: 3.4
+      The return type is now ``unsigned long`` rather than ``long``.
+
 
 .. c:function:: void PyType_Modified(PyTypeObject *type)
 
index b9acaec..55d5b07 100644 (file)
@@ -925,7 +925,7 @@ wchar_t Support
    Return *NULL* on failure.
 
 
-.. c:function:: Py_ssize_t PyUnicode_AsWideChar(PyUnicodeObject *unicode, wchar_t *w, Py_ssize_t size)
+.. c:function:: Py_ssize_t PyUnicode_AsWideChar(PyObject *unicode, wchar_t *w, Py_ssize_t size)
 
    Copy the Unicode object contents into the :c:type:`wchar_t` buffer *w*.  At most
    *size* :c:type:`wchar_t` characters are copied (excluding a possibly trailing
@@ -1324,7 +1324,7 @@ These are the "Raw Unicode Escape" codec APIs:
 
 
 .. c:function:: PyObject* PyUnicode_EncodeRawUnicodeEscape(const Py_UNICODE *s, \
-                              Py_ssize_t size, const char *errors)
+                              Py_ssize_t size)
 
    Encode the :c:type:`Py_UNICODE` buffer of the given *size* using Raw-Unicode-Escape
    and return a bytes object.  Return *NULL* if an exception was raised by the codec.
@@ -1493,8 +1493,8 @@ the user settings on the machine running the codec.
    Return *NULL* if an exception was raised by the codec.
 
 
-.. c:function:: PyObject* PyUnicode_DecodeMBCSStateful(const char *s, int size, \
-                              const char *errors, int *consumed)
+.. c:function:: PyObject* PyUnicode_DecodeMBCSStateful(const char *s, Py_ssize_t size, \
+                              const char *errors, Py_ssize_t *consumed)
 
    If *consumed* is *NULL*, behave like :c:func:`PyUnicode_DecodeMBCS`. If
    *consumed* is not *NULL*, :c:func:`PyUnicode_DecodeMBCSStateful` will not decode
index 3897fdd..5352938 100644 (file)
@@ -306,7 +306,7 @@ the same library that the Python runtime is using.
    Evaluate a precompiled code object, given a particular environment for its
    evaluation.  This environment consists of a dictionary of global variables,
    a mapping object of local variables, arrays of arguments, keywords and
-   defaults, a dictionary of default values for :ref:`keyword-only\
+   defaults, a dictionary of default values for :ref:`keyword-only
    <keyword-only_parameter>` arguments and a closure tuple of cells.
 
 
index 8b469f4..0ac62ab 100644 (file)
@@ -516,6 +516,9 @@ Py_InitModule4:int:apiver::usually provided by Py_InitModule or Py_InitModule3
 PyImport_AddModule:PyObject*::0:reference borrowed from sys.modules
 PyImport_AddModule:const char*:name::
 
+PyImport_AddModuleObject:PyObject*::0:reference borrowed from sys.modules
+PyImport_AddModuleObject:PyObject*:name:0:
+
 PyImport_Cleanup:void:::
 
 PyImport_ExecCodeModule:PyObject*::+1:
@@ -527,6 +530,21 @@ PyImport_ExecCodeModuleEx:const char*:name::
 PyImport_ExecCodeModuleEx:PyObject*:co:0:
 PyImport_ExecCodeModuleEx:const char*:pathname::
 
+PyImport_ExecCodeModuleObject:PyObject*::+1:
+PyImport_ExecCodeModuleObject:const char*:name::
+PyImport_ExecCodeModuleObject:PyObject*:co:0:
+PyImport_ExecCodeModuleObject:PyObject*:pathname:0:
+PyImport_ExecCodeModuleObject:PyObject*:cpathname:0:
+
+PyImport_ExecCodeModuleWithPathnames:PyObject*::+1:
+PyImport_ExecCodeModuleWithPathnames:const char*:name::
+PyImport_ExecCodeModuleWithPathnames:PyObject*:co:0:
+PyImport_ExecCodeModuleWithPathnames:const char*:pathname::
+PyImport_ExecCodeModuleWithPathnames:const char*:cpathname::
+
+PyImport_GetImporter:PyObject*::+1:
+PyImport_GetImporter:PyObject*:path:0:
+
 PyImport_GetMagicNumber:long:::
 
 PyImport_GetModuleDict:PyObject*::0:
@@ -537,6 +555,9 @@ PyImport_Import:PyObject*:name:0:
 PyImport_ImportFrozenModule:int:::
 PyImport_ImportFrozenModule:const char*:::
 
+PyImport_ImportFrozenModuleObject:int:::
+PyImport_ImportFrozenModuleObject:PyObject*::+1:
+
 PyImport_ImportModule:PyObject*::+1:
 PyImport_ImportModule:const char*:name::
 
@@ -553,6 +574,13 @@ PyImport_ImportModuleLevel:PyObject*:locals:0:???
 PyImport_ImportModuleLevel:PyObject*:fromlist:0:???
 PyImport_ImportModuleLevel:int:level::
 
+PyImport_ImportModuleLevelObject:PyObject*::+1:
+PyImport_ImportModuleLevelObject:PyObject*:name:0:
+PyImport_ImportModuleLevelObject:PyObject*:globals:0:???
+PyImport_ImportModuleLevelObject:PyObject*:locals:0:???
+PyImport_ImportModuleLevelObject:PyObject*:fromlist:0:???
+PyImport_ImportModuleLevelObject:int:level::
+
 PyImport_ReloadModule:PyObject*::+1:
 PyImport_ReloadModule:PyObject*:m:0:
 
index f147bb2..207f438 100644 (file)
@@ -183,8 +183,9 @@ the full reference.
    | *sources*              | list of source filenames,      | a list of strings         |
    |                        | relative to the distribution   |                           |
    |                        | root (where the setup script   |                           |
-   |                        | lives), in Unix form (slash-   |                           |
-   |                        | separated) for portability.    |                           |
+   |                        | lives), in Unix form           |                           |
+   |                        | (slash-separated) for          |                           |
+   |                        | portability.                   |                           |
    |                        | Source files may be C, C++,    |                           |
    |                        | SWIG (.i), platform-specific   |                           |
    |                        | resource files, or whatever    |                           |
@@ -936,7 +937,7 @@ timestamp dependency analysis.
 .. function:: newer_group(sources, target[, missing='error'])
 
    Return true if *target* is out-of-date with respect to any file listed in
-   *sources*  In other words, if *target* exists and is newer than every file in
+   *sources*.  In other words, if *target* exists and is newer than every file in
    *sources*, return false; otherwise return true. *missing* controls what we do
    when a source file is missing; the default (``'error'``) is to blow up with an
    :exc:`OSError` from  inside :func:`os.stat`; if it is ``'ignore'``, we silently
@@ -1565,8 +1566,8 @@ lines, and joining lines with backslashes.
    +------------------+--------------------------------+---------+
    | option name      | description                    | default |
    +==================+================================+=========+
-   | *strip_comments* | strip from ``'#'`` to end-of-  | true    |
-   |                  | line, as well as any           |         |
+   | *strip_comments* | strip from ``'#'`` to          | true    |
+   |                  | end-of-line, as well as any    |         |
    |                  | whitespace leading up to the   |         |
    |                  | ``'#'``\ ---unless it is       |         |
    |                  | escaped by a backslash         |         |
index 5e1a049..92d796f 100644 (file)
@@ -63,9 +63,9 @@ distribution to generate: for example, ::
 
    python setup.py bdist --format=zip
 
-would, when run on a Unix system, create :file:`Distutils-1.0.{plat}.zip`\
----again, this archive would be unpacked from the root directory to install the
-Distutils.
+would, when run on a Unix system, create
+:file:`Distutils-1.0.{plat}.zip`\ ---again, this archive would be unpacked
+from the root directory to install the Distutils.
 
 The available formats for built distributions are:
 
index cd10a7f..0874d05 100644 (file)
@@ -13,8 +13,8 @@ edit is a cheap and easy way to solicit it.  Configuration files also let you
 provide default values for any command option, which the installer can then
 override either on the command-line or by editing the config file.
 
-The setup configuration file is a useful middle-ground between the setup script
----which, ideally, would be opaque to installers [#]_---and the command-line to
+The setup configuration file is a useful middle-ground between the setup
+script---which, ideally, would be opaque to installers [#]_---and the command-line to
 the setup script, which is outside of your control and entirely up to the
 installer.  In fact, :file:`setup.cfg` (and any other Distutils configuration
 files present on the target system) are processed after the contents of the
index 130f4a7..2a28840 100644 (file)
@@ -544,8 +544,9 @@ or more format codes between parentheses.  For example::
 :c:func:`PyObject_CallObject` returns a Python object pointer: this is the return
 value of the Python function.  :c:func:`PyObject_CallObject` is
 "reference-count-neutral" with respect to its arguments.  In the example a new
-tuple was created to serve as the argument list, which is :c:func:`Py_DECREF`\
--ed immediately after the :c:func:`PyObject_CallObject` call.
+tuple was created to serve as the argument list, which is
+:c:func:`Py_DECREF`\ -ed immediately after the :c:func:`PyObject_CallObject`
+call.
 
 The return value of :c:func:`PyObject_CallObject` is "new": either it is a brand
 new object, or it is an existing object whose reference count has been
index fd04a83..a082817 100644 (file)
@@ -277,7 +277,7 @@ However sometimes you have to run the embedded Python interpreter in the same
 thread as your rest application and you can't allow the
 :c:func:`PyRun_InteractiveLoop` to stop while waiting for user input.  The one
 solution then is to call :c:func:`PyParser_ParseString` and test for ``e.error``
-equal to ``E_EOF``, which means the input is incomplete).  Here's a sample code
+equal to ``E_EOF``, which means the input is incomplete.  Here's a sample code
 fragment, untested, inspired by code from Alex Farber::
 
    #include <Python.h>
index 4e842f5..9ec90e8 100644 (file)
@@ -306,17 +306,19 @@ usually around 18 months between major releases.
 
 The developers issue "bugfix" releases of older versions, so the stability of
 existing releases gradually improves.  Bugfix releases, indicated by a third
-component of the version number (e.g. 2.5.3, 2.6.2), are managed for stability;
+component of the version number (e.g. 3.5.3, 3.6.2), are managed for stability;
 only fixes for known problems are included in a bugfix release, and it's
 guaranteed that interfaces will remain the same throughout a series of bugfix
 releases.
 
 The latest stable releases can always be found on the `Python download page
-<https://www.python.org/downloads/>`_.  There are two recommended production-ready
-versions at this point in time, because at the moment there are two branches of
-stable releases: 2.x and 3.x.  Python 3.x may be less useful than 2.x, since
-currently there is more third party software available for Python 2 than for
-Python 3.  Python 2 code will generally not run unchanged in Python 3.
+<https://www.python.org/downloads/>`_.  There are two production-ready version
+of Python: 2.x and 3.x, but the recommended one at this times is Python 3.x.
+Although Python 2.x is still widely used, `it will not be
+maintained after January 1, 2020 <https://www.python.org/dev/peps/pep-0373/>`_.
+Python 2.x was known for having more third-party libraries available, however,
+by the time of this writing, most of the widely used libraries support Python 3.x,
+and some are even dropping the Python 2.x support.
 
 
 How many people are using Python?
index f183984..2b44f65 100644 (file)
@@ -23,23 +23,10 @@ This is not necessarily a straightforward question. If you are already familiar
 with running programs from the Windows command line then everything will seem
 obvious; otherwise, you might need a little more guidance.
 
-.. sidebar:: |Python Development on XP|_
-   :subtitle: `Python Development on XP`_
-
-   This series of screencasts aims to get you up and running with Python on
-   Windows XP.  The knowledge is distilled into 1.5 hours and will get you up
-   and running with the right Python distribution, coding in your choice of IDE,
-   and debugging and writing solid code with unit-tests.
-
-.. |Python Development on XP| image:: python-video-icon.png
-.. _`Python Development on XP`:
-   http://showmedo.com/videotutorials/series?name=pythonOzsvaldPyNewbieSeries
-
 Unless you use some sort of integrated development environment, you will end up
 *typing* Windows commands into what is variously referred to as a "DOS window"
 or "Command prompt window".  Usually you can create such a window from your
-Start menu; under Windows 7 the menu selection is :menuselection:`Start -->
-Programs --> Accessories --> Command Prompt`.  You should be able to recognize
+search bar by searching for ``cmd``.  You should be able to recognize
 when you have started such a window because you will see a Windows "command
 prompt", which usually looks like this:
 
@@ -64,19 +51,19 @@ compiles it into bytecodes, and then executes the bytecodes to run your
 program. So, how do you arrange for the interpreter to handle your Python?
 
 First, you need to make sure that your command window recognises the word
-"python" as an instruction to start the interpreter.  If you have opened a
-command window, you should try entering the command ``python`` and hitting
+"py" as an instruction to start the interpreter.  If you have opened a
+command window, you should try entering the command ``py`` and hitting
 return:
 
 .. code-block:: doscon
 
-   C:\Users\YourName> python
+   C:\Users\YourName> py
 
 You should then see something like:
 
 .. code-block:: pycon
 
-   Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit (Intel)] on win32
+   Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>>
 
@@ -93,64 +80,33 @@ by entering a few expressions of your choice and seeing the results:
     'HelloHelloHello'
 
 Many people use the interactive mode as a convenient yet highly programmable
-calculator.  When you want to end your interactive Python session, hold the :kbd:`Ctrl`
-key down while you enter a :kbd:`Z`, then hit the ":kbd:`Enter`" key to get back to your
-Windows command prompt.
+calculator.  When you want to end your interactive Python session,
+call the :func:`exit` function or hold the :kbd:`Ctrl` key down
+while you enter a :kbd:`Z`, then hit the ":kbd:`Enter`" key to get
+back to your Windows command prompt.
 
 You may also find that you have a Start-menu entry such as :menuselection:`Start
---> Programs --> Python 3.3 --> Python (command line)` that results in you
+--> Programs --> Python 3.x --> Python (command line)` that results in you
 seeing the ``>>>`` prompt in a new window.  If so, the window will disappear
-after you enter the :kbd:`Ctrl-Z` character; Windows is running a single "python"
+after you call the :func:`exit` function or enter the :kbd:`Ctrl-Z`
+character; Windows is running a single "python"
 command in the window, and closes it when you terminate the interpreter.
 
-If the ``python`` command, instead of displaying the interpreter prompt ``>>>``,
-gives you a message like::
-
-   'python' is not recognized as an internal or external command, operable program or batch file.
-
-.. sidebar:: |Adding Python to DOS Path|_
-   :subtitle: `Adding Python to DOS Path`_
-
-   Python is not added to the DOS path by default.  This screencast will walk
-   you through the steps to add the correct entry to the `System Path`, allowing
-   Python to be executed from the command-line by all users.
-
-.. |Adding Python to DOS Path| image:: python-video-icon.png
-.. _`Adding Python to DOS Path`:
-   http://showmedo.com/videotutorials/video?name=960000&fromSeriesID=96
-
-
-or::
-
-   Bad command or filename
-
-then you need to make sure that your computer knows where to find the Python
-interpreter.  To do this you will have to modify a setting called PATH, which is
-a list of directories where Windows will look for programs.
-
-You should arrange for Python's installation directory to be added to the PATH
-of every command window as it starts.  If you installed Python fairly recently
-then the command ::
-
-   dir C:\py*
+Now that we know the ``py`` command is recognized, you can give your
+Python script to it. You'll have to give either an absolute or a
+relative path to the Python script. Let's say your Python script is
+located in your desktop and is named ``hello.py``, and your command
+prompt is nicely opened in your home directory so you're seeing something
+similar to::
 
-will probably tell you where it is installed; the usual location is something
-like ``C:\Python33``.  Otherwise you will be reduced to a search of your whole
-disk ... use :menuselection:`Tools --> Find` or hit the :guilabel:`Search`
-button and look for "python.exe".  Supposing you discover that Python is
-installed in the ``C:\Python33`` directory (the default at the time of writing),
-you should make sure that entering the command ::
+   C:\Users\YourName>
 
-   c:\Python33\python
+So now you'll ask the ``py`` command to give your script to Python by
+typing ``py`` followed by your script path::
 
-starts up the interpreter as above (and don't forget you'll need a ":kbd:`Ctrl-Z`" and
-an ":kbd:`Enter`" to get out of it). Once you have verified the directory, you can
-add it to the system path to make it easier to start Python by just running
-the ``python`` command. This is currently an option in the installer as of
-CPython 3.3.
 
-More information about environment variables can be found on the
-:ref:`Using Python on Windows <setting-envvars>` page.
+   C:\Users\YourName> py Desktop\hello.py
+   hello
 
 How do I make Python scripts executable?
 ----------------------------------------
@@ -324,36 +280,3 @@ How do I check for a keypress without blocking?
 Use the msvcrt module.  This is a standard Windows-specific extension module.
 It defines a function ``kbhit()`` which checks whether a keyboard hit is
 present, and ``getch()`` which gets one character without echoing it.
-
-
-How do I emulate os.kill() in Windows?
---------------------------------------
-
-Prior to Python 2.7 and 3.2, to terminate a process, you can use :mod:`ctypes`:
-
-.. code-block:: python
-
-   import ctypes
-
-   def kill(pid):
-       """kill function for Win32"""
-       kernel32 = ctypes.windll.kernel32
-       handle = kernel32.OpenProcess(1, 0, pid)
-       return (0 != kernel32.TerminateProcess(handle, 0))
-
-In 2.7 and 3.2, :func:`os.kill` is implemented similar to the above function,
-with the additional feature of being able to send :kbd:`Ctrl+C` and :kbd:`Ctrl+Break`
-to console subprocesses which are designed to handle those signals. See
-:func:`os.kill` for further details.
-
-How do I extract the downloaded documentation on Windows?
----------------------------------------------------------
-
-Sometimes, when you download the documentation package to a Windows machine
-using a web browser, the file extension of the saved file ends up being .EXE.
-This is a mistake; the extension should be .TGZ.
-
-Simply rename the downloaded file to have the .TGZ extension, and WinZip will be
-able to handle it.  (If your copy of WinZip doesn't, get a newer one from
-https://www.winzip.com.)
-
index cf2ca67..2aab8bf 100644 (file)
@@ -95,7 +95,7 @@ Glossary
       that it contains :keyword:`yield` expressions for producing a series of
       values usable in an :keyword:`async for` loop.
 
-      Usually refers to a asynchronous generator function, but may refer to an
+      Usually refers to an asynchronous generator function, but may refer to an
       *asynchronous generator iterator* in some contexts.  In cases where the
       intended meaning isn't clear, using the full terms avoids ambiguity.
 
@@ -108,8 +108,8 @@ Glossary
 
       This is an :term:`asynchronous iterator` which when called using the
       :meth:`__anext__` method returns an awaitable object which will execute
-      that the body of the asynchronous generator function until the
-      next :keyword:`yield` expression.
+      the body of the asynchronous generator function until the next
+      :keyword:`yield` expression.
 
       Each :keyword:`yield` temporarily suspends processing, remembering the
       location execution state (including local variables and pending
@@ -389,7 +389,7 @@ Glossary
       An :term:`annotation` of a function parameter or return value.
 
       Function annotations are usually used for
-      :term:`type hints <type hint>`: for example this function is expected to take two
+      :term:`type hints <type hint>`: for example, this function is expected to take two
       :class:`int` arguments and is also expected to have an :class:`int`
       return value::
 
index 9914f8d..af8c432 100644 (file)
@@ -971,7 +971,7 @@ provided:
 
 The :class:`NullHandler`, :class:`StreamHandler` and :class:`FileHandler`
 classes are defined in the core logging package. The other handlers are
-defined in a sub- module, :mod:`logging.handlers`. (There is also another
+defined in a sub-module, :mod:`logging.handlers`. (There is also another
 sub-module, :mod:`logging.config`, for configuration functionality.)
 
 Logged messages are formatted for presentation through instances of the
index 4842313..5a59b4d 100644 (file)
@@ -554,10 +554,10 @@ C headers              ``--install-headers``
 
 These override options can be relative, absolute,
 or explicitly defined in terms of one of the installation base directories.
-(There are two installation base directories, and they are normally the same---
-they only differ when you use the Unix "prefix scheme" and supply different
-``--prefix`` and ``--exec-prefix`` options; using ``--install-lib`` will
-override values computed or given for ``--install-purelib`` and
+(There are two installation base directories, and they are normally the
+same---they only differ when you use the Unix "prefix scheme" and supply
+different ``--prefix`` and ``--exec-prefix`` options; using ``--install-lib``
+will override values computed or given for ``--install-purelib`` and
 ``--install-platlib``, and is recommended for schemes that don't make a
 difference between Python and extension modules.)
 
@@ -584,10 +584,10 @@ in this case.)
 
 If you maintain Python on Windows, you might want third-party modules to live in
 a subdirectory of :file:`{prefix}`, rather than right in :file:`{prefix}`
-itself.  This is almost as easy as customizing the script installation directory
----you just have to remember that there are two types of modules to worry about,
-Python and extension modules, which can conveniently be both controlled by one
-option::
+itself.  This is almost as easy as customizing the script installation
+directory---you just have to remember that there are two types of modules
+to worry about, Python and extension modules, which can conveniently be both
+controlled by one option::
 
    python setup.py install --install-lib=Site
 
index 7071076..fc39a2e 100644 (file)
@@ -18,10 +18,10 @@ see the PEP for why this was added to Python. (See also :pep:`3141` and the
 :mod:`numbers` module regarding a type hierarchy for numbers based on ABCs.)
 
 The :mod:`collections` module has some concrete classes that derive from
-ABCs; these can, of course, be further derived. In addition the
+ABCs; these can, of course, be further derived. In addition, the
 :mod:`collections.abc` submodule has some ABCs that can be used to test whether
-a class or instance provides a particular interface, for example, is it
-hashable or a mapping.
+a class or instance provides a particular interface, for example, if it is
+hashable or if it is a mapping.
 
 
 This module provides the metaclass :class:`ABCMeta` for defining ABCs and
@@ -217,7 +217,7 @@ The :mod:`abc` module also provides the following decorator:
    the descriptor must identify itself as abstract using
    :attr:`__isabstractmethod__`. In general, this attribute should be ``True``
    if any of the methods used to compose the descriptor are abstract. For
-   example, Python's built-in property does the equivalent of::
+   example, Python's built-in :class:`property` does the equivalent of::
 
       class Descriptor:
           ...
index a9cb5c5..5196202 100644 (file)
@@ -844,6 +844,8 @@ values are:
   Note that ``nargs=1`` produces a list of one item.  This is different from
   the default, in which the item is produced by itself.
 
+.. index:: single: ? (question mark); in argparse module
+
 * ``'?'``. One argument will be consumed from the command line if possible, and
   produced as a single item.  If no command-line argument is present, the value from
   default_ will be produced.  Note that for optional arguments, there is an
@@ -876,6 +878,8 @@ values are:
      Namespace(infile=<_io.TextIOWrapper name='<stdin>' encoding='UTF-8'>,
                outfile=<_io.TextIOWrapper name='<stdout>' encoding='UTF-8'>)
 
+.. index:: single: * (asterisk); in argparse module
+
 * ``'*'``.  All command-line arguments present are gathered into a list.  Note that
   it generally doesn't make much sense to have more than one positional argument
   with ``nargs='*'``, but multiple optional arguments with ``nargs='*'`` is
@@ -888,6 +892,8 @@ values are:
      >>> parser.parse_args('a b --foo x y --bar 1 2'.split())
      Namespace(bar=['1', '2'], baz=['a', 'b'], foo=['x', 'y'])
 
+.. index:: single: + (plus); in argparse module
+
 * ``'+'``. Just like ``'*'``, all command-line args present are gathered into a
   list.  Additionally, an error message will be generated if there wasn't at
   least one command-line argument present.  For example::
index 6376f5f..eb66754 100644 (file)
@@ -41,6 +41,9 @@ Node classes
    with alternatives (aka "sums"), the left-hand side class is abstract: only
    instances of specific constructor nodes are ever created.
 
+   .. index:: single: ? (question mark); in AST grammar
+   .. index:: single: * (asterisk); in AST grammar
+
    .. attribute:: _fields
 
       Each concrete class has an attribute :attr:`_fields` which gives the names
index 3b4a8ff..d57edb7 100644 (file)
@@ -61,6 +61,10 @@ A :class:`Cmd` instance has the following methods:
 
    An end-of-file on input is passed back as the string ``'EOF'``.
 
+   .. index::
+      single: ? (question mark); in a command interpreter
+      single: ! (exclamation); in a command interpreter
+
    An interpreter instance will recognize a command name ``foo`` if and only if it
    has a method :meth:`do_foo`.  As a special case, a line beginning with the
    character ``'?'`` is dispatched to the method :meth:`do_help`.  As another
index 24008a0..9921351 100644 (file)
@@ -312,6 +312,14 @@ defined and implemented by all standard Python codecs:
 The following error handlers are only applicable to
 :term:`text encodings <text encoding>`:
 
+.. index::
+   single: ? (question mark); replacement character
+   single: \ (backslash); escape sequence
+   single: \x; escape sequence
+   single: \u; escape sequence
+   single: \U; escape sequence
+   single: \N; escape sequence
+
 +-------------------------+-----------------------------------------------+
 | Value                   | Meaning                                       |
 +=========================+===============================================+
@@ -1113,10 +1121,10 @@ particular, the following variants typically exist:
 |                 | ks_c-5601, ks_c-5601-1987,     |                                |
 |                 | ksx1001, ks_x-1001             |                                |
 +-----------------+--------------------------------+--------------------------------+
-| gb2312          | chinese, csiso58gb231280, euc- | Simplified Chinese             |
-|                 | cn, euccn, eucgb2312-cn,       |                                |
-|                 | gb2312-1980, gb2312-80, iso-   |                                |
-|                 | ir-58                          |                                |
+| gb2312          | chinese, csiso58gb231280,      | Simplified Chinese             |
+|                 | euc-cn, euccn, eucgb2312-cn,   |                                |
+|                 | gb2312-1980, gb2312-80,        |                                |
+|                 | iso-ir-58                      |                                |
 +-----------------+--------------------------------+--------------------------------+
 | gbk             | 936, cp936, ms936              | Unified Chinese                |
 +-----------------+--------------------------------+--------------------------------+
index 9794e73..69dfd0f 100644 (file)
@@ -137,6 +137,12 @@ And::
    An :class:`Executor` subclass that uses a pool of at most *max_workers*
    threads to execute calls asynchronously.
 
+   *initializer* is an optional callable that is called at the start of
+   each worker thread; *initargs* is a tuple of arguments passed to the
+   initializer.  Should *initializer* raise an exception, all currently
+   pending jobs will raise a :exc:`~concurrent.futures.thread.BrokenThreadPool`,
+   as well any attempt to submit more jobs to the pool.
+
    .. versionchanged:: 3.5
       If *max_workers* is ``None`` or
       not given, it will default to the number of processors on the machine,
@@ -147,7 +153,7 @@ And::
 
    .. versionadded:: 3.6
       The *thread_name_prefix* argument was added to allow users to
-      control the threading.Thread names for worker threads created by
+      control the :class:`threading.Thread` names for worker threads created by
       the pool for easier debugging.
 
 .. _threadpoolexecutor-example:
index 4abc6aa..79e1896 100644 (file)
@@ -291,6 +291,8 @@ On top of the core functionality, :class:`ConfigParser` supports
 interpolation.  This means values can be preprocessed before returning them
 from ``get()`` calls.
 
+.. index:: single: % (percent); interpolation in configuration files
+
 .. class:: BasicInterpolation()
 
    The default implementation used by :class:`ConfigParser`.  It enables
@@ -319,6 +321,8 @@ from ``get()`` calls.
    ``%(my_dir)s/Pictures`` as the value of ``my_pictures`` and
    ``%(home_dir)s/lumberjack`` as the value of ``my_dir``.
 
+.. index:: single: $ (dollar); interpolation in configuration files
+
 .. class:: ExtendedInterpolation()
 
    An alternative handler for interpolation which implements a more advanced
@@ -691,7 +695,7 @@ More advanced customization may be achieved by overriding default values of
 these parser attributes.  The defaults are defined on the classes, so they may
 be overridden by subclasses or by attribute assignment.
 
-.. attribute:: BOOLEAN_STATES
+.. attribute:: ConfigParser.BOOLEAN_STATES
 
   By default when using :meth:`~ConfigParser.getboolean`, config parsers
   consider the following values ``True``: ``'1'``, ``'yes'``, ``'true'``,
@@ -714,7 +718,7 @@ be overridden by subclasses or by attribute assignment.
   Other typical Boolean pairs include ``accept``/``reject`` or
   ``enabled``/``disabled``.
 
-.. method:: optionxform(option)
+.. method:: ConfigParser.optionxform(option)
 
   This method transforms option names on every read, get, or set
   operation.  The default converts the name to lowercase.  This also
@@ -745,7 +749,7 @@ be overridden by subclasses or by attribute assignment.
      >>> list(custom['Section2'].keys())
      ['AnotherKey']
 
-.. attribute:: SECTCRE
+.. attribute:: ConfigParser.SECTCRE
 
   A compiled regular expression used to parse section headers.  The default
   matches ``[section]`` to the name ``"section"``.  Whitespace is considered
index 78f1619..634ff00 100644 (file)
@@ -51,10 +51,11 @@ A small number of constants live in the built-in namespace.  They are:
       See :exc:`NotImplementedError` for details on when to use it.
 
 
+.. index:: single: ...; ellipsis literal
 .. data:: Ellipsis
 
-   The same as ``...``.  Special value used mostly in conjunction with extended
-   slicing syntax for user-defined container data types.
+   The same as the ellipsis literal "``...``".  Special value used mostly in conjunction
+   with extended slicing syntax for user-defined container data types.
 
 
 .. data:: __debug__
index 2041d91..c7bd89f 100644 (file)
@@ -22,7 +22,7 @@ Interface summary:
    Return a shallow copy of *x*.
 
 
-.. function:: deepcopy(x)
+.. function:: deepcopy(x[, memo])
 
    Return a deep copy of *x*.
 
@@ -52,7 +52,7 @@ copy operations:
 
 The :func:`deepcopy` function avoids these problems by:
 
-* keeping a "memo" dictionary of objects already copied during the current
+* keeping a ``memo`` dictionary of objects already copied during the current
   copying pass; and
 
 * letting user-defined classes override the copying operation or the set of
@@ -82,7 +82,7 @@ In order for a class to define its own copy implementation, it can define
 special methods :meth:`__copy__` and :meth:`__deepcopy__`.  The former is called
 to implement the shallow copy operation; no additional arguments are passed.
 The latter is called to implement the deep copy operation; it is passed one
-argument, the memo dictionary.  If the :meth:`__deepcopy__` implementation needs
+argument, the ``memo`` dictionary.  If the :meth:`__deepcopy__` implementation needs
 to make a deep copy of a component, it should call the :func:`deepcopy` function
 with the component as first argument and the memo dictionary as second argument.
 
index dbd4274..bccc76b 100644 (file)
@@ -84,7 +84,7 @@ The :mod:`crypt` module defines the following functions:
    may be available on all platforms), or a full encrypted password
    including salt, as returned by this function.  If *salt* is not
    provided, the strongest method will be used (as returned by
-   :func:`methods`.
+   :func:`methods`).
 
    Checking a password is usually done by passing the plain-text password
    as *word* and the full results of a previous :func:`crypt` call,
index 04b2a26..a69dbb2 100644 (file)
@@ -207,6 +207,10 @@ The following function takes either a single-character string or integer value;
 it returns a string.
 
 
+.. index::
+   single: ^ (caret); in curses module
+   single: ! (exclamation); in curses module
+
 .. function:: unctrl(c)
 
    Return a string representation of the ASCII character *c*.  If *c* is printable,
index 88bc328..25f2fd3 100644 (file)
@@ -276,9 +276,10 @@ Supported operations:
 | ``+t1``                        | Returns a :class:`timedelta` object with the  |
 |                                | same value. (2)                               |
 +--------------------------------+-----------------------------------------------+
-| ``-t1``                        | equivalent to :class:`timedelta`\             |
-|                                | (-*t1.days*, -*t1.seconds*,                   |
-|                                | -*t1.microseconds*), and to *t1*\* -1. (1)(4) |
+| ``-t1``                        | equivalent to                                 |
+|                                | :class:`timedelta`\ (-*t1.days*,              |
+|                                | -*t1.seconds*, -*t1.microseconds*),           |
+|                                | and to *t1*\* -1. (1)(4)                      |
 +--------------------------------+-----------------------------------------------+
 | ``abs(t)``                     | equivalent to +\ *t* when ``t.days >= 0``, and|
 |                                | to -*t* when ``t.days < 0``. (2)              |
@@ -1927,6 +1928,9 @@ Class attributes:
    The UTC timezone, ``timezone(timedelta(0))``.
 
 
+.. index::
+   single: % (percent); datetime format
+
 .. _strftime-strptime-behavior:
 
 :meth:`strftime` and :meth:`strptime` Behavior
@@ -1941,7 +1945,9 @@ although not all objects support a :meth:`timetuple` method.
 Conversely, the :meth:`datetime.strptime` class method creates a
 :class:`.datetime` object from a string representing a date and time and a
 corresponding format string. ``datetime.strptime(date_string, format)`` is
-equivalent to ``datetime(*(time.strptime(date_string, format)[0:6]))``.
+equivalent to ``datetime(*(time.strptime(date_string, format)[0:6]))``, except
+when the format includes sub-second components or timezone offset information,
+which are supported in ``datetime.strptime`` but are discarded by ``time.strptime``.
 
 For :class:`.time` objects, the format codes for year, month, and day should not
 be used, as time objects have no such values.  If they're used anyway, ``1900``
index 6743bdc..f044cb2 100644 (file)
@@ -457,14 +457,15 @@ The :class:`SequenceMatcher` class has this constructor:
 
    .. method:: get_matching_blocks()
 
-      Return list of triples describing matching subsequences. Each triple is of
-      the form ``(i, j, n)``, and means that ``a[i:i+n] == b[j:j+n]``.  The
+      Return list of triples describing non-overlapping matching subsequences.
+      Each triple is of the form ``(i, j, n)``,
+      and means that ``a[i:i+n] == b[j:j+n]``.  The
       triples are monotonically increasing in *i* and *j*.
 
       The last triple is a dummy, and has the value ``(len(a), len(b), 0)``.  It
       is the only triple with ``n == 0``.  If ``(i, j, n)`` and ``(i', j', n')``
       are adjacent triples in the list, and the second is not the last triple in
-      the list, then ``i+n != i'`` or ``j+n != j'``; in other words, adjacent
+      the list, then ``i+n < i'`` or ``j+n < j'``; in other words, adjacent
       triples always describe non-adjacent equal blocks.
 
       .. XXX Explain why a dummy is used!
index 587a0a0..a138e68 100644 (file)
@@ -321,6 +321,10 @@ but doctest isn't trying to do an exact emulation of any specific Python shell.
    NO!!!
    >>>
 
+.. index::
+   single: >>>; interpreter prompt
+   single: ...; interpreter prompt
+
 Any expected output must immediately follow the final ``'>>> '`` or ``'... '``
 line containing the code, and the expected output (if any) extends to the next
 ``'>>> '`` or all-whitespace line.
@@ -481,6 +485,8 @@ Some details you should read once, but won't need to remember:
   to test a :exc:`SyntaxError` that omits the traceback header, you will need to
   manually add the traceback header line to your test example.
 
+.. index:: single: ^ (caret); marker
+
 * For some :exc:`SyntaxError`\ s, Python displays the character position of the
   syntax error, using a ``^`` marker::
 
@@ -532,6 +538,7 @@ doctest decides whether actual output matches an example's expected output:
    option will probably go away, but not for several years.
 
 
+.. index:: single: <BLANKLINE>
 .. data:: DONT_ACCEPT_BLANKLINE
 
    By default, if an expected output block contains a line containing only the
@@ -551,6 +558,7 @@ doctest decides whether actual output matches an example's expected output:
    your source.
 
 
+.. index:: single: ...; in doctests
 .. data:: ELLIPSIS
 
    When specified, an ellipsis marker (``...``) in the expected output can match
@@ -686,6 +694,10 @@ useful unless you intend to extend :mod:`doctest` internals via subclassing:
       MY_FLAG = register_optionflag('MY_FLAG')
 
 
+.. index::
+   single: # (hash); in doctests
+   single: + (plus); in doctests
+   single: - (minus); in doctests
 .. _doctest-directives:
 
 Directives
index 7e11782..ed38015 100644 (file)
@@ -149,10 +149,10 @@ Here are the methods of the :class:`Message` class:
 
    .. method:: is_multipart()
 
-      Return ``True`` if the message's payload is a list of sub-\
-      :class:`Message` objects, otherwise return ``False``.  When
+      Return ``True`` if the message's payload is a list of
+      sub-\ :class:`Message` objects, otherwise return ``False``.  When
       :meth:`is_multipart` returns ``False``, the payload should be a string
-      object (which might be a CTE encoded binary payload.  (Note that
+      object (which might be a CTE encoded binary payload).  (Note that
       :meth:`is_multipart` returning ``True`` does not necessarily mean that
       "msg.get_content_maintype() == 'multipart'" will return the ``True``.
       For example, ``is_multipart`` will return ``True`` when the
index 261d0d6..77b8099 100644 (file)
@@ -92,7 +92,7 @@ message objects.
 
    .. method:: __str__()
 
-      Equivalent to `as_string(policy=self.policy.clone(utf8=True)`.  Allows
+      Equivalent to ``as_string(policy=self.policy.clone(utf8=True))``.  Allows
       ``str(msg)`` to produce a string containing the serialized message in a
       readable format.
 
@@ -130,8 +130,8 @@ message objects.
 
    .. method:: is_multipart()
 
-      Return ``True`` if the message's payload is a list of sub-\
-      :class:`EmailMessage` objects, otherwise return ``False``.  When
+      Return ``True`` if the message's payload is a list of
+      sub-\ :class:`EmailMessage` objects, otherwise return ``False``.  When
       :meth:`is_multipart` returns ``False``, the payload should be a string
       object (which might be a CTE encoded binary payload).  Note that
       :meth:`is_multipart` returning ``True`` does not necessarily mean that
@@ -379,7 +379,7 @@ message objects.
 
       Note that existing parameter values of headers may be accessed through
       the :attr:`~email.headerregistry.BaseHeader.params` attribute of the
-      header value (for example, ``msg['Content-Type'].params['charset']``.
+      header value (for example, ``msg['Content-Type'].params['charset']``).
 
       .. versionchanged:: 3.4 ``replace`` keyword was added.
 
@@ -679,7 +679,7 @@ message objects.
       specified by the current :mod:`~email.policy`.  If the added part
       has no :mailheader:`Content-Disposition` header, add one with the value
       ``attachment``.  This method can be used both for explicit attachments
-      (:mailheader:`Content-Disposition: attachment` and ``inline`` attachments
+      (:mailheader:`Content-Disposition: attachment`) and ``inline`` attachments
       (:mailheader:`Content-Disposition: inline`), by passing appropriate
       options to the ``content_manager``.
 
index e0cab6a..d9a6161 100644 (file)
@@ -164,7 +164,7 @@ message body, instead setting the payload to the raw body.
       envelope header.  The header block is terminated either by the end of the
       data or by a blank line.  Following the header block is the body of the
       message (which may contain MIME-encoded subparts, including subparts
-      with a :mailheader:`Content-Transfer-Encoding` of ``8bit``.
+      with a :mailheader:`Content-Transfer-Encoding` of ``8bit``).
 
       Optional *headersonly* is a flag specifying whether to stop parsing after
       reading the headers or not.  The default is ``False``, meaning it parses
@@ -238,7 +238,7 @@ in the top-level :mod:`email` package namespace.
 
    Return a message object structure from a :term:`bytes-like object`.  This is
    equivalent to ``BytesParser().parsebytes(s)``.  Optional *_class* and
-   *strict* are interpreted as with the :class:`~email.parser.BytesParser` class
+   *policy* are interpreted as with the :class:`~email.parser.BytesParser` class
    constructor.
 
    .. versionadded:: 3.2
index 1033d8c..fae99cf 100644 (file)
@@ -87,7 +87,7 @@ to advanced applications.
 Following those is a set of examples of using the fundamental parts of the APIs
 covered in the preceding sections.
 
-The forgoing represent the modern (unicode friendly) API of the email package.
+The foregoing represent the modern (unicode friendly) API of the email package.
 The remaining sections, starting with the :class:`~email.message.Message`
 class, cover the legacy :data:`~email.policy.compat32` API that deals much more
 directly with the details of how email messages are represented.  The
@@ -126,7 +126,7 @@ Legacy API:
    email.header.rst
    email.charset.rst
    email.encoders.rst
-   email.util.rst
+   email.utils.rst
    email.iterators.rst
 
 
index cfa1649..5c0cac8 100644 (file)
@@ -52,7 +52,7 @@ will be set as :attr:`__cause__` on the raised exception. Setting
 :attr:`__cause__` also implicitly sets the :attr:`__suppress_context__`
 attribute to ``True``, so that using ``raise new_exc from None``
 effectively replaces the old exception with the new one for display
-purposes (e.g. converting :exc:`KeyError` to :exc:`AttributeError`, while
+purposes (e.g. converting :exc:`KeyError` to :exc:`AttributeError`), while
 leaving the old exception available in :attr:`__context__` for introspection
 when debugging.
 
index 634c26e..fb0a1e3 100644 (file)
@@ -16,6 +16,13 @@ This module provides support for Unix shell-style wildcards, which are *not* the
 same as regular expressions (which are documented in the :mod:`re` module).  The
 special characters used in shell-style wildcards are:
 
+.. index::
+   single: * (asterisk); in glob-style wildcards
+   single: ? (question mark); in glob-style wildcards
+   single: [] (square brackets); in glob-style wildcards
+   single: ! (exclamation); in glob-style wildcards
+   single: - (minus); in glob-style wildcards
+
 +------------+------------------------------------+
 | Pattern    | Meaning                            |
 +============+====================================+
@@ -35,7 +42,7 @@ For example, ``'[?]'`` matches the character ``'?'``.
 
 Note that the filename separator (``'/'`` on Unix) is *not* special to this
 module.  See module :mod:`glob` for pathname expansion (:mod:`glob` uses
-:func:`fnmatch` to match pathname segments).  Similarly, filenames starting with
+:func:`.filter` to match pathname segments).  Similarly, filenames starting with
 a period are not special for this module, and are matched by the ``*`` and ``?``
 patterns.
 
index b6e5246..bc528dd 100644 (file)
@@ -1383,8 +1383,8 @@ are always available.  They are listed here in alphabetical order.
    Has two optional arguments which must be specified as keyword arguments.
 
    *key* specifies a function of one argument that is used to extract a comparison
-   key from each list element: ``key=str.lower``.  The default value is ``None``
-   (compare the elements directly).
+   key from each element in *iterable* (for example, ``key=str.lower``).  The
+   default value is ``None`` (compare the elements directly).
 
    *reverse* is a boolean value.  If set to ``True``, then the list elements are
    sorted as if each comparison were reversed.
index 28062c1..41c06c6 100644 (file)
@@ -80,6 +80,11 @@ The :mod:`functools` module defines the following functions:
    The cache's size limit assures that the cache does not grow without bound on
    long-running processes such as web servers.
 
+   In general, the LRU cache should only be used when you want to reuse
+   previously computed values.  Accordingly, it doesn't make sense to cache
+   functions with side-effects, functions that need to create distinct mutable
+   objects on each call, or impure functions such as time() or random().
+
    Example of an LRU cache for static web content::
 
         @lru_cache(maxsize=32)
@@ -167,10 +172,11 @@ The :mod:`functools` module defines the following functions:
 
 .. function:: partial(func, *args, **keywords)
 
-   Return a new :class:`partial` object which when called will behave like *func*
-   called with the positional arguments *args* and keyword arguments *keywords*. If
-   more arguments are supplied to the call, they are appended to *args*. If
-   additional keyword arguments are supplied, they extend and override *keywords*.
+   Return a new :ref:`partial object<partial-objects>` which when called
+   will behave like *func* called with the positional arguments *args*
+   and keyword arguments *keywords*. If more arguments are supplied to the
+   call, they are appended to *args*. If additional keyword arguments are
+   supplied, they extend and override *keywords*.
    Roughly equivalent to::
 
       def partial(func, *args, **keywords):
@@ -209,7 +215,7 @@ The :mod:`functools` module defines the following functions:
    :func:`classmethod`, :func:`staticmethod`, :func:`abstractmethod` or
    another instance of :class:`partialmethod`), calls to ``__get__`` are
    delegated to the underlying descriptor, and an appropriate
-   :class:`partial` object returned as the result.
+   :ref:`partial object<partial-objects>` returned as the result.
 
    When *func* is a non-descriptor callable, an appropriate bound method is
    created dynamically. This behaves like a normal Python function when
index 407853c..c98c5e7 100644 (file)
@@ -61,6 +61,7 @@ class-based API instead.
    *domain*, which is returned.
 
 
+.. index:: single: _ (underscore); gettext
 .. function:: gettext(message)
 
    Return the localized translation of *message*, based on the current global
index 25bd4b7..0db10b5 100644 (file)
 
 --------------
 
+.. index::
+   single: * (asterisk); in glob-style wildcards
+   single: ? (question mark); in glob-style wildcards
+   single: [] (square brackets); in glob-style wildcards
+   single: ! (exclamation); in glob-style wildcards
+   single: - (minus); in glob-style wildcards
+   single: . (dot); in glob-style wildcards
+
 The :mod:`glob` module finds all the pathnames matching a specified pattern
 according to the rules used by the Unix shell, although results are returned in
 arbitrary order.  No tilde expansion is done, but ``*``, ``?``, and character
@@ -36,6 +44,9 @@ For example, ``'[?]'`` matches the character ``'?'``.
    :file:`../../Tools/\*/\*.gif`), and can contain shell-style wildcards. Broken
    symlinks are included in the results (as in the shell).
 
+   .. index::
+      single: **; in glob-style wildcards
+
    If *recursive* is true, the pattern "``**``" will match any files and zero or
    more directories and subdirectories.  If the pattern is followed by an
    ``os.sep``, only directories and subdirectories match.
index 7e33e74..d04033b 100644 (file)
@@ -110,17 +110,17 @@ The module also offers three general purpose functions based on heaps.
 
    Return a list with the *n* largest elements from the dataset defined by
    *iterable*.  *key*, if provided, specifies a function of one argument that is
-   used to extract a comparison key from each element in the iterable:
-   ``key=str.lower`` Equivalent to:  ``sorted(iterable, key=key,
-   reverse=True)[:n]``
+   used to extract a comparison key from each element in *iterable* (for example,
+   ``key=str.lower``).  Equivalent to:  ``sorted(iterable, key=key,
+   reverse=True)[:n]``.
 
 
 .. function:: nsmallest(n, iterable, key=None)
 
    Return a list with the *n* smallest elements from the dataset defined by
    *iterable*.  *key*, if provided, specifies a function of one argument that is
-   used to extract a comparison key from each element in the iterable:
-   ``key=str.lower`` Equivalent to:  ``sorted(iterable, key=key)[:n]``
+   used to extract a comparison key from each element in *iterable* (for example,
+   ``key=str.lower``).  Equivalent to:  ``sorted(iterable, key=key)[:n]``.
 
 
 The latter two functions perform best for smaller values of *n*.  For larger
index b29020b..2d1a96d 100644 (file)
 
 This module defines classes for implementing HTTP servers (Web servers).
 
+.. warning::
+
+    :mod:`http.server` is not recommended for production. It only implements
+    only basic security checks.
+
 One class, :class:`HTTPServer`, is a :class:`socketserver.TCPServer` subclass.
 It creates and listens at the HTTP socket, dispatching the requests to a
 handler.  Code to create and run the server looks like this::
index 58e6193..964d492 100644 (file)
@@ -20,7 +20,7 @@ IDLE has the following features:
 
 * coded in 100% pure Python, using the :mod:`tkinter` GUI toolkit
 
-* cross-platform: works mostly the same on Windows, Unix, and Mac OS X
+* cross-platform: works mostly the same on Windows, Unix, and macOS
 
 * Python shell window (interactive interpreter) with colorizing
   of code input, output, and error messages
@@ -40,13 +40,17 @@ Menus
 -----
 
 IDLE has two main window types, the Shell window and the Editor window.  It is
-possible to have multiple editor windows simultaneously.  Output windows, such
-as used for Edit / Find in Files, are a subtype of edit window.  They currently
-have the same top menu as Editor windows but a different default title and
-context menu.
+possible to have multiple editor windows simultaneously.  On Windows and
+Linux, each has its own top menu.  Each menu documented below indicates
+which window type it is associated with.
 
-IDLE's menus dynamically change based on which window is currently selected.
-Each menu documented below indicates which window type it is associated with.
+Output windows, such as used for Edit => Find in Files, are a subtype of editor
+window.  They currently have the same top menu but a different
+default title and context menu.
+
+On macOS, there is one application menu.  It dynamically changes according
+to the window currently selected.  It has an IDLE menu, and some entries
+described below are moved around to conform to Apple guidlines.
 
 File menu (Shell and Editor)
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -263,7 +267,7 @@ Options menu (Shell and Editor)
 Configure IDLE
    Open a configuration dialog and change preferences for the following:
    fonts, indentation, keybindings, text color themes, startup windows and
-   size, additional help sources, and extensions (see below).  On OS X,
+   size, additional help sources, and extensions (see below).  On macOS,
    open the configuration dialog by selecting Preferences in the application
    menu.  To use a new built-in color theme (IDLE Dark) with older IDLEs,
    save it as a new custom theme.
@@ -295,7 +299,7 @@ About IDLE
    Display version, copyright, license, credits, and more.
 
 IDLE Help
-   Display a help file for IDLE detailing the menu options, basic editing and
+   Display this IDLE document, detailing the menu options, basic editing and
    navigation, and other tips.
 
 Python Docs
@@ -306,7 +310,8 @@ Turtle Demo
    Run the turtledemo module with example python code and turtle drawings.
 
 Additional help sources may be added here with the Configure IDLE dialog under
-the General tab.
+the General tab. See the "Help sources" subsection below for more
+on Help menu choices.
 
 .. index::
    single: Cut
@@ -319,7 +324,7 @@ the General tab.
 Context Menus
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Open a context menu by right-clicking in a window (Control-click on OS X).
+Open a context menu by right-clicking in a window (Control-click on macOS).
 Context menus have the standard clipboard functions also on the Edit menu.
 
 Cut
@@ -341,17 +346,42 @@ Set Breakpoint
 Clear Breakpoint
    Clear the breakpoint on that line.
 
-Shell and Output windows have the following.
+Shell and Output windows also have the following.
 
 Go to file/line
    Same as in Debug menu.
 
+The Shell window also has an output squeezing facility explained in the
+the *Python Shell window* subsection below.
+
+Squeeze
+   If the cursor is over an output line, squeeze all the output between
+   the code above and the prompt below down to a 'Squeezed text' label.
+
 
 Editing and navigation
 ----------------------
 
+Editor windows
+^^^^^^^^^^^^^^
+
+IDLE may open editor windows when it starts, depending on settings
+and how you start IDLE.  Thereafter, use the File menu.  There can be only
+one open editor window for a given file.
+
+The title bar contains the name of the file, the full path, and the version
+of Python and IDLE running the window.  The status bar contains the line
+number ('Ln') and column number ('Col').  Line numbers start with 1;
+column numbers with 0.
+
+IDLE assumes that files with a known .py* extension contain Python code
+and that other files do not.  Run Python code with the Run menu.
+
+Key bindings
+^^^^^^^^^^^^
+
 In this section, 'C' refers to the :kbd:`Control` key on Windows and Unix and
-the :kbd:`Command` key on Mac OSX.
+the :kbd:`Command` key on macOS.
 
 * :kbd:`Backspace` deletes to the left; :kbd:`Del` deletes to the right
 
@@ -389,7 +419,6 @@ the :kbd:`Command` key on Mac OSX.
 Standard keybindings (like :kbd:`C-c` to copy and :kbd:`C-v` to paste)
 may work.  Keybindings are selected in the Configure IDLE dialog.
 
-
 Automatic indentation
 ^^^^^^^^^^^^^^^^^^^^^
 
@@ -477,6 +506,17 @@ or immediately run an existing file before editing.
 Python Shell window
 ^^^^^^^^^^^^^^^^^^^
 
+With IDLE's Shell, one enters, edits, and recalls complete statements.
+Most consoles and terminals only work with a single physical line at a time.
+
+When one pastes code into Shell, it is not compiled and possibly executed
+until one hits :kbd:`Return`.  One may edit pasted code first.
+If one pastes more that one statement into Shell, the result will be a
+:exc:`SyntaxError` when multiple statements are compiled as if they were one.
+
+The editing features described in previous subsections work when entering
+code interactively.  IDLE's Shell window also responds to the following keys.
+
 * :kbd:`C-c` interrupts executing command
 
 * :kbd:`C-d` sends end-of-file; closes window if typed at a ``>>>`` prompt
@@ -486,13 +526,12 @@ Python Shell window
   Command history
 
   * :kbd:`Alt-p` retrieves previous command matching what you have typed. On
-    OS X use :kbd:`C-p`.
+    macOS use :kbd:`C-p`.
 
-  * :kbd:`Alt-n` retrieves next. On OS X use :kbd:`C-n`.
+  * :kbd:`Alt-n` retrieves next. On macOS use :kbd:`C-n`.
 
   * :kbd:`Return` while on any previous command retrieves that command
 
-
 Text colors
 ^^^^^^^^^^^
 
@@ -526,7 +565,6 @@ looked for in the user's home directory.  Statements in this file will be
 executed in the Tk namespace, so this file is not useful for importing
 functions to be used from IDLE's Python shell.
 
-
 Command line usage
 ^^^^^^^^^^^^^^^^^^
 
@@ -554,7 +592,6 @@ If there are arguments:
 * Otherwise, arguments are files opened for editing and
   ``sys.argv`` reflects the arguments passed to IDLE itself.
 
-
 Startup failure
 ^^^^^^^^^^^^^^^
 
@@ -598,27 +635,84 @@ be to delete one or more of the configuration files.
 If IDLE quits with no message, and it was not started from a console, try
 starting from a console (``python -m idlelib)`` and see if a message appears.
 
-
-IDLE-console differences
-^^^^^^^^^^^^^^^^^^^^^^^^
+Running user code
+^^^^^^^^^^^^^^^^^
 
 With rare exceptions, the result of executing Python code with IDLE is
-intended to be the same as executing the same code in a console window.
+intended to be the same as executing the same code by the default method,
+directly with Python in a text-mode system console or terminal window.
 However, the different interface and operation occasionally affect
-visible results.  For instance, ``sys.modules`` starts with more entries.
+visible results.  For instance, ``sys.modules`` starts with more entries,
+and ``threading.activeCount()`` returns 2 instead of 1.
+
+By default, IDLE runs user code in a separate OS process rather than in
+the user interface process that runs the shell and editor.  In the execution
+process, it replaces ``sys.stdin``, ``sys.stdout``, and ``sys.stderr``
+with objects that get input from and send output to the Shell window.
+The original values stored in ``sys.__stdin__``, ``sys.__stdout__``, and
+``sys.__stderr__`` are not touched, but may be ``None``.
 
-IDLE also replaces ``sys.stdin``, ``sys.stdout``, and ``sys.stderr`` with
-objects that get input from and send output to the Shell window.
 When Shell has the focus, it controls the keyboard and screen.  This is
 normally transparent, but functions that directly access the keyboard
-and screen will not work.  If ``sys`` is reset with ``importlib.reload(sys)``,
-IDLE's changes are lost and things like ``input``, ``raw_input``, and
-``print`` will not work correctly.
-
-With IDLE's Shell, one enters, edits, and recalls complete statements.
-Some consoles only work with a single physical line at a time.  IDLE uses
-``exec`` to run each statement.  As a result, ``'__builtins__'`` is always
-defined for each statement.
+and screen will not work.  These include system-specific functions that
+determine whether a key has been pressed and if so, which.
+
+IDLE's standard stream replacements are not inherited by subprocesses
+created in the execution process, whether directly by user code or by modules
+such as multiprocessing.  If such subprocess use ``input`` from sys.stdin
+or ``print`` or ``write`` to sys.stdout or sys.stderr,
+IDLE should be started in a command line window.  The secondary subprocess
+will then be attached to that window for input and output.
+
+If ``sys`` is reset by user code, such as with ``importlib.reload(sys)``,
+IDLE's changes are lost and input from the keyboard and output to the screen
+will not work correctly.
+
+User output in Shell
+^^^^^^^^^^^^^^^^^^^^
+
+When a program outputs text, the result is determined by the
+corresponding output device.  When IDLE executes user code, ``sys.stdout``
+and ``sys.stderr`` are connected to the display area of IDLE's Shell.  Some of
+its features are inherited from the underlying Tk Text widget.  Others
+are programmed additions.  Where it matters, Shell is designed for development
+rather than production runs.
+
+For instance, Shell never throws away output.  A program that sends unlimited
+output to Shell will eventually fill memory, resulting in a memory error.
+In contrast, some system text windows only keep the last n lines of output.
+A Windows console, for instance, keeps a user-settable 1 to 9999 lines,
+with 300 the default.
+
+Text widgets display a subset of Unicode, the Basic Multilingual Plane (BMP).
+Which characters get a proper glyph instead of a replacement box depends on
+the operating system and installed fonts.  Newline characters cause following
+text to appear on a new line, but other control characters are either
+replaced with a box or deleted.  However, ``repr()``, which is used for
+interactive echo of expression values, replaces control characters,
+some BMP codepoints, and all non-BMP characters with escape codes
+before they are output.
+
+Normal and error output are generally kept separate (on separate lines)
+from code input and each other.  They each get different highlight colors.
+
+For SyntaxError tracebacks, the normal '^' marking where the error was
+detected is replaced by coloring the text with an error highlight.
+When code run from a file causes other exceptions, one may right click
+on a traceback line to jump to the corresponding line in an IDLE editor.
+The file will be opened if necessary.
+
+Shell has a special facility for squeezing output lines down to a
+'Squeezed text' label.  This is done automatically
+for output over N lines (N = 50 by default).
+N can be changed in the PyShell section of the General
+page of the Settings dialog.  Output with fewer lines can be squeezed by
+right clicking on the output.  This can be useful lines long enough to slow
+down scrolling.
+
+Squeezed output is expanded in place by double-clicking the label.
+It can also be sent to the clipboard or a separate view window by
+right-clicking the label.
 
 Developing tkinter applications
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -674,15 +768,25 @@ with the default subprocess if at all possible.
 Help and preferences
 --------------------
 
-Additional help sources
-^^^^^^^^^^^^^^^^^^^^^^^
+Help sources
+^^^^^^^^^^^^
 
-IDLE includes a help menu entry called "Python Docs" that will open the
-extensive sources of help, including tutorials, available at docs.python.org.
-Selected URLs can be added or removed from the help menu at any time using the
-Configure IDLE dialog. See the IDLE help option in the help menu of IDLE for
-more information.
+Help menu entry "IDLE Help" displays a formatted html version of the
+IDLE chapter of the Library Reference.  The result, in a read-only
+tkinter text window, is close to what one sees in a web browser.
+Navigate through the text with a mousewheel,
+the scrollbar, or up and down arrow keys held down.
+Or click the TOC (Table of Contents) button and select a section
+header in the opened box.
 
+Help menu entry "Python Docs" opens the extensive sources of help,
+including tutorials, available at docs.python.org/x.y, where 'x.y'
+is the currently running Python version.  If your system
+has an off-line copy of the docs (this may be an installation option),
+that will be opened instead.
+
+Selected URLs can be added or removed from the help menu at any time using the
+General tab of the Configure IDLE dialog .
 
 Setting preferences
 ^^^^^^^^^^^^^^^^^^^
@@ -692,6 +796,12 @@ changed via Configure IDLE on the Option menu.  Keys can be user defined;
 IDLE ships with four built-in key sets. In addition, a user can create a
 custom key set in the Configure IDLE dialog under the keys tab.
 
+IDLE on macOS
+^^^^^^^^^^^^^
+
+Under System Preferences: Dock, one can set "Prefer tabs when opening
+documents" to "Always".  This setting is not compatible with the tk/tkinter
+GUI framework used by IDLE, and it breaks a few IDLE features.
 
 Extensions
 ^^^^^^^^^^
index 356d160..25055f7 100644 (file)
@@ -1404,7 +1404,7 @@ Importing a source file directly
 ''''''''''''''''''''''''''''''''
 
 To import a Python source file directly, use the following recipe
-(Python 3.4 and newer only)::
+(Python 3.5 and newer only)::
 
   import importlib.util
   import sys
@@ -1482,7 +1482,7 @@ Python 3.6 and newer for other parts of the code).
       if '.' in absolute_name:
           parent_name, _, child_name = absolute_name.rpartition('.')
           parent_module = import_module(parent_name)
-          path = parent_module.spec.submodule_search_locations
+          path = parent_module.__spec__.submodule_search_locations
       for finder in sys.meta_path:
           spec = finder.find_spec(absolute_name, path)
           if spec is not None:
index 6be28a2..891dedd 100644 (file)
@@ -129,9 +129,6 @@ attributes:
 |           | f_locals          | local namespace seen by   |
 |           |                   | this frame                |
 +-----------+-------------------+---------------------------+
-|           | f_restricted      | 0 or 1 if frame is in     |
-|           |                   | restricted execution mode |
-+-----------+-------------------+---------------------------+
 |           | f_trace           | tracing function for this |
 |           |                   | frame, or ``None``        |
 +-----------+-------------------+---------------------------+
index 28aac92..981c385 100644 (file)
@@ -31,7 +31,7 @@ be used for each of them.  A concrete object belonging to any of these
 categories is called a :term:`file object`.  Other common terms are *stream*
 and *file-like object*.
 
-Independently of its category, each concrete stream object will also have
+Independent of its category, each concrete stream object will also have
 various capabilities: it can be read-only, write-only, or read-write. It can
 also allow arbitrary random access (seeking forwards or backwards to any
 location), or only sequential access (for example in the case of a socket or
index aa9da91..98ca86e 100644 (file)
@@ -652,7 +652,9 @@ when serializing Python :class:`int` values of extremely large magnitude, or
 when serializing instances of "exotic" numerical types such as
 :class:`decimal.Decimal`.
 
+
 .. _json-commandline:
+.. program:: json.tool
 
 Command Line Interface
 ----------------------
@@ -684,6 +686,7 @@ specified, :attr:`sys.stdin` and :attr:`sys.stdout` will be used respectively:
    :option:`--sort-keys` option to sort the output of dictionaries
    alphabetically by key.
 
+
 Command line options
 ^^^^^^^^^^^^^^^^^^^^
 
index 9a0c570..2addc0e 100644 (file)
@@ -148,10 +148,8 @@ The :mod:`locale` module defines the following exception and functions:
    +--------------+-----------------------------------------+
 
    The function sets temporarily the ``LC_CTYPE`` locale to the ``LC_NUMERIC``
-   locale to decode ``decimal_point`` and ``thousands_sep`` byte strings if
-   they are non-ASCII or longer than 1 byte, and the ``LC_NUMERIC`` locale is
-   different than the ``LC_CTYPE`` locale. This temporary change affects other
-   threads.
+   locale or the ``LC_MONETARY`` locale if locales are different and numeric or
+   monetary strings are non-ASCII. This temporary change affects other threads.
 
    .. versionchanged:: 3.6.5
       The function now sets temporarily the ``LC_CTYPE`` locale to the
index 590d556..df74688 100644 (file)
@@ -882,7 +882,7 @@ re-entrant, and so cannot be invoked from such signal handlers.
 Module-Level Functions
 ----------------------
 
-In addition to the classes described above, there are a number of module- level
+In addition to the classes described above, there are a number of module-level
 functions.
 
 
@@ -931,8 +931,8 @@ functions.
    There are three keyword arguments in *kwargs* which are inspected: *exc_info*
    which, if it does not evaluate as false, causes exception information to be
    added to the logging message. If an exception tuple (in the format returned by
-   :func:`sys.exc_info`) is provided, it is used; otherwise, :func:`sys.exc_info`
-   is called to get the exception information.
+   :func:`sys.exc_info`) or an exception instance is provided, it is used;
+   otherwise, :func:`sys.exc_info` is called to get the exception information.
 
    The second optional keyword argument is *stack_info*, which defaults to
    ``False``. If true, stack information is added to the logging
index d965fa3..6c0f9a0 100644 (file)
@@ -61,7 +61,7 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
 
    *offset* may be specified as a non-negative integer offset. mmap references
    will be relative to the offset from the beginning of the file. *offset*
-   defaults to 0.  *offset* must be a multiple of the ALLOCATIONGRANULARITY.
+   defaults to 0.  *offset* must be a multiple of the :const:`ALLOCATIONGRANULARITY`.
 
 
 .. class:: mmap(fileno, length, flags=MAP_SHARED, prot=PROT_WRITE|PROT_READ, access=ACCESS_DEFAULT[, offset])
@@ -90,8 +90,8 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
 
    *offset* may be specified as a non-negative integer offset. mmap references
    will be relative to the offset from the beginning of the file. *offset*
-   defaults to 0.  *offset* must be a multiple of the PAGESIZE or
-   ALLOCATIONGRANULARITY.
+   defaults to 0. *offset* must be a multiple of :const:`ALLOCATIONGRANULARITY`
+   which is equal to :const:`PAGESIZE` on Unix systems.
 
    To ensure validity of the created memory mapping the file specified
    by the descriptor *fileno* is internally automatically synchronized
@@ -185,7 +185,8 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
       use of this call there is no guarantee that changes are written back before
       the object is destroyed.  If *offset* and *size* are specified, only
       changes to the given range of bytes will be flushed to disk; otherwise, the
-      whole extent of the mapping is flushed.
+      whole extent of the mapping is flushed.  *offset* must be a multiple of the
+      :const:`PAGESIZE` or :const:`ALLOCATIONGRANULARITY`.
 
       **(Windows version)** A nonzero value returned indicates success; zero
       indicates failure.
index e9b82ee..3afc77b 100644 (file)
@@ -379,8 +379,8 @@ types is covered in section :ref:`optparse-extending-optparse`.
 Handling boolean (flag) options
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Flag options---set a variable to true or false when a particular option is seen
----are quite common.  :mod:`optparse` supports them with two separate actions,
+Flag options---set a variable to true or false when a particular option is
+seen---are quite common.  :mod:`optparse` supports them with two separate actions,
 ``store_true`` and ``store_false``.  For example, you might have a ``verbose``
 flag that is turned on with ``-v`` and off with ``-q``::
 
@@ -388,8 +388,8 @@ flag that is turned on with ``-v`` and off with ``-q``::
    parser.add_option("-q", action="store_false", dest="verbose")
 
 Here we have two different options with the same destination, which is perfectly
-OK.  (It just means you have to be a bit careful when setting default values---
-see below.)
+OK.  (It just means you have to be a bit careful when setting default
+values---see below.)
 
 When :mod:`optparse` encounters ``-v`` on the command line, it sets
 ``options.verbose`` to ``True``; when it encounters ``-q``,
@@ -525,9 +525,9 @@ help message:
   default: ``"Usage: %prog [options]"``, which is fine if your script doesn't
   take any positional arguments.
 
-* every option defines a help string, and doesn't worry about line-wrapping---
-  :mod:`optparse` takes care of wrapping lines and making the help output look
-  good.
+* every option defines a help string, and doesn't worry about
+  line-wrapping---\ :mod:`optparse` takes care of wrapping lines and making
+  the help output look good.
 
 * options that take a value indicate this fact in their automatically-generated
   help message, e.g. for the "mode" option::
index 06493f9..9b655d7 100644 (file)
@@ -152,6 +152,8 @@ the :mod:`glob` module.)
       Accepts a :term:`path-like object`.
 
 
+.. index:: single: ~ (tilde); home directory expansion
+
 .. function:: expanduser(path)
 
    On Unix and Windows, return the argument with an initial component of ``~`` or
@@ -175,6 +177,9 @@ the :mod:`glob` module.)
    .. versionchanged:: 3.6
       Accepts a :term:`path-like object`.
 
+.. index::
+   single: $ (dollar); environment variables expansion
+   single: % (percent); environment variables expansion (Windows)
 
 .. function:: expandvars(path)
 
index e9ee514..a36164e 100644 (file)
@@ -2586,7 +2586,7 @@ features:
    morph to the target dynamically.  If the target is present, the type of the
    symlink will be created to match. Otherwise, the symlink will be created
    as a directory if *target_is_directory* is ``True`` or a file symlink (the
-   default) otherwise.  On non-Window platforms, *target_is_directory* is ignored.
+   default) otherwise.  On non-Windows platforms, *target_is_directory* is ignored.
 
    Symbolic link support was introduced in Windows 6.0 (Vista).  :func:`symlink`
    will raise a :exc:`NotImplementedError` on Windows versions earlier than 6.0.
@@ -3557,11 +3557,11 @@ written in Python, such as a mail server's external command delivery program.
 .. function:: wait3(options)
 
    Similar to :func:`waitpid`, except no process id argument is given and a
-   3-element tuple containing the child's process id, exit status indication, and
-   resource usage information is returned.  Refer to :mod:`resource`.\
-   :func:`~resource.getrusage` for details on resource usage information.  The
-   option argument is the same as that provided to :func:`waitpid` and
-   :func:`wait4`.
+   3-element tuple containing the child's process id, exit status indication,
+   and resource usage information is returned.  Refer to
+   :mod:`resource`.\ :func:`~resource.getrusage` for details on resource usage
+   information.  The option argument is the same as that provided to
+   :func:`waitpid` and :func:`wait4`.
 
    Availability: Unix.
 
@@ -3867,6 +3867,7 @@ are defined for all platforms.
 Higher-level operations on pathnames are defined in the :mod:`os.path` module.
 
 
+.. index:: single: . (dot); in pathnames
 .. data:: curdir
 
    The constant string used by the operating system to refer to the current
@@ -3874,6 +3875,7 @@ Higher-level operations on pathnames are defined in the :mod:`os.path` module.
    :mod:`os.path`.
 
 
+.. index:: single: ..; in pathnames
 .. data:: pardir
 
    The constant string used by the operating system to refer to the parent
@@ -3881,6 +3883,8 @@ Higher-level operations on pathnames are defined in the :mod:`os.path` module.
    :mod:`os.path`.
 
 
+.. index:: single: / (slash); in pathnames
+.. index:: single: \ (backslash); in pathnames (Windows)
 .. data:: sep
 
    The character used by the operating system to separate pathname components.
@@ -3890,6 +3894,7 @@ Higher-level operations on pathnames are defined in the :mod:`os.path` module.
    useful. Also available via :mod:`os.path`.
 
 
+.. index:: single: / (slash); in pathnames
 .. data:: altsep
 
    An alternative character used by the operating system to separate pathname
@@ -3898,12 +3903,15 @@ Higher-level operations on pathnames are defined in the :mod:`os.path` module.
    :mod:`os.path`.
 
 
+.. index:: single: . (dot); in pathnames
 .. data:: extsep
 
    The character which separates the base filename from the extension; for example,
    the ``'.'`` in :file:`os.py`. Also available via :mod:`os.path`.
 
 
+.. index:: single: : (colon); path separator (POSIX)
+   single: ; (semicolon)
 .. data:: pathsep
 
    The character conventionally used by the operating system to separate search
index 522bb7e..a7d3dac 100644 (file)
@@ -153,8 +153,7 @@ and (read-only) attributes:
    number of bytes written.  If the audio device is in blocking mode (the
    default), the entire data is always written (again, this is different from
    usual Unix device semantics).  If the device is in non-blocking mode, some
-   data may not be written
-   ---see :meth:`writeall`.
+   data may not be written---see :meth:`writeall`.
 
    .. versionchanged:: 3.5
       Writable :term:`bytes-like object` is now accepted.
index 2b10ee2..52cbb62 100644 (file)
@@ -235,6 +235,9 @@ process more convenient:
    *errors* tell pickle how to decode 8-bit string instances pickled by Python
    2; these default to 'ASCII' and 'strict', respectively.  The *encoding* can
    be 'bytes' to read these 8-bit string instances as bytes objects.
+   Using ``encoding='latin1'`` is required for unpickling NumPy arrays and
+   instances of :class:`~datetime.datetime`, :class:`~datetime.date` and
+   :class:`~datetime.time` pickled by Python 2.
 
 .. function:: loads(bytes_object, \*, fix_imports=True, encoding="ASCII", errors="strict")
 
@@ -252,6 +255,9 @@ process more convenient:
    *errors* tell pickle how to decode 8-bit string instances pickled by Python
    2; these default to 'ASCII' and 'strict', respectively.  The *encoding* can
    be 'bytes' to read these 8-bit string instances as bytes objects.
+   Using ``encoding='latin1'`` is required for unpickling NumPy arrays and
+   instances of :class:`~datetime.datetime`, :class:`~datetime.date` and
+   :class:`~datetime.time` pickled by Python 2.
 
 
 The :mod:`pickle` module defines three exceptions:
index aa97d3e..deadf18 100644 (file)
@@ -30,6 +30,8 @@ The :mod:`pprint` module defines one class:
 .. First the implementation class:
 
 
+.. index:: single: ...; placeholder
+
 .. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, \
                          compact=False)
 
@@ -217,135 +219,156 @@ let's fetch information about a project from `PyPI <https://pypi.org>`_::
    >>> import json
    >>> import pprint
    >>> from urllib.request import urlopen
-   >>> with urlopen('http://pypi.org/project/Twisted/json') as url:
-   ...     http_info = url.info()
-   ...     raw_data = url.read().decode(http_info.get_content_charset())
-   >>> project_info = json.loads(raw_data)
+   >>> with urlopen('https://pypi.org/pypi/sampleproject/json') as resp:
+   ...     project_info = json.load(resp)['info']
 
 In its basic form, :func:`pprint` shows the whole object::
 
    >>> pprint.pprint(project_info)
-   {'info': {'_pypi_hidden': False,
-             '_pypi_ordering': 125,
-             'author': 'Glyph Lefkowitz',
-             'author_email': 'glyph@twistedmatrix.com',
-             'bugtrack_url': '',
-             'cheesecake_code_kwalitee_id': None,
-             'cheesecake_documentation_id': None,
-             'cheesecake_installability_id': None,
-             'classifiers': ['Programming Language :: Python :: 2.6',
-                             'Programming Language :: Python :: 2.7',
-                             'Programming Language :: Python :: 2 :: Only'],
-             'description': 'An extensible framework for Python programming, with '
-                            'special focus\r\n'
-                            'on event-based network programming and multiprotocol '
-                            'integration.',
-             'docs_url': '',
-             'download_url': 'UNKNOWN',
-             'home_page': 'http://twistedmatrix.com/',
-             'keywords': '',
-             'license': 'MIT',
-             'maintainer': '',
-             'maintainer_email': '',
-             'name': 'Twisted',
-             'package_url': 'http://pypi.org/project/Twisted',
-             'platform': 'UNKNOWN',
-             'release_url': 'http://pypi.org/project/Twisted/12.3.0',
-             'requires_python': None,
-             'stable_version': None,
-             'summary': 'An asynchronous networking framework written in Python',
-             'version': '12.3.0'},
-    'urls': [{'comment_text': '',
-              'downloads': 71844,
-              'filename': 'Twisted-12.3.0.tar.bz2',
-              'has_sig': False,
-              'md5_digest': '6e289825f3bf5591cfd670874cc0862d',
-              'packagetype': 'sdist',
-              'python_version': 'source',
-              'size': 2615733,
-              'upload_time': '2012-12-26T12:47:03',
-              'url': 'https://pypi.org/packages/source/T/Twisted/Twisted-12.3.0.tar.bz2'},
-             {'comment_text': '',
-              'downloads': 5224,
-              'filename': 'Twisted-12.3.0.win32-py2.7.msi',
-              'has_sig': False,
-              'md5_digest': '6b778f5201b622a5519a2aca1a2fe512',
-              'packagetype': 'bdist_msi',
-              'python_version': '2.7',
-              'size': 2916352,
-              'upload_time': '2012-12-26T12:48:15',
-              'url': 'https://pypi.org/packages/2.7/T/Twisted/Twisted-12.3.0.win32-py2.7.msi'}]}
+   {'author': 'The Python Packaging Authority',
+    'author_email': 'pypa-dev@googlegroups.com',
+    'bugtrack_url': None,
+    'classifiers': ['Development Status :: 3 - Alpha',
+                    'Intended Audience :: Developers',
+                    'License :: OSI Approved :: MIT License',
+                    'Programming Language :: Python :: 2',
+                    'Programming Language :: Python :: 2.6',
+                    'Programming Language :: Python :: 2.7',
+                    'Programming Language :: Python :: 3',
+                    'Programming Language :: Python :: 3.2',
+                    'Programming Language :: Python :: 3.3',
+                    'Programming Language :: Python :: 3.4',
+                    'Topic :: Software Development :: Build Tools'],
+    'description': 'A sample Python project\n'
+                   '=======================\n'
+                   '\n'
+                   'This is the description file for the project.\n'
+                   '\n'
+                   'The file should use UTF-8 encoding and be written using '
+                   'ReStructured Text. It\n'
+                   'will be used to generate the project webpage on PyPI, and '
+                   'should be written for\n'
+                   'that purpose.\n'
+                   '\n'
+                   'Typical contents for this file would include an overview of '
+                   'the project, basic\n'
+                   'usage examples, etc. Generally, including the project '
+                   'changelog in here is not\n'
+                   'a good idea, although a simple "What\'s New" section for the '
+                   'most recent version\n'
+                   'may be appropriate.',
+    'description_content_type': None,
+    'docs_url': None,
+    'download_url': 'UNKNOWN',
+    'downloads': {'last_day': -1, 'last_month': -1, 'last_week': -1},
+    'home_page': 'https://github.com/pypa/sampleproject',
+    'keywords': 'sample setuptools development',
+    'license': 'MIT',
+    'maintainer': None,
+    'maintainer_email': None,
+    'name': 'sampleproject',
+    'package_url': 'https://pypi.org/project/sampleproject/',
+    'platform': 'UNKNOWN',
+    'project_url': 'https://pypi.org/project/sampleproject/',
+    'project_urls': {'Download': 'UNKNOWN',
+                     'Homepage': 'https://github.com/pypa/sampleproject'},
+    'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
+    'requires_dist': None,
+    'requires_python': None,
+    'summary': 'A sample Python project',
+    'version': '1.2.0'}
 
 The result can be limited to a certain *depth* (ellipsis is used for deeper
 contents)::
 
-   >>> pprint.pprint(project_info, depth=2)
-   {'info': {'_pypi_hidden': False,
-             '_pypi_ordering': 125,
-             'author': 'Glyph Lefkowitz',
-             'author_email': 'glyph@twistedmatrix.com',
-             'bugtrack_url': '',
-             'cheesecake_code_kwalitee_id': None,
-             'cheesecake_documentation_id': None,
-             'cheesecake_installability_id': None,
-             'classifiers': [...],
-             'description': 'An extensible framework for Python programming, with '
-                            'special focus\r\n'
-                            'on event-based network programming and multiprotocol '
-                            'integration.',
-             'docs_url': '',
-             'download_url': 'UNKNOWN',
-             'home_page': 'http://twistedmatrix.com/',
-             'keywords': '',
-             'license': 'MIT',
-             'maintainer': '',
-             'maintainer_email': '',
-             'name': 'Twisted',
-             'package_url': 'http://pypi.org/project/Twisted',
-             'platform': 'UNKNOWN',
-             'release_url': 'http://pypi.org/project/Twisted/12.3.0',
-             'requires_python': None,
-             'stable_version': None,
-             'summary': 'An asynchronous networking framework written in Python',
-             'version': '12.3.0'},
-    'urls': [{...}, {...}]}
+   >>> pprint.pprint(project_info, depth=1)
+   {'author': 'The Python Packaging Authority',
+    'author_email': 'pypa-dev@googlegroups.com',
+    'bugtrack_url': None,
+    'classifiers': [...],
+    'description': 'A sample Python project\n'
+                   '=======================\n'
+                   '\n'
+                   'This is the description file for the project.\n'
+                   '\n'
+                   'The file should use UTF-8 encoding and be written using '
+                   'ReStructured Text. It\n'
+                   'will be used to generate the project webpage on PyPI, and '
+                   'should be written for\n'
+                   'that purpose.\n'
+                   '\n'
+                   'Typical contents for this file would include an overview of '
+                   'the project, basic\n'
+                   'usage examples, etc. Generally, including the project '
+                   'changelog in here is not\n'
+                   'a good idea, although a simple "What\'s New" section for the '
+                   'most recent version\n'
+                   'may be appropriate.',
+    'description_content_type': None,
+    'docs_url': None,
+    'download_url': 'UNKNOWN',
+    'downloads': {...},
+    'home_page': 'https://github.com/pypa/sampleproject',
+    'keywords': 'sample setuptools development',
+    'license': 'MIT',
+    'maintainer': None,
+    'maintainer_email': None,
+    'name': 'sampleproject',
+    'package_url': 'https://pypi.org/project/sampleproject/',
+    'platform': 'UNKNOWN',
+    'project_url': 'https://pypi.org/project/sampleproject/',
+    'project_urls': {...},
+    'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
+    'requires_dist': None,
+    'requires_python': None,
+    'summary': 'A sample Python project',
+    'version': '1.2.0'}
 
 Additionally, maximum character *width* can be suggested. If a long object
 cannot be split, the specified width will be exceeded::
 
-   >>> pprint.pprint(project_info, depth=2, width=50)
-   {'info': {'_pypi_hidden': False,
-             '_pypi_ordering': 125,
-             'author': 'Glyph Lefkowitz',
-             'author_email': 'glyph@twistedmatrix.com',
-             'bugtrack_url': '',
-             'cheesecake_code_kwalitee_id': None,
-             'cheesecake_documentation_id': None,
-             'cheesecake_installability_id': None,
-             'classifiers': [...],
-             'description': 'An extensible '
-                            'framework for Python '
-                            'programming, with '
-                            'special focus\r\n'
-                            'on event-based network '
-                            'programming and '
-                            'multiprotocol '
-                            'integration.',
-             'docs_url': '',
-             'download_url': 'UNKNOWN',
-             'home_page': 'http://twistedmatrix.com/',
-             'keywords': '',
-             'license': 'MIT',
-             'maintainer': '',
-             'maintainer_email': '',
-             'name': 'Twisted',
-             'package_url': 'http://pypi.org/project/Twisted',
-             'platform': 'UNKNOWN',
-             'release_url': 'http://pypi.org/project/Twisted/12.3.0',
-             'requires_python': None,
-             'stable_version': None,
-             'summary': 'An asynchronous networking '
-                        'framework written in '
-                        'Python',
-             'version': '12.3.0'},
-    'urls': [{...}, {...}]}
+   >>> pprint.pprint(project_info, depth=1, width=60)
+   {'author': 'The Python Packaging Authority',
+    'author_email': 'pypa-dev@googlegroups.com',
+    'bugtrack_url': None,
+    'classifiers': [...],
+    'description': 'A sample Python project\n'
+                   '=======================\n'
+                   '\n'
+                   'This is the description file for the '
+                   'project.\n'
+                   '\n'
+                   'The file should use UTF-8 encoding and be '
+                   'written using ReStructured Text. It\n'
+                   'will be used to generate the project '
+                   'webpage on PyPI, and should be written '
+                   'for\n'
+                   'that purpose.\n'
+                   '\n'
+                   'Typical contents for this file would '
+                   'include an overview of the project, '
+                   'basic\n'
+                   'usage examples, etc. Generally, including '
+                   'the project changelog in here is not\n'
+                   'a good idea, although a simple "What\'s '
+                   'New" section for the most recent version\n'
+                   'may be appropriate.',
+    'description_content_type': None,
+    'docs_url': None,
+    'download_url': 'UNKNOWN',
+    'downloads': {...},
+    'home_page': 'https://github.com/pypa/sampleproject',
+    'keywords': 'sample setuptools development',
+    'license': 'MIT',
+    'maintainer': None,
+    'maintainer_email': None,
+    'name': 'sampleproject',
+    'package_url': 'https://pypi.org/project/sampleproject/',
+    'platform': 'UNKNOWN',
+    'project_url': 'https://pypi.org/project/sampleproject/',
+    'project_urls': {...},
+    'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
+    'requires_dist': None,
+    'requires_python': None,
+    'summary': 'A sample Python project',
+    'version': '1.2.0'}
index 82632b9..89d36a9 100644 (file)
@@ -93,15 +93,21 @@ the expression ``(?:a{6})*`` matches any multiple of six ``'a'`` characters.
 
 The special characters are:
 
+.. index:: single: . (dot); in regular expressions
+
 ``.``
    (Dot.)  In the default mode, this matches any character except a newline.  If
    the :const:`DOTALL` flag has been specified, this matches any character
    including a newline.
 
+.. index:: single: ^ (caret); in regular expressions
+
 ``^``
    (Caret.)  Matches the start of the string, and in :const:`MULTILINE` mode also
    matches immediately after each newline.
 
+.. index:: single: $ (dollar); in regular expressions
+
 ``$``
    Matches the end of the string or just before the newline at the end of the
    string, and in :const:`MULTILINE` mode also matches before a newline.  ``foo``
@@ -111,20 +117,31 @@ The special characters are:
    a single ``$`` in ``'foo\n'`` will find two (empty) matches: one just before
    the newline, and one at the end of the string.
 
+.. index:: single: * (asterisk); in regular expressions
+
 ``*``
    Causes the resulting RE to match 0 or more repetitions of the preceding RE, as
    many repetitions as are possible.  ``ab*`` will match 'a', 'ab', or 'a' followed
    by any number of 'b's.
 
+.. index:: single: + (plus); in regular expressions
+
 ``+``
    Causes the resulting RE to match 1 or more repetitions of the preceding RE.
    ``ab+`` will match 'a' followed by any non-zero number of 'b's; it will not
    match just 'a'.
 
+.. index:: single: ? (question mark); in regular expressions
+
 ``?``
    Causes the resulting RE to match 0 or 1 repetitions of the preceding RE.
    ``ab?`` will match either 'a' or 'ab'.
 
+.. index::
+   single: *?; in regular expressions
+   single: +?; in regular expressions
+   single: ??; in regular expressions
+
 ``*?``, ``+?``, ``??``
    The ``'*'``, ``'+'``, and ``'?'`` qualifiers are all :dfn:`greedy`; they match
    as much text as possible.  Sometimes this behaviour isn't desired; if the RE
@@ -134,6 +151,9 @@ The special characters are:
    characters as possible will be matched.  Using the RE ``<.*?>`` will match
    only ``'<a>'``.
 
+.. index::
+   single: {} (curly brackets); in regular expressions
+
 ``{m}``
    Specifies that exactly *m* copies of the previous RE should be matched; fewer
    matches cause the entire RE not to match.  For example, ``a{6}`` will match
@@ -155,6 +175,8 @@ The special characters are:
    6-character string ``'aaaaaa'``, ``a{3,5}`` will match 5 ``'a'`` characters,
    while ``a{3,5}?`` will only match 3 characters.
 
+.. index:: single: \ (backslash); in regular expressions
+
 ``\``
    Either escapes special characters (permitting you to match characters like
    ``'*'``, ``'?'``, and so forth), or signals a special sequence; special
@@ -168,12 +190,17 @@ The special characters are:
    is complicated and hard to understand, so it's highly recommended that you use
    raw strings for all but the simplest expressions.
 
+.. index::
+   single: [] (square brackets); in regular expressions
+
 ``[]``
    Used to indicate a set of characters.  In a set:
 
    * Characters can be listed individually, e.g. ``[amk]`` will match ``'a'``,
      ``'m'``, or ``'k'``.
 
+   .. index:: single: - (minus); in regular expressions
+
    * Ranges of characters can be indicated by giving two characters and separating
      them by a ``'-'``, for example ``[a-z]`` will match any lowercase ASCII letter,
      ``[0-5][0-9]`` will match all the two-digits numbers from ``00`` to ``59``, and
@@ -185,10 +212,14 @@ The special characters are:
      ``[(+*)]`` will match any of the literal characters ``'('``, ``'+'``,
      ``'*'``, or ``')'``.
 
+   .. index:: single: \ (backslash); in regular expressions
+
    * Character classes such as ``\w`` or ``\S`` (defined below) are also accepted
      inside a set, although the characters they match depends on whether
      :const:`ASCII` or :const:`LOCALE` mode is in force.
 
+   .. index:: single: ^ (caret); in regular expressions
+
    * Characters that are not within a range can be matched by :dfn:`complementing`
      the set.  If the first character of the set is ``'^'``, all the characters
      that are *not* in the set will be matched.  For example, ``[^5]`` will match
@@ -200,6 +231,8 @@ The special characters are:
      place it at the beginning of the set.  For example, both ``[()[\]{}]`` and
      ``[]()[{}]`` will both match a parenthesis.
 
+.. index:: single: | (vertical bar); in regular expressions
+
 ``|``
    ``A|B``, where *A* and *B* can be arbitrary REs, creates a regular expression that
    will match either *A* or *B*.  An arbitrary number of REs can be separated by the
@@ -211,6 +244,9 @@ The special characters are:
    greedy.  To match a literal ``'|'``, use ``\|``, or enclose it inside a
    character class, as in ``[|]``.
 
+.. index::
+   single: () (parentheses); in regular expressions
+
 ``(...)``
    Matches whatever regular expression is inside the parentheses, and indicates the
    start and end of a group; the contents of a group can be retrieved after a match
@@ -218,6 +254,8 @@ The special characters are:
    special sequence, described below.  To match the literals ``'('`` or ``')'``,
    use ``\(`` or ``\)``, or enclose them inside a character class: ``[(]``, ``[)]``.
 
+.. index:: single: (?; in regular expressions
+
 ``(?...)``
    This is an extension notation (a ``'?'`` following a ``'('`` is not meaningful
    otherwise).  The first character after the ``'?'`` determines what the meaning
@@ -239,6 +277,8 @@ The special characters are:
    :func:`re.compile` function.  Flags should be used first in the
    expression string.
 
+.. index:: single: (?:; in regular expressions
+
 ``(?:...)``
    A non-capturing version of regular parentheses.  Matches whatever regular
    expression is inside the parentheses, but the substring matched by the group
@@ -255,6 +295,8 @@ The special characters are:
 
    .. versionadded:: 3.6
 
+.. index:: single: (?P<; in regular expressions
+
 ``(?P<name>...)``
    Similar to regular parentheses, but the substring matched by the group is
    accessible via the symbolic group name *name*.  Group names must be valid
@@ -280,10 +322,14 @@ The special characters are:
    |                                       | * ``\1``                         |
    +---------------------------------------+----------------------------------+
 
+.. index:: single: (?P=; in regular expressions
+
 ``(?P=name)``
    A backreference to a named group; it matches whatever text was matched by the
    earlier group named *name*.
 
+.. index:: single: (?#; in regular expressions
+
 ``(?#...)``
    A comment; the contents of the parentheses are simply ignored.
 
@@ -292,11 +338,15 @@ The special characters are:
    called a :dfn:`lookahead assertion`.  For example, ``Isaac (?=Asimov)`` will match
    ``'Isaac '`` only if it's followed by ``'Asimov'``.
 
+.. index:: single: (?!; in regular expressions
+
 ``(?!...)``
    Matches if ``...`` doesn't match next.  This is a :dfn:`negative lookahead assertion`.
    For example, ``Isaac (?!Asimov)`` will match ``'Isaac '`` only if it's *not*
    followed by ``'Asimov'``.
 
+.. index:: single: (?<=; in regular expressions
+
 ``(?<=...)``
    Matches if the current position in the string is preceded by a match for ``...``
    that ends at the current position.  This is called a :dfn:`positive lookbehind
@@ -322,6 +372,8 @@ The special characters are:
    .. versionchanged:: 3.5
       Added support for group references of fixed length.
 
+.. index:: single: (?<!; in regular expressions
+
 ``(?<!...)``
    Matches if the current position in the string is not preceded by a match for
    ``...``.  This is called a :dfn:`negative lookbehind assertion`.  Similar to
@@ -343,6 +395,8 @@ If the ordinary character is not an ASCII digit or an ASCII letter, then the
 resulting RE will match the second character.  For example, ``\$`` matches the
 character ``'$'``.
 
+.. index:: single: \ (backslash); in regular expressions
+
 ``\number``
    Matches the contents of the group of the same number.  Groups are numbered
    starting from 1.  For example, ``(.+) \1`` matches ``'the the'`` or ``'55 55'``,
@@ -353,9 +407,13 @@ character ``'$'``.
    ``'['`` and ``']'`` of a character class, all numeric escapes are treated as
    characters.
 
+.. index:: single: \A; in regular expressions
+
 ``\A``
    Matches only at the start of the string.
 
+.. index:: single: \b; in regular expressions
+
 ``\b``
    Matches the empty string, but only at the beginning or end of a word.
    A word is defined as a sequence of word characters.  Note that formally,
@@ -370,6 +428,8 @@ character ``'$'``.
    Inside a character range, ``\b`` represents the backspace character, for
    compatibility with Python's string literals.
 
+.. index:: single: \B; in regular expressions
+
 ``\B``
    Matches the empty string, but only when it is *not* at the beginning or end
    of a word.  This means that ``r'py\B'`` matches ``'python'``, ``'py3'``,
@@ -379,6 +439,8 @@ character ``'$'``.
    be changed by using the :const:`ASCII` flag.  Word boundaries are
    determined by the current locale if the :const:`LOCALE` flag is used.
 
+.. index:: single: \d; in regular expressions
+
 ``\d``
    For Unicode (str) patterns:
       Matches any Unicode decimal digit (that is, any character in
@@ -391,6 +453,8 @@ character ``'$'``.
    For 8-bit (bytes) patterns:
       Matches any decimal digit; this is equivalent to ``[0-9]``.
 
+.. index:: single: \D; in regular expressions
+
 ``\D``
    Matches any character which is not a decimal digit. This is
    the opposite of ``\d``. If the :const:`ASCII` flag is used this
@@ -398,6 +462,8 @@ character ``'$'``.
    regular expression, so in such cases using an explicit ``[^0-9]`` may
    be a better choice).
 
+.. index:: single: \s; in regular expressions
+
 ``\s``
    For Unicode (str) patterns:
       Matches Unicode whitespace characters (which includes
@@ -412,6 +478,8 @@ character ``'$'``.
       Matches characters considered whitespace in the ASCII character set;
       this is equivalent to ``[ \t\n\r\f\v]``.
 
+.. index:: single: \S; in regular expressions
+
 ``\S``
    Matches any character which is not a whitespace character. This is
    the opposite of ``\s``. If the :const:`ASCII` flag is used this
@@ -419,6 +487,8 @@ character ``'$'``.
    regular expression, so in such cases using an explicit ``[^ \t\n\r\f\v]`` may
    be a better choice).
 
+.. index:: single: \w; in regular expressions
+
 ``\w``
    For Unicode (str) patterns:
       Matches Unicode word characters; this includes most characters
@@ -434,6 +504,8 @@ character ``'$'``.
       used, matches characters considered alphanumeric in the current locale
       and the underscore.
 
+.. index:: single: \W; in regular expressions
+
 ``\W``
    Matches any character which is not a word character. This is
    the opposite of ``\w``. If the :const:`ASCII` flag is used this
@@ -443,9 +515,25 @@ character ``'$'``.
    used, matches characters considered alphanumeric in the current locale
    and the underscore.
 
+.. index:: single: \Z; in regular expressions
+
 ``\Z``
    Matches only at the end of the string.
 
+.. index::
+   single: \a; in regular expressions
+   single: \b; in regular expressions
+   single: \f; in regular expressions
+   single: \n; in regular expressions
+   single: \N; in regular expressions
+   single: \r; in regular expressions
+   single: \t; in regular expressions
+   single: \u; in regular expressions
+   single: \U; in regular expressions
+   single: \v; in regular expressions
+   single: \x; in regular expressions
+   single: \\; in regular expressions
+
 Most of the standard escapes supported by Python string literals are also
 accepted by the regular expression parser::
 
@@ -599,6 +687,8 @@ form.
 .. data:: X
           VERBOSE
 
+   .. index:: single: # (hash); in regular expressions
+
    This flag allows you to write regular expressions that look nicer and are
    more readable by allowing you to visually separate logical sections of the
    pattern and add comments. Whitespace within the pattern is ignored, except
@@ -772,6 +862,8 @@ form.
    when not adjacent to a previous match, so ``sub('x*', '-', 'abc')`` returns
    ``'-a-b-c-'``.
 
+   .. index:: single: \g; in regular expressions
+
    In string-type *repl* arguments, in addition to the character escapes and
    backreferences described above,
    ``\g<name>`` will use the substring matched by the group named ``name``, as
@@ -1489,38 +1581,40 @@ successive matches::
     import collections
     import re
 
-    Token = collections.namedtuple('Token', ['typ', 'value', 'line', 'column'])
+    Token = collections.namedtuple('Token', ['type', 'value', 'line', 'column'])
 
     def tokenize(code):
         keywords = {'IF', 'THEN', 'ENDIF', 'FOR', 'NEXT', 'GOSUB', 'RETURN'}
         token_specification = [
-            ('NUMBER',  r'\d+(\.\d*)?'),  # Integer or decimal number
-            ('ASSIGN',  r':='),           # Assignment operator
-            ('END',     r';'),            # Statement terminator
-            ('ID',      r'[A-Za-z]+'),    # Identifiers
-            ('OP',      r'[+\-*/]'),      # Arithmetic operators
-            ('NEWLINE', r'\n'),           # Line endings
-            ('SKIP',    r'[ \t]+'),       # Skip over spaces and tabs
-            ('MISMATCH',r'.'),            # Any other character
+            ('NUMBER',   r'\d+(\.\d*)?'),  # Integer or decimal number
+            ('ASSIGN',   r':='),           # Assignment operator
+            ('END',      r';'),            # Statement terminator
+            ('ID',       r'[A-Za-z]+'),    # Identifiers
+            ('OP',       r'[+\-*/]'),      # Arithmetic operators
+            ('NEWLINE',  r'\n'),           # Line endings
+            ('SKIP',     r'[ \t]+'),       # Skip over spaces and tabs
+            ('MISMATCH', r'.'),            # Any other character
         ]
         tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification)
         line_num = 1
         line_start = 0
         for mo in re.finditer(tok_regex, code):
             kind = mo.lastgroup
-            value = mo.group(kind)
-            if kind == 'NEWLINE':
+            value = mo.group()
+            column = mo.start() - line_start
+            if kind == 'NUMBER':
+                value = float(value) if '.' in value else int(value)
+            elif kind == 'ID' and value in keywords:
+                kind = value
+            elif kind == 'NEWLINE':
                 line_start = mo.end()
                 line_num += 1
+                continue
             elif kind == 'SKIP':
-                pass
+                continue
             elif kind == 'MISMATCH':
                 raise RuntimeError(f'{value!r} unexpected on line {line_num}')
-            else:
-                if kind == 'ID' and value in keywords:
-                    kind = value
-                column = mo.start() - line_start
-                yield Token(kind, value, line_num, column)
+            yield Token(kind, value, line_num, column)
 
     statements = '''
         IF quantity THEN
@@ -1534,25 +1628,25 @@ successive matches::
 
 The tokenizer produces the following output::
 
-    Token(typ='IF', value='IF', line=2, column=4)
-    Token(typ='ID', value='quantity', line=2, column=7)
-    Token(typ='THEN', value='THEN', line=2, column=16)
-    Token(typ='ID', value='total', line=3, column=8)
-    Token(typ='ASSIGN', value=':=', line=3, column=14)
-    Token(typ='ID', value='total', line=3, column=17)
-    Token(typ='OP', value='+', line=3, column=23)
-    Token(typ='ID', value='price', line=3, column=25)
-    Token(typ='OP', value='*', line=3, column=31)
-    Token(typ='ID', value='quantity', line=3, column=33)
-    Token(typ='END', value=';', line=3, column=41)
-    Token(typ='ID', value='tax', line=4, column=8)
-    Token(typ='ASSIGN', value=':=', line=4, column=12)
-    Token(typ='ID', value='price', line=4, column=15)
-    Token(typ='OP', value='*', line=4, column=21)
-    Token(typ='NUMBER', value='0.05', line=4, column=23)
-    Token(typ='END', value=';', line=4, column=27)
-    Token(typ='ENDIF', value='ENDIF', line=5, column=4)
-    Token(typ='END', value=';', line=5, column=9)
+    Token(type='IF', value='IF', line=2, column=4)
+    Token(type='ID', value='quantity', line=2, column=7)
+    Token(type='THEN', value='THEN', line=2, column=16)
+    Token(type='ID', value='total', line=3, column=8)
+    Token(type='ASSIGN', value=':=', line=3, column=14)
+    Token(type='ID', value='total', line=3, column=17)
+    Token(type='OP', value='+', line=3, column=23)
+    Token(type='ID', value='price', line=3, column=25)
+    Token(type='OP', value='*', line=3, column=31)
+    Token(type='ID', value='quantity', line=3, column=33)
+    Token(type='END', value=';', line=3, column=41)
+    Token(type='ID', value='tax', line=4, column=8)
+    Token(type='ASSIGN', value=':=', line=4, column=12)
+    Token(type='ID', value='price', line=4, column=15)
+    Token(type='OP', value='*', line=4, column=21)
+    Token(type='NUMBER', value=0.05, line=4, column=23)
+    Token(type='END', value=';', line=4, column=27)
+    Token(type='ENDIF', value='ENDIF', line=5, column=4)
+    Token(type='END', value=';', line=5, column=9)
 
 
 .. [Frie09] Friedl, Jeffrey. Mastering Regular Expressions. 3rd ed., O'Reilly
index 0905b98..dbe2a71 100644 (file)
@@ -42,6 +42,9 @@ In addition to size-limiting tools, the module also provides a decorator for
 detecting recursive calls to :meth:`__repr__` and substituting a placeholder
 string instead.
 
+
+.. index:: single: ...; placeholder
+
 .. decorator:: recursive_repr(fillvalue="...")
 
    Decorator for :meth:`__repr__` methods to detect recursive calls within the
index 3d8cb03..c3f7bd6 100644 (file)
@@ -166,7 +166,7 @@ Directory and files operations
 .. function:: copy2(src, dst, *, follow_symlinks=True)
 
    Identical to :func:`~shutil.copy` except that :func:`copy2`
-   also attempts to preserve all file metadata.
+   also attempts to preserve file metadata.
 
    When *follow_symlinks* is false, and *src* is a symbolic
    link, :func:`copy2` attempts to copy all metadata from the
index dabb4fe..e1f4a4b 100644 (file)
@@ -49,6 +49,10 @@ the key "include-system-site-packages" set to anything other than "false"
 (case-insensitive), the system-level prefixes will still also be
 searched for site-packages; otherwise they won't.
 
+.. index::
+   single: # (hash); comment
+   statement: import
+
 A path configuration file is a file whose name has the form :file:`{name}.pth`
 and exists in one of the four directories mentioned above; its contents are
 additional items (one per line) to be added to ``sys.path``.  Non-existing items
index 6fb0934..f59c184 100644 (file)
@@ -41,7 +41,7 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions).
    the OS default behavior will be used.
 
    For normal use, you should only require the initialization/connect,
-   :meth:`sendmail`, and :meth:`~smtplib.quit` methods.
+   :meth:`sendmail`, and :meth:`SMTP.quit` methods.
    An example is included below.
 
    The :class:`SMTP` class supports the :keyword:`with` statement.  When used
index a904804..f426a9c 100644 (file)
@@ -534,6 +534,9 @@ Cursor Objects
 
    A :class:`Cursor` instance has the following attributes and methods.
 
+   .. index:: single: ? (question mark); in SQL statements
+   .. index:: single: : (colon); in SQL statements
+
    .. method:: execute(sql[, parameters])
 
       Executes an SQL statement. The SQL statement may be parameterized (i. e.
index b256312..c8f6904 100644 (file)
@@ -81,9 +81,9 @@ mode:
 
 .. function:: S_IMODE(mode)
 
-   Return the portion of the file's mode that can be set by :func:`os.chmod`\
-   ---that is, the file's permission bits, plus the sticky bit, set-group-id, and
-   set-user-id bits (on systems that support them).
+   Return the portion of the file's mode that can be set by
+   :func:`os.chmod`\ ---that is, the file's permission bits, plus the sticky
+   bit, set-group-id, and set-user-id bits (on systems that support them).
 
 
 .. function:: S_IFMT(mode)
index 6de7e1a..00e1f4c 100644 (file)
@@ -123,9 +123,9 @@ Comparisons
    pair: chaining; comparisons
    pair: operator; comparison
    operator: ==
-   operator: <
+   operator: < (less)
    operator: <=
-   operator: >
+   operator: > (greater)
    operator: >=
    operator: !=
    operator: is
@@ -248,12 +248,16 @@ and imaginary parts.
    builtin: int
    builtin: float
    builtin: complex
-   operator: +
-   operator: -
-   operator: *
-   operator: /
+   single: operator; + (plus)
+   single: + (plus); unary operator
+   single: + (plus); binary operator
+   single: operator; - (minus)
+   single: - (minus); unary operator
+   single: - (minus); binary operator
+   operator: * (asterisk)
+   operator: / (slash)
    operator: //
-   operator: %
+   operator: % (percent)
    operator: **
 
 Python fully supports mixed arithmetic: when a binary arithmetic operator has
@@ -389,12 +393,12 @@ Bitwise Operations on Integer Types
    pair: bitwise; operations
    pair: shifting; operations
    pair: masking; operations
-   operator: |
-   operator: ^
-   operator: &
+   operator: | (vertical bar)
+   operator: ^ (caret)
+   operator: & (ampersand)
    operator: <<
    operator: >>
-   operator: ~
+   operator: ~ (tilde)
 
 Bitwise operations only make sense for integers. The result of bitwise
 operations is calculated as though carried out in two's complement with an
@@ -441,7 +445,7 @@ Notes:
 (4)
    Performing these calculations with at least one extra sign extension bit in
    a finite two's complement representation (a working bit-width of
-   ``1 + max(x.bit_length(), y.bit_length()`` or more) is sufficient to get the
+   ``1 + max(x.bit_length(), y.bit_length())`` or more) is sufficient to get the
    same result as if there were an infinite number of sign bits.
 
 
@@ -2087,8 +2091,7 @@ expression support in the :mod:`re` module).
    single: string; interpolation, printf
    single: printf-style formatting
    single: sprintf-style formatting
-   single: % formatting
-   single: % interpolation
+   single: % (percent); printf-style formatting
 
 .. note::
 
@@ -2110,6 +2113,11 @@ object. [5]_  Otherwise, *values* must be a tuple with exactly the number of
 items specified by the format string, or a single mapping object (for example, a
 dictionary).
 
+.. index::
+   single: () (parentheses); in printf-style formatting
+   single: * (asterisk); in printf-style formatting
+   single: . (dot); in printf-style formatting
+
 A conversion specifier contains two or more characters and has the following
 components, which must occur in this order:
 
@@ -2148,6 +2156,12 @@ sequential parameter list).
 
 The conversion flag characters are:
 
+.. index::
+   single: # (hash); in printf-style formatting
+   single: - (minus); in printf-style formatting
+   single: + (plus); in printf-style formatting
+   single: space; in printf-style formatting
+
 +---------+---------------------------------------------------------------------+
 | Flag    | Meaning                                                             |
 +=========+=====================================================================+
@@ -3159,7 +3173,7 @@ place, and instead produce new objects.
 
    Return a copy of the sequence left filled with ASCII ``b'0'`` digits to
    make a sequence of length *width*. A leading sign prefix (``b'+'``/
-   ``b'-'`` is handled by inserting the padding *after* the sign character
+   ``b'-'``) is handled by inserting the padding *after* the sign character
    rather than before. For :class:`bytes` objects, the original sequence is
    returned if *width* is less than or equal to ``len(seq)``.
 
@@ -3182,18 +3196,17 @@ place, and instead produce new objects.
 ----------------------------------
 
 .. index::
-   single: formatting, bytes (%)
-   single: formatting, bytearray (%)
-   single: interpolation, bytes (%)
-   single: interpolation, bytearray (%)
+   single: formatting; bytes (%)
+   single: formatting; bytearray (%)
+   single: interpolation; bytes (%)
+   single: interpolation; bytearray (%)
    single: bytes; formatting
    single: bytearray; formatting
    single: bytes; interpolation
    single: bytearray; interpolation
    single: printf-style formatting
    single: sprintf-style formatting
-   single: % formatting
-   single: % interpolation
+   single: % (percent); printf-style formatting
 
 .. note::
 
@@ -3214,6 +3227,11 @@ object. [5]_  Otherwise, *values* must be a tuple with exactly the number of
 items specified by the format bytes object, or a single mapping object (for
 example, a dictionary).
 
+.. index::
+   single: () (parentheses); in printf-style formatting
+   single: * (asterisk); in printf-style formatting
+   single: . (dot); in printf-style formatting
+
 A conversion specifier contains two or more characters and has the following
 components, which must occur in this order:
 
@@ -3252,6 +3270,12 @@ sequential parameter list).
 
 The conversion flag characters are:
 
+.. index::
+   single: # (hash); in printf-style formatting
+   single: - (minus); in printf-style formatting
+   single: + (plus); in printf-style formatting
+   single: space; in printf-style formatting
+
 +---------+---------------------------------------------------------------------+
 | Flag    | Meaning                                                             |
 +=========+=====================================================================+
@@ -3715,7 +3739,7 @@ copying.
 
       ``nbytes == product(shape) * itemsize == len(m.tobytes())``. This is
       the amount of space in bytes that the array would use in a contiguous
-      representation. It is not necessarily equal to len(m)::
+      representation. It is not necessarily equal to ``len(m)``::
 
          >>> import array
          >>> a = array.array('i', [1,2,3,4,5])
@@ -4527,6 +4551,7 @@ supports no special operations.  There is exactly one null object, named
 It is written as ``None``.
 
 
+.. index:: single: ...; ellipsis literal
 .. _bltin-ellipsis-object:
 
 The Ellipsis Object
index a87d285..f5c2291 100644 (file)
@@ -192,6 +192,13 @@ subclasses can define their own format string syntax).  The syntax is
 related to that of :ref:`formatted string literals <f-strings>`, but
 there are differences.
 
+.. index::
+   single: {} (curly brackets); in string formatting
+   single: . (dot); in string formatting
+   single: [] (square brackets); in string formatting
+   single: ! (exclamation); in string formatting
+   single: : (colon); in string formatting
+
 Format strings contain "replacement fields" surrounded by curly braces ``{}``.
 Anything that is not contained in braces is considered literal text, which is
 copied unchanged to the output.  If you need to include a brace character in the
@@ -323,6 +330,12 @@ affect the :func:`format` function.
 
 The meaning of the various alignment options is as follows:
 
+   .. index::
+      single: < (less); in string formatting
+      single: > (greater); in string formatting
+      single: = (equals); in string formatting
+      single: ^ (caret); in string formatting
+
    +---------+----------------------------------------------------------+
    | Option  | Meaning                                                  |
    +=========+==========================================================+
@@ -349,6 +362,11 @@ meaning in this case.
 The *sign* option is only valid for number types, and can be one of the
 following:
 
+   .. index::
+      single: + (plus); in string formatting
+      single: - (minus); in string formatting
+      single: space; in string formatting
+
    +---------+----------------------------------------------------------+
    | Option  | Meaning                                                  |
    +=========+==========================================================+
@@ -363,6 +381,8 @@ following:
    +---------+----------------------------------------------------------+
 
 
+.. index:: single: # (hash); in string formatting
+
 The ``'#'`` option causes the "alternate form" to be used for the
 conversion.  The alternate form is defined differently for different
 types.  This option is only valid for integer, float, complex and
@@ -375,6 +395,8 @@ decimal-point character appears in the result of these conversions
 only if a digit follows it. In addition, for ``'g'`` and ``'G'``
 conversions, trailing zeros are not removed from the result.
 
+.. index:: single: , (comma); in string formatting
+
 The ``','`` option signals the use of a comma for a thousands separator.
 For a locale aware separator, use the ``'n'`` integer presentation type
 instead.
@@ -382,6 +404,8 @@ instead.
 .. versionchanged:: 3.1
    Added the ``','`` option (see also :pep:`378`).
 
+.. index:: single: _ (underscore); in string formatting
+
 The ``'_'`` option signals the use of an underscore for a thousands
 separator for floating point presentation types and for integer
 presentation type ``'d'``.  For integer presentation types ``'b'``,
@@ -434,11 +458,11 @@ The available integer presentation types are:
    +---------+----------------------------------------------------------+
    | ``'o'`` | Octal format. Outputs the number in base 8.              |
    +---------+----------------------------------------------------------+
-   | ``'x'`` | Hex format. Outputs the number in base 16, using lower-  |
-   |         | case letters for the digits above 9.                     |
+   | ``'x'`` | Hex format. Outputs the number in base 16, using         |
+   |         | lower-case letters for the digits above 9.               |
    +---------+----------------------------------------------------------+
-   | ``'X'`` | Hex format. Outputs the number in base 16, using upper-  |
-   |         | case letters for the digits above 9.                     |
+   | ``'X'`` | Hex format. Outputs the number in base 16, using         |
+   |         | upper-case letters for the digits above 9.               |
    +---------+----------------------------------------------------------+
    | ``'n'`` | Number. This is the same as ``'d'``, except that it uses |
    |         | the current locale setting to insert the appropriate     |
@@ -527,7 +551,7 @@ addition of the ``{}`` and with ``:`` used instead of ``%``.
 For example, ``'%03.2f'`` can be translated to ``'{:03.2f}'``.
 
 The new format syntax also supports new and different options, shown in the
-follow examples.
+following examples.
 
 Accessing arguments by position::
 
@@ -660,9 +684,17 @@ Nesting arguments and more complex examples::
 Template strings
 ----------------
 
-Templates provide simpler string substitutions as described in :pep:`292`.
-Instead of the normal ``%``\ -based substitutions, Templates support ``$``\
--based substitutions, using the following rules:
+Template strings provide simpler string substitutions as described in
+:pep:`292`.  A primary use case for template strings is for
+internationalization (i18n) since in that context, the simpler syntax and
+functionality makes it easier to translate than other built-in string
+formatting facilities in Python.  As an example of a library built on template
+strings for i18n, see the
+`flufl.i18n <http://flufli18n.readthedocs.io/en/latest/>`_ package.
+
+.. index:: single: $ (dollar); in template strings
+
+Template strings support ``$``-based substitutions, using the following rules:
 
 * ``$$`` is an escape; it is replaced with a single ``$``.
 
@@ -707,7 +739,7 @@ these rules.  The methods of :class:`Template` are:
       simply return ``$`` instead of raising :exc:`ValueError`.
 
       While other exceptions may still occur, this method is called "safe"
-      because substitutions always tries to return a usable string instead of
+      because it always tries to return a usable string instead of
       raising an exception.  In another sense, :meth:`safe_substitute` may be
       anything other than safe, since it will silently ignore malformed
       templates containing dangling delimiters, unmatched braces, or
index cc3017b..32bc71f 100644 (file)
@@ -116,6 +116,13 @@ By default, C types are represented in the machine's native format and byte
 order, and properly aligned by skipping pad bytes if necessary (according to the
 rules used by the C compiler).
 
+.. index::
+   single: @ (at); in struct format strings
+   single: = (equals); in struct format strings
+   single: < (less); in struct format strings
+   single: > (greater); in struct format strings
+   single: ! (exclamation); in struct format strings
+
 Alternatively, the first character of the format string can be used to indicate
 the byte order, size and alignment of the packed data, according to the
 following table:
@@ -239,6 +246,8 @@ platform-dependent.
 Notes:
 
 (1)
+   .. index:: single: ? (question mark); in struct format strings
+
    The ``'?'`` conversion code corresponds to the :c:type:`_Bool` type defined by
    C99. If this type is not available, it is simulated using a :c:type:`char`. In
    standard mode, it is always represented by one byte.
@@ -321,6 +330,8 @@ are used.  Note that for :func:`unpack`, the ``'p'`` format character consumes
 ``count`` bytes, but that the string returned can never contain more than 255
 bytes.
 
+.. index:: single: ? (question mark); in struct format strings
+
 For the ``'?'`` format character, the return value is either :const:`True` or
 :const:`False`. When packing, the truth value of the argument object is used.
 Either 0 or 1 in the native or standard bool representation will be packed, and
index 68521df..9198466 100644 (file)
@@ -286,6 +286,7 @@ always available.
    :const:`debug`                :option:`-d`
    :const:`inspect`              :option:`-i`
    :const:`interactive`          :option:`-i`
+   :const:`isolated`             :option:`-I`
    :const:`optimize`             :option:`-O` or :option:`-OO`
    :const:`dont_write_bytecode`  :option:`-B`
    :const:`no_user_site`         :option:`-s`
@@ -306,6 +307,8 @@ always available.
    .. versionchanged:: 3.3
       Removed obsolete ``division_warning`` attribute.
 
+   .. versionchanged:: 3.4
+      Added ``isolated`` attribute for :option:`-I` ``isolated`` flag.
 
 .. data:: float_info
 
@@ -960,6 +963,8 @@ always available.
    .. index::
       single: interpreter prompts
       single: prompts, interpreter
+      single: >>>; interpreter prompt
+      single: ...; interpreter prompt
 
    Strings specifying the primary and secondary prompt of the interpreter.  These
    are only defined if the interpreter is in interactive mode.  Their initial
index f066a76..d29396e 100644 (file)
@@ -188,7 +188,7 @@ Other functions
 
    Windows will return one of:
 
-   - win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
+   - win-amd64 (64bit Windows on AMD64, aka x86_64, Intel64, and EM64T)
    - win-ia64 (64bit Windows on Itanium)
    - win32 (all others - specifically, sys.platform is returned)
 
index 7693ecd..d75a87c 100644 (file)
@@ -51,8 +51,8 @@ The module defines the following functions:
 
 .. function:: tcsendbreak(fd, duration)
 
-   Send a break on file descriptor *fd*.  A zero *duration* sends a break for 0.25
-   --0.5 seconds; a nonzero *duration* has a system dependent meaning.
+   Send a break on file descriptor *fd*.  A zero *duration* sends a break for
+   0.25--0.5 seconds; a nonzero *duration* has a system dependent meaning.
 
 
 .. function:: tcdrain(fd)
index 438007d..d254466 100644 (file)
@@ -268,6 +268,8 @@ hyphenated words; only then will long words be broken if necessary, unless
       .. versionadded:: 3.4
 
 
+   .. index:: single: ...; placeholder
+
    .. attribute:: placeholder
 
       (default: ``' [...]'``) String that will appear at the end of the output
index 0624099..808ae05 100644 (file)
@@ -308,6 +308,9 @@ Functions
       :pep:`475` for the rationale).
 
 
+.. index::
+   single: % (percent); datetime format
+
 .. function:: strftime(format[, t])
 
    Convert a tuple or :class:`struct_time` representing a time as returned by
@@ -439,6 +442,9 @@ Functions
    it is 3.
 
 
+.. index::
+   single: % (percent); datetime format
+
 .. function:: strptime(string[, format])
 
    Parse a string representing a time according to a format.  The return value
index d9c1c35..60cf892 100644 (file)
@@ -205,6 +205,7 @@ A Simple Hello World Program
     class Application(tk.Frame):
         def __init__(self, master=None):
             super().__init__(master)
+            self.master = master
             self.pack()
             self.create_widgets()
 
@@ -215,7 +216,7 @@ A Simple Hello World Program
             self.hi_there.pack(side="top")
 
             self.quit = tk.Button(self, text="QUIT", fg="red",
-                                  command=root.destroy)
+                                  command=self.master.destroy)
             self.quit.pack(side="bottom")
 
         def say_hi(self):
@@ -262,6 +263,8 @@ To make a widget in Tk, the command is always of the form::
 *classCommand*
    denotes which kind of widget to make (a button, a label, a menu...)
 
+.. index:: single: . (dot); in Tkinter
+
 *newPathname*
    is the new name for this widget.  All names in Tk must be unique.  To help
    enforce this, widgets in Tk are named with *pathnames*, just like files in a
index 7ac3cac..462a6a5 100644 (file)
@@ -44,7 +44,11 @@ The module defines the following functions:
 
    * if *tb* is not ``None``, it prints a header ``Traceback (most recent
      call last):``
+
    * it prints the exception *etype* and *value* after the stack trace
+
+   .. index:: single: ^ (caret); marker
+
    * if *type(value)* is :exc:`SyntaxError` and *value* has the appropriate
      format, it prints the line where the syntax error occurred with a caret
      indicating the approximate position of the error.
index 2b5d3e5..8135c93 100644 (file)
@@ -1310,7 +1310,7 @@ Using events
 
    :param fun: a function with two arguments which will be called with the
                coordinates of the clicked point on the canvas
-   :param num: number of the mouse-button, defaults to 1 (left mouse button)
+   :param btn: number of the mouse-button, defaults to 1 (left mouse button)
    :param add: ``True`` or ``False`` -- if ``True``, a new binding will be
                added, otherwise it will replace a former binding
 
@@ -1331,7 +1331,7 @@ Using events
 
    :param fun: a function with two arguments which will be called with the
                coordinates of the clicked point on the canvas
-   :param num: number of the mouse-button, defaults to 1 (left mouse button)
+   :param btn: number of the mouse-button, defaults to 1 (left mouse button)
    :param add: ``True`` or ``False`` -- if ``True``, a new binding will be
                added, otherwise it will replace a former binding
 
@@ -1355,7 +1355,7 @@ Using events
 
    :param fun: a function with two arguments which will be called with the
                coordinates of the clicked point on the canvas
-   :param num: number of the mouse-button, defaults to 1 (left mouse button)
+   :param btn: number of the mouse-button, defaults to 1 (left mouse button)
    :param add: ``True`` or ``False`` -- if ``True``, a new binding will be
                added, otherwise it will replace a former binding
 
@@ -1736,7 +1736,7 @@ Using screen events
 
    :param fun: a function with two arguments which will be called with the
                coordinates of the clicked point on the canvas
-   :param num: number of the mouse-button, defaults to 1 (left mouse button)
+   :param btn: number of the mouse-button, defaults to 1 (left mouse button)
    :param add: ``True`` or ``False`` -- if ``True``, a new binding will be
                added, otherwise it will replace a former binding
 
index e80cd3f..915c3da 100644 (file)
@@ -780,32 +780,25 @@ The module defines the following classes, functions and decorators:
 
    .. versionadded:: 3.5.2
 
-.. class:: io
+.. class:: IO
+           TextIO
+           BinaryIO
 
-   Wrapper namespace for I/O stream types.
-
-   This defines the generic type ``IO[AnyStr]`` and subclasses ``TextIO``
-   and ``BinaryIO``, deriving from ``IO[str]`` and ``IO[bytes]``,
-   respectively. These represent the types of I/O streams such as returned by
+   Generic type ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])``
+   and ``BinaryIO(IO[bytes])``
+   represent the types of I/O streams such as returned by
    :func:`open`.
 
-   These types are also accessible directly as ``typing.IO``,
-   ``typing.TextIO``, and ``typing.BinaryIO``.
-
-.. class:: re
+.. class:: Pattern
+           Match
 
-   Wrapper namespace for regular expression matching types.
-
-   This defines the type aliases ``Pattern`` and ``Match`` which
+   These type aliases
    correspond to the return types from :func:`re.compile` and
    :func:`re.match`.  These types (and the corresponding functions)
    are generic in ``AnyStr`` and can be made specific by writing
    ``Pattern[str]``, ``Pattern[bytes]``, ``Match[str]``, or
    ``Match[bytes]``.
 
-   These types are also accessible directly as ``typing.Pattern``
-   and ``typing.Match``.
-
 .. class:: NamedTuple
 
    Typed version of namedtuple.
index 05f3374..cfba727 100644 (file)
@@ -153,6 +153,15 @@ You use the :data:`call` object to construct lists for comparing with
     >>> mock.mock_calls == expected
     True
 
+However, parameters to calls that return mocks are not recorded, which means it is not
+possible to track nested calls where the parameters used to create ancestors are important:
+
+    >>> m = Mock()
+    >>> m.factory(important=True).deliver()
+    <Mock name='mock.factory().deliver()' id='...'>
+    >>> m.mock_calls[-1] == call.factory(important=False).deliver()
+    True
+
 
 Setting Return Values and Attributes
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index 6841ef8..01f5a64 100644 (file)
@@ -680,6 +680,19 @@ the *new_callable* argument to :func:`patch`.
         unpacked as tuples to get at the individual arguments. See
         :ref:`calls as tuples <calls-as-tuples>`.
 
+        .. note::
+
+            The way :attr:`mock_calls` are recorded means that where nested
+            calls are made, the parameters of ancestor calls are not recorded
+            and so will always compare equal:
+
+                >>> mock = MagicMock()
+                >>> mock.top(a=3).bottom()
+                <MagicMock name='mock.top().bottom()' id='...'>
+                >>> mock.mock_calls
+                [call.top(a=3), call.top().bottom()]
+                >>> mock.mock_calls[-1] == call.top(a=-1).bottom()
+                True
 
     .. attribute:: __class__
 
index dd85e9e..3a8af0c 100644 (file)
@@ -56,7 +56,7 @@ test runner
       Kent Beck's original paper on testing frameworks using the pattern shared
       by :mod:`unittest`.
 
-   `Nose <https://nose.readthedocs.org/en/latest/>`_ and `py.test <http://pytest.org>`_
+   `Nose <https://nose.readthedocs.io/>`_ and `pytest <https://docs.pytest.org/>`_
       Third-party unittest frameworks with a lighter-weight syntax for writing
       tests.  For example, ``assert func(10) == 42``.
 
@@ -588,7 +588,7 @@ Distinguishing test iterations using subtests
 
 .. versionadded:: 3.4
 
-When some of your tests differ only by a some very small differences, for
+When there are very small differences among your tests, for
 instance some parameters, unittest allows you to distinguish them inside
 the body of a test method using the :meth:`~TestCase.subTest` context manager.
 
@@ -1142,7 +1142,7 @@ Test cases
       If *delta* is supplied instead of *places* then the difference
       between *first* and *second* must be less or equal to (or greater than) *delta*.
 
-      Supplying both *delta* and *places* raises a ``TypeError``.
+      Supplying both *delta* and *places* raises a :exc:`TypeError`.
 
       .. versionchanged:: 3.2
          :meth:`assertAlmostEqual` automatically considers almost equal objects
index 1cc69e6..d991254 100644 (file)
@@ -134,7 +134,7 @@ or on combining URL components into a URL string.
       returning :const:`None`.
 
 
-.. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace')
+.. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None)
 
    Parse a query string given as a string argument (data of type
    :mimetype:`application/x-www-form-urlencoded`).  Data are returned as a
@@ -155,6 +155,10 @@ or on combining URL components into a URL string.
    percent-encoded sequences into Unicode characters, as accepted by the
    :meth:`bytes.decode` method.
 
+   The optional argument *max_num_fields* is the maximum number of fields to
+   read. If set, then throws a :exc:`ValueError` if there are more than
+   *max_num_fields* fields read.
+
    Use the :func:`urllib.parse.urlencode` function (with the ``doseq``
    parameter set to ``True``) to convert such dictionaries into query
    strings.
@@ -163,8 +167,11 @@ or on combining URL components into a URL string.
    .. versionchanged:: 3.2
       Add *encoding* and *errors* parameters.
 
+   .. versionchanged:: 3.6.8
+      Added *max_num_fields* parameter.
+
 
-.. function:: parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace')
+.. function:: parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None)
 
    Parse a query string given as a string argument (data of type
    :mimetype:`application/x-www-form-urlencoded`).  Data are returned as a list of
@@ -184,12 +191,19 @@ or on combining URL components into a URL string.
    percent-encoded sequences into Unicode characters, as accepted by the
    :meth:`bytes.decode` method.
 
+   The optional argument *max_num_fields* is the maximum number of fields to
+   read. If set, then throws a :exc:`ValueError` if there are more than
+   *max_num_fields* fields read.
+
    Use the :func:`urllib.parse.urlencode` function to convert such lists of pairs into
    query strings.
 
    .. versionchanged:: 3.2
       Add *encoding* and *errors* parameters.
 
+   .. versionchanged:: 3.6.8
+      Added *max_num_fields* parameter.
+
 
 .. function:: urlunparse(parts)
 
index 0890f74..8af97f0 100644 (file)
@@ -297,7 +297,7 @@ The following classes are provided:
    Cause requests to go through a proxy. If *proxies* is given, it must be a
    dictionary mapping protocol names to URLs of proxies. The default is to read
    the list of proxies from the environment variables
-   :envvar:`<protocol>_proxy`.  If no proxy environment variables are set, then
+   ``<protocol>_proxy``.  If no proxy environment variables are set, then
    in a Windows environment proxy settings are obtained from the registry's
    Internet Settings section, and in a Mac OS X environment proxy information
    is retrieved from the OS X System Configuration Framework.
index 14f7896..e9c0261 100644 (file)
@@ -224,6 +224,9 @@ This module offers the following functions:
       See :ref:`above <exception-changed>`.
 
 
+.. index::
+   single: % (percent); environment variables expansion (Windows)
+
 .. function:: ExpandEnvironmentStrings(str)
 
    Expands environment variable placeholders ``%NAME%`` in strings like
index 40470e8..15b1cb0 100644 (file)
@@ -156,7 +156,7 @@ module documentation.  This section lists the differences between the API and
    encoding. Encoding this string in an encoding other than UTF-8 is
    likely incorrect, since UTF-8 is the default encoding of XML.
 
-.. method:: Node.toprettyxml(indent="", newl="", encoding="")
+.. method:: Node.toprettyxml(indent="\\t", newl="\\n", encoding=None)
 
    Return a pretty-printed version of the document. *indent* specifies the
    indentation string and defaults to a tabulator; *newl* specifies the string
index 1a8f183..254b539 100644 (file)
@@ -40,7 +40,7 @@ The convenience functions are:
 
    Create and return a SAX :class:`~xml.sax.xmlreader.XMLReader` object.  The
    first parser found will
-   be used.  If *parser_list* is provided, it must be a sequence of strings which
+   be used.  If *parser_list* is provided, it must be a list of strings which
    name modules that have a function named :func:`create_parser`.  Modules listed
    in *parser_list* will be used before modules in the default list of parsers.
 
index a5d4211..b65b61d 100644 (file)
@@ -347,7 +347,7 @@ ZipFile Objects
    Return the name of the first bad file, or else return ``None``.
 
    .. versionchanged:: 3.6
-      Calling :meth:`testfile` on a closed ZipFile will raise a
+      Calling :meth:`testzip` on a closed ZipFile will raise a
       :exc:`ValueError`.  Previously, a :exc:`RuntimeError` was raised.
 
 
@@ -362,13 +362,6 @@ ZipFile Objects
 
    .. note::
 
-      There is no official file name encoding for ZIP files. If you have unicode file
-      names, you must convert them to byte strings in your desired encoding before
-      passing them to :meth:`write`. WinZip interprets all file names as encoded in
-      CP437, also known as DOS Latin.
-
-   .. note::
-
       Archive names should be relative to the archive root, that is, they should not
       start with a path separator.
 
@@ -385,7 +378,9 @@ ZipFile Objects
 
 .. method:: ZipFile.writestr(zinfo_or_arcname, data[, compress_type])
 
-   Write the string *data* to the archive; *zinfo_or_arcname* is either the file
+   Write a file into the archive.  The contents is *data*, which may be either
+   a :class:`str` or a :class:`bytes` instance; if it is a :class:`str`,
+   it is encoded as UTF-8 first.  *zinfo_or_arcname* is either the file
    name it will be given in the archive, or a :class:`ZipInfo` instance.  If it's
    an instance, at least the filename, date, and time must be given.  If it's a
    name, the date and time is set to the current date and time.
@@ -425,11 +420,11 @@ The following data attributes are also available:
 
 .. attribute:: ZipFile.comment
 
-   The comment text associated with the ZIP file.  If assigning a comment to a
+   The comment associated with the ZIP file as a :class:`bytes` object.
+   If assigning a comment to a
    :class:`ZipFile` instance created with mode ``'w'``, ``'x'`` or ``'a'``,
-   this should be a
-   string no longer than 65535 bytes.  Comments longer than this will be
-   truncated in the written archive when :meth:`close` is called.
+   it should be no longer than 65535 bytes.  Comments longer than this will be
+   truncated.
 
 
 .. _pyzipfile-objects:
@@ -583,13 +578,14 @@ Instances have the following methods and attributes:
 
 .. attribute:: ZipInfo.comment
 
-   Comment for the individual archive member.
+   Comment for the individual archive member as a :class:`bytes` object.
 
 
 .. attribute:: ZipInfo.extra
 
    Expansion field data.  The `PKZIP Application Note`_ contains
-   some comments on the internal structure of the data contained in this string.
+   some comments on the internal structure of the data contained in this
+   :class:`bytes` object.
 
 
 .. attribute:: ZipInfo.create_system
index 2ddb3e2..d8aa065 100644 (file)
@@ -16,7 +16,7 @@ if not defined SPHINXBUILD (
         %PYTHON% -m pip install sphinx\r
         if errorlevel 1 exit /B\r
     )\r
-    set SPHINXBUILD=%PYTHON% -c "import sphinx, sys; sys.argv[0] = 'sphinx-build'; sys.exit(sphinx.main())"\r
+    set SPHINXBUILD=%PYTHON% -c "import sphinx.cmd.build, sys; sys.exit(sphinx.cmd.build.main())"\r
 )\r
 \r
 %PYTHON% -c "import python_docs_theme" > nul 2> nul\r
@@ -115,13 +115,15 @@ goto end
 :build\r
 if not exist "%BUILDDIR%" mkdir "%BUILDDIR%"\r
 \r
+rem PY_MISC_NEWS_DIR is also used by our Sphinx extension in tools/extensions/pyspecific.py\r
+if not defined PY_MISC_NEWS_DIR set PY_MISC_NEWS_DIR=%BUILDDIR%\%1\r
 if exist ..\Misc\NEWS (\r
-    echo.Copying Misc\NEWS to build\NEWS\r
-    copy ..\Misc\NEWS build\NEWS > nul\r
+    echo.Copying Misc\NEWS to %PY_MISC_NEWS_DIR%\NEWS\r
+    copy ..\Misc\NEWS "%PY_MISC_NEWS_DIR%\NEWS" > nul\r
 ) else if exist ..\Misc\NEWS.D (\r
     if defined BLURB (\r
         echo.Merging Misc/NEWS with %BLURB%\r
-        %BLURB% merge -f build\NEWS\r
+        %BLURB% merge -f "%PY_MISC_NEWS_DIR%\NEWS"\r
     ) else (\r
         echo.No Misc/NEWS file and Blurb is not available.\r
         exit /B 1\r
index 1f75330..8d050a6 100644 (file)
@@ -21,6 +21,7 @@ also syntactically compound statements.
 .. index::
    single: clause
    single: suite
+   single: ; (semicolon)
 
 A compound statement consists of one or more 'clauses.'  A clause consists of a
 header and a 'suite.'  The clause headers of a particular compound statement are
@@ -84,8 +85,7 @@ The :keyword:`if` statement
    statement: if
    keyword: elif
    keyword: else
-           keyword: elif
-           keyword: else
+   single: : (colon); compound statement
 
 The :keyword:`if` statement is used for conditional execution:
 
@@ -111,6 +111,7 @@ The :keyword:`while` statement
    keyword: else
    pair: loop; statement
    keyword: else
+   single: : (colon); compound statement
 
 The :keyword:`while` statement is used for repeated execution as long as an
 expression is true:
@@ -149,6 +150,7 @@ The :keyword:`for` statement
    keyword: else
    pair: target; list
    object: sequence
+   single: : (colon); compound statement
 
 The :keyword:`for` statement is used to iterate over the elements of a sequence
 (such as a string, tuple or list) or other iterable object:
@@ -229,7 +231,9 @@ The :keyword:`try` statement
    statement: try
    keyword: except
    keyword: finally
-.. index:: keyword: except
+   keyword: else
+   keyword: as
+   single: : (colon); compound statement
 
 The :keyword:`try` statement specifies exception handlers and/or cleanup code
 for a group of statements:
@@ -263,6 +267,8 @@ exception, the original search for a handler is canceled and a search starts for
 the new exception in the surrounding code and on the call stack (it is treated
 as if the entire :keyword:`try` statement raised the exception).
 
+.. index:: single: as; except clause
+
 When a matching except clause is found, the exception is assigned to the target
 specified after the :keyword:`as` keyword in that except clause, if present, and
 the except clause's suite is executed.  All except clauses must have an
@@ -308,9 +314,11 @@ from a function that handled an exception.
    statement: break
    statement: continue
 
-The optional :keyword:`else` clause is executed if and when control flows off
-the end of the :keyword:`try` clause. [#]_ Exceptions in the :keyword:`else`
-clause are not handled by the preceding :keyword:`except` clauses.
+The optional :keyword:`else` clause is executed if the control flow leaves the
+:keyword:`try` suite, no exception was raised, and no :keyword:`return`,
+:keyword:`continue`, or :keyword:`break` statement was executed.  Exceptions in
+the :keyword:`else` clause are not handled by the preceding :keyword:`except`
+clauses.
 
 .. index:: keyword: finally
 
@@ -374,8 +382,11 @@ The :keyword:`with` statement
 =============================
 
 .. index::
-    statement: with
-    single: as; with statement
+   statement: with
+   keyword: as
+   single: as; with statement
+   single: , (comma); with statement
+   single: : (colon); compound statement
 
 The :keyword:`with` statement is used to wrap the execution of a block with
 methods defined by a context manager (see section :ref:`context-managers`).
@@ -462,6 +473,9 @@ Function definitions
    object: function
    pair: function; name
    pair: name; binding
+   single: () (parentheses); function definition
+   single: , (comma); parameter list
+   single: : (colon); compound statement
 
 A function definition defines a user-defined function object (see section
 :ref:`types`):
@@ -491,7 +505,7 @@ The function definition does not execute the function body; this gets executed
 only when the function is called. [#]_
 
 .. index::
-  statement: @
+   single: @ (at); function definition
 
 A function definition may be wrapped by one or more :term:`decorator` expressions.
 Decorator expressions are evaluated when the function is defined, in the scope
@@ -514,6 +528,7 @@ except that the original function is not temporarily bound to the name ``func``.
 .. index::
    triple: default; parameter; value
    single: argument; function definition
+   single: = (equals); function definition
 
 When one or more :term:`parameters <parameter>` have the form *parameter* ``=``
 *expression*, the function is said to have "default parameter values."  For a
@@ -540,8 +555,8 @@ e.g.::
        return penguin
 
 .. index::
-  statement: *
-  statement: **
+   single: * (asterisk); function definition
+   single: **; function definition
 
 Function call semantics are described in more detail in section :ref:`calls`. A
 function call always assigns values to all parameters mentioned in the parameter
@@ -554,7 +569,10 @@ new empty mapping of the same type.  Parameters after "``*``" or
 "``*identifier``" are keyword-only parameters and may only be passed
 used keyword arguments.
 
-.. index:: pair: function; annotations
+.. index::
+   pair: function; annotations
+   single: ->; function annotations
+   single: : (colon); function annotations
 
 Parameters may have annotations of the form "``: expression``" following the
 parameter name.  Any parameter may have an annotation even those of the form
@@ -603,6 +621,9 @@ Class definitions
    pair: execution; frame
    single: inheritance
    single: docstring
+   single: () (parentheses); class definition
+   single: , (comma); expression list
+   single: : (colon); compound statement
 
 A class definition defines a class object (see section :ref:`types`):
 
@@ -641,6 +662,9 @@ the definition syntax.
 
 Class creation can be customized heavily using :ref:`metaclasses <metaclasses>`.
 
+.. index::
+   single: @ (at); class definition
+
 Classes can also be decorated: just like when decorating functions, ::
 
    @f1(arg)
@@ -667,8 +691,14 @@ can be used to create instance variables with different implementation details.
 
 .. seealso::
 
-   :pep:`3115` - Metaclasses in Python 3
+   :pep:`3115` - Metaclasses in Python 3000
+      The proposal that changed the declaration of metaclasses to the current
+      syntax, and the semantics for how classes with metaclasses are
+      constructed.
+
    :pep:`3129` - Class Decorators
+      The proposal that added class decorators.  Function and method decorators
+      were introduced in :pep:`318`.
 
 
 Coroutines
@@ -793,6 +823,8 @@ It is a :exc:`SyntaxError` to use ``async with`` statement outside of an
 .. seealso::
 
    :pep:`492` - Coroutines with async and await syntax
+      The proposal that made coroutines a proper standalone concept in Python,
+      and added supporting syntax.
 
 
 .. rubric:: Footnotes
@@ -801,10 +833,6 @@ It is a :exc:`SyntaxError` to use ``async with`` statement outside of an
    there is a :keyword:`finally` clause which happens to raise another
    exception. That new exception causes the old one to be lost.
 
-.. [#] Currently, control "flows off the end" except in the case of an exception
-   or the execution of a :keyword:`return`, :keyword:`continue`, or
-   :keyword:`break` statement.
-
 .. [#] A string literal appearing as the first statement in the function body is
    transformed into the function's ``__doc__`` attribute and therefore the
    function's :term:`docstring`.
index 8386df1..143376b 100644 (file)
@@ -165,7 +165,9 @@ NotImplemented
 
 
 Ellipsis
-   .. index:: object: Ellipsis
+   .. index::
+      object: Ellipsis
+      single: ...; ellipsis literal
 
    This type has a single value.  There is a single object with this value. This
    object is accessed through the literal ``...`` or the built-in name
@@ -1766,8 +1768,9 @@ Metaclasses
 ^^^^^^^^^^^
 
 .. index::
-    single: metaclass
-    builtin: type
+   single: metaclass
+   builtin: type
+   single: = (equals); class definition
 
 By default, classes are constructed using :func:`type`. The class body is
 executed in a new namespace and the class name is bound locally to the
@@ -1915,46 +1918,14 @@ becomes the :attr:`~object.__dict__` attribute of the class object.
       Describes the implicit ``__class__`` closure reference
 
 
-Metaclass example
-^^^^^^^^^^^^^^^^^
+Uses for metaclasses
+^^^^^^^^^^^^^^^^^^^^
 
 The potential uses for metaclasses are boundless. Some ideas that have been
 explored include enum, logging, interface checking, automatic delegation,
 automatic property creation, proxies, frameworks, and automatic resource
 locking/synchronization.
 
-Here is an example of a metaclass that uses an :class:`collections.OrderedDict`
-to remember the order that class variables are defined::
-
-    class OrderedClass(type):
-
-        @classmethod
-        def __prepare__(metacls, name, bases, **kwds):
-            return collections.OrderedDict()
-
-        def __new__(cls, name, bases, namespace, **kwds):
-            result = type.__new__(cls, name, bases, dict(namespace))
-            result.members = tuple(namespace)
-            return result
-
-    class A(metaclass=OrderedClass):
-        def one(self): pass
-        def two(self): pass
-        def three(self): pass
-        def four(self): pass
-
-    >>> A.members
-    ('__module__', 'one', 'two', 'three', 'four')
-
-When the class definition for *A* gets executed, the process begins with
-calling the metaclass's :meth:`__prepare__` method which returns an empty
-:class:`collections.OrderedDict`.  That mapping records the methods and
-attributes of *A* as they are defined within the body of the class statement.
-Once those definitions are executed, the ordered dictionary is fully populated
-and the metaclass's :meth:`__new__` method gets invoked.  That method builds
-the new type and it saves the ordered dictionary keys in an attribute
-called ``members``.
-
 
 Customizing instance and subclass checks
 ----------------------------------------
@@ -2074,6 +2045,8 @@ through the container; for mappings, :meth:`__iter__` should be the same as
    .. versionadded:: 3.4
 
 
+.. index:: object: slice
+
 .. note::
 
    Slicing is done exclusively with the following three methods.  A call like ::
@@ -2089,8 +2062,6 @@ through the container; for mappings, :meth:`__iter__` should be the same as
 
 .. method:: object.__getitem__(self, key)
 
-   .. index:: object: slice
-
    Called to implement evaluation of ``self[key]``. For sequence types, the
    accepted keys should be integers and slice objects.  Note that the special
    interpretation of negative indexes (if the class wishes to emulate a sequence
@@ -2106,12 +2077,6 @@ through the container; for mappings, :meth:`__iter__` should be the same as
       indexes to allow proper detection of the end of the sequence.
 
 
-.. method:: object.__missing__(self, key)
-
-   Called by :class:`dict`\ .\ :meth:`__getitem__` to implement ``self[key]`` for dict subclasses
-   when key is not in the dictionary.
-
-
 .. method:: object.__setitem__(self, key, value)
 
    Called to implement assignment to ``self[key]``.  Same note as for
@@ -2130,6 +2095,12 @@ through the container; for mappings, :meth:`__iter__` should be the same as
    values as for the :meth:`__getitem__` method.
 
 
+.. method:: object.__missing__(self, key)
+
+   Called by :class:`dict`\ .\ :meth:`__getitem__` to implement ``self[key]`` for dict subclasses
+   when key is not in the dictionary.
+
+
 .. method:: object.__iter__(self)
 
    This method is called when an iterator is required for a container. This method
index d08abdf..1a69e97 100644 (file)
@@ -22,7 +22,7 @@ The following are blocks: a module, a function body, and a class definition.
 Each command typed interactively is a block.  A script file (a file given as
 standard input to the interpreter or specified as a command line argument to the
 interpreter) is a code block.  A script command (a command specified on the
-interpreter command line with the '**-c**' option) is a code block.  The string
+interpreter command line with the :option:`-c` option) is a code block.  The string
 argument passed to the built-in functions :func:`eval` and :func:`exec` is a
 code block.
 
@@ -52,7 +52,7 @@ Binding of names
 
 :dfn:`Names` refer to objects.  Names are introduced by name binding operations.
 
-.. index:: statement: from
+.. index:: single: from; import statement
 
 The following constructs bind names: formal parameters to functions,
 :keyword:`import` statements, class and function definitions (these bind the
index 3f929bf..e13072f 100644 (file)
@@ -128,7 +128,9 @@ value.
 Parenthesized forms
 -------------------
 
-.. index:: single: parenthesized form
+.. index::
+   single: parenthesized form
+   single: () (parentheses); tuple display
 
 A parenthesized form is an optional expression list enclosed in parentheses:
 
@@ -146,8 +148,9 @@ immutable, the rules for literals apply (i.e., two occurrences of the empty
 tuple may or may not yield the same object).
 
 .. index::
-   single: comma
+   single: comma; tuple display
    pair: tuple; display
+   single: , (comma); tuple display
 
 Note that tuples are not formed by the parentheses, but rather by use of the
 comma operator.  The exception is the empty tuple, for which parentheses *are*
@@ -168,6 +171,11 @@ called "displays", each of them in two flavors:
 * they are computed via a set of looping and filtering instructions, called a
   :dfn:`comprehension`.
 
+.. index::
+   single: for; in comprehensions
+   single: if; in comprehensions
+   single: async for; in comprehensions
+
 Common syntax elements for comprehensions are:
 
 .. productionlist::
@@ -186,6 +194,9 @@ each time the innermost block is reached.
 Note that the comprehension is executed in a separate scope, so names assigned
 to in the target list don't "leak" into the enclosing scope.
 
+.. index::
+   single: await; in comprehensions
+
 Since Python 3.6, in an :keyword:`async def` function, an :keyword:`async for`
 clause may be used to iterate over a :term:`asynchronous iterator`.
 A comprehension in an :keyword:`async def` function may consist of either a
@@ -208,6 +219,8 @@ List displays
    pair: list; comprehensions
    pair: empty; list
    object: list
+   single: [] (square brackets); list expression
+   single: , (comma); expression list
 
 A list display is a possibly empty series of expressions enclosed in square
 brackets:
@@ -227,8 +240,11 @@ the list is constructed from the elements resulting from the comprehension.
 Set displays
 ------------
 
-.. index:: pair: set; display
-           object: set
+.. index::
+   pair: set; display
+   object: set
+   single: {} (curly brackets); set expression
+   single: , (comma); expression list
 
 A set display is denoted by curly braces and distinguishable from dictionary
 displays by the lack of colons separating keys and values:
@@ -251,9 +267,13 @@ dictionary.
 Dictionary displays
 -------------------
 
-.. index:: pair: dictionary; display
-           key, datum, key/datum pair
-           object: dictionary
+.. index::
+   pair: dictionary; display
+   key, datum, key/datum pair
+   object: dictionary
+   single: {} (curly brackets); dictionary expression
+   single: : (colon); in dictionary expressions
+   single: , (comma); in dictionary displays
 
 A dictionary display is a possibly empty series of key/datum pairs enclosed in
 curly braces:
@@ -272,7 +292,9 @@ used as a key into the dictionary to store the corresponding datum.  This means
 that you can specify the same key multiple times in the key/datum list, and the
 final dictionary's value for that key will be the last one given.
 
-.. index:: unpacking; dictionary, **; in dictionary displays
+.. index::
+   unpacking; dictionary
+   single: **; in dictionary displays
 
 A double asterisk ``**`` denotes :dfn:`dictionary unpacking`.
 Its operand must be a :term:`mapping`.  Each mapping item is added
@@ -302,8 +324,10 @@ prevails.
 Generator expressions
 ---------------------
 
-.. index:: pair: generator; expression
-           object: generator
+.. index::
+   pair: generator; expression
+   object: generator
+   single: () (parentheses); generator expression
 
 A generator expression is a compact generator notation in parentheses:
 
@@ -342,6 +366,7 @@ Yield expressions
 
 .. index::
    keyword: yield
+   keyword: from
    pair: yield; expression
    pair: generator; function
 
@@ -359,7 +384,7 @@ coroutine function to be an asynchronous generator. For example::
     def gen():  # defines a generator function
         yield 123
 
-    async def agen(): # defines an asynchronous generator function (PEP 525)
+    async def agen(): # defines an asynchronous generator function
         yield 123
 
 Generator functions are described below, while asynchronous generator
@@ -397,6 +422,9 @@ finalized (by reaching a zero reference count or by being garbage collected),
 the generator-iterator's :meth:`~generator.close` method will be called,
 allowing any pending :keyword:`finally` clauses to execute.
 
+.. index::
+   single: from; yield from expression
+
 When ``yield from <expr>`` is used, it treats the supplied expression as
 a subiterator. All values produced by that subiterator are passed directly
 to the caller of the current generator's methods. Any values passed in with
@@ -431,6 +459,10 @@ on the right hand side of an assignment statement.
       The proposal to introduce the :token:`yield_from` syntax, making delegation
       to sub-generators easy.
 
+   :pep:`525` - Asynchronous Generators
+      The proposal that expanded on :pep:`492` by adding generator capabilities to
+      coroutine functions.
+
 .. index:: object: generator
 .. _generator-methods:
 
@@ -676,7 +708,9 @@ syntax is:
 Attribute references
 --------------------
 
-.. index:: pair: attribute; reference
+.. index::
+   pair: attribute; reference
+   single: . (dot); attribute reference
 
 An attribute reference is a primary followed by a period and a name:
 
@@ -702,7 +736,9 @@ same attribute reference may yield different objects.
 Subscriptions
 -------------
 
-.. index:: single: subscription
+.. index::
+   single: subscription
+   single: [] (square brackets); subscription
 
 .. index::
    object: sequence
@@ -759,6 +795,8 @@ Slicings
 .. index::
    single: slicing
    single: slice
+   single: : (colon); slicing
+   single: , (comma); slicing
 
 .. index::
    object: sequence
@@ -808,6 +846,9 @@ substituting ``None`` for missing expressions.
    object: callable
    single: call
    single: argument; call semantics
+   single: () (parentheses); call
+   single: , (comma); argument list
+   single: = (equals); in function calls
 
 .. _calls:
 
@@ -884,7 +925,7 @@ and the argument values as corresponding values), or a (new) empty dictionary if
 there were no excess keyword arguments.
 
 .. index::
-   single: *; in function calls
+   single: * (asterisk); in function calls
    single: unpacking; in function calls
 
 If the syntax ``*expression`` appears in the function call, ``expression`` must
@@ -990,6 +1031,7 @@ a class instance:
    if that method was called.
 
 
+.. index:: keyword: await
 .. _await:
 
 Await expression
@@ -1009,6 +1051,10 @@ Can only be used inside a :term:`coroutine function`.
 The power operator
 ==================
 
+.. index::
+   pair: power; operation
+   operator: **
+
 The power operator binds more tightly than unary operators on its left; it binds
 less tightly than unary operators on its right.  The syntax is:
 
@@ -1051,15 +1097,21 @@ All unary arithmetic and bitwise operations have the same priority:
 .. index::
    single: negation
    single: minus
+   single: operator; - (minus)
+   single: - (minus); unary operator
 
 The unary ``-`` (minus) operator yields the negation of its numeric argument.
 
-.. index:: single: plus
+.. index::
+   single: plus
+   single: operator; + (plus)
+   single: + (plus); unary operator
 
 The unary ``+`` (plus) operator yields its numeric argument unchanged.
 
-.. index:: single: inversion
-
+.. index::
+   single: inversion
+   operator: ~ (tilde)
 
 The unary ``~`` (invert) operator yields the bitwise inversion of its integer
 argument.  The bitwise inversion of ``x`` is defined as ``-(x+1)``.  It only
@@ -1089,7 +1141,9 @@ operators and one for additive operators:
          : `m_expr` "%" `u_expr`
    a_expr: `m_expr` | `a_expr` "+" `m_expr` | `a_expr` "-" `m_expr`
 
-.. index:: single: multiplication
+.. index::
+   single: multiplication
+   operator: * (asterisk)
 
 The ``*`` (multiplication) operator yields the product of its arguments.  The
 arguments must either both be numbers, or one argument must be an integer and
@@ -1099,7 +1153,7 @@ repetition is performed; a negative repetition factor yields an empty sequence.
 
 .. index::
    single: matrix multiplication
-   operator: @
+   operator: @ (at)
 
 The ``@`` (at) operator is intended to be used for matrix multiplication.  No
 builtin Python types implement this operator.
@@ -1109,6 +1163,8 @@ builtin Python types implement this operator.
 .. index::
    exception: ZeroDivisionError
    single: division
+   operator: / (slash)
+   operator: //
 
 The ``/`` (division) and ``//`` (floor division) operators yield the quotient of
 their arguments.  The numeric arguments are first converted to a common type.
@@ -1117,7 +1173,9 @@ integer; the result is that of mathematical division with the 'floor' function
 applied to the result.  Division by zero raises the :exc:`ZeroDivisionError`
 exception.
 
-.. index:: single: modulo
+.. index::
+   single: modulo
+   operator: % (percent)
 
 The ``%`` (modulo) operator yields the remainder from the division of the first
 argument by the second.  The numeric arguments are first converted to a common
@@ -1142,14 +1200,20 @@ The floor division operator, the modulo operator, and the :func:`divmod`
 function are not defined for complex numbers.  Instead, convert to a floating
 point number using the :func:`abs` function if appropriate.
 
-.. index:: single: addition
+.. index::
+   single: addition
+   single: operator; + (plus)
+   single: + (plus); binary operator
 
 The ``+`` (addition) operator yields the sum of its arguments.  The arguments
 must either both be numbers or both be sequences of the same type.  In the
 former case, the numbers are converted to a common type and then added together.
 In the latter case, the sequences are concatenated.
 
-.. index:: single: subtraction
+.. index::
+   single: subtraction
+   single: operator; - (minus)
+   single: - (minus); binary operator
 
 The ``-`` (subtraction) operator yields the difference of its arguments.  The
 numeric arguments are first converted to a common type.
@@ -1160,7 +1224,10 @@ numeric arguments are first converted to a common type.
 Shifting operations
 ===================
 
-.. index:: pair: shifting; operation
+.. index::
+   pair: shifting; operation
+   operator: <<
+   operator: >>
 
 The shifting operations have lower priority than the arithmetic operations:
 
@@ -1195,7 +1262,9 @@ Each of the three bitwise operations has a different priority level:
    xor_expr: `and_expr` | `xor_expr` "^" `and_expr`
    or_expr: `xor_expr` | `or_expr` "|" `xor_expr`
 
-.. index:: pair: bitwise; and
+.. index::
+   pair: bitwise; and
+   operator: & (ampersand)
 
 The ``&`` operator yields the bitwise AND of its arguments, which must be
 integers.
@@ -1203,6 +1272,7 @@ integers.
 .. index::
    pair: bitwise; xor
    pair: exclusive; or
+   operator: ^ (caret)
 
 The ``^`` operator yields the bitwise XOR (exclusive OR) of its arguments, which
 must be integers.
@@ -1210,6 +1280,7 @@ must be integers.
 .. index::
    pair: bitwise; or
    pair: inclusive; or
+   operator: | (vertical bar)
 
 The ``|`` operator yields the bitwise (inclusive) OR of its arguments, which
 must be integers.
@@ -1220,9 +1291,15 @@ must be integers.
 Comparisons
 ===========
 
-.. index:: single: comparison
-
-.. index:: pair: C; language
+.. index::
+   single: comparison
+   pair: C; language
+   operator: < (less)
+   operator: > (greater)
+   operator: <=
+   operator: >=
+   operator: ==
+   operator: !=
 
 Unlike C, all comparison operations in Python have the same priority, which is
 lower than that of any arithmetic, shifting or bitwise operation.  Also unlike
@@ -1526,7 +1603,7 @@ returned; otherwise, *y* is evaluated and the resulting value is returned.
 The expression ``x or y`` first evaluates *x*; if *x* is true, its value is
 returned; otherwise, *y* is evaluated and the resulting value is returned.
 
-(Note that neither :keyword:`and` nor :keyword:`or` restrict the value and type
+Note that neither :keyword:`and` nor :keyword:`or` restrict the value and type
 they return to ``False`` and ``True``, but rather return the last evaluated
 argument.  This is sometimes useful, e.g., if ``s`` is a string that should be
 replaced by a default value if it is empty, the expression ``s or 'foo'`` yields
@@ -1541,6 +1618,8 @@ Conditional expressions
 .. index::
    pair: conditional; expression
    pair: ternary; operator
+   single: if; conditional expression
+   single: else; conditional expression
 
 .. productionlist::
    conditional_expression: `or_test` ["if" `or_test` "else" `expression`]
@@ -1567,10 +1646,11 @@ Lambdas
    pair: lambda; expression
    pair: lambda; form
    pair: anonymous; function
+   single: : (colon); lambda expression
 
 .. productionlist::
-   lambda_expr: "lambda" [`parameter_list`]: `expression`
-   lambda_expr_nocond: "lambda" [`parameter_list`]: `expression_nocond`
+   lambda_expr: "lambda" [`parameter_list`] ":" `expression`
+   lambda_expr_nocond: "lambda" [`parameter_list`] ":" `expression_nocond`
 
 Lambda expressions (sometimes called lambda forms) are used to create anonymous
 functions. The expression ``lambda parameters: expression`` yields a function
@@ -1591,7 +1671,9 @@ annotations.
 Expression lists
 ================
 
-.. index:: pair: expression; list
+.. index::
+   pair: expression; list
+   single: , (comma); expression list
 
 .. productionlist::
    expression_list: `expression` ("," `expression`)* [","]
@@ -1608,7 +1690,7 @@ evaluated from left to right.
 
 .. index::
    pair: iterable; unpacking
-   single: *; in expression lists
+   single: * (asterisk); in expression lists
 
 An asterisk ``*`` denotes :dfn:`iterable unpacking`.  Its operand must be
 an :term:`iterable`.  The iterable is expanded into a sequence of items,
@@ -1653,7 +1735,8 @@ their suffixes::
 Operator precedence
 ===================
 
-.. index:: pair: operator; precedence
+.. index::
+   pair: operator; precedence
 
 The following table summarizes the operator precedence in Python, from lowest
 precedence (least binding) to highest precedence (most binding).  Operators in
@@ -1701,7 +1784,7 @@ precedence and have a left-to-right chaining feature as described in the
 +-----------------------------------------------+-------------------------------------+
 | ``**``                                        | Exponentiation [#]_                 |
 +-----------------------------------------------+-------------------------------------+
-| ``await`` ``x``                               | Await expression                    |
+| :keyword:`await` ``x``                        | Await expression                    |
 +-----------------------------------------------+-------------------------------------+
 | ``x[index]``, ``x[index:index]``,             | Subscription, slicing,              |
 | ``x(arguments...)``, ``x.attribute``          | call, attribute reference           |
index 61f5853..b295eed 100644 (file)
@@ -128,8 +128,8 @@ Namespace packages
 ------------------
 
 .. index::
-    pair:: package; namespace
-    pair:: package; portion
+    pair: package; namespace
+    pair: package; portion
 
 A namespace package is a composite of various :term:`portions <portion>`,
 where each portion contributes a subpackage to the parent package.  Portions
@@ -925,7 +925,7 @@ In :ref:`the remaining cases <using-on-interface-options>`
 :mod:`__main__` does not correspond directly with an importable module:
 
 - interactive prompt
-- -c switch
+- :option:`-c` option
 - running from stdin
 - running directly from a source or bytecode file
 
index a861996..bee0244 100644 (file)
@@ -65,6 +65,7 @@ Comments
 --------
 
 .. index:: comment, hash character
+   single: # (hash); comment
 
 A comment starts with a hash character (``#``) that is not part of a string
 literal, and ends at the end of the physical line.  A comment signifies the end
@@ -78,6 +79,7 @@ Encoding declarations
 ---------------------
 
 .. index:: source character set, encoding declarations (source file)
+   single: # (hash); source encoding declaration
 
 If a comment in the first or second line of the Python script matches the
 regular expression ``coding[=:]\s*([-\w.]+)``, this comment is processed as an
@@ -349,6 +351,9 @@ exactly as written here:
    assert     else       import     pass
    break      except     in         raise
 
+.. index::
+   single: _, identifiers
+   single: __, identifiers
 .. _id-classes:
 
 Reserved classes of identifiers
@@ -395,13 +400,16 @@ Literals
 Literals are notations for constant values of some built-in types.
 
 
+.. index:: string literal, bytes literal, ASCII
+   single: ' (single quote); string literal
+   single: " (double quote); string literal
+   single: u'; string literal
+   single: u"; string literal
 .. _strings:
 
 String and Bytes literals
 -------------------------
 
-.. index:: string literal, bytes literal, ASCII
-
 String literals are described by the following lexical definitions:
 
 .. productionlist::
@@ -434,6 +442,8 @@ declaration; it is UTF-8 if no encoding declaration is given in the source file;
 see section :ref:`encodings`.
 
 .. index:: triple-quoted string, Unicode Consortium, raw string
+   single: """; string literal
+   single: '''; string literal
 
 In plain English: Both types of literals can be enclosed in matching single quotes
 (``'``) or double quotes (``"``).  They can also be enclosed in matching groups
@@ -442,11 +452,19 @@ of three single or double quotes (these are generally referred to as
 characters that otherwise have a special meaning, such as newline, backslash
 itself, or the quote character.
 
+.. index::
+   single: b'; bytes literal
+   single: b"; bytes literal
+
 Bytes literals are always prefixed with ``'b'`` or ``'B'``; they produce an
 instance of the :class:`bytes` type instead of the :class:`str` type.  They
 may only contain ASCII characters; bytes with a numeric value of 128 or greater
 must be expressed with escapes.
 
+.. index::
+   single: r'; raw string literal
+   single: r"; raw string literal
+
 Both string and bytes literals may optionally be prefixed with a letter ``'r'``
 or ``'R'``; such strings are called :dfn:`raw strings` and treat backslashes as
 literal characters.  As a result, in string literals, ``'\U'`` and ``'\u'``
@@ -463,6 +481,10 @@ is not supported.
    to simplify the maintenance of dual Python 2.x and 3.x codebases.
    See :pep:`414` for more information.
 
+.. index::
+   single: f'; formatted string literal
+   single: f"; formatted string literal
+
 A string literal with ``'f'`` or ``'F'`` in its prefix is a
 :dfn:`formatted string literal`; see :ref:`f-strings`.  The ``'f'`` may be
 combined with ``'r'``, but not with ``'b'`` or ``'u'``, therefore raw
@@ -473,6 +495,19 @@ retained), except that three unescaped quotes in a row terminate the literal.  (
 "quote" is the character used to open the literal, i.e. either ``'`` or ``"``.)
 
 .. index:: physical line, escape sequence, Standard C, C
+   single: \ (backslash); escape sequence
+   single: \\; escape sequence
+   single: \a; escape sequence
+   single: \b; escape sequence
+   single: \f; escape sequence
+   single: \n; escape sequence
+   single: \r; escape sequence
+   single: \t; escape sequence
+   single: \v; escape sequence
+   single: \x; escape sequence
+   single: \N; escape sequence
+   single: \u; escape sequence
+   single: \U; escape sequence
 
 Unless an ``'r'`` or ``'R'`` prefix is present, escape sequences in string and
 bytes literals are interpreted according to rules similar to those used by
@@ -601,6 +636,9 @@ and formatted string literals may be concatenated with plain string literals.
    single: string; formatted literal
    single: string; interpolated literal
    single: f-string
+   single: {} (curly brackets); in formatted string literal
+   single: ! (exclamation); in formatted string literal
+   single: : (colon); in formatted string literal
 .. _f-strings:
 
 Formatted string literals
@@ -735,6 +773,12 @@ actually an expression composed of the unary operator '``-``' and the literal
 ``1``.
 
 
+.. index::
+   single: 0b; integer literal
+   single: 0o; integer literal
+   single: 0x; integer literal
+   single: _ (underscore); in numeric literal
+
 .. _integers:
 
 Integer literals
@@ -775,6 +819,10 @@ Some examples of integer literals::
    Underscores are now allowed for grouping purposes in literals.
 
 
+.. index::
+   single: . (dot); in numeric literal
+   single: e; in numeric literal
+   single: _ (underscore); in numeric literal
 .. _floating:
 
 Floating point literals
@@ -803,6 +851,8 @@ Some examples of floating point literals::
    Underscores are now allowed for grouping purposes in literals.
 
 
+.. index::
+   single: j; in numeric literal
 .. _imaginary:
 
 Imaginary literals
index 76630df..8a6714d 100644 (file)
@@ -25,6 +25,7 @@ simple statements is:
               : | `break_stmt`
               : | `continue_stmt`
               : | `import_stmt`
+              : | `future_stmt`
               : | `global_stmt`
               : | `nonlocal_stmt`
 
@@ -71,7 +72,7 @@ Assignment statements
 =====================
 
 .. index::
-   single: =; assignment statement
+   single: = (equals); assignment statement
    pair: assignment; statement
    pair: binding; name
    pair: rebinding; name
@@ -112,17 +113,18 @@ unacceptable.  The rules observed by various types and the exceptions raised are
 given with the definition of the object types (see section :ref:`types`).
 
 .. index:: triple: target; list; assignment
+   single: , (comma); in target list
+   single: * (asterisk); in assignment target list
+   single: [] (square brackets); in assignment target list
+   single: () (parentheses); in assignment target list
 
 Assignment of an object to a target list, optionally enclosed in parentheses or
 square brackets, is recursively defined as follows.
 
-* If the target list is empty: The object must also be an empty iterable.
+* If the target list is a single target with no trailing comma,
+  optionally in parentheses, the object is assigned to that target.
 
-* If the target list is a single target in parentheses: The object is assigned
-  to that target.
-
-* If the target list is a comma-separated list of targets, or a single target
-  in square brackets: The object must be an iterable with the same number of
+* Else: The object must be an iterable with the same number of
   items as there are targets in the target list, and the items are assigned,
   from left to right, to the corresponding targets.
 
@@ -321,6 +323,7 @@ Annotated assignment statements
 .. index::
    pair: annotated; assignment
    single: statement; assignment, annotated
+   single: : (colon); annotated variable
 
 Annotation assignment is the combination, in a single statement,
 of a variable or attribute annotation and an optional assignment statement:
@@ -353,8 +356,15 @@ target, then the interpreter evaluates the target except for the last
 
 .. seealso::
 
-   :pep:`526` - Variable and attribute annotation syntax
+   :pep:`526` - Syntax for Variable Annotations
+      The proposal that added syntax for annotating the types of variables
+      (including class variables and instance variables), instead of expressing
+      them through comments.
+
    :pep:`484` - Type hints
+      The proposal that added the :mod:`typing` module to provide a standard
+      syntax for type annotations that can be used in static analysis tools and
+      IDEs.
 
 
 .. _assert:
@@ -365,6 +375,7 @@ The :keyword:`assert` statement
 .. index::
    statement: assert
    pair: debugging; assertions
+   single: , (comma); expression list
 
 Assert statements are a convenient way to insert debugging assertions into a
 program:
@@ -389,7 +400,7 @@ The extended form, ``assert expression1, expression2``, is equivalent to ::
 These equivalences assume that :const:`__debug__` and :exc:`AssertionError` refer to
 the built-in variables with those names.  In the current implementation, the
 built-in variable :const:`__debug__` is ``True`` under normal circumstances,
-``False`` when optimization is requested (command line option -O).  The current
+``False`` when optimization is requested (command line option :option:`-O`).  The current
 code generator emits no code for an assert statement when optimization is
 requested at compile time.  Note that it is unnecessary to include the source
 code for the expression that failed in the error message; it will be displayed
@@ -706,6 +717,9 @@ The :keyword:`import` statement
    single: module; importing
    pair: name; binding
    keyword: from
+   keyword: as
+   exception: ImportError
+   single: , (comma); import statement
 
 .. productionlist::
    import_stmt: "import" `module` ["as" `identifier`] ("," `module` ["as" `identifier`])*
@@ -755,8 +769,7 @@ available in the local namespace in one of three ways:
 
 .. index::
    pair: name; binding
-   keyword: from
-   exception: ImportError
+   single: from; import statement
 
 The :keyword:`from` form uses a slightly more complex process:
 
@@ -780,6 +793,8 @@ Examples::
    from foo.bar import baz    # foo.bar.baz imported and bound as baz
    from foo import attr       # foo imported and foo.attr bound as attr
 
+.. index:: single: * (asterisk); import statement
+
 If the list of identifiers is replaced by a star (``'*'``), all public
 names defined in the module are bound in the local namespace for the scope
 where the :keyword:`import` statement occurs.
@@ -825,7 +840,9 @@ determine dynamically the modules to be loaded.
 Future statements
 -----------------
 
-.. index:: pair: future; statement
+.. index::
+   pair: future; statement
+   single: __future__; future statement
 
 A :dfn:`future statement` is a directive to the compiler that a particular
 module should be compiled using syntax or semantics that will be available in a
@@ -909,6 +926,7 @@ The :keyword:`global` statement
 .. index::
    statement: global
    triple: global; name; binding
+   single: , (comma); identifier list
 
 .. productionlist::
    global_stmt: "global" `identifier` ("," `identifier`)*
@@ -953,6 +971,7 @@ The :keyword:`nonlocal` statement
 =================================
 
 .. index:: statement: nonlocal
+   single: , (comma); identifier list
 
 .. productionlist::
    nonlocal_stmt: "nonlocal" `identifier` ("," `identifier`)*
index 6f2e357..e999971 100644 (file)
@@ -8,6 +8,8 @@ https://bugs.python.org/issue32174
 import re
 from html.entities import codepoint2name
 
+from sphinx.util.logging import getLogger
+
 # escape the characters which codepoint > 0x7F
 def _process(string):
     def escape(matchobj):
@@ -23,7 +25,7 @@ def _process(string):
 
 def escape_for_chm(app, pagename, templatename, context, doctree):
     # only works for .chm output
-    if not hasattr(app.builder, 'name') or app.builder.name != 'htmlhelp':
+    if getattr(app.builder, 'name', '') != 'htmlhelp':
         return
 
     # escape the `body` part to 7-bit ASCII
@@ -31,9 +33,25 @@ def escape_for_chm(app, pagename, templatename, context, doctree):
     if body is not None:
         context['body'] = _process(body)
 
+def fixup_keywords(app, exception):
+    # only works for .chm output
+    if getattr(app.builder, 'name', '') != 'htmlhelp' or exception:
+        return
+
+    getLogger(__name__).info('fixing HTML escapes in keywords file...')
+    outdir = app.builder.outdir
+    outname = app.builder.config.htmlhelp_basename
+    with app.builder.open_file(outdir, outname + '.hhk', 'r') as f:
+        index = f.read()
+    with app.builder.open_file(outdir, outname + '.hhk', 'w') as f:
+        f.write(index.replace('&#x27;', '&#39;'))
+
 def setup(app):
     # `html-page-context` event emitted when the HTML builder has
     # created a context dictionary to render a template with.
     app.connect('html-page-context', escape_for_chm)
+    # `build-finished` event emitted when all the files have been
+    # output.
+    app.connect('build-finished', fixup_keywords)
 
     return {'version': '1.0', 'parallel_read_safe': True}
index 02e7a13..dec7f0c 100644 (file)
@@ -11,7 +11,7 @@
 
 import re
 import codecs
-from os import path
+from os import getenv, path
 from time import asctime
 from pprint import pformat
 from docutils.io import StringOutput
@@ -253,7 +253,9 @@ class MiscNews(Directive):
         fname = self.arguments[0]
         source = self.state_machine.input_lines.source(
             self.lineno - self.state_machine.input_offset - 1)
-        source_dir = path.dirname(path.abspath(source))
+        source_dir = getenv('PY_MISC_NEWS_DIR')
+        if not source_dir:
+            source_dir = path.dirname(path.abspath(source))
         fpath = path.join(source_dir, fname)
         self.state.document.settings.record_dependencies.add(fpath)
         try:
@@ -388,11 +390,9 @@ def setup(app):
     app.add_directive('deprecated-removed', DeprecatedRemoved)
     app.add_builder(PydocTopicsBuilder)
     app.add_builder(suspicious.CheckSuspiciousMarkupBuilder)
-    app.add_description_unit('opcode', 'opcode', '%s (opcode)',
-                             parse_opcode_signature)
-    app.add_description_unit('pdbcommand', 'pdbcmd', '%s (pdb command)',
-                             parse_pdb_command)
-    app.add_description_unit('2to3fixer', '2to3fixer', '%s (2to3 fixer)')
+    app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature)
+    app.add_object_type('pdbcommand', 'pdbcmd', '%s (pdb command)', parse_pdb_command)
+    app.add_object_type('2to3fixer', '2to3fixer', '%s (2to3 fixer)')
     app.add_directive_to_domain('py', 'decorator', PyDecoratorFunction)
     app.add_directive_to_domain('py', 'decoratormethod', PyDecoratorMethod)
     app.add_directive_to_domain('py', 'coroutinefunction', PyCoroutineFunction)
index d885ff2..20dad93 100644 (file)
       else
         buf.push('<option value="' + language + '">' + title + '</option>');
     });
+    if (!(current_language in all_languages)) {
+        // In case we're browsing a language that is not yet in all_languages.
+        buf.push('<option value="' + current_language + '" selected="selected">' +
+                 current_language + '</option>');
+        all_languages[current_language] = current_language;
+    }
     buf.push('</select>');
     return buf.join('');
   }
index 482ffc0..ed434ce 100644 (file)
@@ -14,7 +14,7 @@ faq/programming,,:chr,">=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,
 faq/programming,,::,for x in sequence[::-1]:
 faq/programming,,:reduce,"print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y,"
 faq/programming,,:reduce,"Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro,"
-faq/windows,,:bd8afb90ebf2,"Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit (Intel)] on win32"
+faq/windows,,:d48eceb,"Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32"
 howto/cporting,,:encode,"if (!PyArg_ParseTuple(args, ""O:encode_object"", &myobj))"
 howto/cporting,,:say,"if (!PyArg_ParseTuple(args, ""U:say_hello"", &name))"
 howto/curses,,:black,"colors when it activates color mode.  They are: 0:black, 1:red,"
@@ -180,9 +180,17 @@ library/pathlib,,:Program,>>> PureWindowsPath('c:Program Files/').anchor
 library/pdb,,:lineno,filename:lineno
 library/pickle,,:memory,"conn = sqlite3.connect("":memory:"")"
 library/posix,,`,"CFLAGS=""`getconf LFS_CFLAGS`"" OPT=""-g -O2 $CFLAGS"""
-library/pprint,,::,"'Programming Language :: Python :: 2 :: Only'],"
 library/pprint,,::,"'Programming Language :: Python :: 2.6',"
 library/pprint,,::,"'Programming Language :: Python :: 2.7',"
+library/pprint,225,::,"'classifiers': ['Development Status :: 3 - Alpha',"
+library/pprint,225,::,"'Intended Audience :: Developers',"
+library/pprint,225,::,"'License :: OSI Approved :: MIT License',"
+library/pprint,225,::,"'Programming Language :: Python :: 2',"
+library/pprint,225,::,"'Programming Language :: Python :: 3',"
+library/pprint,225,::,"'Programming Language :: Python :: 3.2',"
+library/pprint,225,::,"'Programming Language :: Python :: 3.3',"
+library/pprint,225,::,"'Programming Language :: Python :: 3.4',"
+library/pprint,225,::,"'Topic :: Software Development :: Build Tools'],"
 library/profile,,:lineno,filename:lineno(function)
 library/pyexpat,,:elem1,<py:elem1 />
 library/pyexpat,,:py,"xmlns:py = ""http://www.python.org/ns/"">"
index 3131050..e69e9a3 100644 (file)
@@ -1,12 +1,13 @@
 <h3>{% trans %}Download{% endtrans %}</h3>
 <p><a href="{{ pathto('download') }}">{% trans %}Download these documents{% endtrans %}</a></p>
-<h3>{% trans %}Docs for other versions{% endtrans %}</h3>
+<h3>{% trans %}Docs by version{% endtrans %}</h3>
 <ul>
   <li><a href="https://docs.python.org/3.8/">{% trans %}Python 3.8 (in development){% endtrans %}</a></li>
   <li><a href="https://docs.python.org/3.7/">{% trans %}Python 3.7 (stable){% endtrans %}</a></li>
+  <li><a href="https://docs.python.org/3.6/">{% trans %}Python 3.6 (stable){% endtrans %}</a></li>
   <li><a href="https://docs.python.org/3.5/">{% trans %}Python 3.5 (security-fixes){% endtrans %}</a></li>
   <li><a href="https://docs.python.org/2.7/">{% trans %}Python 2.7 (stable){% endtrans %}</a></li>
-  <li><a href="https://www.python.org/doc/versions/">{% trans %}Old versions{% endtrans %}</a></li>
+  <li><a href="https://www.python.org/doc/versions/">{% trans %}All versions{% endtrans %}</a></li>
 </ul>
 
 <h3>{% trans %}Other resources{% endtrans %}</h3>
index f26838c..914da42 100644 (file)
@@ -672,6 +672,9 @@ be treated as a non-public part of the API (whether it is a function, a method
 or a data member).  It should be considered an implementation detail and subject
 to change without notice.
 
+.. index::
+   pair: name; mangling
+
 Since there is a valid use-case for class-private members (namely to avoid name
 clashes of names with names defined by subclasses), there is limited support for
 such a mechanism, called :dfn:`name mangling`.  Any identifier of the form
@@ -703,6 +706,11 @@ breaking intraclass method calls.  For example::
            for item in zip(keys, values):
                self.items_list.append(item)
 
+The above example would work even if ``MappingSubclass`` were to introduce a
+``__update`` identifier since it is replaced with ``_Mapping__update`` in the
+``Mapping`` class  and ``_MappingSubclass__update`` in the ``MappingSubclass``
+class respectively.
+
 Note that the mangling rules are designed mostly to avoid accidents; it still is
 possible to access or modify a variable that is considered private.  This can
 even be useful in special circumstances, such as in the debugger.
index 4bcdafd..bf6fbe2 100644 (file)
@@ -526,7 +526,7 @@ Arbitrary Argument Lists
 ------------------------
 
 .. index::
-  statement: *
+   single: * (asterisk); in function calls
 
 Finally, the least frequently used option is to specify that a function can be
 called with an arbitrary number of arguments.  These arguments will be wrapped
@@ -570,10 +570,10 @@ or tuple::
    [3, 4, 5]
 
 .. index::
-  statement: **
+   single: **; in function calls
 
-In the same fashion, dictionaries can deliver keyword arguments with the ``**``\
--operator::
+In the same fashion, dictionaries can deliver keyword arguments with the
+``**``\ -operator::
 
    >>> def parrot(voltage, state='a stiff', action='voom'):
    ...     print("-- This parrot wouldn't", action, end=' ')
@@ -675,7 +675,8 @@ Function Annotations
 .. sectionauthor:: Zachary Ware <zachary.ware@gmail.com>
 .. index::
    pair: function; annotations
-   single: -> (return annotation assignment)
+   single: ->; function annotations
+   single: : (colon); function annotations
 
 :ref:`Function annotations <function>` are completely optional metadata
 information about the types used by user-defined functions (see :pep:`3107` and
index aba61da..957cbf9 100644 (file)
@@ -314,7 +314,7 @@ to create specific exception classes for different error conditions::
            self.next = next
            self.message = message
 
-Most exceptions are defined with names that end in "Error," similar to the
+Most exceptions are defined with names that end in "Error", similar to the
 naming of the standard exceptions.
 
 Many standard modules define their own exceptions to report errors that may
index 2454bf0..5d6812d 100644 (file)
@@ -11,6 +11,8 @@ with a prompt are output from the interpreter. Note that a secondary prompt on a
 line by itself in an example means you must type a blank line; this is used to
 end a multi-line command.
 
+.. index:: single: # (hash); comment
+
 Many of the examples in this manual, even those entered at the interactive
 prompt, include comments.  Comments in Python start with the hash character,
 ``#``, and extend to the end of the physical line.  A comment may appear at the
index 858d2e1..51caf0f 100644 (file)
@@ -140,7 +140,7 @@ Editors and IDEs
 ================
 
 There are a number of IDEs that support Python programming language.
-Many editors and IDEs provide syntax highlighting, debugging tools, and PEP-8 checks.
+Many editors and IDEs provide syntax highlighting, debugging tools, and :pep:`8` checks.
 
 Please go to `Python Editors <https://wiki.python.org/moin/PythonEditors>`_ and
 `Integrated Development Environments <https://wiki.python.org/moin/IntegratedDevelopmentEnvironments>`_
index 4c7795a..d2f76af 100644 (file)
@@ -7,9 +7,10 @@ Running this command creates the target directory (creating any parent
 directories that don't exist already) and places a ``pyvenv.cfg`` file in it
 with a ``home`` key pointing to the Python installation from which the command
 was run.  It also creates a ``bin`` (or ``Scripts`` on Windows) subdirectory
-containing a copy of the ``python`` binary (or binaries, in the case of
-Windows).  It also creates an (initially empty) ``lib/pythonX.Y/site-packages``
-subdirectory (on Windows, this is ``Lib\site-packages``). If an existing
+containing a copy/symlink of the Python binary/binaries (as appropriate for the
+platform or arguments used at environment creation time). It also creates an
+(initially empty) ``lib/pythonX.Y/site-packages`` subdirectory
+(on Windows, this is ``Lib\site-packages``). If an existing
 directory is specified, it will be re-used.
 
 .. deprecated:: 3.6
@@ -87,7 +88,8 @@ path.
 
 Once a virtual environment has been created, it can be "activated" using a
 script in the virtual environment's binary directory. The invocation of the
-script is platform-specific:
+script is platform-specific (`<venv>` must be replaced by the path of the
+directory containing the virtual environment):
 
 +-------------+-----------------+-----------------------------------------+
 | Platform    | Shell           | Command to activate virtual environment |
index a429468..0ee6656 100644 (file)
@@ -613,11 +613,11 @@ user's "application data" directory (i.e. the directory returned by calling the
 Windows function ``SHGetFolderPath`` with ``CSIDL_LOCAL_APPDATA``) and ``py.ini`` in the
 same directory as the launcher. The same .ini files are used for both the
 'console' version of the launcher (i.e. py.exe) and for the 'windows' version
-(i.e. pyw.exe)
+(i.e. pyw.exe).
 
 Customization specified in the "application directory" will have precedence over
 the one next to the executable, so a user, who may not have write access to the
-.ini file next to the launcher, can override commands in that global .ini file)
+.ini file next to the launcher, can override commands in that global .ini file.
 
 Customizing default Python versions
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index a0bb81a..9671db2 100644 (file)
@@ -576,9 +576,9 @@ similar to a :keyword:`return` statement.  The big difference between
 variables are preserved.  On the next call to the generator's ``next()`` method,
 the function will resume executing immediately after the :keyword:`yield`
 statement.  (For complicated reasons, the :keyword:`yield` statement isn't
-allowed inside the :keyword:`try` block of a :keyword:`try`...\
-:keyword:`finally` statement; read :pep:`255` for a full explanation of the
-interaction between :keyword:`yield` and exceptions.)
+allowed inside the :keyword:`try` block of a
+:keyword:`try`...\ :keyword:`finally` statement; read :pep:`255` for a full
+explanation of the interaction between :keyword:`yield` and exceptions.)
 
 Here's a sample usage of the :func:`generate_ints` generator::
 
index 5cdd51b..7290695 100644 (file)
@@ -162,9 +162,9 @@ similar to a :keyword:`return` statement.  The big difference between
 variables are preserved.  On the next call to the generator's ``.next()``
 method, the function will resume executing immediately after the
 :keyword:`yield` statement.  (For complicated reasons, the :keyword:`yield`
-statement isn't allowed inside the :keyword:`try` block of a :keyword:`try`...\
-:keyword:`finally` statement; read :pep:`255` for a full explanation of the
-interaction between :keyword:`yield` and exceptions.)
+statement isn't allowed inside the :keyword:`try` block of a
+:keyword:`try`...\ :keyword:`finally` statement; read :pep:`255` for a full
+explanation of the interaction between :keyword:`yield` and exceptions.)
 
 Here's a sample usage of the :func:`generate_ints` generator::
 
@@ -1247,8 +1247,8 @@ complete list of changes, or look through the CVS logs for all the details.
   will have to change your ``import`` statements to import it as :mod:`bsddb`.
 
 * The new :mod:`bz2` module is an interface to the bz2 data compression library.
-  bz2-compressed data is usually smaller than  corresponding :mod:`zlib`\
-  -compressed data. (Contributed by Gustavo Niemeyer.)
+  bz2-compressed data is usually smaller than  corresponding
+  :mod:`zlib`\ -compressed data. (Contributed by Gustavo Niemeyer.)
 
 * A set of standard date/time types has been added in the new :mod:`datetime`
   module.  See the following section for more details.
index b0defba..8c262eb 100644 (file)
@@ -448,8 +448,9 @@ when you're doing something with the returned value, as in the above example.
 The parentheses aren't always necessary, but it's easier to always add them
 instead of having to remember when they're needed.
 
-(:pep:`342` explains the exact rules, which are that a :keyword:`yield`\
--expression must always be parenthesized except when it occurs at the top-level
+(:pep:`342` explains the exact rules, which are that a
+:keyword:`yield`\ -expression must always be parenthesized except when it
+occurs at the top-level
 expression on the right-hand side of an assignment.  This means you can write
 ``val = yield i`` but have to use parentheses when there's an operation, as in
 ``val = (yield i) + 12``.)
index 6597170..1099623 100644 (file)
@@ -1452,10 +1452,10 @@ in :issue:`18143`.)
 
 :class:`~ssl.SSLContext` has a new method,
 :meth:`~ssl.SSLContext.cert_store_stats`, that reports the number of loaded
-``X.509`` certs, ``X.509 CA`` certs, and certificate revocation lists (``crl``\
-s), as well as a :meth:`~ssl.SSLContext.get_ca_certs` method that returns a
-list of the loaded ``CA`` certificates.  (Contributed by Christian Heimes in
-:issue:`18147`.)
+``X.509`` certs, ``X.509 CA`` certs, and certificate revocation lists
+(``crl``\ s), as well as a :meth:`~ssl.SSLContext.get_ca_certs` method that
+returns a list of the loaded ``CA`` certificates.  (Contributed by Christian
+Heimes in :issue:`18147`.)
 
 If OpenSSL 0.9.8 or later is available, :class:`~ssl.SSLContext` has a new
 attribute :attr:`~ssl.SSLContext.verify_flags` that can be used to control the
index 96a8831..0095844 100644 (file)
@@ -2433,3 +2433,8 @@ Notable changes in Python 3.6.7
 
 :mod:`xml.dom.minidom` and mod:`xml.sax` modules no longer process
 external entities by default. See also :issue:`17239`.
+
+In 3.6.7 the :mod:`tokenize` module now implicitly emits a ``NEWLINE`` token
+when provided with input that does not have a trailing new line.  This behavior
+now matches what the C tokenizer does internally.
+(Contributed by Ammar Askar in :issue:`33899`.)
index 6177bad..bf1dfac 100644 (file)
 #include "pyport.h"
 #include "pymacro.h"
 
+/* A convenient way for code to know if clang's memory sanitizer is enabled. */
+#if defined(__has_feature)
+#  if __has_feature(memory_sanitizer)
+#    if !defined(_Py_MEMORY_SANITIZER)
+#      define _Py_MEMORY_SANITIZER
+#    endif
+#  endif
+#endif
+
 #include "pyatomic.h"
 
 /* Debug-mode build with pymalloc implies PYMALLOC_DEBUG.
index 38d4709..f46aef1 100644 (file)
@@ -38,10 +38,12 @@ PyAPI_FUNC(PyObject *) PyEval_GetGlobals(void);
 PyAPI_FUNC(PyObject *) PyEval_GetLocals(void);
 PyAPI_FUNC(struct _frame *) PyEval_GetFrame(void);
 
+#ifndef Py_LIMITED_API
+/* Helper to look up a builtin object */
+PyAPI_FUNC(PyObject *) _PyEval_GetBuiltinId(_Py_Identifier *);
 /* Look at the current frame's (if any) code's co_flags, and turn on
    the corresponding compiler flags in cf->cf_flags.  Return 1 if any
    flag was set, else return 0. */
-#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf);
 #endif
 
index 9fce7d2..4efcf13 100644 (file)
@@ -29,6 +29,19 @@ PyAPI_FUNC(char*) _Py_EncodeLocaleEx(
 
 PyAPI_FUNC(PyObject *) _Py_device_encoding(int);
 
+#if defined(MS_WINDOWS) || defined(__APPLE__)
+    /* On Windows, the count parameter of read() is an int (bpo-9015, bpo-9611).
+       On macOS 10.13, read() and write() with more than INT_MAX bytes
+       fail with EINVAL (bpo-24658). */
+#   define _PY_READ_MAX  INT_MAX
+#   define _PY_WRITE_MAX INT_MAX
+#else
+    /* write() should truncate the input to PY_SSIZE_T_MAX bytes,
+       but it's safer to do it ourself to have a portable behaviour */
+#   define _PY_READ_MAX  PY_SSIZE_T_MAX
+#   define _PY_WRITE_MAX PY_SSIZE_T_MAX
+#endif
+
 #ifdef MS_WINDOWS
 struct _Py_stat_struct {
     unsigned long st_dev;
index 63e37b8..deac940 100644 (file)
@@ -520,6 +520,7 @@ struct _Py_Identifier;
 PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
 PyAPI_FUNC(void) _Py_BreakPoint(void);
 PyAPI_FUNC(void) _PyObject_Dump(PyObject *);
+PyAPI_FUNC(int) _PyObject_IsFreed(PyObject *);
 #endif
 PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
 PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *);
index ee403a8..065b0cc 100644 (file)
 /*--start constants--*/
 #define PY_MAJOR_VERSION       3
 #define PY_MINOR_VERSION       6
-#define PY_MICRO_VERSION       7
+#define PY_MICRO_VERSION       8
 #define PY_RELEASE_LEVEL       PY_RELEASE_LEVEL_FINAL
 #define PY_RELEASE_SERIAL      0
 
 /* Version as a string */
-#define PY_VERSION             "3.6.7"
+#define PY_VERSION             "3.6.8"
 /*--end constants--*/
 
 /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
index c28c137..44f2030 100644 (file)
@@ -93,9 +93,9 @@ PyAPI_FUNC(void) PyErr_SetExcInfo(PyObject *, PyObject *, PyObject *);
 #endif
 
 #if defined(__clang__) || \
-    (defined(__GNUC_MAJOR__) && \
-     ((__GNUC_MAJOR__ >= 3) || \
-      (__GNUC_MAJOR__ == 2) && (__GNUC_MINOR__ >= 5)))
+    (defined(__GNUC__) && \
+     ((__GNUC__ >= 3) || \
+      (__GNUC__ == 2) && (__GNUC_MINOR__ >= 5)))
 #define _Py_NO_RETURN __attribute__((__noreturn__))
 #else
 #define _Py_NO_RETURN
index 01abfa9..9a52821 100644 (file)
@@ -27,7 +27,9 @@ PyAPI_FUNC(void) Py_InitializeEx(int);
 PyAPI_FUNC(void) _Py_InitializeEx_Private(int, int);
 #endif
 PyAPI_FUNC(void) Py_Finalize(void);
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000
 PyAPI_FUNC(int) Py_FinalizeEx(void);
+#endif
 PyAPI_FUNC(int) Py_IsInitialized(void);
 PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void);
 PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *);
index a7eb4d2..a9f0186 100644 (file)
@@ -59,7 +59,9 @@ PyAPI_FUNC(int) _PyTraceMalloc_Untrack(
 PyAPI_FUNC(PyObject*) _PyTraceMalloc_GetTraceback(
     _PyTraceMalloc_domain_t domain,
     uintptr_t ptr);
-#endif   /* !Py_LIMITED_API */
+
+PyAPI_FUNC(int) _PyMem_IsFreed(void *ptr, size_t size);
+#endif   /* !defined(Py_LIMITED_API) */
 
 
 /* BEWARE:
index f498873..c81a381 100644 (file)
@@ -2143,10 +2143,10 @@ PyAPI_FUNC(PyObject *) _PyUnicode_XStrip(
    see Objects/stringlib/localeutil.h */
 #ifndef Py_LIMITED_API
 PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGrouping(
-    PyObject *unicode,
-    Py_ssize_t index,
+    _PyUnicodeWriter *writer,
     Py_ssize_t n_buffer,
-    void *digits,
+    PyObject *digits,
+    Py_ssize_t d_pos,
     Py_ssize_t n_digits,
     Py_ssize_t min_width,
     const char *grouping,
index e37852e..db6674e 100644 (file)
@@ -17,7 +17,7 @@ __all__ = [
 _UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS',
                             'BLDSHARED', 'LDSHARED', 'CC', 'CXX',
                             'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
-                            'PY_CORE_CFLAGS')
+                            'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS')
 
 # configuration variables that may contain compiler calls
 _COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX')
index 0b40928..e7df67d 100644 (file)
@@ -2062,7 +2062,7 @@ class Decimal(object):
         if not other and not self:
             return context._raise_error(InvalidOperation,
                                         'at least one of pow() 1st argument '
-                                        'and 2nd argument must be nonzero ;'
+                                        'and 2nd argument must be nonzero'
                                         '0**0 is not defined')
 
         # compute sign of result
index accd669..48dd1fc 100644 (file)
@@ -182,6 +182,17 @@ def _ensure_resolved(address, *, family=0, type=socket.SOCK_STREAM, proto=0,
                                 proto=proto, flags=flags)
 
 
+if hasattr(socket, 'TCP_NODELAY'):
+    def _set_nodelay(sock):
+        if (sock.family in {socket.AF_INET, socket.AF_INET6} and
+                _is_stream_socket(sock.type) and
+                sock.proto == socket.IPPROTO_TCP):
+            sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+else:
+    def _set_nodelay(sock):
+        pass
+
+
 def _run_until_complete_cb(fut):
     exc = fut._exception
     if (isinstance(exc, BaseException)
index 6f621ef..079b7a2 100644 (file)
@@ -350,6 +350,11 @@ class _ProactorSocketTransport(_ProactorReadPipeTransport,
                                transports.Transport):
     """Transport for connected sockets."""
 
+    def __init__(self, loop, sock, protocol, waiter=None,
+                 extra=None, server=None):
+        super().__init__(loop, sock, protocol, waiter, extra, server)
+        base_events._set_nodelay(sock)
+
     def _set_extra(self, sock):
         self._extra['socket'] = sock
         try:
index bc7c740..af21d5e 100644 (file)
@@ -40,17 +40,6 @@ def _test_selector_event(selector, fd, event):
         return bool(key.events & event)
 
 
-if hasattr(socket, 'TCP_NODELAY'):
-    def _set_nodelay(sock):
-        if (sock.family in {socket.AF_INET, socket.AF_INET6} and
-                base_events._is_stream_socket(sock.type) and
-                sock.proto == socket.IPPROTO_TCP):
-            sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-else:
-    def _set_nodelay(sock):
-        pass
-
-
 class BaseSelectorEventLoop(base_events.BaseEventLoop):
     """Selector event loop.
 
@@ -691,7 +680,7 @@ class _SelectorSocketTransport(_SelectorTransport):
         # Disable the Nagle algorithm -- small writes will be
         # sent without waiting for the TCP ACK.  This generally
         # decreases the latency (in some cases significantly.)
-        _set_nodelay(self._sock)
+        base_events._set_nodelay(self._sock)
 
         self._loop.call_soon(self._protocol.connection_made, self)
         # only start reading when connection_made() has been called
index f417204..116b3fc 100644 (file)
@@ -42,6 +42,21 @@ else:
     from socket import socketpair  # pragma: no cover
 
 
+def data_file(filename):
+    if hasattr(support, 'TEST_HOME_DIR'):
+        fullname = os.path.join(support.TEST_HOME_DIR, filename)
+        if os.path.isfile(fullname):
+            return fullname
+    fullname = os.path.join(os.path.dirname(os.__file__), 'test', filename)
+    if os.path.isfile(fullname):
+        return fullname
+    raise FileNotFoundError(filename)
+
+
+ONLYCERT = data_file('ssl_cert.pem')
+ONLYKEY = data_file('ssl_key.pem')
+
+
 def dummy_ssl_context():
     if ssl is None:
         return None
@@ -114,12 +129,8 @@ class SSLWSGIServerMixin:
         # contains the ssl key and certificate files) differs
         # between the stdlib and stand-alone asyncio.
         # Prefer our own if we can find it.
-        here = os.path.join(os.path.dirname(__file__), '..', 'tests')
-        if not os.path.isdir(here):
-            here = os.path.join(os.path.dirname(os.__file__),
-                                'test', 'test_asyncio')
-        keyfile = os.path.join(here, 'ssl_key.pem')
-        certfile = os.path.join(here, 'ssl_cert.pem')
+        keyfile = ONLYKEY
+        certfile = ONLYCERT
         context = ssl.SSLContext()
         context.load_cert_chain(certfile, keyfile)
 
index 6ae8512..a6d4476 100755 (executable)
@@ -121,7 +121,7 @@ def label(code):
 # ____________________________________________________________
 
 def main():
-    import os, sys
+    import os, sys, pstats
     from optparse import OptionParser
     usage = "cProfile.py [-o output_file_path] [-s sort] scriptfile [arg] ..."
     parser = OptionParser(usage=usage)
@@ -130,7 +130,8 @@ def main():
         help="Save stats to <outfile>", default=None)
     parser.add_option('-s', '--sort', dest="sort",
         help="Sort order when printing to stdout, based on pstats.Stats class",
-        default=-1)
+        default=-1,
+        choices=sorted(pstats.Stats.sort_arg_dict_default))
 
     if not sys.argv[1:]:
         parser.print_usage()
index 233a496..56f243e 100755 (executable)
@@ -404,7 +404,8 @@ class FieldStorage:
     """
     def __init__(self, fp=None, headers=None, outerboundary=b'',
                  environ=os.environ, keep_blank_values=0, strict_parsing=0,
-                 limit=None, encoding='utf-8', errors='replace'):
+                 limit=None, encoding='utf-8', errors='replace',
+                 max_num_fields=None):
         """Constructor.  Read multipart/* until last part.
 
         Arguments, all optional:
@@ -444,10 +445,14 @@ class FieldStorage:
             for the page sending the form (content-type : meta http-equiv or
             header)
 
+        max_num_fields: int. If set, then __init__ throws a ValueError
+            if there are more than n fields read by parse_qsl().
+
         """
         method = 'GET'
         self.keep_blank_values = keep_blank_values
         self.strict_parsing = strict_parsing
+        self.max_num_fields = max_num_fields
         if 'REQUEST_METHOD' in environ:
             method = environ['REQUEST_METHOD'].upper()
         self.qs_on_post = None
@@ -670,12 +675,11 @@ class FieldStorage:
         qs = qs.decode(self.encoding, self.errors)
         if self.qs_on_post:
             qs += '&' + self.qs_on_post
-        self.list = []
         query = urllib.parse.parse_qsl(
             qs, self.keep_blank_values, self.strict_parsing,
-            encoding=self.encoding, errors=self.errors)
-        for key, value in query:
-            self.list.append(MiniFieldStorage(key, value))
+            encoding=self.encoding, errors=self.errors,
+            max_num_fields=self.max_num_fields)
+        self.list = [MiniFieldStorage(key, value) for key, value in query]
         self.skip_lines()
 
     FieldStorageClass = None
@@ -689,9 +693,9 @@ class FieldStorage:
         if self.qs_on_post:
             query = urllib.parse.parse_qsl(
                 self.qs_on_post, self.keep_blank_values, self.strict_parsing,
-                encoding=self.encoding, errors=self.errors)
-            for key, value in query:
-                self.list.append(MiniFieldStorage(key, value))
+                encoding=self.encoding, errors=self.errors,
+                max_num_fields=self.max_num_fields)
+            self.list.extend(MiniFieldStorage(key, value) for key, value in query)
 
         klass = self.FieldStorageClass or self.__class__
         first_line = self.fp.readline() # bytes
@@ -706,6 +710,11 @@ class FieldStorage:
             first_line = self.fp.readline()
             self.bytes_read += len(first_line)
 
+        # Propagate max_num_fields into the sub class appropriately
+        max_num_fields = self.max_num_fields
+        if max_num_fields is not None:
+            max_num_fields -= len(self.list)
+
         while True:
             parser = FeedParser()
             hdr_text = b""
@@ -727,7 +736,15 @@ class FieldStorage:
 
             part = klass(self.fp, headers, ib, environ, keep_blank_values,
                          strict_parsing,self.limit-self.bytes_read,
-                         self.encoding, self.errors)
+                         self.encoding, self.errors, max_num_fields)
+
+            if max_num_fields is not None:
+                max_num_fields -= 1
+                if part.list:
+                    max_num_fields -= len(part.list)
+                if max_num_fields < 0:
+                    raise ValueError('Max number of fields exceeded')
+
             self.bytes_read += part.bytes_read
             self.list.append(part)
             if part.done or self.bytes_read >= self.length > 0:
index 1c9ceb6..3921046 100644 (file)
@@ -16,10 +16,6 @@ import importlib.util
 import py_compile
 import struct
 
-try:
-    from concurrent.futures import ProcessPoolExecutor
-except ImportError:
-    ProcessPoolExecutor = None
 from functools import partial
 
 __all__ = ["compile_dir","compile_file","compile_path"]
@@ -68,9 +64,17 @@ def compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None,
     optimize:  optimization level or -1 for level of the interpreter
     workers:   maximum number of parallel workers
     """
-    if workers is not None and workers < 0:
-        raise ValueError('workers must be greater or equal to 0')
-
+    ProcessPoolExecutor = None
+    if workers is not None:
+        if workers < 0:
+            raise ValueError('workers must be greater or equal to 0')
+        elif workers != 1:
+            try:
+                # Only import when needed, as low resource platforms may
+                # fail to import it
+                from concurrent.futures import ProcessPoolExecutor
+            except ImportError:
+                workers = 1
     files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels,
                       ddir=ddir)
     success = True
index 20fa056..092ec5a 100644 (file)
@@ -12,6 +12,7 @@ class BytesTest(unittest.TestCase):
             x.value = "y"
         c_char.from_param(b"x")
         self.assertRaises(TypeError, c_char.from_param, "x")
+        self.assertIn('xbd', repr(c_char.from_param(b"\xbd")))
         (c_char * 3)(b"a", b"b", b"c")
         self.assertRaises(TypeError, c_char * 3, "a", "b", "c")
 
index b8782fc..2f3aa48 100644 (file)
@@ -693,9 +693,19 @@ class date:
 
         year, month, day (required, base 1)
         """
-        if month is None and isinstance(year, bytes) and len(year) == 4 and \
-                1 <= year[2] <= 12:
+        if (month is None and
+            isinstance(year, (bytes, str)) and len(year) == 4 and
+            1 <= ord(year[2:3]) <= 12):
             # Pickle support
+            if isinstance(year, str):
+                try:
+                    year = year.encode('latin1')
+                except UnicodeEncodeError:
+                    # More informative error message.
+                    raise ValueError(
+                        "Failed to encode latin1 string when unpickling "
+                        "a date object. "
+                        "pickle.load(data, encoding='latin1') is assumed.")
             self = object.__new__(cls)
             self.__setstate(year)
             self._hashcode = -1
@@ -1056,8 +1066,18 @@ class time:
         tzinfo (default to None)
         fold (keyword only, default to zero)
         """
-        if isinstance(hour, bytes) and len(hour) == 6 and hour[0]&0x7F < 24:
+        if (isinstance(hour, (bytes, str)) and len(hour) == 6 and
+            ord(hour[0:1])&0x7F < 24):
             # Pickle support
+            if isinstance(hour, str):
+                try:
+                    hour = hour.encode('latin1')
+                except UnicodeEncodeError:
+                    # More informative error message.
+                    raise ValueError(
+                        "Failed to encode latin1 string when unpickling "
+                        "a time object. "
+                        "pickle.load(data, encoding='latin1') is assumed.")
             self = object.__new__(cls)
             self.__setstate(hour, minute or None)
             self._hashcode = -1
@@ -1368,8 +1388,18 @@ class datetime(date):
 
     def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
                 microsecond=0, tzinfo=None, *, fold=0):
-        if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2]&0x7F <= 12:
+        if (isinstance(year, (bytes, str)) and len(year) == 10 and
+            1 <= ord(year[2:3])&0x7F <= 12):
             # Pickle support
+            if isinstance(year, str):
+                try:
+                    year = bytes(year, 'latin1')
+                except UnicodeEncodeError:
+                    # More informative error message.
+                    raise ValueError(
+                        "Failed to encode latin1 string when unpickling "
+                        "a datetime object. "
+                        "pickle.load(data, encoding='latin1') is assumed.")
             self = object.__new__(cls)
             self.__setstate(year, month)
             self._hashcode = -1
index 78ae575..b002dc3 100644 (file)
@@ -166,7 +166,15 @@ def make_zipfile(base_name, base_dir, verbose=0, dry_run=0):
                 zip = zipfile.ZipFile(zip_filename, "w",
                                       compression=zipfile.ZIP_STORED)
 
+            if base_dir != os.curdir:
+                path = os.path.normpath(os.path.join(base_dir, ''))
+                zip.write(path, path)
+                log.info("adding '%s'", path)
             for dirpath, dirnames, filenames in os.walk(base_dir):
+                for name in dirnames:
+                    path = os.path.normpath(os.path.join(dirpath, name, ''))
+                    zip.write(path, path)
+                    log.info("adding '%s'", path)
                 for name in filenames:
                     path = os.path.normpath(os.path.join(dirpath, name))
                     if os.path.isfile(path):
index e9274d9..f0d6b5b 100644 (file)
@@ -32,7 +32,7 @@ class bdist_dumb(Command):
                     ('skip-build', None,
                      "skip rebuilding everything (for testing/debugging)"),
                     ('relative', None,
-                     "build the archive using relative paths"
+                     "build the archive using relative paths "
                      "(default: false)"),
                     ('owner=', 'u',
                      "Owner name used when creating a tar file"
index a4bd5a5..80104c3 100644 (file)
@@ -98,14 +98,14 @@ class bdist_msi(Command):
                     ('no-target-compile', 'c',
                      "do not compile .py to .pyc on the target system"),
                     ('no-target-optimize', 'o',
-                     "do not compile .py to .pyo (optimized)"
+                     "do not compile .py to .pyo (optimized) "
                      "on the target system"),
                     ('dist-dir=', 'd',
                      "directory to put final built distributions in"),
                     ('skip-build', None,
                      "skip rebuilding everything (for testing/debugging)"),
                     ('install-script=', None,
-                     "basename of installation script to be run after"
+                     "basename of installation script to be run after "
                      "installation or before deinstallation"),
                     ('pre-install-script=', None,
                      "Fully qualified filename of a script to be run before "
index ac46217..02f10dd 100644 (file)
@@ -58,7 +58,7 @@ class bdist_rpm(Command):
          "RPM \"vendor\" (eg. \"Joe Blow <joe@example.com>\") "
          "[default: maintainer or author from setup script]"),
         ('packager=', None,
-         "RPM packager (eg. \"Jane Doe <jane@example.net>\")"
+         "RPM packager (eg. \"Jane Doe <jane@example.net>\") "
          "[default: vendor]"),
         ('doc-files=', None,
          "list of documentation files (space or comma-separated)"),
index 0871a4f..fde5675 100644 (file)
@@ -29,7 +29,7 @@ class bdist_wininst(Command):
                     ('no-target-compile', 'c',
                      "do not compile .py to .pyc on the target system"),
                     ('no-target-optimize', 'o',
-                     "do not compile .py to .pyo (optimized)"
+                     "do not compile .py to .pyo (optimized) "
                      "on the target system"),
                     ('dist-dir=', 'd',
                      "directory to put final built distributions in"),
@@ -40,7 +40,7 @@ class bdist_wininst(Command):
                     ('skip-build', None,
                      "skip rebuilding everything (for testing/debugging)"),
                     ('install-script=', None,
-                     "basename of installation script to be run after"
+                     "basename of installation script to be run after "
                      "installation or before deinstallation"),
                     ('pre-install-script=', None,
                      "Fully qualified filename of a script to be run before "
index 74de782..8ed4065 100644 (file)
@@ -365,7 +365,7 @@ class build_ext(Command):
             ext_name, build_info = ext
 
             log.warn("old-style (ext_name, build_info) tuple found in "
-                     "ext_modules for extension '%s'"
+                     "ext_modules for extension '%s' "
                      "-- please convert to Extension instance", ext_name)
 
             if not (isinstance(ext_name, str) and
index 02fa1e2..18a0313 100644 (file)
@@ -122,12 +122,13 @@ class ArchiveUtilTestCase(support.TempdirManager,
         try:
             names = tar.getnames()
             names.sort()
-            return tuple(names)
+            return names
         finally:
             tar.close()
 
-    _created_files = ('dist', 'dist/file1', 'dist/file2',
-                      'dist/sub', 'dist/sub/file3', 'dist/sub2')
+    _zip_created_files = ['dist/', 'dist/file1', 'dist/file2',
+                          'dist/sub/', 'dist/sub/file3', 'dist/sub2/']
+    _created_files = [p.rstrip('/') for p in _zip_created_files]
 
     def _create_files(self):
         # creating something to tar
@@ -244,8 +245,7 @@ class ArchiveUtilTestCase(support.TempdirManager,
         tarball = base_name + '.zip'
         self.assertTrue(os.path.exists(tarball))
         with zipfile.ZipFile(tarball) as zf:
-            self.assertEqual(sorted(zf.namelist()),
-                             ['dist/file1', 'dist/file2', 'dist/sub/file3'])
+            self.assertEqual(sorted(zf.namelist()), self._zip_created_files)
 
     @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
     def test_make_zipfile_no_zlib(self):
@@ -271,8 +271,7 @@ class ArchiveUtilTestCase(support.TempdirManager,
                          [((tarball, "w"), {'compression': zipfile.ZIP_STORED})])
         self.assertTrue(os.path.exists(tarball))
         with zipfile.ZipFile(tarball) as zf:
-            self.assertEqual(sorted(zf.namelist()),
-                             ['dist/file1', 'dist/file2', 'dist/sub/file3'])
+            self.assertEqual(sorted(zf.namelist()), self._zip_created_files)
 
     def test_check_archive_formats(self):
         self.assertEqual(check_archive_formats(['gztar', 'xxx', 'zip']),
index c8ccdc2..01a233b 100644 (file)
@@ -84,7 +84,7 @@ class BuildDumbTestCase(support.TempdirManager,
         finally:
             fp.close()
 
-        contents = sorted(os.path.basename(fn) for fn in contents)
+        contents = sorted(filter(None, map(os.path.basename, contents)))
         wanted = ['foo-0.1-py%s.%s.egg-info' % sys.version_info[:2], 'foo.py']
         if not sys.dont_write_bytecode:
             wanted.append('foo.%s.pyc' % sys.implementation.cache_tag)
index 5444b81..23db126 100644 (file)
@@ -128,7 +128,9 @@ class SDistTestCase(BasePyPIRCCommandTestCase):
             zip_file.close()
 
         # making sure everything has been pruned correctly
-        self.assertEqual(len(content), 4)
+        expected = ['', 'PKG-INFO', 'README', 'setup.py',
+                    'somecode/', 'somecode/__init__.py']
+        self.assertEqual(sorted(content), ['fake-1.0/' + x for x in expected])
 
     @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
     @unittest.skipIf(find_executable('tar') is None,
@@ -226,7 +228,13 @@ class SDistTestCase(BasePyPIRCCommandTestCase):
             zip_file.close()
 
         # making sure everything was added
-        self.assertEqual(len(content), 12)
+        expected = ['', 'PKG-INFO', 'README', 'buildout.cfg',
+                    'data/', 'data/data.dt', 'inroot.txt',
+                    'scripts/', 'scripts/script.py', 'setup.py',
+                    'some/', 'some/file.txt', 'some/other_file.txt',
+                    'somecode/', 'somecode/__init__.py', 'somecode/doc.dat',
+                    'somecode/doc.txt']
+        self.assertEqual(sorted(content), ['fake-1.0/' + x for x in expected])
 
         # checking the MANIFEST
         f = open(join(self.tmp_dir, 'MANIFEST'))
index de7ab5d..1fb8cb4 100644 (file)
@@ -2210,8 +2210,8 @@ def get_section(value):
         digits += value[0]
         value = value[1:]
     if digits[0] == '0' and digits != '0':
-        section.defects.append(errors.InvalidHeaderError("section number"
-            "has an invalid leading 0"))
+        section.defects.append(errors.InvalidHeaderError(
+                "section number has an invalid leading 0"))
     section.number = int(digits)
     section.append(ValueTerminal(digits, 'digits'))
     return section, value
index 4748ba4..09c572d 100644 (file)
@@ -8,9 +8,9 @@ import tempfile
 __all__ = ["version", "bootstrap"]
 
 
-_SETUPTOOLS_VERSION = "39.0.1"
+_SETUPTOOLS_VERSION = "40.6.2"
 
-_PIP_VERSION = "10.0.1"
+_PIP_VERSION = "18.1"
 
 _PROJECTS = [
     ("setuptools", _SETUPTOOLS_VERSION),
diff --git a/Lib/ensurepip/_bundled/pip-10.0.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-10.0.1-py2.py3-none-any.whl
deleted file mode 100644 (file)
index 9837092..0000000
Binary files a/Lib/ensurepip/_bundled/pip-10.0.1-py2.py3-none-any.whl and /dev/null differ
diff --git a/Lib/ensurepip/_bundled/pip-18.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-18.1-py2.py3-none-any.whl
new file mode 100644 (file)
index 0000000..c3c146f
Binary files /dev/null and b/Lib/ensurepip/_bundled/pip-18.1-py2.py3-none-any.whl differ
similarity index 54%
rename from Lib/ensurepip/_bundled/setuptools-39.0.1-py2.py3-none-any.whl
rename to Lib/ensurepip/_bundled/setuptools-40.6.2-py2.py3-none-any.whl
index edc3ca2..4c8a619 100644 (file)
Binary files a/Lib/ensurepip/_bundled/setuptools-39.0.1-py2.py3-none-any.whl and b/Lib/ensurepip/_bundled/setuptools-40.6.2-py2.py3-none-any.whl differ
index a02e595..2ff251a 100644 (file)
@@ -732,7 +732,7 @@ else:
                                  "exclusive")
             if keyfile is not None or certfile is not None:
                 import warnings
-                warnings.warn("keyfile and certfile are deprecated, use a"
+                warnings.warn("keyfile and certfile are deprecated, use a "
                               "custom context instead", DeprecationWarning, 2)
             self.keyfile = keyfile
             self.certfile = certfile
index 8ecd85a..e2951b0 100644 (file)
@@ -1,8 +1,52 @@
-What's New in IDLE 3.6.7
-Released on 2018-09-24?
+What's New in IDLE 3.6.8
+Released on 2018-12-20?
+**This is the final 3.6 bugfix maintenance release**
 ======================================
 
 
+bpo-34864: When starting IDLE on MacOS, warn if the system setting
+"Prefer tabs when opening documents" is "Always".  As previous
+documented for this issue, running IDLE with this setting causes
+problems.  If the setting is changed while IDLE is running,
+there will be no warning until IDLE is restarted.
+
+bpo-35213: Where appropriate, use 'macOS' in idlelib.
+
+bpo-34864: Document two IDLE on MacOS issues.  The System Preferences
+Dock "prefer tabs always" setting disables some IDLE features.
+Menus are a bit different than as described for Windows and Linux.
+
+bpo-35202: Remove unused imports in idlelib.
+
+bpo-33000: Document that IDLE's shell has no line limit.
+A program that runs indefinitely can overfill memory.
+
+bpo-23220: Explain how IDLE's Shell displays output.
+Add new subsection "User output in Shell".
+
+bpo-35099: Improve the doc about IDLE running user code.
+"IDLE -- console differences" is renamed "Running user code".
+It mostly covers the implications of using custom sys.stdxxx objects.
+
+bpo-35097: Add IDLE doc subsection explaining editor windows.
+Topics include opening, title and status bars, .py* extension, and running.
+
+Issue 35093: Document the IDLE document viewer in the IDLE doc.
+Add a paragraph in "Help and preferences", "Help sources" subsection.
+
+bpo-1529353: Explain Shell text squeezing in the IDLE doc.
+
+bpo-35088: Update idlelib.help.copy_string docstring.
+We now use git and backporting instead of hg and forward merging.
+
+bpo-35087: Update idlelib help files for the current doc build.
+The main change is the elimination of chapter-section numbers.
+
+
+What's New in IDLE 3.6.7
+Released on 2018-10-20
+======================================
+
 bpo-1529353: Output over N lines (50 by default) is squeezed down to a button.
 N can be changed in the PyShell section of the General page of the
 Settings dialog.  Fewer, but possibly extra long, lines can be squeezed by
index 7c88a4d..ef88528 100644 (file)
@@ -13,7 +13,7 @@ import re
 from sys import maxsize as INFINITY
 
 import tkinter
-from tkinter.constants import TOP, LEFT, X, W, SUNKEN
+from tkinter.constants import TOP, X, SUNKEN
 
 from idlelib.config import idleConf
 
index 0eb90fc..79d988f 100644 (file)
@@ -562,12 +562,11 @@ class IdleConf:
         result = self.GetKeySet(self.CurrentKeys())
 
         if sys.platform == "darwin":
-            # OS X Tk variants do not support the "Alt" keyboard modifier.
-            # So replace all keybingings that use "Alt" with ones that
-            # use the "Option" keyboard modifier.
-            # TODO (Ned?): the "Option" modifier does not work properly for
-            #        Cocoa Tk and XQuartz Tk so we should not use it
-            #        in default OS X KeySets.
+            # macOS (OS X) Tk variants do not support the "Alt"
+            # keyboard modifier.  Replace it with "Option".
+            # TODO (Ned?): the "Option" modifier does not work properly
+            #     for Cocoa Tk and XQuartz Tk so we should not use it
+            #     in the default 'OSX' keyset.
             for k, v in result.items():
                 v2 = [ x.replace('<Alt-', '<Option-') for x in v ]
                 if v != v2:
index 01a3bd2..0e6dcfb 100644 (file)
@@ -157,7 +157,7 @@ class IdbAdapter:
     #----------called by a DictProxy----------
 
     def dict_keys(self, did):
-        raise NotImplemented("dict_keys not public or pickleable")
+        raise NotImplementedError("dict_keys not public or pickleable")
 ##         dict = dicttable[did]
 ##         return dict.keys()
 
index 5262839..0d20085 100644 (file)
@@ -115,7 +115,6 @@ def _test():  # TODO check and convert to htest
     from tkinter import Tk
     from idlelib.editor import fixwordbreaks
     from idlelib.run import fix_scaling
-    import sys
     root = Tk()
     fix_scaling(root)
     fixwordbreaks(root)
index 5b4d093..e2bf773 100644 (file)
@@ -6,14 +6,18 @@
   <head>
     <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-    <title>26.5. IDLE &#8212; Python 3.8.0a0 documentation</title>
+    <title>IDLE &#8212; Python 3.8.0a0 documentation</title>
     <link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
     <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
-    <script type="text/javascript" src="../_static/documentation_options.js"></script>
+
+    <script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
     <script type="text/javascript" src="../_static/jquery.js"></script>
     <script type="text/javascript" src="../_static/underscore.js"></script>
     <script type="text/javascript" src="../_static/doctools.js"></script>
+    <script async="async" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
+
     <script type="text/javascript" src="../_static/sidebar.js"></script>
+
     <link rel="search" type="application/opensearchdescription+xml"
           title="Search within Python 3.8.0a0 documentation"
           href="../_static/opensearch.xml"/>
     <link rel="index" title="Index" href="../genindex.html" />
     <link rel="search" title="Search" href="../search.html" />
     <link rel="copyright" title="Copyright" href="../copyright.html" />
-    <link rel="next" title="26.6. Other Graphical User Interface Packages" href="othergui.html" />
-    <link rel="prev" title="26.4. tkinter.scrolledtext — Scrolled Text Widget" href="tkinter.scrolledtext.html" />
+    <link rel="next" title="Other Graphical User Interface Packages" href="othergui.html" />
+    <link rel="prev" title="tkinter.scrolledtext — Scrolled Text Widget" href="tkinter.scrolledtext.html" />
     <link rel="canonical" href="https://docs.python.org/3/library/idle.html" />
 
 
 
 
 
+
+    <style>
+      @media only screen {
+        table.full-width-table {
+            width: 100%;
+        }
+      }
+    </style>
+
     <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
 
     <script type="text/javascript" src="../_static/copybutton.js"></script>
           <a href="../py-modindex.html" title="Python Module Index"
              >modules</a> |</li>
         <li class="right" >
-          <a href="othergui.html" title="26.6. Other Graphical User Interface Packages"
+          <a href="othergui.html" title="Other Graphical User Interface Packages"
              accesskey="N">next</a> |</li>
         <li class="right" >
-          <a href="tkinter.scrolledtext.html" title="26.4. tkinter.scrolledtext — Scrolled Text Widget"
+          <a href="tkinter.scrolledtext.html" title="tkinter.scrolledtext — Scrolled Text Widget"
              accesskey="P">previous</a> |</li>
 
     <li><img src="../_static/py.png" alt=""
@@ -63,7 +76,7 @@
     </li>
 
           <li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> &#187;</li>
-          <li class="nav-item nav-item-2"><a href="tk.html" accesskey="U">26. Graphical User Interfaces with Tk</a> &#187;</li>
+          <li class="nav-item nav-item-2"><a href="tk.html" accesskey="U">Graphical User Interfaces with Tk</a> &#187;</li>
     <li class="right">
 
 
           <div class="body" role="main">
 
   <div class="section" id="idle">
-<span id="id1"></span><h1>26.5. IDLE<a class="headerlink" href="#idle" title="Permalink to this headline">¶</a></h1>
+<span id="id1"></span><h1>IDLE<a class="headerlink" href="#idle" title="Permalink to this headline">¶</a></h1>
 <p><strong>Source code:</strong> <a class="reference external" href="https://github.com/python/cpython/tree/master/Lib/idlelib/">Lib/idlelib/</a></p>
 <hr class="docutils" id="index-0" />
 <p>IDLE is Python’s Integrated Development and Learning Environment.</p>
 <p>IDLE has the following features:</p>
 <ul class="simple">
 <li>coded in 100% pure Python, using the <a class="reference internal" href="tkinter.html#module-tkinter" title="tkinter: Interface to Tcl/Tk for graphical user interfaces"><code class="xref py py-mod docutils literal notranslate"><span class="pre">tkinter</span></code></a> GUI toolkit</li>
-<li>cross-platform: works mostly the same on Windows, Unix, and Mac OS X</li>
+<li>cross-platform: works mostly the same on Windows, Unix, and macOS</li>
 <li>Python shell window (interactive interpreter) with colorizing
 of code input, output, and error messages</li>
 <li>multi-window text editor with multiple undo, Python colorizing,
@@ -107,16 +120,19 @@ of global and local namespaces</li>
 <li>configuration, browsers, and other dialogs</li>
 </ul>
 <div class="section" id="menus">
-<h2>26.5.1. Menus<a class="headerlink" href="#menus" title="Permalink to this headline">¶</a></h2>
+<h2>Menus<a class="headerlink" href="#menus" title="Permalink to this headline">¶</a></h2>
 <p>IDLE has two main window types, the Shell window and the Editor window.  It is
-possible to have multiple editor windows simultaneously.  Output windows, such
-as used for Edit / Find in Files, are a subtype of edit window.  They currently
-have the same top menu as Editor windows but a different default title and
-context menu.</p>
-<p>IDLE’s menus dynamically change based on which window is currently selected.
-Each menu documented below indicates which window type it is associated with.</p>
+possible to have multiple editor windows simultaneously.  On Windows and
+Linux, each has its own top menu.  Each menu documented below indicates
+which window type it is associated with.</p>
+<p>Output windows, such as used for Edit =&gt; Find in Files, are a subtype of editor
+window.  They currently have the same top menu but a different
+default title and context menu.</p>
+<p>On macOS, there is one application menu.  It dynamically changes according
+to the window currently selected.  It has an IDLE menu, and some entries
+described below are moved around to conform to Apple guidlines.</p>
 <div class="section" id="file-menu-shell-and-editor">
-<h3>26.5.1.1. File menu (Shell and Editor)<a class="headerlink" href="#file-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
+<h3>File menu (Shell and Editor)<a class="headerlink" href="#file-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
 <dl class="docutils">
 <dt>New File</dt>
 <dd>Create a new file editing window.</dd>
@@ -154,7 +170,7 @@ file.</dd>
 </dl>
 </div>
 <div class="section" id="edit-menu-shell-and-editor">
-<h3>26.5.1.2. Edit menu (Shell and Editor)<a class="headerlink" href="#edit-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
+<h3>Edit menu (Shell and Editor)<a class="headerlink" href="#edit-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
 <dl class="docutils">
 <dt>Undo</dt>
 <dd>Undo the last change to the current window.  A maximum of 1000 changes may
@@ -198,7 +214,7 @@ function parameter hints.</dd>
 </dl>
 </div>
 <div class="section" id="format-menu-editor-window-only">
-<h3>26.5.1.3. Format menu (Editor window only)<a class="headerlink" href="#format-menu-editor-window-only" title="Permalink to this headline">¶</a></h3>
+<h3>Format menu (Editor window only)<a class="headerlink" href="#format-menu-editor-window-only" title="Permalink to this headline">¶</a></h3>
 <dl class="docutils">
 <dt>Indent Region</dt>
 <dd>Shift selected lines right by the indent width (default 4 spaces).</dd>
@@ -229,7 +245,7 @@ including lines within multiline strings.</dd>
 </dl>
 </div>
 <div class="section" id="run-menu-editor-window-only">
-<span id="index-2"></span><h3>26.5.1.4. Run menu (Editor window only)<a class="headerlink" href="#run-menu-editor-window-only" title="Permalink to this headline">¶</a></h3>
+<span id="index-2"></span><h3>Run menu (Editor window only)<a class="headerlink" href="#run-menu-editor-window-only" title="Permalink to this headline">¶</a></h3>
 <dl class="docutils">
 <dt>Python Shell</dt>
 <dd>Open or wake up the Python Shell window.</dd>
@@ -250,7 +266,7 @@ line.</dd>
 </dl>
 </div>
 <div class="section" id="shell-menu-shell-window-only">
-<h3>26.5.1.5. Shell menu (Shell window only)<a class="headerlink" href="#shell-menu-shell-window-only" title="Permalink to this headline">¶</a></h3>
+<h3>Shell menu (Shell window only)<a class="headerlink" href="#shell-menu-shell-window-only" title="Permalink to this headline">¶</a></h3>
 <dl class="docutils">
 <dt>View Last Restart</dt>
 <dd>Scroll the shell window to the last Shell restart.</dd>
@@ -261,7 +277,7 @@ line.</dd>
 </dl>
 </div>
 <div class="section" id="debug-menu-shell-window-only">
-<h3>26.5.1.6. Debug menu (Shell window only)<a class="headerlink" href="#debug-menu-shell-window-only" title="Permalink to this headline">¶</a></h3>
+<h3>Debug menu (Shell window only)<a class="headerlink" href="#debug-menu-shell-window-only" title="Permalink to this headline">¶</a></h3>
 <dl class="docutils">
 <dt>Go to File/Line</dt>
 <dd>Look on the current line. with the cursor, and the line above for a filename
@@ -283,12 +299,12 @@ access to locals and globals.</dd>
 </dl>
 </div>
 <div class="section" id="options-menu-shell-and-editor">
-<h3>26.5.1.7. Options menu (Shell and Editor)<a class="headerlink" href="#options-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
+<h3>Options menu (Shell and Editor)<a class="headerlink" href="#options-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
 <dl class="docutils">
 <dt>Configure IDLE</dt>
 <dd><p class="first">Open a configuration dialog and change preferences for the following:
 fonts, indentation, keybindings, text color themes, startup windows and
-size, additional help sources, and extensions (see below).  On OS X,
+size, additional help sources, and extensions (see below).  On macOS,
 open the configuration dialog by selecting Preferences in the application
 menu.  To use a new built-in color theme (IDLE Dark) with older IDLEs,
 save it as a new custom theme.</p>
@@ -303,7 +319,7 @@ line in this pane exposes that line at the top of the editor.</dd>
 </dl>
 </div>
 <div class="section" id="window-menu-shell-and-editor">
-<h3>26.5.1.8. Window menu (Shell and Editor)<a class="headerlink" href="#window-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
+<h3>Window menu (Shell and Editor)<a class="headerlink" href="#window-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
 <dl class="docutils">
 <dt>Zoom Height</dt>
 <dd>Toggles the window between normal size and maximum height. The initial size
@@ -314,25 +330,26 @@ Configure IDLE dialog.</dd>
 it to the foreground (deiconifying it if necessary).</p>
 </div>
 <div class="section" id="help-menu-shell-and-editor">
-<h3>26.5.1.9. Help menu (Shell and Editor)<a class="headerlink" href="#help-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
+<h3>Help menu (Shell and Editor)<a class="headerlink" href="#help-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
 <dl class="docutils">
 <dt>About IDLE</dt>
 <dd>Display version, copyright, license, credits, and more.</dd>
 <dt>IDLE Help</dt>
-<dd>Display a help file for IDLE detailing the menu options, basic editing and
+<dd>Display this IDLE document, detailing the menu options, basic editing and
 navigation, and other tips.</dd>
 <dt>Python Docs</dt>
 <dd>Access local Python documentation, if installed, or start a web browser
 and open docs.python.org showing the latest Python documentation.</dd>
 <dt>Turtle Demo</dt>
-<dd>Run the turtledemo module with example python code and turtle drawings.</dd>
+<dd>Run the turtledemo module with example Python code and turtle drawings.</dd>
 </dl>
 <p>Additional help sources may be added here with the Configure IDLE dialog under
-the General tab.</p>
+the General tab. See the “Help sources” subsection below for more
+on Help menu choices.</p>
 </div>
 <div class="section" id="context-menus">
-<span id="index-4"></span><h3>26.5.1.10. Context Menus<a class="headerlink" href="#context-menus" title="Permalink to this headline">¶</a></h3>
-<p>Open a context menu by right-clicking in a window (Control-click on OS X).
+<span id="index-4"></span><h3>Context Menus<a class="headerlink" href="#context-menus" title="Permalink to this headline">¶</a></h3>
+<p>Open a context menu by right-clicking in a window (Control-click on macOS).
 Context menus have the standard clipboard functions also on the Edit menu.</p>
 <dl class="docutils">
 <dt>Cut</dt>
@@ -351,17 +368,38 @@ debugger.  Breakpoints for a file are saved in the user’s .idlerc directory.</
 <dt>Clear Breakpoint</dt>
 <dd>Clear the breakpoint on that line.</dd>
 </dl>
-<p>Shell and Output windows have the following.</p>
+<p>Shell and Output windows also have the following.</p>
 <dl class="docutils">
 <dt>Go to file/line</dt>
 <dd>Same as in Debug menu.</dd>
 </dl>
+<p>The Shell window also has an output squeezing facility explained in the
+the <em>Python Shell window</em> subsection below.</p>
+<dl class="docutils">
+<dt>Squeeze</dt>
+<dd>If the cursor is over an output line, squeeze all the output between
+the code above and the prompt below down to a ‘Squeezed text’ label.</dd>
+</dl>
 </div>
 </div>
 <div class="section" id="editing-and-navigation">
-<h2>26.5.2. Editing and navigation<a class="headerlink" href="#editing-and-navigation" title="Permalink to this headline">¶</a></h2>
+<h2>Editing and navigation<a class="headerlink" href="#editing-and-navigation" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="editor-windows">
+<h3>Editor windows<a class="headerlink" href="#editor-windows" title="Permalink to this headline">¶</a></h3>
+<p>IDLE may open editor windows when it starts, depending on settings
+and how you start IDLE.  Thereafter, use the File menu.  There can be only
+one open editor window for a given file.</p>
+<p>The title bar contains the name of the file, the full path, and the version
+of Python and IDLE running the window.  The status bar contains the line
+number (‘Ln’) and column number (‘Col’).  Line numbers start with 1;
+column numbers with 0.</p>
+<p>IDLE assumes that files with a known .py* extension contain Python code
+and that other files do not.  Run Python code with the Run menu.</p>
+</div>
+<div class="section" id="key-bindings">
+<h3>Key bindings<a class="headerlink" href="#key-bindings" title="Permalink to this headline">¶</a></h3>
 <p>In this section, ‘C’ refers to the <kbd class="kbd docutils literal notranslate">Control</kbd> key on Windows and Unix and
-the <kbd class="kbd docutils literal notranslate">Command</kbd> key on Mac OSX.</p>
+the <kbd class="kbd docutils literal notranslate">Command</kbd> key on macOS.</p>
 <ul>
 <li><p class="first"><kbd class="kbd docutils literal notranslate">Backspace</kbd> deletes to the left; <kbd class="kbd docutils literal notranslate">Del</kbd> deletes to the right</p>
 </li>
@@ -395,8 +433,9 @@ this)</li>
 </ul>
 <p>Standard keybindings (like <kbd class="kbd docutils literal notranslate">C-c</kbd> to copy and <kbd class="kbd docutils literal notranslate">C-v</kbd> to paste)
 may work.  Keybindings are selected in the Configure IDLE dialog.</p>
+</div>
 <div class="section" id="automatic-indentation">
-<h3>26.5.2.1. Automatic indentation<a class="headerlink" href="#automatic-indentation" title="Permalink to this headline">¶</a></h3>
+<h3>Automatic indentation<a class="headerlink" href="#automatic-indentation" title="Permalink to this headline">¶</a></h3>
 <p>After a block-opening statement, the next line is indented by 4 spaces (in the
 Python Shell window by one tab).  After certain keywords (break, return etc.)
 the next line is dedented.  In leading indentation, <kbd class="kbd docutils literal notranslate">Backspace</kbd> deletes up
@@ -406,7 +445,7 @@ are restricted to four spaces due to Tcl/Tk limitations.</p>
 <p>See also the indent/dedent region commands in the edit menu.</p>
 </div>
 <div class="section" id="completions">
-<h3>26.5.2.2. Completions<a class="headerlink" href="#completions" title="Permalink to this headline">¶</a></h3>
+<h3>Completions<a class="headerlink" href="#completions" title="Permalink to this headline">¶</a></h3>
 <p>Completions are supplied for functions, classes, and attributes of classes,
 both built-in and user-defined. Completions are also provided for
 filenames.</p>
@@ -441,7 +480,7 @@ much can be found by default, e.g. the re module.</p>
 longer or disable the extension.</p>
 </div>
 <div class="section" id="calltips">
-<h3>26.5.2.3. Calltips<a class="headerlink" href="#calltips" title="Permalink to this headline">¶</a></h3>
+<h3>Calltips<a class="headerlink" href="#calltips" title="Permalink to this headline">¶</a></h3>
 <p>A calltip is shown when one types <kbd class="kbd docutils literal notranslate">(</kbd> after the name of an <em>accessible</em>
 function.  A name expression may include dots and subscripts.  A calltip
 remains until it is clicked, the cursor is moved out of the argument area,
@@ -464,7 +503,15 @@ might want to run a file after writing the import statements at the top,
 or immediately run an existing file before editing.</p>
 </div>
 <div class="section" id="python-shell-window">
-<h3>26.5.2.4. Python Shell window<a class="headerlink" href="#python-shell-window" title="Permalink to this headline">¶</a></h3>
+<h3>Python Shell window<a class="headerlink" href="#python-shell-window" title="Permalink to this headline">¶</a></h3>
+<p>With IDLE’s Shell, one enters, edits, and recalls complete statements.
+Most consoles and terminals only work with a single physical line at a time.</p>
+<p>When one pastes code into Shell, it is not compiled and possibly executed
+until one hits <kbd class="kbd docutils literal notranslate">Return</kbd>.  One may edit pasted code first.
+If one pastes more that one statement into Shell, the result will be a
+<a class="reference internal" href="exceptions.html#SyntaxError" title="SyntaxError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">SyntaxError</span></code></a> when multiple statements are compiled as if they were one.</p>
+<p>The editing features described in previous subsections work when entering
+code interactively.  IDLE’s Shell window also responds to the following keys.</p>
 <ul>
 <li><p class="first"><kbd class="kbd docutils literal notranslate">C-c</kbd> interrupts executing command</p>
 </li>
@@ -474,15 +521,15 @@ or immediately run an existing file before editing.</p>
 <p>Command history</p>
 <ul class="simple">
 <li><kbd class="kbd docutils literal notranslate">Alt-p</kbd> retrieves previous command matching what you have typed. On
-OS X use <kbd class="kbd docutils literal notranslate">C-p</kbd>.</li>
-<li><kbd class="kbd docutils literal notranslate">Alt-n</kbd> retrieves next. On OS X use <kbd class="kbd docutils literal notranslate">C-n</kbd>.</li>
+macOS use <kbd class="kbd docutils literal notranslate">C-p</kbd>.</li>
+<li><kbd class="kbd docutils literal notranslate">Alt-n</kbd> retrieves next. On macOS use <kbd class="kbd docutils literal notranslate">C-n</kbd>.</li>
 <li><kbd class="kbd docutils literal notranslate">Return</kbd> while on any previous command retrieves that command</li>
 </ul>
 </li>
 </ul>
 </div>
 <div class="section" id="text-colors">
-<h3>26.5.2.5. Text colors<a class="headerlink" href="#text-colors" title="Permalink to this headline">¶</a></h3>
+<h3>Text colors<a class="headerlink" href="#text-colors" title="Permalink to this headline">¶</a></h3>
 <p>Idle defaults to black on white text, but colors text with special meanings.
 For the shell, these are shell output, shell error, user output, and
 user error.  For Python code, at the shell prompt or in an editor, these are
@@ -496,7 +543,7 @@ text in popups and dialogs is not user-configurable.</p>
 </div>
 </div>
 <div class="section" id="startup-and-code-execution">
-<h2>26.5.3. Startup and code execution<a class="headerlink" href="#startup-and-code-execution" title="Permalink to this headline">¶</a></h2>
+<h2>Startup and code execution<a class="headerlink" href="#startup-and-code-execution" title="Permalink to this headline">¶</a></h2>
 <p>Upon startup with the <code class="docutils literal notranslate"><span class="pre">-s</span></code> option, IDLE will execute the file referenced by
 the environment variables <span class="target" id="index-5"></span><code class="xref std std-envvar docutils literal notranslate"><span class="pre">IDLESTARTUP</span></code> or <span class="target" id="index-6"></span><a class="reference internal" href="../using/cmdline.html#envvar-PYTHONSTARTUP"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PYTHONSTARTUP</span></code></a>.
 IDLE first checks for <code class="docutils literal notranslate"><span class="pre">IDLESTARTUP</span></code>; if <code class="docutils literal notranslate"><span class="pre">IDLESTARTUP</span></code> is present the file
@@ -510,7 +557,7 @@ looked for in the user’s home directory.  Statements in this file will be
 executed in the Tk namespace, so this file is not useful for importing
 functions to be used from IDLE’s Python shell.</p>
 <div class="section" id="command-line-usage">
-<h3>26.5.3.1. Command line usage<a class="headerlink" href="#command-line-usage" title="Permalink to this headline">¶</a></h3>
+<h3>Command line usage<a class="headerlink" href="#command-line-usage" title="Permalink to this headline">¶</a></h3>
 <div class="highlight-none notranslate"><div class="highlight"><pre><span></span>idle.py [-c command] [-d] [-e] [-h] [-i] [-r file] [-s] [-t title] [-] [arg] ...
 
 -c command  run command in the shell window
@@ -535,7 +582,7 @@ set in the Options dialog.</li>
 </ul>
 </div>
 <div class="section" id="startup-failure">
-<h3>26.5.3.2. Startup failure<a class="headerlink" href="#startup-failure" title="Permalink to this headline">¶</a></h3>
+<h3>Startup failure<a class="headerlink" href="#startup-failure" title="Permalink to this headline">¶</a></h3>
 <p>IDLE uses a socket to communicate between the IDLE GUI process and the user
 code execution process.  A connection must be established whenever the Shell
 starts or restarts.  (The latter is indicated by a divider line that says
@@ -570,26 +617,75 @@ be to delete one or more of the configuration files.</p>
 <p>If IDLE quits with no message, and it was not started from a console, try
 starting from a console (<code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">idlelib)</span></code> and see if a message appears.</p>
 </div>
-<div class="section" id="idle-console-differences">
-<h3>26.5.3.3. IDLE-console differences<a class="headerlink" href="#idle-console-differences" title="Permalink to this headline">¶</a></h3>
+<div class="section" id="running-user-code">
+<h3>Running user code<a class="headerlink" href="#running-user-code" title="Permalink to this headline">¶</a></h3>
 <p>With rare exceptions, the result of executing Python code with IDLE is
-intended to be the same as executing the same code in a console window.
+intended to be the same as executing the same code by the default method,
+directly with Python in a text-mode system console or terminal window.
 However, the different interface and operation occasionally affect
-visible results.  For instance, <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code> starts with more entries.</p>
-<p>IDLE also replaces <code class="docutils literal notranslate"><span class="pre">sys.stdin</span></code>, <code class="docutils literal notranslate"><span class="pre">sys.stdout</span></code>, and <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code> with
-objects that get input from and send output to the Shell window.
-When Shell has the focus, it controls the keyboard and screen.  This is
+visible results.  For instance, <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code> starts with more entries,
+and <code class="docutils literal notranslate"><span class="pre">threading.activeCount()</span></code> returns 2 instead of 1.</p>
+<p>By default, IDLE runs user code in a separate OS process rather than in
+the user interface process that runs the shell and editor.  In the execution
+process, it replaces <code class="docutils literal notranslate"><span class="pre">sys.stdin</span></code>, <code class="docutils literal notranslate"><span class="pre">sys.stdout</span></code>, and <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code>
+with objects that get input from and send output to the Shell window.
+The original values stored in <code class="docutils literal notranslate"><span class="pre">sys.__stdin__</span></code>, <code class="docutils literal notranslate"><span class="pre">sys.__stdout__</span></code>, and
+<code class="docutils literal notranslate"><span class="pre">sys.__stderr__</span></code> are not touched, but may be <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p>
+<p>When Shell has the focus, it controls the keyboard and screen.  This is
 normally transparent, but functions that directly access the keyboard
-and screen will not work.  If <code class="docutils literal notranslate"><span class="pre">sys</span></code> is reset with <code class="docutils literal notranslate"><span class="pre">importlib.reload(sys)</span></code>,
-IDLE’s changes are lost and things like <code class="docutils literal notranslate"><span class="pre">input</span></code>, <code class="docutils literal notranslate"><span class="pre">raw_input</span></code>, and
-<code class="docutils literal notranslate"><span class="pre">print</span></code> will not work correctly.</p>
-<p>With IDLE’s Shell, one enters, edits, and recalls complete statements.
-Some consoles only work with a single physical line at a time.  IDLE uses
-<code class="docutils literal notranslate"><span class="pre">exec</span></code> to run each statement.  As a result, <code class="docutils literal notranslate"><span class="pre">'__builtins__'</span></code> is always
-defined for each statement.</p>
+and screen will not work.  These include system-specific functions that
+determine whether a key has been pressed and if so, which.</p>
+<p>IDLE’s standard stream replacements are not inherited by subprocesses
+created in the execution process, whether directly by user code or by modules
+such as multiprocessing.  If such subprocess use <code class="docutils literal notranslate"><span class="pre">input</span></code> from sys.stdin
+or <code class="docutils literal notranslate"><span class="pre">print</span></code> or <code class="docutils literal notranslate"><span class="pre">write</span></code> to sys.stdout or sys.stderr,
+IDLE should be started in a command line window.  The secondary subprocess
+will then be attached to that window for input and output.</p>
+<p>If <code class="docutils literal notranslate"><span class="pre">sys</span></code> is reset by user code, such as with <code class="docutils literal notranslate"><span class="pre">importlib.reload(sys)</span></code>,
+IDLE’s changes are lost and input from the keyboard and output to the screen
+will not work correctly.</p>
+</div>
+<div class="section" id="user-output-in-shell">
+<h3>User output in Shell<a class="headerlink" href="#user-output-in-shell" title="Permalink to this headline">¶</a></h3>
+<p>When a program outputs text, the result is determined by the
+corresponding output device.  When IDLE executes user code, <code class="docutils literal notranslate"><span class="pre">sys.stdout</span></code>
+and <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code> are connected to the display area of IDLE’s Shell.  Some of
+its features are inherited from the underlying Tk Text widget.  Others
+are programmed additions.  Where it matters, Shell is designed for development
+rather than production runs.</p>
+<p>For instance, Shell never throws away output.  A program that sends unlimited
+output to Shell will eventually fill memory, resulting in a memory error.
+In contrast, some system text windows only keep the last n lines of output.
+A Windows console, for instance, keeps a user-settable 1 to 9999 lines,
+with 300 the default.</p>
+<p>Text widgets display a subset of Unicode, the Basic Multilingual Plane (BMP).
+Which characters get a proper glyph instead of a replacement box depends on
+the operating system and installed fonts.  Newline characters cause following
+text to appear on a new line, but other control characters are either
+replaced with a box or deleted.  However, <code class="docutils literal notranslate"><span class="pre">repr()</span></code>, which is used for
+interactive echo of expression values, replaces control characters,
+some BMP codepoints, and all non-BMP characters with escape codes
+before they are output.</p>
+<p>Normal and error output are generally kept separate (on separate lines)
+from code input and each other.  They each get different highlight colors.</p>
+<p>For SyntaxError tracebacks, the normal ‘^’ marking where the error was
+detected is replaced by coloring the text with an error highlight.
+When code run from a file causes other exceptions, one may right click
+on a traceback line to jump to the corresponding line in an IDLE editor.
+The file will be opened if necessary.</p>
+<p>Shell has a special facility for squeezing output lines down to a
+‘Squeezed text’ label.  This is done automatically
+for output over N lines (N = 50 by default).
+N can be changed in the PyShell section of the General
+page of the Settings dialog.  Output with fewer lines can be squeezed by
+right clicking on the output.  This can be useful lines long enough to slow
+down scrolling.</p>
+<p>Squeezed output is expanded in place by double-clicking the label.
+It can also be sent to the clipboard or a separate view window by
+right-clicking the label.</p>
 </div>
 <div class="section" id="developing-tkinter-applications">
-<h3>26.5.3.4. Developing tkinter applications<a class="headerlink" href="#developing-tkinter-applications" title="Permalink to this headline">¶</a></h3>
+<h3>Developing tkinter applications<a class="headerlink" href="#developing-tkinter-applications" title="Permalink to this headline">¶</a></h3>
 <p>IDLE is intentionally different from standard Python in order to
 facilitate development of tkinter programs.  Enter <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">tkinter</span> <span class="pre">as</span> <span class="pre">tk;</span>
 <span class="pre">root</span> <span class="pre">=</span> <span class="pre">tk.Tk()</span></code> in standard Python and nothing appears.  Enter the same
@@ -609,7 +705,7 @@ interact with the live application.  One just has to remember to
 re-enable the mainloop call when running in standard Python.</p>
 </div>
 <div class="section" id="running-without-a-subprocess">
-<h3>26.5.3.5. Running without a subprocess<a class="headerlink" href="#running-without-a-subprocess" title="Permalink to this headline">¶</a></h3>
+<h3>Running without a subprocess<a class="headerlink" href="#running-without-a-subprocess" title="Permalink to this headline">¶</a></h3>
 <p>By default, IDLE executes user code in a separate subprocess via a socket,
 which uses the internal loopback interface.  This connection is not
 externally visible and no data is sent to or received from the Internet.
@@ -635,24 +731,39 @@ with the default subprocess if at all possible.</p>
 </div>
 </div>
 <div class="section" id="help-and-preferences">
-<h2>26.5.4. Help and preferences<a class="headerlink" href="#help-and-preferences" title="Permalink to this headline">¶</a></h2>
-<div class="section" id="additional-help-sources">
-<h3>26.5.4.1. Additional help sources<a class="headerlink" href="#additional-help-sources" title="Permalink to this headline">¶</a></h3>
-<p>IDLE includes a help menu entry called “Python Docs” that will open the
-extensive sources of help, including tutorials, available at docs.python.org.
-Selected URLs can be added or removed from the help menu at any time using the
-Configure IDLE dialog. See the IDLE help option in the help menu of IDLE for
-more information.</p>
+<h2>Help and preferences<a class="headerlink" href="#help-and-preferences" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="help-sources">
+<h3>Help sources<a class="headerlink" href="#help-sources" title="Permalink to this headline">¶</a></h3>
+<p>Help menu entry “IDLE Help” displays a formatted html version of the
+IDLE chapter of the Library Reference.  The result, in a read-only
+tkinter text window, is close to what one sees in a web browser.
+Navigate through the text with a mousewheel,
+the scrollbar, or up and down arrow keys held down.
+Or click the TOC (Table of Contents) button and select a section
+header in the opened box.</p>
+<p>Help menu entry “Python Docs” opens the extensive sources of help,
+including tutorials, available at docs.python.org/x.y, where ‘x.y’
+is the currently running Python version.  If your system
+has an off-line copy of the docs (this may be an installation option),
+that will be opened instead.</p>
+<p>Selected URLs can be added or removed from the help menu at any time using the
+General tab of the Configure IDLE dialog .</p>
 </div>
 <div class="section" id="setting-preferences">
-<h3>26.5.4.2. Setting preferences<a class="headerlink" href="#setting-preferences" title="Permalink to this headline">¶</a></h3>
+<h3>Setting preferences<a class="headerlink" href="#setting-preferences" title="Permalink to this headline">¶</a></h3>
 <p>The font preferences, highlighting, keys, and general preferences can be
 changed via Configure IDLE on the Option menu.  Keys can be user defined;
 IDLE ships with four built-in key sets. In addition, a user can create a
 custom key set in the Configure IDLE dialog under the keys tab.</p>
 </div>
+<div class="section" id="idle-on-macos">
+<h3>IDLE on macOS<a class="headerlink" href="#idle-on-macos" title="Permalink to this headline">¶</a></h3>
+<p>Under System Preferences: Dock, one can set “Prefer tabs when opening
+documents” to “Always”.  This setting is not compatible with the tk/tkinter
+GUI framework used by IDLE, and it breaks a few IDLE features.</p>
+</div>
 <div class="section" id="extensions">
-<h3>26.5.4.3. Extensions<a class="headerlink" href="#extensions" title="Permalink to this headline">¶</a></h3>
+<h3>Extensions<a class="headerlink" href="#extensions" title="Permalink to this headline">¶</a></h3>
 <p>IDLE contains an extension facility.  Preferences for extensions can be
 changed with the Extensions tab of the preferences dialog. See the
 beginning of config-extensions.def in the idlelib directory for further
@@ -668,42 +779,46 @@ also used for testing.</p>
       </div>
       <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
         <div class="sphinxsidebarwrapper">
-  <h3><a href="../contents.html">Table Of Contents</a></h3>
+  <h3><a href="../contents.html">Table of Contents</a></h3>
   <ul>
-<li><a class="reference internal" href="#">26.5. IDLE</a><ul>
-<li><a class="reference internal" href="#menus">26.5.1. Menus</a><ul>
-<li><a class="reference internal" href="#file-menu-shell-and-editor">26.5.1.1. File menu (Shell and Editor)</a></li>
-<li><a class="reference internal" href="#edit-menu-shell-and-editor">26.5.1.2. Edit menu (Shell and Editor)</a></li>
-<li><a class="reference internal" href="#format-menu-editor-window-only">26.5.1.3. Format menu (Editor window only)</a></li>
-<li><a class="reference internal" href="#run-menu-editor-window-only">26.5.1.4. Run menu (Editor window only)</a></li>
-<li><a class="reference internal" href="#shell-menu-shell-window-only">26.5.1.5. Shell menu (Shell window only)</a></li>
-<li><a class="reference internal" href="#debug-menu-shell-window-only">26.5.1.6. Debug menu (Shell window only)</a></li>
-<li><a class="reference internal" href="#options-menu-shell-and-editor">26.5.1.7. Options menu (Shell and Editor)</a></li>
-<li><a class="reference internal" href="#window-menu-shell-and-editor">26.5.1.8. Window menu (Shell and Editor)</a></li>
-<li><a class="reference internal" href="#help-menu-shell-and-editor">26.5.1.9. Help menu (Shell and Editor)</a></li>
-<li><a class="reference internal" href="#context-menus">26.5.1.10. Context Menus</a></li>
+<li><a class="reference internal" href="#">IDLE</a><ul>
+<li><a class="reference internal" href="#menus">Menus</a><ul>
+<li><a class="reference internal" href="#file-menu-shell-and-editor">File menu (Shell and Editor)</a></li>
+<li><a class="reference internal" href="#edit-menu-shell-and-editor">Edit menu (Shell and Editor)</a></li>
+<li><a class="reference internal" href="#format-menu-editor-window-only">Format menu (Editor window only)</a></li>
+<li><a class="reference internal" href="#run-menu-editor-window-only">Run menu (Editor window only)</a></li>
+<li><a class="reference internal" href="#shell-menu-shell-window-only">Shell menu (Shell window only)</a></li>
+<li><a class="reference internal" href="#debug-menu-shell-window-only">Debug menu (Shell window only)</a></li>
+<li><a class="reference internal" href="#options-menu-shell-and-editor">Options menu (Shell and Editor)</a></li>
+<li><a class="reference internal" href="#window-menu-shell-and-editor">Window menu (Shell and Editor)</a></li>
+<li><a class="reference internal" href="#help-menu-shell-and-editor">Help menu (Shell and Editor)</a></li>
+<li><a class="reference internal" href="#context-menus">Context Menus</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#editing-and-navigation">26.5.2. Editing and navigation</a><ul>
-<li><a class="reference internal" href="#automatic-indentation">26.5.2.1. Automatic indentation</a></li>
-<li><a class="reference internal" href="#completions">26.5.2.2. Completions</a></li>
-<li><a class="reference internal" href="#calltips">26.5.2.3. Calltips</a></li>
-<li><a class="reference internal" href="#python-shell-window">26.5.2.4. Python Shell window</a></li>
-<li><a class="reference internal" href="#text-colors">26.5.2.5. Text colors</a></li>
+<li><a class="reference internal" href="#editing-and-navigation">Editing and navigation</a><ul>
+<li><a class="reference internal" href="#editor-windows">Editor windows</a></li>
+<li><a class="reference internal" href="#key-bindings">Key bindings</a></li>
+<li><a class="reference internal" href="#automatic-indentation">Automatic indentation</a></li>
+<li><a class="reference internal" href="#completions">Completions</a></li>
+<li><a class="reference internal" href="#calltips">Calltips</a></li>
+<li><a class="reference internal" href="#python-shell-window">Python Shell window</a></li>
+<li><a class="reference internal" href="#text-colors">Text colors</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#startup-and-code-execution">26.5.3. Startup and code execution</a><ul>
-<li><a class="reference internal" href="#command-line-usage">26.5.3.1. Command line usage</a></li>
-<li><a class="reference internal" href="#startup-failure">26.5.3.2. Startup failure</a></li>
-<li><a class="reference internal" href="#idle-console-differences">26.5.3.3. IDLE-console differences</a></li>
-<li><a class="reference internal" href="#developing-tkinter-applications">26.5.3.4. Developing tkinter applications</a></li>
-<li><a class="reference internal" href="#running-without-a-subprocess">26.5.3.5. Running without a subprocess</a></li>
+<li><a class="reference internal" href="#startup-and-code-execution">Startup and code execution</a><ul>
+<li><a class="reference internal" href="#command-line-usage">Command line usage</a></li>
+<li><a class="reference internal" href="#startup-failure">Startup failure</a></li>
+<li><a class="reference internal" href="#running-user-code">Running user code</a></li>
+<li><a class="reference internal" href="#user-output-in-shell">User output in Shell</a></li>
+<li><a class="reference internal" href="#developing-tkinter-applications">Developing tkinter applications</a></li>
+<li><a class="reference internal" href="#running-without-a-subprocess">Running without a subprocess</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#help-and-preferences">26.5.4. Help and preferences</a><ul>
-<li><a class="reference internal" href="#additional-help-sources">26.5.4.1. Additional help sources</a></li>
-<li><a class="reference internal" href="#setting-preferences">26.5.4.2. Setting preferences</a></li>
-<li><a class="reference internal" href="#extensions">26.5.4.3. Extensions</a></li>
+<li><a class="reference internal" href="#help-and-preferences">Help and preferences</a><ul>
+<li><a class="reference internal" href="#help-sources">Help sources</a></li>
+<li><a class="reference internal" href="#setting-preferences">Setting preferences</a></li>
+<li><a class="reference internal" href="#idle-on-macos">IDLE on macOS</a></li>
+<li><a class="reference internal" href="#extensions">Extensions</a></li>
 </ul>
 </li>
 </ul>
@@ -712,10 +827,10 @@ also used for testing.</p>
 
   <h4>Previous topic</h4>
   <p class="topless"><a href="tkinter.scrolledtext.html"
-                        title="previous chapter">26.4. <code class="docutils literal notranslate"><span class="pre">tkinter.scrolledtext</span></code> — Scrolled Text Widget</a></p>
+                        title="previous chapter"><code class="docutils literal notranslate"><span class="pre">tkinter.scrolledtext</span></code> — Scrolled Text Widget</a></p>
   <h4>Next topic</h4>
   <p class="topless"><a href="othergui.html"
-                        title="next chapter">26.6. Other Graphical User Interface Packages</a></p>
+                        title="next chapter">Other Graphical User Interface Packages</a></p>
   <div role="note" aria-label="source link">
     <h3>This Page</h3>
     <ul class="this-page-menu">
@@ -741,10 +856,10 @@ also used for testing.</p>
           <a href="../py-modindex.html" title="Python Module Index"
              >modules</a> |</li>
         <li class="right" >
-          <a href="othergui.html" title="26.6. Other Graphical User Interface Packages"
+          <a href="othergui.html" title="Other Graphical User Interface Packages"
              >next</a> |</li>
         <li class="right" >
-          <a href="tkinter.scrolledtext.html" title="26.4. tkinter.scrolledtext — Scrolled Text Widget"
+          <a href="tkinter.scrolledtext.html" title="tkinter.scrolledtext — Scrolled Text Widget"
              >previous</a> |</li>
 
     <li><img src="../_static/py.png" alt=""
@@ -757,7 +872,7 @@ also used for testing.</p>
     </li>
 
           <li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> &#187;</li>
-          <li class="nav-item nav-item-2"><a href="tk.html" >26. Graphical User Interfaces with Tk</a> &#187;</li>
+          <li class="nav-item nav-item-2"><a href="tk.html" >Graphical User Interfaces with Tk</a> &#187;</li>
     <li class="right">
 
 
@@ -784,11 +899,11 @@ also used for testing.</p>
 <br />
     <br />
 
-    Last updated on Jun 10, 2018.
+    Last updated on Nov 12, 2018.
     <a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
     <br />
 
-    Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.7.4.
+    Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.8.1.
     </div>
 
   </body>
index 21b5ea5..0603ede 100644 (file)
@@ -126,7 +126,10 @@ class HelpParser(HTMLParser):
         if tag in ['h1', 'h2', 'h3']:
             self.indent(0)  # clear tag, reset indent
             if self.show:
-                self.toc.append((self.header, self.text.index('insert')))
+                indent = ('        ' if tag == 'h3' else
+                          '    ' if tag == 'h2' else
+                          '')
+                self.toc.append((indent+self.header, self.text.index('insert')))
         elif tag in ['span', 'em']:
             self.chartags = ''
         elif tag == 'a':
@@ -142,11 +145,15 @@ class HelpParser(HTMLParser):
         if self.show and not self.hdrlink:
             d = data if self.pre else data.replace('\n', ' ')
             if self.tags == 'h1':
-                self.hprefix = d[0:d.index(' ')]
-            if self.tags in ['h1', 'h2', 'h3'] and self.hprefix != '':
-                if d[0:len(self.hprefix)] == self.hprefix:
-                    d = d[len(self.hprefix):].strip()
-                self.header += d
+                try:
+                    self.hprefix = d[0:d.index(' ')]
+                except ValueError:
+                    self.hprefix = ''
+            if self.tags in ['h1', 'h2', 'h3']:
+                if (self.hprefix != '' and
+                    d[0:len(self.hprefix)] == self.hprefix):
+                    d = d[len(self.hprefix):]
+                self.header += d.strip()
             self.text.insert('end', d, (self.tags, self.chartags))
 
 
@@ -233,28 +240,28 @@ class HelpWindow(Toplevel):
 def copy_strip():
     """Copy idle.html to idlelib/help.html, stripping trailing whitespace.
 
-    Files with trailing whitespace cannot be pushed to the hg cpython
+    Files with trailing whitespace cannot be pushed to the git cpython
     repository.  For 3.x (on Windows), help.html is generated, after
-    editing idle.rst in the earliest maintenance version, with
+    editing idle.rst on the master branch, with
       sphinx-build -bhtml . build/html
       python_d.exe -c "from idlelib.help import copy_strip; copy_strip()"
-    After refreshing TortoiseHG workshop to generate a diff,
-    check  both the diff and displayed text.  Push the diff along with
-    the idle.rst change and merge both into default (or an intermediate
-    maintenance version).
-
-    When the 'earlist' version gets its final maintenance release,
-    do an update as described above, without editing idle.rst, to
-    rebase help.html on the next version of idle.rst.  Do not worry
-    about version changes as version is not displayed.  Examine other
-    changes and the result of Help -> IDLE Help.
-
-    If maintenance and default versions of idle.rst diverge, and
-    merging does not go smoothly, then consider generating
-    separate help.html files from separate idle.htmls.
+    Check build/html/library/idle.html, the help.html diff, and the text
+    displayed by Help => IDLE Help.  Add a blurb and create a PR.
+
+    It can be worthwhile to occasionally generate help.html without
+    touching idle.rst.  Changes to the master version and to the doc
+    build system may result in changes that should not changed
+    the displayed text, but might break HelpParser.
+
+    As long as master and maintenance versions of idle.rst remain the
+    same, help.html can be backported.  The internal Python version
+    number is not displayed.  If maintenance idle.rst diverges from
+    the master version, then instead of backporting help.html from
+    master, repeat the proceedure above to generate a maintenance
+    version.
     """
     src = join(abspath(dirname(dirname(dirname(__file__)))),
-               'Doc', 'build', 'html', 'library', 'idle.html')
+            'Doc', 'build', 'html', 'library', 'idle.html')
     dst = join(abspath(dirname(__file__)), 'help.html')
     with open(src, 'rb') as inn,\
          open(dst, 'wb') as out:
index 7581fe2..7e7e0ae 100644 (file)
@@ -224,7 +224,7 @@ class HyperParser:
         given index, which is empty if there is no real one.
         """
         if not self.is_in_code():
-            raise ValueError("get_expression should only be called"
+            raise ValueError("get_expression should only be called "
                              "if index is inside a code.")
 
         rawtext = self.rawtext
index 8c1c24d..583e607 100644 (file)
@@ -117,7 +117,7 @@ ConfigDialog_spec = {
            "font face of the text in the area below it.\nIn the "
            "'Highlighting' tab, try different color schemes. Clicking "
            "items in the sample program should update the choices above it."
-           "\nIn the 'Keys', 'General' and 'Extensions' tabs, test settings"
+           "\nIn the 'Keys', 'General' and 'Extensions' tabs, test settings "
            "of interest."
            "\n[Ok] to close the dialog.[Apply] to apply the settings and "
            "and [Cancel] to revert all changes.\nRe-run the test to ensure "
@@ -152,7 +152,7 @@ GetKeysDialog_spec = {
     'msg': "Test for different key modifier sequences.\n"
            "<nothing> is invalid.\n"
            "No modifier key is invalid.\n"
-           "Shift key with [a-z],[0-9], function key, move key, tab, space"
+           "Shift key with [a-z],[0-9], function key, move key, tab, space "
            "is invalid.\nNo validity checking if advanced key binding "
            "entry is used."
     }
@@ -234,7 +234,7 @@ _percolator_spec = {
     'file': 'percolator',
     'kwds': {},
     'msg': "There are two tracers which can be toggled using a checkbox.\n"
-           "Toggling a tracer 'on' by checking it should print tracer"
+           "Toggling a tracer 'on' by checking it should print tracer "
            "output to the console or to the IDLE shell.\n"
            "If both the tracers are 'on', the output from the tracer which "
            "was switched 'on' later, should be printed first\n"
@@ -335,7 +335,7 @@ ViewWindow_spec = {
 _widget_redirector_spec = {
     'file': 'redirector',
     'kwds': {},
-    'msg': "Every text insert should be printed to the console."
+    'msg': "Every text insert should be printed to the console "
            "or the IDLE shell."
     }
 
index 6e35129..a54f51f 100644 (file)
@@ -260,7 +260,7 @@ class Text:
         elif op == '!=':
             return line1 != line2 or  char1 != char2
         else:
-            raise TclError('''bad comparison operator "%s":'''
+            raise TclError('''bad comparison operator "%s": '''
                                   '''must be <, <=, ==, >=, >, or !=''' % op)
 
     # The following Text methods normally do something and return None.
index 35cc346..70345f8 100644 (file)
@@ -11,7 +11,6 @@ import os.path
 from idlelib import _pyclbr as pyclbr
 from tkinter import Tk
 
-from idlelib import filelist
 from idlelib.tree import TreeNode
 
 
index 8c91972..169d054 100644 (file)
@@ -4,7 +4,6 @@
 Much of IdleConf is also exercised by ConfigDialog and test_configdialog.
 """
 from idlelib import config
-import copy
 import sys
 import os
 import tempfile
index 0847166..abe5749 100644 (file)
@@ -2,11 +2,10 @@
 
 from idlelib import config_key
 from test.support import requires
-import sys
 import unittest
 from tkinter import Tk
 from idlelib.idle_test.mock_idle import Func
-from idlelib.idle_test.mock_tk import Var, Mbox_func
+from idlelib.idle_test.mock_tk import Mbox_func
 
 
 class ValidationTest(unittest.TestCase):
index dbfcd01..5472a04 100644 (file)
@@ -8,7 +8,7 @@ requires('gui')
 import unittest
 from unittest import mock
 from idlelib.idle_test.mock_idle import Func
-from tkinter import Tk, Frame, StringVar, IntVar, BooleanVar, DISABLED, NORMAL
+from tkinter import Tk, StringVar, IntVar, BooleanVar, DISABLED, NORMAL
 from idlelib import config
 from idlelib.configdialog import idleConf, changes, tracers
 
index 48be65b..81eff39 100644 (file)
@@ -3,7 +3,6 @@
 from idlelib import rpc
 import unittest
 
-import marshal
 
 
 class CodePicklerTest(unittest.TestCase):
index bac86ac..aa5bdfb 100644 (file)
@@ -4,7 +4,7 @@
 from idlelib import zoomheight
 import unittest
 from test.support import requires
-from tkinter import Tk, Text
+from tkinter import Tk
 from idlelib.editor import EditorWindow
 
 
index fcd8dcc..f5bced5 100644 (file)
@@ -41,7 +41,7 @@ else:
             # these problems, falling back to ASCII
             locale_encoding = locale.nl_langinfo(locale.CODESET)
             if locale_encoding is None or locale_encoding == '':
-                # situation occurs on Mac OS X
+                # situation occurs on macOS
                 locale_encoding = 'ascii'
             codecs.lookup(locale_encoding)
         except (NameError, AttributeError, LookupError):
@@ -51,7 +51,7 @@ else:
             try:
                 locale_encoding = locale.getdefaultlocale()[1]
                 if locale_encoding is None or locale_encoding == '':
-                    # situation occurs on Mac OS X
+                    # situation occurs on macOS
                     locale_encoding = 'ascii'
                 codecs.lookup(locale_encoding)
             except (ValueError, LookupError):
index d3ae224..9be4ed2 100644 (file)
@@ -1,6 +1,8 @@
 """
-A number of functions that enhance IDLE on Mac OSX.
+A number of functions that enhance IDLE on macOS.
 """
+from os.path import expanduser
+import plistlib
 from sys import platform  # Used in _init_tk_type, changed by test.
 
 import tkinter
@@ -79,14 +81,47 @@ def tkVersionWarning(root):
         patchlevel = root.tk.call('info', 'patchlevel')
         if patchlevel not in ('8.5.7', '8.5.9'):
             return False
-        return (r"WARNING: The version of Tcl/Tk ({0}) in use may"
-                r" be unstable.\n"
-                r"Visit http://www.python.org/download/mac/tcltk/"
-                r" for current information.".format(patchlevel))
+        return ("WARNING: The version of Tcl/Tk ({0}) in use may"
+                " be unstable.\n"
+                "Visit http://www.python.org/download/mac/tcltk/"
+                " for current information.".format(patchlevel))
     else:
         return False
 
 
+def readSystemPreferences():
+    """
+    Fetch the macOS system preferences.
+    """
+    if platform != 'darwin':
+        return None
+
+    plist_path = expanduser('~/Library/Preferences/.GlobalPreferences.plist')
+    try:
+        with open(plist_path, 'rb') as plist_file:
+            return plistlib.load(plist_file)
+    except OSError:
+        return None
+
+
+def preferTabsPreferenceWarning():
+    """
+    Warn if "Prefer tabs when opening documents" is set to "Always".
+    """
+    if platform != 'darwin':
+        return None
+
+    prefs = readSystemPreferences()
+    if prefs and prefs.get('AppleWindowTabbingMode') == 'always':
+        return (
+            'WARNING: The system preference "Prefer tabs when opening'
+            ' documents" is set to "Always". This will cause various problems'
+            ' with IDLE. For the best experience, change this setting when'
+            ' running IDLE (via System Preferences -> Dock).'
+        )
+    return None
+
+
 ## Fix the menu and related functions.
 
 def addOpenEventSupport(root, flist):
@@ -192,7 +227,7 @@ def overrideRootMenu(root, flist):
         root.bind('<<close-all-windows>>', flist.close_all_callback)
 
         # The binding above doesn't reliably work on all versions of Tk
-        # on MacOSX. Adding command definition below does seem to do the
+        # on macOS. Adding command definition below does seem to do the
         # right thing for now.
         root.createcommand('exit', flist.close_all_callback)
 
index 4af9f1a..e962142 100644 (file)
@@ -109,7 +109,7 @@ class OutputWindow(EditorWindow):
         Return:
             Length of text inserted.
         """
-        if isinstance(s, (bytes, bytes)):
+        if isinstance(s, bytes):
             s = s.decode(iomenu.encoding, "replace")
         self.text.insert(mark, s, tags)
         self.text.see(mark)
index 1eeb915..81e7f53 100644 (file)
@@ -11,7 +11,6 @@ _closere - line that must be followed by dedent.
 _chew_ordinaryre - non-special characters.
 """
 import re
-import sys
 
 # Reason last statement is continued (or C_NONE if it's not).
 (C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE,
index 5458c59..81a97ef 100755 (executable)
@@ -12,11 +12,11 @@ except ImportError:
 # Valid arguments for the ...Awareness call below are defined in the following.
 # https://msdn.microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspx
 if sys.platform == 'win32':
-    import ctypes
-    PROCESS_SYSTEM_DPI_AWARE = 1
     try:
+        import ctypes
+        PROCESS_SYSTEM_DPI_AWARE = 1
         ctypes.OleDLL('shcore').SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
-    except (AttributeError, OSError):
+    except (ImportError, AttributeError, OSError):
         pass
 
 import tkinter.messagebox as tkMessageBox
@@ -38,6 +38,7 @@ from platform import python_version
 import re
 import socket
 import subprocess
+from textwrap import TextWrapper
 import threading
 import time
 import tokenize
@@ -1273,6 +1274,14 @@ class PyShell(OutputWindow):
         self.set_line_and_column()
         self.io.reset_undo()
 
+    def show_warning(self, msg):
+        width = self.interp.tkconsole.width
+        wrapper = TextWrapper(width=width, tabsize=8, expand_tabs=True)
+        wrapped_msg = '\n'.join(wrapper.wrap(msg))
+        if not wrapped_msg.endswith('\n'):
+            wrapped_msg += '\n'
+        self.per.bottom.insert("iomark linestart", wrapped_msg, "stderr")
+
     def resetoutput(self):
         source = self.text.get("iomark", "end-1c")
         if self.history:
@@ -1541,12 +1550,20 @@ def main():
             shell.interp.execfile(script)
     elif shell:
         # If there is a shell window and no cmd or script in progress,
-        # check for problematic OS X Tk versions and print a warning
-        # message in the IDLE shell window; this is less intrusive
-        # than always opening a separate window.
+        # check for problematic issues and print warning message(s) in
+        # the IDLE shell window; this is less intrusive than always
+        # opening a separate window.
+
+        # Warn if using a problematic OS X Tk version.
         tkversionwarning = macosx.tkVersionWarning(root)
         if tkversionwarning:
-            shell.interp.runcommand("print('%s')" % tkversionwarning)
+            shell.show_warning(tkversionwarning)
+
+        # Warn if the "Prefer tabs when opening documents" system
+        # preference is set to "Always".
+        prefer_tabs_preference_warning = macosx.preferTabsPreferenceWarning()
+        if prefer_tabs_preference_warning:
+            shell.show_warning(prefer_tabs_preference_warning)
 
     while flist.inversedict:  # keep IDLE running while files are open.
         root.mainloop()
index b9a01d6..67b2cc0 100644 (file)
@@ -1277,7 +1277,7 @@ if HAVE_SSL:
                                  "exclusive")
             if keyfile is not None or certfile is not None:
                 import warnings
-                warnings.warn("keyfile and certfile are deprecated, use a"
+                warnings.warn("keyfile and certfile are deprecated, use a "
                               "custom ssl_context instead", DeprecationWarning, 2)
             self.keyfile = keyfile
             self.certfile = certfile
index dd3b784..fbd8619 100644 (file)
@@ -1070,8 +1070,10 @@ def getargspec(func):
     Alternatively, use getfullargspec() for an API with a similar namedtuple
     based interface, but full support for annotations and keyword-only
     parameters.
+
+    Deprecated since Python 3.5, use `inspect.getfullargspec()`.
     """
-    warnings.warn("inspect.getargspec() is deprecated, "
+    warnings.warn("inspect.getargspec() is deprecated since Python 3.0, "
                   "use inspect.signature() or inspect.getfullargspec()",
                   DeprecationWarning, stacklevel=2)
     args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \
@@ -2784,19 +2786,25 @@ class Signature:
 
     @classmethod
     def from_function(cls, func):
-        """Constructs Signature for the given python function."""
+        """Constructs Signature for the given python function.
+
+        Deprecated since Python 3.5, use `Signature.from_callable()`.
+        """
 
-        warnings.warn("inspect.Signature.from_function() is deprecated, "
-                      "use Signature.from_callable()",
+        warnings.warn("inspect.Signature.from_function() is deprecated since "
+                      "Python 3.5, use Signature.from_callable()",
                       DeprecationWarning, stacklevel=2)
         return _signature_from_function(cls, func)
 
     @classmethod
     def from_builtin(cls, func):
-        """Constructs Signature for the given builtin function."""
+        """Constructs Signature for the given builtin function.
+
+        Deprecated since Python 3.5, use `Signature.from_callable()`.
+        """
 
-        warnings.warn("inspect.Signature.from_builtin() is deprecated, "
-                      "use Signature.from_callable()",
+        warnings.warn("inspect.Signature.from_builtin() is deprecated since "
+                      "Python 3.5, use Signature.from_callable()",
                       DeprecationWarning, stacklevel=2)
         return _signature_from_builtin(cls, func)
 
index 09cb6f6..b6c786f 100644 (file)
@@ -31,7 +31,8 @@ class FixExecfile(fixer_base.BaseFix):
         # call.
         execfile_paren = node.children[-1].children[-1].clone()
         # Construct open().read().
-        open_args = ArgList([filename.clone()], rparen=execfile_paren)
+        open_args = ArgList([filename.clone(), Comma(), String('"rb"', ' ')],
+                            rparen=execfile_paren)
         open_call = Node(syms.power, [Name("open"), open_args])
         read = [Node(syms.trailer, [Dot(), Name('read')]),
                 Node(syms.trailer, [LParen(), RParen()])]
index 3e1a255..052ab73 100644 (file)
@@ -1201,36 +1201,36 @@ class Test_execfile(FixerTestCase):
 
     def test_conversion(self):
         b = """execfile("fn")"""
-        a = """exec(compile(open("fn").read(), "fn", 'exec'))"""
+        a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'))"""
         self.check(b, a)
 
         b = """execfile("fn", glob)"""
-        a = """exec(compile(open("fn").read(), "fn", 'exec'), glob)"""
+        a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), glob)"""
         self.check(b, a)
 
         b = """execfile("fn", glob, loc)"""
-        a = """exec(compile(open("fn").read(), "fn", 'exec'), glob, loc)"""
+        a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), glob, loc)"""
         self.check(b, a)
 
         b = """execfile("fn", globals=glob)"""
-        a = """exec(compile(open("fn").read(), "fn", 'exec'), globals=glob)"""
+        a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), globals=glob)"""
         self.check(b, a)
 
         b = """execfile("fn", locals=loc)"""
-        a = """exec(compile(open("fn").read(), "fn", 'exec'), locals=loc)"""
+        a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), locals=loc)"""
         self.check(b, a)
 
         b = """execfile("fn", globals=glob, locals=loc)"""
-        a = """exec(compile(open("fn").read(), "fn", 'exec'), globals=glob, locals=loc)"""
+        a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), globals=glob, locals=loc)"""
         self.check(b, a)
 
     def test_spacing(self):
         b = """execfile( "fn" )"""
-        a = """exec(compile(open( "fn" ).read(), "fn", 'exec'))"""
+        a = """exec(compile(open( "fn", "rb" ).read(), "fn", 'exec'))"""
         self.check(b, a)
 
         b = """execfile("fn",  globals = glob)"""
-        a = """exec(compile(open("fn").read(), "fn", 'exec'),  globals = glob)"""
+        a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'),  globals = glob)"""
         self.check(b, a)
 
 
index 5a7e649..7321354 100644 (file)
@@ -450,6 +450,7 @@ def _default_mime_types():
         '.mht'    : 'message/rfc822',
         '.mhtml'  : 'message/rfc822',
         '.mif'    : 'application/x-mif',
+        '.mjs'    : 'application/javascript',
         '.mov'    : 'video/quicktime',
         '.movie'  : 'video/x-sgi-movie',
         '.mp2'    : 'audio/mpeg',
index 32254d8..a545f3c 100644 (file)
@@ -147,9 +147,8 @@ class Pool(object):
     '''
     _wrap_exception = True
 
-    @staticmethod
-    def Process(ctx, *args, **kwds):
-        return ctx.Process(*args, **kwds)
+    def Process(self, *args, **kwds):
+        return self._ctx.Process(*args, **kwds)
 
     def __init__(self, processes=None, initializer=None, initargs=(),
                  maxtasksperchild=None, context=None):
@@ -176,15 +175,13 @@ class Pool(object):
 
         self._worker_handler = threading.Thread(
             target=Pool._handle_workers,
-            args=(self._cache, self._taskqueue, self._ctx, self.Process,
-                  self._processes, self._pool, self._inqueue, self._outqueue,
-                  self._initializer, self._initargs, self._maxtasksperchild,
-                  self._wrap_exception)
+            args=(self, )
             )
         self._worker_handler.daemon = True
         self._worker_handler._state = RUN
         self._worker_handler.start()
 
+
         self._task_handler = threading.Thread(
             target=Pool._handle_tasks,
             args=(self._taskqueue, self._quick_put, self._outqueue,
@@ -210,62 +207,43 @@ class Pool(object):
             exitpriority=15
             )
 
-    @staticmethod
-    def _join_exited_workers(pool):
+    def _join_exited_workers(self):
         """Cleanup after any worker processes which have exited due to reaching
         their specified lifetime.  Returns True if any workers were cleaned up.
         """
         cleaned = False
-        for i in reversed(range(len(pool))):
-            worker = pool[i]
+        for i in reversed(range(len(self._pool))):
+            worker = self._pool[i]
             if worker.exitcode is not None:
                 # worker exited
                 util.debug('cleaning up worker %d' % i)
                 worker.join()
                 cleaned = True
-                del pool[i]
+                del self._pool[i]
         return cleaned
 
     def _repopulate_pool(self):
-        return self._repopulate_pool_static(self._ctx, self.Process,
-                                            self._processes,
-                                            self._pool, self._inqueue,
-                                            self._outqueue, self._initializer,
-                                            self._initargs,
-                                            self._maxtasksperchild,
-                                            self._wrap_exception)
-
-    @staticmethod
-    def _repopulate_pool_static(ctx, Process, processes, pool, inqueue,
-                                outqueue, initializer, initargs,
-                                maxtasksperchild, wrap_exception):
         """Bring the number of pool processes up to the specified number,
         for use after reaping workers which have exited.
         """
-        for i in range(processes - len(pool)):
-            w = Process(ctx, target=worker,
-                        args=(inqueue, outqueue,
-                              initializer,
-                              initargs, maxtasksperchild,
-                              wrap_exception)
-                       )
-            pool.append(w)
+        for i in range(self._processes - len(self._pool)):
+            w = self.Process(target=worker,
+                             args=(self._inqueue, self._outqueue,
+                                   self._initializer,
+                                   self._initargs, self._maxtasksperchild,
+                                   self._wrap_exception)
+                            )
+            self._pool.append(w)
             w.name = w.name.replace('Process', 'PoolWorker')
             w.daemon = True
             w.start()
             util.debug('added worker')
 
-    @staticmethod
-    def _maintain_pool(ctx, Process, processes, pool, inqueue, outqueue,
-                       initializer, initargs, maxtasksperchild,
-                       wrap_exception):
+    def _maintain_pool(self):
         """Clean up any exited workers and start replacements for them.
         """
-        if Pool._join_exited_workers(pool):
-            Pool._repopulate_pool_static(ctx, Process, processes, pool,
-                                         inqueue, outqueue, initializer,
-                                         initargs, maxtasksperchild,
-                                         wrap_exception)
+        if self._join_exited_workers():
+            self._repopulate_pool()
 
     def _setup_queues(self):
         self._inqueue = self._ctx.SimpleQueue()
@@ -418,20 +396,16 @@ class Pool(object):
         return result
 
     @staticmethod
-    def _handle_workers(cache, taskqueue, ctx, Process, processes, pool,
-                        inqueue, outqueue, initializer, initargs,
-                        maxtasksperchild, wrap_exception):
+    def _handle_workers(pool):
         thread = threading.current_thread()
 
         # Keep maintaining workers until the cache gets drained, unless the pool
         # is terminated.
-        while thread._state == RUN or (cache and thread._state != TERMINATE):
-            Pool._maintain_pool(ctx, Process, processes, pool, inqueue,
-                               outqueue, initializer, initargs,
-                               maxtasksperchild, wrap_exception)
+        while thread._state == RUN or (pool._cache and thread._state != TERMINATE):
+            pool._maintain_pool()
             time.sleep(0.1)
         # send sentinel to stop workers
-        taskqueue.put(None)
+        pool._taskqueue.put(None)
         util.debug('worker handler exiting')
 
     @staticmethod
@@ -807,7 +781,7 @@ class ThreadPool(Pool):
     _wrap_exception = False
 
     @staticmethod
-    def Process(ctx, *args, **kwds):
+    def Process(*args, **kwds):
         from .dummy import Process
         return Process(*args, **kwds)
 
index 24113e7..1b23a15 100644 (file)
@@ -545,8 +545,8 @@ else:  # use native Windows method on Windows
     def abspath(path):
         """Return the absolute version of a path."""
         try:
-            return _getfullpathname(path)
-        except OSError:
+            return normpath(_getfullpathname(path))
+        except (OSError, ValueError):
             return _abspath_fallback(path)
 
 # realpath is a no-op on systems without islink support
index 4205abd..fa56d41 100755 (executable)
@@ -243,27 +243,29 @@ def _dist_try_harder(distname, version, id):
     if os.path.exists('/var/adm/inst-log/info'):
         # SuSE Linux stores distribution information in that file
         distname = 'SuSE'
-        for line in open('/var/adm/inst-log/info'):
-            tv = line.split()
-            if len(tv) == 2:
-                tag, value = tv
-            else:
-                continue
-            if tag == 'MIN_DIST_VERSION':
-                version = value.strip()
-            elif tag == 'DIST_IDENT':
-                values = value.split('-')
-                id = values[2]
+        with open('/var/adm/inst-log/info') as f:
+            for line in f:
+                tv = line.split()
+                if len(tv) == 2:
+                    tag, value = tv
+                else:
+                    continue
+                if tag == 'MIN_DIST_VERSION':
+                    version = value.strip()
+                elif tag == 'DIST_IDENT':
+                    values = value.split('-')
+                    id = values[2]
         return distname, version, id
 
     if os.path.exists('/etc/.installed'):
         # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
-        for line in open('/etc/.installed'):
-            pkg = line.split('-')
-            if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
-                # XXX does Caldera support non Intel platforms ? If yes,
-                #     where can we find the needed id ?
-                return 'OpenLinux', pkg[1], id
+        with open('/etc/.installed') as f:
+            for line in f:
+                pkg = line.split('-')
+                if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
+                    # XXX does Caldera support non Intel platforms ? If yes,
+                    #     where can we find the needed id ?
+                    return 'OpenLinux', pkg[1], id
 
     if os.path.isdir('/usr/lib/setup'):
         # Check for slackware version tag file (thanks to Greg Andruk)
index d8a62c0..9796f0d 100644 (file)
@@ -436,7 +436,7 @@ if HAVE_SSL:
                                  "exclusive")
             if keyfile is not None or certfile is not None:
                 import warnings
-                warnings.warn("keyfile and certfile are deprecated, use a"
+                warnings.warn("keyfile and certfile are deprecated, use a "
                               "custom context instead", DeprecationWarning, 2)
             self.keyfile = keyfile
             self.certfile = certfile
index e92186c..ca578a5 100644 (file)
@@ -246,7 +246,12 @@ def expanduser(path):
     if i == 1:
         if 'HOME' not in os.environ:
             import pwd
-            userhome = pwd.getpwuid(os.getuid()).pw_dir
+            try:
+                userhome = pwd.getpwuid(os.getuid()).pw_dir
+            except KeyError:
+                # bpo-10496: if the current user identifier doesn't exist in the
+                # password database, return the path unchanged
+                return path
         else:
             userhome = os.environ['HOME']
     else:
@@ -257,6 +262,8 @@ def expanduser(path):
         try:
             pwent = pwd.getpwnam(name)
         except KeyError:
+            # bpo-10496: if the user name from the path doesn't exist in the
+            # password database, return the path unchanged
             return path
         userhome = pwent.pw_dir
     if isinstance(path, bytes):
index fffa2d5..b521a55 100644 (file)
@@ -941,8 +941,7 @@ class HTMLDoc(Doc):
         if name == realname:
             title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
         else:
-            if (cl and realname in cl.__dict__ and
-                cl.__dict__[realname] is object):
+            if cl and inspect.getattr_static(cl, realname, []) is object:
                 reallink = '<a href="#%s">%s</a>' % (
                     cl.__name__ + '-' + realname, realname)
                 skipdocs = 1
@@ -1346,8 +1345,7 @@ location listed above.
         if name == realname:
             title = self.bold(realname)
         else:
-            if (cl and realname in cl.__dict__ and
-                cl.__dict__[realname] is object):
+            if cl and inspect.getattr_static(cl, realname, []) is object:
                 skipdocs = 1
             title = self.bold(name) + ' = ' + realname
         argspec = None
index 9dc4a71..e4c6305 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Autogenerated by Sphinx on Sat Oct 20 01:13:41 2018
+# Autogenerated by Sphinx on Sun Dec 23 16:24:21 2018
 topics = {'assert': 'The "assert" statement\n'
            '**********************\n'
            '\n'
@@ -26,7 +26,8 @@ topics = {'assert': 'The "assert" statement\n'
            'implementation, the built-in variable "__debug__" is "True" under\n'
            'normal circumstances, "False" when optimization is requested '
            '(command\n'
-           'line option -O).  The current code generator emits no code for an\n'
+           'line option "-O").  The current code generator emits no code for '
+           'an\n'
            'assert statement when optimization is requested at compile time.  '
            'Note\n'
            'that it is unnecessary to include the source code for the '
@@ -87,23 +88,16 @@ topics = {'assert': 'The "assert" statement\n'
                'parentheses or square brackets, is recursively defined as '
                'follows.\n'
                '\n'
-               '* If the target list is empty: The object must also be an '
-               'empty\n'
-               '  iterable.\n'
-               '\n'
-               '* If the target list is a single target in parentheses: The '
-               'object\n'
-               '  is assigned to that target.\n'
+               '* If the target list is a single target with no trailing '
+               'comma,\n'
+               '  optionally in parentheses, the object is assigned to that '
+               'target.\n'
                '\n'
-               '* If the target list is a comma-separated list of targets, or '
-               'a\n'
-               '  single target in square brackets: The object must be an '
-               'iterable\n'
-               '  with the same number of items as there are targets in the '
-               'target\n'
-               '  list, and the items are assigned, from left to right, to '
-               'the\n'
-               '  corresponding targets.\n'
+               '* Else: The object must be an iterable with the same number of '
+               'items\n'
+               '  as there are targets in the target list, and the items are '
+               'assigned,\n'
+               '  from left to right, to the corresponding targets.\n'
                '\n'
                '  * If the target list contains one target prefixed with an\n'
                '    asterisk, called a “starred” target: The object must be '
@@ -400,9 +394,21 @@ topics = {'assert': 'The "assert" statement\n'
                'the last\n'
                '"__setitem__()" or "__setattr__()" call.\n'
                '\n'
-               'See also: **PEP 526** - Variable and attribute annotation '
-               'syntax\n'
-               '  **PEP 484** - Type hints\n',
+               'See also:\n'
+               '\n'
+               '  **PEP 526** - Syntax for Variable Annotations\n'
+               '     The proposal that added syntax for annotating the types '
+               'of\n'
+               '     variables (including class variables and instance '
+               'variables),\n'
+               '     instead of expressing them through comments.\n'
+               '\n'
+               '  **PEP 484** - Type hints\n'
+               '     The proposal that added the "typing" module to provide a '
+               'standard\n'
+               '     syntax for type annotations that can be used in static '
+               'analysis\n'
+               '     tools and IDEs.\n',
  'atom-identifiers': 'Identifiers (Names)\n'
                      '*******************\n'
                      '\n'
@@ -1176,7 +1182,7 @@ topics = {'assert': 'The "assert" statement\n'
              'is\n'
              'returned.\n'
              '\n'
-             '(Note that neither "and" nor "or" restrict the value and type '
+             'Note that neither "and" nor "or" restrict the value and type '
              'they\n'
              'return to "False" and "True", but rather return the last '
              'evaluated\n'
@@ -1442,7 +1448,7 @@ topics = {'assert': 'The "assert" statement\n'
           'original global namespace. (Usually, the suite contains mostly\n'
           'function definitions.)  When the class’s suite finishes execution, '
           'its\n'
-          'execution frame is discarded but its local namespace is saved. [4] '
+          'execution frame is discarded but its local namespace is saved. [3] '
           'A\n'
           'class object is then created using the inheritance list for the '
           'base\n'
@@ -1492,8 +1498,18 @@ topics = {'assert': 'The "assert" statement\n'
           'unexpected results.  Descriptors can be used to create instance\n'
           'variables with different implementation details.\n'
           '\n'
-          'See also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n'
-          '  Class Decorators\n',
+          'See also:\n'
+          '\n'
+          '  **PEP 3115** - Metaclasses in Python 3000\n'
+          '     The proposal that changed the declaration of metaclasses to '
+          'the\n'
+          '     current syntax, and the semantics for how classes with\n'
+          '     metaclasses are constructed.\n'
+          '\n'
+          '  **PEP 3129** - Class Decorators\n'
+          '     The proposal that added class decorators.  Function and '
+          'method\n'
+          '     decorators were introduced in **PEP 318**.\n',
  'comparisons': 'Comparisons\n'
                 '***********\n'
                 '\n'
@@ -2198,9 +2214,11 @@ topics = {'assert': 'The "assert" statement\n'
              'returning\n'
              'from a function that handled an exception.\n'
              '\n'
-             'The optional "else" clause is executed if and when control flows '
-             'off\n'
-             'the end of the "try" clause. [2] Exceptions in the "else" clause '
+             'The optional "else" clause is executed if the control flow '
+             'leaves the\n'
+             '"try" suite, no exception was raised, and no "return", '
+             '"continue", or\n'
+             '"break" statement was executed.  Exceptions in the "else" clause '
              'are\n'
              'not handled by the preceding "except" clauses.\n'
              '\n'
@@ -2388,7 +2406,7 @@ topics = {'assert': 'The "assert" statement\n'
              '\n'
              'The function definition does not execute the function body; this '
              'gets\n'
-             'executed only when the function is called. [3]\n'
+             'executed only when the function is called. [2]\n'
              '\n'
              'A function definition may be wrapped by one or more *decorator*\n'
              'expressions. Decorator expressions are evaluated when the '
@@ -2561,7 +2579,7 @@ topics = {'assert': 'The "assert" statement\n'
              'function definitions.)  When the class’s suite finishes '
              'execution, its\n'
              'execution frame is discarded but its local namespace is saved. '
-             '[4] A\n'
+             '[3] A\n'
              'class object is then created using the inheritance list for the '
              'base\n'
              'classes and the saved local namespace for the attribute '
@@ -2613,8 +2631,18 @@ topics = {'assert': 'The "assert" statement\n'
              'unexpected results.  Descriptors can be used to create instance\n'
              'variables with different implementation details.\n'
              '\n'
-             'See also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n'
-             '  Class Decorators\n'
+             'See also:\n'
+             '\n'
+             '  **PEP 3115** - Metaclasses in Python 3000\n'
+             '     The proposal that changed the declaration of metaclasses to '
+             'the\n'
+             '     current syntax, and the semantics for how classes with\n'
+             '     metaclasses are constructed.\n'
+             '\n'
+             '  **PEP 3129** - Class Decorators\n'
+             '     The proposal that added class decorators.  Function and '
+             'method\n'
+             '     decorators were introduced in **PEP 318**.\n'
              '\n'
              '\n'
              'Coroutines\n'
@@ -2731,7 +2759,12 @@ topics = {'assert': 'The "assert" statement\n'
              'an\n'
              '"async def" function.\n'
              '\n'
-             'See also: **PEP 492** - Coroutines with async and await syntax\n'
+             'See also:\n'
+             '\n'
+             '  **PEP 492** - Coroutines with async and await syntax\n'
+             '     The proposal that made coroutines a proper standalone '
+             'concept in\n'
+             '     Python, and added supporting syntax.\n'
              '\n'
              '-[ Footnotes ]-\n'
              '\n'
@@ -2740,16 +2773,11 @@ topics = {'assert': 'The "assert" statement\n'
              '    exception. That new exception causes the old one to be '
              'lost.\n'
              '\n'
-             '[2] Currently, control “flows off the end” except in the case '
-             'of\n'
-             '    an exception or the execution of a "return", "continue", or\n'
-             '    "break" statement.\n'
-             '\n'
-             '[3] A string literal appearing as the first statement in the\n'
+             '[2] A string literal appearing as the first statement in the\n'
              '    function body is transformed into the function’s "__doc__"\n'
              '    attribute and therefore the function’s *docstring*.\n'
              '\n'
-             '[4] A string literal appearing as the first statement in the '
+             '[3] A string literal appearing as the first statement in the '
              'class\n'
              '    body is transformed into the namespace’s "__doc__" item and\n'
              '    therefore the class’s *docstring*.\n',
@@ -4172,7 +4200,7 @@ topics = {'assert': 'The "assert" statement\n'
               'argument to the interpreter) is a code block.  A script command '
               '(a\n'
               'command specified on the interpreter command line with the '
-              '‘**-c**’\n'
+              '"-c"\n'
               'option) is a code block.  The string argument passed to the '
               'built-in\n'
               'functions "eval()" and "exec()" is a code block.\n'
@@ -5188,7 +5216,7 @@ topics = {'assert': 'The "assert" statement\n'
                   '\n'
                   'The new format syntax also supports new and different '
                   'options, shown\n'
-                  'in the follow examples.\n'
+                  'in the following examples.\n'
                   '\n'
                   'Accessing arguments by position:\n'
                   '\n'
@@ -5368,7 +5396,7 @@ topics = {'assert': 'The "assert" statement\n'
              '\n'
              'The function definition does not execute the function body; this '
              'gets\n'
-             'executed only when the function is called. [3]\n'
+             'executed only when the function is called. [2]\n'
              '\n'
              'A function definition may be wrapped by one or more *decorator*\n'
              'expressions. Decorator expressions are evaluated when the '
@@ -6119,8 +6147,9 @@ topics = {'assert': 'The "assert" statement\n'
  'lambda': 'Lambdas\n'
            '*******\n'
            '\n'
-           '   lambda_expr        ::= "lambda" [parameter_list]: expression\n'
-           '   lambda_expr_nocond ::= "lambda" [parameter_list]: '
+           '   lambda_expr        ::= "lambda" [parameter_list] ":" '
+           'expression\n'
+           '   lambda_expr_nocond ::= "lambda" [parameter_list] ":" '
            'expression_nocond\n'
            '\n'
            'Lambda expressions (sometimes called lambda forms) are used to '
@@ -7222,12 +7251,6 @@ topics = {'assert': 'The "assert" statement\n'
                    'of the\n'
                    '     sequence.\n'
                    '\n'
-                   'object.__missing__(self, key)\n'
-                   '\n'
-                   '   Called by "dict"."__getitem__()" to implement '
-                   '"self[key]" for dict\n'
-                   '   subclasses when key is not in the dictionary.\n'
-                   '\n'
                    'object.__setitem__(self, key, value)\n'
                    '\n'
                    '   Called to implement assignment to "self[key]".  Same '
@@ -7255,6 +7278,12 @@ topics = {'assert': 'The "assert" statement\n'
                    '   raised for improper *key* values as for the '
                    '"__getitem__()" method.\n'
                    '\n'
+                   'object.__missing__(self, key)\n'
+                   '\n'
+                   '   Called by "dict"."__getitem__()" to implement '
+                   '"self[key]" for dict\n'
+                   '   subclasses when key is not in the dictionary.\n'
+                   '\n'
                    'object.__iter__(self)\n'
                    '\n'
                    '   This method is called when an iterator is required for '
@@ -8632,8 +8661,8 @@ topics = {'assert': 'The "assert" statement\n'
                  '     Describes the implicit "__class__" closure reference\n'
                  '\n'
                  '\n'
-                 'Metaclass example\n'
-                 '-----------------\n'
+                 'Uses for metaclasses\n'
+                 '--------------------\n'
                  '\n'
                  'The potential uses for metaclasses are boundless. Some ideas '
                  'that have\n'
@@ -8643,48 +8672,6 @@ topics = {'assert': 'The "assert" statement\n'
                  'frameworks, and\n'
                  'automatic resource locking/synchronization.\n'
                  '\n'
-                 'Here is an example of a metaclass that uses an\n'
-                 '"collections.OrderedDict" to remember the order that class '
-                 'variables\n'
-                 'are defined:\n'
-                 '\n'
-                 '   class OrderedClass(type):\n'
-                 '\n'
-                 '       @classmethod\n'
-                 '       def __prepare__(metacls, name, bases, **kwds):\n'
-                 '           return collections.OrderedDict()\n'
-                 '\n'
-                 '       def __new__(cls, name, bases, namespace, **kwds):\n'
-                 '           result = type.__new__(cls, name, bases, '
-                 'dict(namespace))\n'
-                 '           result.members = tuple(namespace)\n'
-                 '           return result\n'
-                 '\n'
-                 '   class A(metaclass=OrderedClass):\n'
-                 '       def one(self): pass\n'
-                 '       def two(self): pass\n'
-                 '       def three(self): pass\n'
-                 '       def four(self): pass\n'
-                 '\n'
-                 '   >>> A.members\n'
-                 "   ('__module__', 'one', 'two', 'three', 'four')\n"
-                 '\n'
-                 'When the class definition for *A* gets executed, the process '
-                 'begins\n'
-                 'with calling the metaclass’s "__prepare__()" method which '
-                 'returns an\n'
-                 'empty "collections.OrderedDict".  That mapping records the '
-                 'methods and\n'
-                 'attributes of *A* as they are defined within the body of the '
-                 'class\n'
-                 'statement. Once those definitions are executed, the ordered '
-                 'dictionary\n'
-                 'is fully populated and the metaclass’s "__new__()" method '
-                 'gets\n'
-                 'invoked.  That method builds the new type and it saves the '
-                 'ordered\n'
-                 'dictionary keys in an attribute called "members".\n'
-                 '\n'
                  '\n'
                  'Customizing instance and subclass checks\n'
                  '========================================\n'
@@ -8884,12 +8871,6 @@ topics = {'assert': 'The "assert" statement\n'
                  'the\n'
                  '     sequence.\n'
                  '\n'
-                 'object.__missing__(self, key)\n'
-                 '\n'
-                 '   Called by "dict"."__getitem__()" to implement "self[key]" '
-                 'for dict\n'
-                 '   subclasses when key is not in the dictionary.\n'
-                 '\n'
                  'object.__setitem__(self, key, value)\n'
                  '\n'
                  '   Called to implement assignment to "self[key]".  Same note '
@@ -8917,6 +8898,12 @@ topics = {'assert': 'The "assert" statement\n'
                  '   raised for improper *key* values as for the '
                  '"__getitem__()" method.\n'
                  '\n'
+                 'object.__missing__(self, key)\n'
+                 '\n'
+                 '   Called by "dict"."__getitem__()" to implement "self[key]" '
+                 'for dict\n'
+                 '   subclasses when key is not in the dictionary.\n'
+                 '\n'
                  'object.__iter__(self)\n'
                  '\n'
                  '   This method is called when an iterator is required for a '
@@ -10556,8 +10543,11 @@ topics = {'assert': 'The "assert" statement\n'
         'restored to their previous values (before the call) when returning\n'
         'from a function that handled an exception.\n'
         '\n'
-        'The optional "else" clause is executed if and when control flows off\n'
-        'the end of the "try" clause. [2] Exceptions in the "else" clause are\n'
+        'The optional "else" clause is executed if the control flow leaves '
+        'the\n'
+        '"try" suite, no exception was raised, and no "return", "continue", '
+        'or\n'
+        '"break" statement was executed.  Exceptions in the "else" clause are\n'
         'not handled by the preceding "except" clauses.\n'
         '\n'
         'If "finally" is present, it specifies a ‘cleanup’ handler.  The '
index bd4760f..dd12448 100644 (file)
@@ -171,11 +171,15 @@ else:
         pass
 
 def copystat(src, dst, *, follow_symlinks=True):
-    """Copy all stat info (mode bits, atime, mtime, flags) from src to dst.
+    """Copy file metadata
 
-    If the optional flag `follow_symlinks` is not set, symlinks aren't followed if and
-    only if both `src` and `dst` are symlinks.
+    Copy the permission bits, last access time, last modification time, and
+    flags from `src` to `dst`. On Linux, copystat() also copies the "extended
+    attributes" where possible. The file contents, owner, and group are
+    unaffected. `src` and `dst` are path names given as strings.
 
+    If the optional flag `follow_symlinks` is not set, symlinks aren't
+    followed if and only if both `src` and `dst` are symlinks.
     """
     def _nop(*args, ns=None, follow_symlinks=None):
         pass
@@ -243,8 +247,10 @@ def copy(src, dst, *, follow_symlinks=True):
     return dst
 
 def copy2(src, dst, *, follow_symlinks=True):
-    """Copy data and all stat info ("cp -p src dst"). Return the file's
-    destination."
+    """Copy data and metadata. Return the file's destination.
+
+    Metadata is copied with copystat(). Please see the copystat function
+    for more information.
 
     The destination may be a directory.
 
index 5e1bc0b..6091c7f 100755 (executable)
@@ -762,7 +762,7 @@ class SMTP:
                                  "exclusive")
             if keyfile is not None or certfile is not None:
                 import warnings
-                warnings.warn("keyfile and certfile are deprecated, use a"
+                warnings.warn("keyfile and certfile are deprecated, use a "
                               "custom context instead", DeprecationWarning, 2)
             if context is None:
                 context = ssl._create_stdlib_context(certfile=certfile,
@@ -1019,7 +1019,7 @@ if _have_ssl:
                                  "exclusive")
             if keyfile is not None or certfile is not None:
                 import warnings
-                warnings.warn("keyfile and certfile are deprecated, use a"
+                warnings.warn("keyfile and certfile are deprecated, use a "
                               "custom context instead", DeprecationWarning, 2)
             self.keyfile = keyfile
             self.certfile = certfile
index c4d544b..6a0aeee 100644 (file)
@@ -234,6 +234,9 @@ class BaseServer:
 
                 while not self.__shutdown_request:
                     ready = selector.select(poll_interval)
+                    # bpo-35017: shutdown() called during select(), exit immediately.
+                    if self.__shutdown_request:
+                        break
                     if ready:
                         self._handle_request_noblock()
 
index 34cd233..1c59a3c 100644 (file)
@@ -256,24 +256,6 @@ class RegressionTests(unittest.TestCase):
         cur.execute("pragma page_size")
         row = cur.fetchone()
 
-    def CheckSetDict(self):
-        """
-        See http://bugs.python.org/issue7478
-
-        It was possible to successfully register callbacks that could not be
-        hashed. Return codes of PyDict_SetItem were not checked properly.
-        """
-        class NotHashable:
-            def __call__(self, *args, **kw):
-                pass
-            def __hash__(self):
-                raise TypeError()
-        var = NotHashable()
-        self.assertRaises(TypeError, self.con.create_function, var)
-        self.assertRaises(TypeError, self.con.create_aggregate, var)
-        self.assertRaises(TypeError, self.con.set_authorizer, var)
-        self.assertRaises(TypeError, self.con.set_progress_handler, var)
-
     def CheckConnectionCall(self):
         """
         Call a connection with a non-string SQL request: check error handling
@@ -398,9 +380,72 @@ class RegressionTests(unittest.TestCase):
         support.gc_collect()
 
 
+class UnhashableFunc:
+    __hash__ = None
+
+    def __init__(self, return_value=None):
+        self.calls = 0
+        self.return_value = return_value
+
+    def __call__(self, *args, **kwargs):
+        self.calls += 1
+        return self.return_value
+
+
+class UnhashableCallbacksTestCase(unittest.TestCase):
+    """
+    https://bugs.python.org/issue34052
+
+    Registering unhashable callbacks raises TypeError, callbacks are not
+    registered in SQLite after such registration attempt.
+    """
+    def setUp(self):
+        self.con = sqlite.connect(':memory:')
+
+    def tearDown(self):
+        self.con.close()
+
+    def test_progress_handler(self):
+        f = UnhashableFunc(return_value=0)
+        with self.assertRaisesRegex(TypeError, 'unhashable type'):
+            self.con.set_progress_handler(f, 1)
+        self.con.execute('SELECT 1')
+        self.assertFalse(f.calls)
+
+    def test_func(self):
+        func_name = 'func_name'
+        f = UnhashableFunc()
+        with self.assertRaisesRegex(TypeError, 'unhashable type'):
+            self.con.create_function(func_name, 0, f)
+        msg = 'no such function: %s' % func_name
+        with self.assertRaisesRegex(sqlite.OperationalError, msg):
+            self.con.execute('SELECT %s()' % func_name)
+        self.assertFalse(f.calls)
+
+    def test_authorizer(self):
+        f = UnhashableFunc(return_value=sqlite.SQLITE_DENY)
+        with self.assertRaisesRegex(TypeError, 'unhashable type'):
+            self.con.set_authorizer(f)
+        self.con.execute('SELECT 1')
+        self.assertFalse(f.calls)
+
+    def test_aggr(self):
+        class UnhashableType(type):
+            __hash__ = None
+        aggr_name = 'aggr_name'
+        with self.assertRaisesRegex(TypeError, 'unhashable type'):
+            self.con.create_aggregate(aggr_name, 0, UnhashableType('Aggr', (), {}))
+        msg = 'no such function: %s' % aggr_name
+        with self.assertRaisesRegex(sqlite.OperationalError, msg):
+            self.con.execute('SELECT %s()' % aggr_name)
+
+
 def suite():
     regression_suite = unittest.makeSuite(RegressionTests, "Check")
-    return unittest.TestSuite((regression_suite,))
+    return unittest.TestSuite((
+        regression_suite,
+        unittest.makeSuite(UnhashableCallbacksTestCase),
+    ))
 
 def test():
     runner = unittest.TextTestRunner()
index cd216a1..58d3e93 100644 (file)
@@ -848,8 +848,8 @@ class SSLSocket(socket):
             return self._sslobj.session_reused
 
     def dup(self):
-        raise NotImplemented("Can't dup() %s instances" %
-                             self.__class__.__name__)
+        raise NotImplementedError("Can't dup() %s instances" %
+                                  self.__class__.__name__)
 
     def _checkClosed(self, msg=None):
         # raise an exception here if you wish to check for spurious closes
index 290ae44..8c3fa1b 100644 (file)
@@ -232,15 +232,13 @@ def _optim_args_from_interpreter_flags():
 
 def _args_from_interpreter_flags():
     """Return a list of command-line arguments reproducing the current
-    settings in sys.flags and sys.warnoptions."""
+    settings in sys.flags, sys.warnoptions and sys._xoptions."""
     flag_opt_map = {
         'debug': 'd',
         # 'inspect': 'i',
         # 'interactive': 'i',
         'dont_write_bytecode': 'B',
-        'no_user_site': 's',
         'no_site': 'S',
-        'ignore_environment': 'E',
         'verbose': 'v',
         'bytes_warning': 'b',
         'quiet': 'q',
@@ -251,8 +249,30 @@ def _args_from_interpreter_flags():
         v = getattr(sys.flags, flag)
         if v > 0:
             args.append('-' + opt * v)
+
+    if sys.flags.isolated:
+        args.append('-I')
+    else:
+        if sys.flags.ignore_environment:
+            args.append('-E')
+        if sys.flags.no_user_site:
+            args.append('-s')
+
     for opt in sys.warnoptions:
         args.append('-W' + opt)
+
+    # -X options
+    xoptions = getattr(sys, '_xoptions', {})
+    for opt in ('faulthandler', 'tracemalloc',
+                'showalloccount', 'showrefcount', 'utf8'):
+        if opt in xoptions:
+            value = xoptions[opt]
+            if value is True:
+                arg = opt
+            else:
+                arg = '%s=%s' % (opt, value)
+            args.extend(('-X', arg))
+
     return args
 
 
index 6667f11..d5c1ec1 100644 (file)
@@ -2199,6 +2199,7 @@ class _TestPool(BaseTestCase):
             with self.Pool(2) as p:
                 r = p.map_async(sqr, L)
                 self.assertEqual(r.get(), expected)
+            p.join()
             self.assertRaises(ValueError, p.map_async, sqr, L)
 
     @classmethod
@@ -2216,6 +2217,7 @@ class _TestPool(BaseTestCase):
                     exc = e
                 else:
                     self.fail('expected RuntimeError')
+            p.join()
             self.assertIs(type(exc), RuntimeError)
             self.assertEqual(exc.args, (123,))
             cause = exc.__cause__
@@ -2240,6 +2242,7 @@ class _TestPool(BaseTestCase):
                     self.fail('expected SayWhenError')
                 self.assertIs(type(exc), SayWhenError)
                 self.assertIs(exc.__cause__, None)
+            p.join()
 
     @classmethod
     def _test_wrapped_exception(cls):
@@ -2250,6 +2253,7 @@ class _TestPool(BaseTestCase):
         with self.Pool(1) as p:
             with self.assertRaises(RuntimeError):
                 p.apply(self._test_wrapped_exception)
+        p.join()
 
     def test_map_no_failfast(self):
         # Issue #23992: the fail-fast behaviour when an exception is raised
@@ -2285,12 +2289,6 @@ class _TestPool(BaseTestCase):
         # they were released too.
         self.assertEqual(CountedObject.n_instances, 0)
 
-    def test_del_pool(self):
-        p = self.Pool(1)
-        wr = weakref.ref(p)
-        del p
-        gc.collect()
-        self.assertIsNone(wr())
 
 def raising():
     raise KeyError("key")
index 40a457c..a11908a 100644 (file)
@@ -35,6 +35,7 @@ import time as _time
 import _strptime
 #
 
+pickle_loads = {pickle.loads, pickle._loads}
 
 pickle_choices = [(pickle, pickle, proto)
                   for proto in range(pickle.HIGHEST_PROTOCOL + 1)]
@@ -872,19 +873,50 @@ class TestTimeDelta(HarmlessMixedComparison, unittest.TestCase):
         class BadInt(int):
             def __mul__(self, other):
                 return Prod()
+            def __rmul__(self, other):
+                return Prod()
+            def __floordiv__(self, other):
+                return Prod()
+            def __rfloordiv__(self, other):
+                return Prod()
 
         class Prod:
+            def __add__(self, other):
+                return Sum()
             def __radd__(self, other):
                 return Sum()
 
         class Sum(int):
             def __divmod__(self, other):
-                # negative remainder
-                return (0, -1)
-
-        timedelta(microseconds=BadInt(1))
-        timedelta(hours=BadInt(1))
-        timedelta(weeks=BadInt(1))
+                return divmodresult
+
+        for divmodresult in [None, (), (0, 1, 2), (0, -1)]:
+            with self.subTest(divmodresult=divmodresult):
+                # The following examples should not crash.
+                try:
+                    timedelta(microseconds=BadInt(1))
+                except TypeError:
+                    pass
+                try:
+                    timedelta(hours=BadInt(1))
+                except TypeError:
+                    pass
+                try:
+                    timedelta(weeks=BadInt(1))
+                except (TypeError, ValueError):
+                    pass
+                try:
+                    timedelta(1) * BadInt(1)
+                except (TypeError, ValueError):
+                    pass
+                try:
+                    BadInt(1) * timedelta(1)
+                except TypeError:
+                    pass
+                try:
+                    timedelta(1) // BadInt(1)
+                except TypeError:
+                    pass
 
 
 #############################################################################
@@ -1373,6 +1405,19 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase):
             self.assertEqual(orig, derived)
         self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
 
+    def test_compat_unpickle(self):
+        tests = [
+            b"cdatetime\ndate\n(S'\\x07\\xdf\\x0b\\x1b'\ntR.",
+            b'cdatetime\ndate\n(U\x04\x07\xdf\x0b\x1btR.',
+            b'\x80\x02cdatetime\ndate\nU\x04\x07\xdf\x0b\x1b\x85R.',
+        ]
+        args = 2015, 11, 27
+        expected = self.theclass(*args)
+        for data in tests:
+            for loads in pickle_loads:
+                derived = loads(data, encoding='latin1')
+                self.assertEqual(derived, expected)
+
     def test_compare(self):
         t1 = self.theclass(2, 3, 4)
         t2 = self.theclass(2, 3, 4)
@@ -1899,6 +1944,24 @@ class TestDateTime(TestDate):
             derived = unpickler.loads(green)
             self.assertEqual(orig, derived)
 
+    def test_compat_unpickle(self):
+        tests = [
+            b'cdatetime\ndatetime\n('
+            b"S'\\x07\\xdf\\x0b\\x1b\\x14;\\x01\\x00\\x10\\x00'\ntR.",
+
+            b'cdatetime\ndatetime\n('
+            b'U\n\x07\xdf\x0b\x1b\x14;\x01\x00\x10\x00tR.',
+
+            b'\x80\x02cdatetime\ndatetime\n'
+            b'U\n\x07\xdf\x0b\x1b\x14;\x01\x00\x10\x00\x85R.',
+        ]
+        args = 2015, 11, 27, 20, 59, 1, 64**2
+        expected = self.theclass(*args)
+        for data in tests:
+            for loads in pickle_loads:
+                derived = loads(data, encoding='latin1')
+                self.assertEqual(derived, expected)
+
     def test_more_compare(self):
         # The test_compare() inherited from TestDate covers the error cases.
         # We just want to test lexicographic ordering on the members datetime
@@ -2578,6 +2641,19 @@ class TestTime(HarmlessMixedComparison, unittest.TestCase):
             derived = unpickler.loads(green)
             self.assertEqual(orig, derived)
 
+    def test_compat_unpickle(self):
+        tests = [
+            b"cdatetime\ntime\n(S'\\x14;\\x10\\x00\\x10\\x00'\ntR.",
+            b'cdatetime\ntime\n(U\x06\x14;\x10\x00\x10\x00tR.',
+            b'\x80\x02cdatetime\ntime\nU\x06\x14;\x10\x00\x10\x00\x85R.',
+        ]
+        args = 20, 59, 16, 64**2
+        expected = self.theclass(*args)
+        for data in tests:
+            for loads in pickle_loads:
+                derived = loads(data, encoding='latin1')
+                self.assertEqual(derived, expected)
+
     def test_bool(self):
         # time is always True.
         cls = self.theclass
@@ -2950,6 +3026,40 @@ class TestTimeTZ(TestTime, TZInfoBase, unittest.TestCase):
             self.assertEqual(derived.tzname(), 'cookie')
         self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
 
+    def test_compat_unpickle(self):
+        tests = [
+            b"cdatetime\ntime\n(S'\\x05\\x06\\x07\\x01\\xe2@'\n"
+            b"ctest.datetimetester\nPicklableFixedOffset\n(tR"
+            b"(dS'_FixedOffset__offset'\ncdatetime\ntimedelta\n"
+            b"(I-1\nI68400\nI0\ntRs"
+            b"S'_FixedOffset__dstoffset'\nNs"
+            b"S'_FixedOffset__name'\nS'cookie'\nsbtR.",
+
+            b'cdatetime\ntime\n(U\x06\x05\x06\x07\x01\xe2@'
+            b'ctest.datetimetester\nPicklableFixedOffset\n)R'
+            b'}(U\x14_FixedOffset__offsetcdatetime\ntimedelta\n'
+            b'(J\xff\xff\xff\xffJ0\x0b\x01\x00K\x00tR'
+            b'U\x17_FixedOffset__dstoffsetN'
+            b'U\x12_FixedOffset__nameU\x06cookieubtR.',
+
+            b'\x80\x02cdatetime\ntime\nU\x06\x05\x06\x07\x01\xe2@'
+            b'ctest.datetimetester\nPicklableFixedOffset\n)R'
+            b'}(U\x14_FixedOffset__offsetcdatetime\ntimedelta\n'
+            b'J\xff\xff\xff\xffJ0\x0b\x01\x00K\x00\x87R'
+            b'U\x17_FixedOffset__dstoffsetN'
+            b'U\x12_FixedOffset__nameU\x06cookieub\x86R.',
+        ]
+
+        tinfo = PicklableFixedOffset(-300, 'cookie')
+        expected = self.theclass(5, 6, 7, 123456, tzinfo=tinfo)
+        for data in tests:
+            for loads in pickle_loads:
+                derived = loads(data, encoding='latin1')
+                self.assertEqual(derived, expected, repr(data))
+                self.assertIsInstance(derived.tzinfo, PicklableFixedOffset)
+                self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
+                self.assertEqual(derived.tzname(), 'cookie')
+
     def test_more_bool(self):
         # time is always True.
         cls = self.theclass
@@ -3167,6 +3277,43 @@ class TestDateTimeTZ(TestDateTime, TZInfoBase, unittest.TestCase):
             self.assertEqual(derived.tzname(), 'cookie')
         self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
 
+    def test_compat_unpickle(self):
+        tests = [
+            b'cdatetime\ndatetime\n'
+            b"(S'\\x07\\xdf\\x0b\\x1b\\x14;\\x01\\x01\\xe2@'\n"
+            b'ctest.datetimetester\nPicklableFixedOffset\n(tR'
+            b"(dS'_FixedOffset__offset'\ncdatetime\ntimedelta\n"
+            b'(I-1\nI68400\nI0\ntRs'
+            b"S'_FixedOffset__dstoffset'\nNs"
+            b"S'_FixedOffset__name'\nS'cookie'\nsbtR.",
+
+            b'cdatetime\ndatetime\n'
+            b'(U\n\x07\xdf\x0b\x1b\x14;\x01\x01\xe2@'
+            b'ctest.datetimetester\nPicklableFixedOffset\n)R'
+            b'}(U\x14_FixedOffset__offsetcdatetime\ntimedelta\n'
+            b'(J\xff\xff\xff\xffJ0\x0b\x01\x00K\x00tR'
+            b'U\x17_FixedOffset__dstoffsetN'
+            b'U\x12_FixedOffset__nameU\x06cookieubtR.',
+
+            b'\x80\x02cdatetime\ndatetime\n'
+            b'U\n\x07\xdf\x0b\x1b\x14;\x01\x01\xe2@'
+            b'ctest.datetimetester\nPicklableFixedOffset\n)R'
+            b'}(U\x14_FixedOffset__offsetcdatetime\ntimedelta\n'
+            b'J\xff\xff\xff\xffJ0\x0b\x01\x00K\x00\x87R'
+            b'U\x17_FixedOffset__dstoffsetN'
+            b'U\x12_FixedOffset__nameU\x06cookieub\x86R.',
+        ]
+        args = 2015, 11, 27, 20, 59, 1, 123456
+        tinfo = PicklableFixedOffset(-300, 'cookie')
+        expected = self.theclass(*args, **{'tzinfo': tinfo})
+        for data in tests:
+            for loads in pickle_loads:
+                derived = loads(data, encoding='latin1')
+                self.assertEqual(derived, expected)
+                self.assertIsInstance(derived.tzinfo, PicklableFixedOffset)
+                self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
+                self.assertEqual(derived.tzname(), 'cookie')
+
     def test_extreme_hashes(self):
         # If an attempt is made to hash these via subtracting the offset
         # then hashing a datetime object, OverflowError results.  The
index 1caeafe..25c169b 100644 (file)
@@ -10,6 +10,7 @@ sub-second periodicity (contrarily to signal()).
 
 import contextlib
 import faulthandler
+import fcntl
 import os
 import select
 import signal
@@ -44,25 +45,28 @@ class EINTRBaseTest(unittest.TestCase):
     # sleep_time > signal_period
     sleep_time = 0.2
 
-    @classmethod
-    def setUpClass(cls):
-        cls.orig_handler = signal.signal(signal.SIGALRM, lambda *args: None)
-        signal.setitimer(signal.ITIMER_REAL, cls.signal_delay,
-                         cls.signal_period)
+    def sighandler(self, signum, frame):
+        self.signals += 1
 
-        # Issue #25277: Use faulthandler to try to debug a hang on FreeBSD
+    def setUp(self):
+        self.signals = 0
+        self.orig_handler = signal.signal(signal.SIGALRM, self.sighandler)
+        signal.setitimer(signal.ITIMER_REAL, self.signal_delay,
+                         self.signal_period)
+
+        # Use faulthandler as watchdog to debug when a test hangs
+        # (timeout of 10 minutes)
         if hasattr(faulthandler, 'dump_traceback_later'):
             faulthandler.dump_traceback_later(10 * 60, exit=True,
                                               file=sys.__stderr__)
 
-    @classmethod
-    def stop_alarm(cls):
+    @staticmethod
+    def stop_alarm():
         signal.setitimer(signal.ITIMER_REAL, 0, 0)
 
-    @classmethod
-    def tearDownClass(cls):
-        cls.stop_alarm()
-        signal.signal(signal.SIGALRM, cls.orig_handler)
+    def tearDown(self):
+        self.stop_alarm()
+        signal.signal(signal.SIGALRM, self.orig_handler)
         if hasattr(faulthandler, 'cancel_dump_traceback_later'):
             faulthandler.cancel_dump_traceback_later()
 
@@ -345,16 +349,18 @@ class SocketEINTRTest(EINTRBaseTest):
         fp = open(path, 'w')
         fp.close()
 
+    @unittest.skipIf(sys.platform == "darwin",
+                     "hangs under macOS; see bpo-25234, bpo-35363")
     def test_open(self):
         self._test_open("fp = open(path, 'r')\nfp.close()",
                         self.python_open)
 
-    @unittest.skipIf(sys.platform == 'darwin', "hangs under OS X; see issue #25234")
     def os_open(self, path):
         fd = os.open(path, os.O_WRONLY)
         os.close(fd)
 
-    @unittest.skipIf(sys.platform == "darwin", "hangs under OS X; see issue #25234")
+    @unittest.skipIf(sys.platform == "darwin",
+                     "hangs under macOS; see bpo-25234, bpo-35363")
     def test_os_open(self):
         self._test_open("fd = os.open(path, os.O_RDONLY)\nos.close(fd)",
                         self.os_open)
@@ -481,14 +487,43 @@ class SelectEINTRTest(EINTRBaseTest):
         self.assertGreaterEqual(dt, self.sleep_time)
 
 
-def test_main():
-    support.run_unittest(
-        OSEINTRTest,
-        SocketEINTRTest,
-        TimeEINTRTest,
-        SignalEINTRTest,
-        SelectEINTRTest)
+class FNTLEINTRTest(EINTRBaseTest):
+    def _lock(self, lock_func, lock_name):
+        self.addCleanup(support.unlink, support.TESTFN)
+        code = '\n'.join((
+            "import fcntl, time",
+            "with open('%s', 'wb') as f:" % support.TESTFN,
+            "   fcntl.%s(f, fcntl.LOCK_EX)" % lock_name,
+            "   time.sleep(%s)" % self.sleep_time))
+        start_time = time.monotonic()
+        proc = self.subprocess(code)
+        with kill_on_error(proc):
+            with open(support.TESTFN, 'wb') as f:
+                while True:  # synchronize the subprocess
+                    dt = time.monotonic() - start_time
+                    if dt > 60.0:
+                        raise Exception("failed to sync child in %.1f sec" % dt)
+                    try:
+                        lock_func(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
+                        lock_func(f, fcntl.LOCK_UN)
+                        time.sleep(0.01)
+                    except BlockingIOError:
+                        break
+                # the child locked the file just a moment ago for 'sleep_time' seconds
+                # that means that the lock below will block for 'sleep_time' minus some
+                # potential context switch delay
+                lock_func(f, fcntl.LOCK_EX)
+                dt = time.monotonic() - start_time
+                self.assertGreaterEqual(dt, self.sleep_time)
+                self.stop_alarm()
+            proc.wait()
+
+    def test_lockf(self):
+        self._lock(fcntl.lockf, "lockf")
+
+    def test_flock(self):
+        self._lock(fcntl.flock, "flock")
 
 
 if __name__ == "__main__":
-    test_main()
+    unittest.main()
index 2af839a..538ff05 100644 (file)
@@ -170,7 +170,7 @@ def _create_parser():
     group.add_argument('--wait', action='store_true',
                        help='wait for user input, e.g., allow a debugger '
                             'to be attached')
-    group.add_argument('--slaveargs', metavar='ARGS')
+    group.add_argument('--worker-args', metavar='ARGS')
     group.add_argument('-S', '--start', metavar='START',
                        help='the name of the test at which to start.' +
                             more_details)
index b491a08..b6d05f6 100644 (file)
@@ -14,7 +14,7 @@ from test.libregrtest.cmdline import _parse_args
 from test.libregrtest.runtest import (
     findtests, runtest, get_abs_module,
     STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED,
-    INTERRUPTED, CHILD_ERROR,
+    INTERRUPTED, CHILD_ERROR, TEST_DID_NOT_RUN,
     PROGRESS_MIN_TIME, format_test_result)
 from test.libregrtest.setup import setup_tests
 from test.libregrtest.utils import removepy, count, format_duration, printlist
@@ -79,6 +79,7 @@ class Regrtest:
         self.resource_denieds = []
         self.environment_changed = []
         self.rerun = []
+        self.run_no_tests = []
         self.first_result = None
         self.interrupted = False
 
@@ -118,6 +119,8 @@ class Regrtest:
         elif ok == RESOURCE_DENIED:
             self.skipped.append(test)
             self.resource_denieds.append(test)
+        elif ok == TEST_DID_NOT_RUN:
+            self.run_no_tests.append(test)
         elif ok != INTERRUPTED:
             raise ValueError("invalid test result: %r" % ok)
 
@@ -368,6 +371,11 @@ class Regrtest:
             print("%s:" % count(len(self.rerun), "re-run test"))
             printlist(self.rerun)
 
+        if self.run_no_tests:
+            print()
+            print(count(len(self.run_no_tests), "test"), "run no tests:")
+            printlist(self.run_no_tests)
+
     def run_tests_sequential(self):
         if self.ns.trace:
             import trace
@@ -458,6 +466,9 @@ class Regrtest:
             result.append("FAILURE")
         elif self.ns.fail_env_changed and self.environment_changed:
             result.append("ENV CHANGED")
+        elif not any((self.good, self.bad, self.skipped, self.interrupted,
+            self.environment_changed)):
+            result.append("NO TEST RUN")
 
         if self.interrupted:
             result.append("INTERRUPTED")
@@ -582,9 +593,9 @@ class Regrtest:
                 print(msg, file=sys.stderr, flush=True)
                 sys.exit(2)
 
-        if self.ns.slaveargs is not None:
-            from test.libregrtest.runtest_mp import run_tests_slave
-            run_tests_slave(self.ns.slaveargs)
+        if self.ns.worker_args is not None:
+            from test.libregrtest.runtest_mp import run_tests_worker
+            run_tests_worker(self.ns.worker_args)
 
         if self.ns.wait:
             input("Press any key to continue...")
index 4f41080..466b522 100644 (file)
@@ -19,6 +19,7 @@ SKIPPED = -2
 RESOURCE_DENIED = -3
 INTERRUPTED = -4
 CHILD_ERROR = -5   # error in a child process
+TEST_DID_NOT_RUN = -6   # error in a child process
 
 _FORMAT_TEST_RESULT = {
     PASSED: '%s passed',
@@ -28,6 +29,7 @@ _FORMAT_TEST_RESULT = {
     RESOURCE_DENIED: '%s skipped (resource denied)',
     INTERRUPTED: '%s interrupted',
     CHILD_ERROR: '%s crashed',
+    TEST_DID_NOT_RUN: '%s run no tests',
 }
 
 # Minimum duration of a test to display its duration or to mention that
@@ -94,6 +96,7 @@ def runtest(ns, test):
         ENV_CHANGED      test failed because it changed the execution environment
         FAILED           test failed
         PASSED           test passed
+        EMPTY_TEST_SUITE test ran no subtests.
 
     If ns.xmlpath is not None, xml_data is a list containing each
     generated testsuite element.
@@ -197,6 +200,8 @@ def runtest_inner(ns, test, display_failure=True):
             else:
                 print("test", test, "failed", file=sys.stderr, flush=True)
         return FAILED, test_time
+    except support.TestDidNotRun:
+        return TEST_DID_NOT_RUN, test_time
     except:
         msg = traceback.format_exc()
         if not ns.pgo:
index e5e808a..fdbd733 100644 (file)
@@ -28,23 +28,23 @@ WAIT_PROGRESS = 2.0   # seconds
 
 
 def run_test_in_subprocess(testname, ns):
-    """Run the given test in a subprocess with --slaveargs.
+    """Run the given test in a subprocess with --worker-args.
 
     ns is the option Namespace parsed from command-line arguments. regrtest
-    is invoked in a subprocess with the --slaveargs argument; when the
+    is invoked in a subprocess with the --worker-args argument; when the
     subprocess exits, its return code, stdout and stderr are returned as a
     3-tuple.
     """
     from subprocess import Popen, PIPE
 
     ns_dict = vars(ns)
-    slaveargs = (ns_dict, testname)
-    slaveargs = json.dumps(slaveargs)
+    worker_args = (ns_dict, testname)
+    worker_args = json.dumps(worker_args)
 
     cmd = [sys.executable, *support.args_from_interpreter_flags(),
            '-u',    # Unbuffered stdout and stderr
            '-m', 'test.regrtest',
-           '--slaveargs', slaveargs]
+           '--worker-args', worker_args]
     if ns.pgo:
         cmd += ['--pgo']
 
@@ -62,8 +62,8 @@ def run_test_in_subprocess(testname, ns):
     return retcode, stdout, stderr
 
 
-def run_tests_slave(slaveargs):
-    ns_dict, testname = json.loads(slaveargs)
+def run_tests_worker(worker_args):
+    ns_dict, testname = json.loads(worker_args)
     ns = types.SimpleNamespace(**ns_dict)
 
     setup_tests(ns)
index 4a563e9..c5586b4 100644 (file)
@@ -199,32 +199,74 @@ def collect_os(info_add):
     call_func(info_add, 'os.cpu_count', os, 'cpu_count')
     call_func(info_add, 'os.loadavg', os, 'getloadavg')
 
-    # Get environment variables: filter to list
-    # to not leak sensitive information
-    ENV_VARS = (
+    # Environment variables used by the stdlib and tests. Don't log the full
+    # environment: filter to list to not leak sensitive information.
+    #
+    # HTTP_PROXY is not logged because it can contain a password.
+    ENV_VARS = frozenset((
+        "APPDATA",
+        "AR",
+        "ARCHFLAGS",
+        "ARFLAGS",
+        "AUDIODEV",
         "CC",
+        "CFLAGS",
+        "COLUMNS",
+        "COMPUTERNAME",
         "COMSPEC",
+        "CPP",
+        "CPPFLAGS",
         "DISPLAY",
+        "DISTUTILS_DEBUG",
         "DISTUTILS_USE_SDK",
         "DYLD_LIBRARY_PATH",
+        "ENSUREPIP_OPTIONS",
+        "HISTORY_FILE",
         "HOME",
         "HOMEDRIVE",
         "HOMEPATH",
+        "IDLESTARTUP",
         "LANG",
+        "LDFLAGS",
+        "LDSHARED",
         "LD_LIBRARY_PATH",
+        "LINES",
         "MACOSX_DEPLOYMENT_TARGET",
+        "MAILCAPS",
         "MAKEFLAGS",
+        "MIXERDEV",
         "MSSDK",
         "PATH",
+        "PATHEXT",
+        "PIP_CONFIG_FILE",
+        "PLAT",
+        "POSIXLY_CORRECT",
+        "PY_SAX_PARSER",
+        "ProgramFiles",
+        "ProgramFiles(x86)",
+        "RUNNING_ON_VALGRIND",
         "SDK_TOOLS_BIN",
+        "SERVER_SOFTWARE",
         "SHELL",
+        "SOURCE_DATE_EPOCH",
+        "SYSTEMROOT",
         "TEMP",
         "TERM",
+        "TILE_LIBRARY",
+        "TIX_LIBRARY",
         "TMP",
         "TMPDIR",
+        "TRAVIS",
+        "TZ",
         "USERPROFILE",
+        "VIRTUAL_ENV",
         "WAYLAND_DISPLAY",
-    )
+        "WINDIR",
+        "_PYTHON_HOST_PLATFORM",
+        "_PYTHON_PROJECT_BASE",
+        "_PYTHON_SYSCONFIGDATA_NAME",
+        "__PYVENV_LAUNCHER__",
+    ))
     for name, value in os.environ.items():
         uname = name.upper()
         if (uname in ENV_VARS
@@ -365,7 +407,9 @@ def collect_sysconfig(info_add):
         'OPT',
         'PY_CFLAGS',
         'PY_CFLAGS_NODIST',
+        'PY_CORE_LDFLAGS',
         'PY_LDFLAGS',
+        'PY_LDFLAGS_NODIST',
         'Py_DEBUG',
         'Py_ENABLE_SHARED',
         'SHELL',
index 877be51..168b5da 100644 (file)
@@ -21,25 +21,19 @@ class InterProcessSignalTests(unittest.TestCase):
         self.got_signals['SIGUSR1'] += 1
         raise SIGUSR1Exception
 
-    def wait_signal(self, child, signame, exc_class=None):
-        try:
-            if child is not None:
-                # This wait should be interrupted by exc_class
-                # (if set)
-                child.wait()
-
-            timeout = 10.0
-            deadline = time.monotonic() + timeout
-
-            while time.monotonic() < deadline:
-                if self.got_signals[signame]:
-                    return
-                signal.pause()
-        except BaseException as exc:
-            if exc_class is not None and isinstance(exc, exc_class):
-                # got the expected exception
+    def wait_signal(self, child, signame):
+        if child is not None:
+            # This wait should be interrupted by exc_class
+            # (if set)
+            child.wait()
+
+        timeout = 10.0
+        deadline = time.monotonic() + timeout
+
+        while time.monotonic() < deadline:
+            if self.got_signals[signame]:
                 return
-            raise
+            signal.pause()
 
         self.fail('signal %s not received after %s seconds'
                   % (signame, timeout))
@@ -65,8 +59,9 @@ class InterProcessSignalTests(unittest.TestCase):
         self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 0,
                                             'SIGALRM': 0})
 
-        with self.subprocess_send_signal(pid, "SIGUSR1") as child:
-            self.wait_signal(child, 'SIGUSR1', SIGUSR1Exception)
+        with self.assertRaises(SIGUSR1Exception):
+            with self.subprocess_send_signal(pid, "SIGUSR1") as child:
+                self.wait_signal(child, 'SIGUSR1')
         self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 1,
                                             'SIGALRM': 0})
 
@@ -75,8 +70,9 @@ class InterProcessSignalTests(unittest.TestCase):
             child.wait()
 
         try:
-            signal.alarm(1)
-            self.wait_signal(None, 'SIGALRM', KeyboardInterrupt)
+            with self.assertRaises(KeyboardInterrupt):
+                signal.alarm(1)
+                self.wait_signal(None, 'SIGALRM')
             self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 1,
                                                 'SIGALRM': 0})
         finally:
index 3f1962f..66c0fed 100644 (file)
@@ -74,7 +74,7 @@ __all__ = [
     # globals
     "PIPE_MAX_SIZE", "verbose", "max_memuse", "use_resources", "failfast",
     # exceptions
-    "Error", "TestFailed", "ResourceDenied",
+    "Error", "TestFailed", "TestDidNotRun", "ResourceDenied",
     # imports
     "import_module", "import_fresh_module", "CleanImport",
     # modules
@@ -120,6 +120,9 @@ class Error(Exception):
 class TestFailed(Error):
     """Test failed."""
 
+class TestDidNotRun(Error):
+    """Test did not run any subtests."""
+
 class ResourceDenied(unittest.SkipTest):
     """Test skipped because it requested a disallowed resource.
 
@@ -854,7 +857,11 @@ for character in (
     '\u20AC',
 ):
     try:
-        os.fsdecode(os.fsencode(character))
+        # If Python is set up to use the legacy 'mbcs' in Windows,
+        # 'replace' error mode is used, and encode() returns b'?'
+        # for characters missing in the ANSI codepage
+        if os.fsdecode(os.fsencode(character)) != character:
+            raise UnicodeError
     except UnicodeError:
         pass
     else:
@@ -1907,16 +1914,17 @@ def _filter_suite(suite, pred):
 
 def _run_suite(suite):
     """Run tests from a unittest.TestSuite-derived class."""
-    runner = get_test_runner(sys.stdout, verbosity=verbose)
-
-    # TODO: Remove this before merging (here for easy comparison with old impl)
-    #runner = unittest.TextTestRunner(sys.stdout, verbosity=2, failfast=failfast)
+    runner = get_test_runner(sys.stdout,
+                             verbosity=verbose,
+                             capture_output=(junit_xml_list is not None))
 
     result = runner.run(suite)
 
     if junit_xml_list is not None:
         junit_xml_list.append(result.get_xml_element())
 
+    if not result.testsRun:
+        raise TestDidNotRun
     if not result.wasSuccessful():
         if len(result.errors) == 1 and not result.failures:
             err = result.errors[0][1]
index 8988d3d..67e126d 100644 (file)
@@ -60,10 +60,12 @@ class RegressionTestResult(unittest.TextTestResult):
             e.set('time', f'{time.perf_counter() - self.__start_time:0.6f}')
 
         if capture:
-            stdout = self._stdout_buffer.getvalue().rstrip()
-            ET.SubElement(e, 'system-out').text = stdout
-            stderr = self._stderr_buffer.getvalue().rstrip()
-            ET.SubElement(e, 'system-err').text = stderr
+            if self._stdout_buffer is not None:
+                stdout = self._stdout_buffer.getvalue().rstrip()
+                ET.SubElement(e, 'system-out').text = stdout
+            if self._stderr_buffer is not None:
+                stderr = self._stderr_buffer.getvalue().rstrip()
+                ET.SubElement(e, 'system-err').text = stderr
 
         for k, v in args.items():
             if not k or not v:
@@ -152,23 +154,24 @@ class RegressionTestResult(unittest.TextTestResult):
         return e
 
 class QuietRegressionTestRunner:
-    def __init__(self, stream):
+    def __init__(self, stream, buffer=False):
         self.result = RegressionTestResult(stream, None, 0)
+        self.result.buffer = buffer
 
     def run(self, test):
         test(self.result)
         return self.result
 
-def get_test_runner_class(verbosity):
+def get_test_runner_class(verbosity, buffer=False):
     if verbosity:
         return functools.partial(unittest.TextTestRunner,
                                  resultclass=RegressionTestResult,
-                                 buffer=True,
+                                 buffer=buffer,
                                  verbosity=verbosity)
-    return QuietRegressionTestRunner
+    return functools.partial(QuietRegressionTestRunner, buffer=buffer)
 
-def get_test_runner(stream, verbosity):
-    return get_test_runner_class(verbosity)(stream)
+def get_test_runner(stream, verbosity, capture_output=False):
+    return get_test_runner_class(verbosity, capture_output)(stream)
 
 if __name__ == '__main__':
     class TestTests(unittest.TestCase):
index bcba8ca..388a2b1 100644 (file)
@@ -24,7 +24,7 @@ class Test_OSXSupport(unittest.TestCase):
         for cv in ('CFLAGS', 'LDFLAGS', 'CPPFLAGS',
                             'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'CC',
                             'CXX', 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
-                            'PY_CORE_CFLAGS'):
+                            'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS'):
             if cv in self.env:
                 self.env.unset(cv)
 
diff --git a/Lib/test/test_asyncio/keycert3.pem b/Lib/test/test_asyncio/keycert3.pem
deleted file mode 100644 (file)
index 5bfa62c..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMLgD0kAKDb5cFyP
-jbwNfR5CtewdXC+kMXAWD8DLxiTTvhMW7qVnlwOm36mZlszHKvsRf05lT4pegiFM
-9z2j1OlaN+ci/X7NU22TNN6crYSiN77FjYJP464j876ndSxyD+rzys386T+1r1aZ
-aggEdkj1TsSsv1zWIYKlPIjlvhuxAgMBAAECgYA0aH+T2Vf3WOPv8KdkcJg6gCRe
-yJKXOWgWRcicx/CUzOEsTxmFIDPLxqAWA3k7v0B+3vjGw5Y9lycV/5XqXNoQI14j
-y09iNsumds13u5AKkGdTJnZhQ7UKdoVHfuP44ZdOv/rJ5/VD6F4zWywpe90pcbK+
-AWDVtusgGQBSieEl1QJBAOyVrUG5l2yoUBtd2zr/kiGm/DYyXlIthQO/A3/LngDW
-5/ydGxVsT7lAVOgCsoT+0L4efTh90PjzW8LPQrPBWVMCQQDS3h/FtYYd5lfz+FNL
-9CEe1F1w9l8P749uNUD0g317zv1tatIqVCsQWHfVHNdVvfQ+vSFw38OORO00Xqs9
-1GJrAkBkoXXEkxCZoy4PteheO/8IWWLGGr6L7di6MzFl1lIqwT6D8L9oaV2vynFT
-DnKop0pa09Unhjyw57KMNmSE2SUJAkEArloTEzpgRmCq4IK2/NpCeGdHS5uqRlbh
-1VIa/xGps7EWQl5Mn8swQDel/YP3WGHTjfx7pgSegQfkyaRtGpZ9OQJAa9Vumj8m
-JAAtI0Bnga8hgQx7BhTQY4CadDxyiRGOGYhwUzYVCqkb2sbVRH9HnwUaJT7cWBY3
-RnJdHOMXWem7/w==
------END PRIVATE KEY-----
-Certificate:
-    Data:
-        Version: 1 (0x0)
-        Serial Number: 12723342612721443281 (0xb09264b1f2da21d1)
-    Signature Algorithm: sha1WithRSAEncryption
-        Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
-        Validity
-            Not Before: Jan  4 19:47:07 2013 GMT
-            Not After : Nov 13 19:47:07 2022 GMT
-        Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=localhost
-        Subject Public Key Info:
-            Public Key Algorithm: rsaEncryption
-                Public-Key: (1024 bit)
-                Modulus:
-                    00:c2:e0:0f:49:00:28:36:f9:70:5c:8f:8d:bc:0d:
-                    7d:1e:42:b5:ec:1d:5c:2f:a4:31:70:16:0f:c0:cb:
-                    c6:24:d3:be:13:16:ee:a5:67:97:03:a6:df:a9:99:
-                    96:cc:c7:2a:fb:11:7f:4e:65:4f:8a:5e:82:21:4c:
-                    f7:3d:a3:d4:e9:5a:37:e7:22:fd:7e:cd:53:6d:93:
-                    34:de:9c:ad:84:a2:37:be:c5:8d:82:4f:e3:ae:23:
-                    f3:be:a7:75:2c:72:0f:ea:f3:ca:cd:fc:e9:3f:b5:
-                    af:56:99:6a:08:04:76:48:f5:4e:c4:ac:bf:5c:d6:
-                    21:82:a5:3c:88:e5:be:1b:b1
-                Exponent: 65537 (0x10001)
-    Signature Algorithm: sha1WithRSAEncryption
-         2f:42:5f:a3:09:2c:fa:51:88:c7:37:7f:ea:0e:63:f0:a2:9a:
-         e5:5a:e2:c8:20:f0:3f:60:bc:c8:0f:b6:c6:76:ce:db:83:93:
-         f5:a3:33:67:01:8e:04:cd:00:9a:73:fd:f3:35:86:fa:d7:13:
-         e2:46:c6:9d:c0:29:53:d4:a9:90:b8:77:4b:e6:83:76:e4:92:
-         d6:9c:50:cf:43:d0:c6:01:77:61:9a:de:9b:70:f7:72:cd:59:
-         00:31:69:d9:b4:ca:06:9c:6d:c3:c7:80:8c:68:e6:b5:a2:f8:
-         ef:1d:bb:16:9f:77:77:ef:87:62:22:9b:4d:69:a4:3a:1a:f1:
-         21:5e:8c:32:ac:92:fd:15:6b:18:c2:7f:15:0d:98:30:ca:75:
-         8f:1a:71:df:da:1d:b2:ef:9a:e8:2d:2e:02:fd:4a:3c:aa:96:
-         0b:06:5d:35:b3:3d:24:87:4b:e0:b0:58:60:2f:45:ac:2e:48:
-         8a:b0:99:10:65:27:ff:cc:b1:d8:fd:bd:26:6b:b9:0c:05:2a:
-         f4:45:63:35:51:07:ed:83:85:fe:6f:69:cb:bb:40:a8:ae:b6:
-         3b:56:4a:2d:a4:ed:6d:11:2c:4d:ed:17:24:fd:47:bc:d3:41:
-         a2:d3:06:fe:0c:90:d8:d8:94:26:c4:ff:cc:a1:d8:42:77:eb:
-         fc:a9:94:71
------BEGIN CERTIFICATE-----
-MIICpDCCAYwCCQCwkmSx8toh0TANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJY
-WTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNV
-BAMMDW91ci1jYS1zZXJ2ZXIwHhcNMTMwMTA0MTk0NzA3WhcNMjIxMTEzMTk0NzA3
-WjBfMQswCQYDVQQGEwJYWTEXMBUGA1UEBxMOQ2FzdGxlIEFudGhyYXgxIzAhBgNV
-BAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMRIwEAYDVQQDEwlsb2NhbGhv
-c3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMLgD0kAKDb5cFyPjbwNfR5C
-tewdXC+kMXAWD8DLxiTTvhMW7qVnlwOm36mZlszHKvsRf05lT4pegiFM9z2j1Ola
-N+ci/X7NU22TNN6crYSiN77FjYJP464j876ndSxyD+rzys386T+1r1aZaggEdkj1
-TsSsv1zWIYKlPIjlvhuxAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAC9CX6MJLPpR
-iMc3f+oOY/CimuVa4sgg8D9gvMgPtsZ2ztuDk/WjM2cBjgTNAJpz/fM1hvrXE+JG
-xp3AKVPUqZC4d0vmg3bkktacUM9D0MYBd2Ga3ptw93LNWQAxadm0ygacbcPHgIxo
-5rWi+O8duxafd3fvh2Iim01ppDoa8SFejDKskv0VaxjCfxUNmDDKdY8acd/aHbLv
-mugtLgL9SjyqlgsGXTWzPSSHS+CwWGAvRawuSIqwmRBlJ//Msdj9vSZruQwFKvRF
-YzVRB+2Dhf5vacu7QKiutjtWSi2k7W0RLE3tFyT9R7zTQaLTBv4MkNjYlCbE/8yh
-2EJ36/yplHE=
------END CERTIFICATE-----
diff --git a/Lib/test/test_asyncio/pycacert.pem b/Lib/test/test_asyncio/pycacert.pem
deleted file mode 100644 (file)
index 09b1f3e..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-Certificate:
-    Data:
-        Version: 3 (0x2)
-        Serial Number: 12723342612721443280 (0xb09264b1f2da21d0)
-    Signature Algorithm: sha1WithRSAEncryption
-        Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
-        Validity
-            Not Before: Jan  4 19:47:07 2013 GMT
-            Not After : Jan  2 19:47:07 2023 GMT
-        Subject: C=XY, O=Python Software Foundation CA, CN=our-ca-server
-        Subject Public Key Info:
-            Public Key Algorithm: rsaEncryption
-                Public-Key: (2048 bit)
-                Modulus:
-                    00:e7:de:e9:e3:0c:9f:00:b6:a1:fd:2b:5b:96:d2:
-                    6f:cc:e0:be:86:b9:20:5e:ec:03:7a:55:ab:ea:a4:
-                    e9:f9:49:85:d2:66:d5:ed:c7:7a:ea:56:8e:2d:8f:
-                    e7:42:e2:62:28:a9:9f:d6:1b:8e:eb:b5:b4:9c:9f:
-                    14:ab:df:e6:94:8b:76:1d:3e:6d:24:61:ed:0c:bf:
-                    00:8a:61:0c:df:5c:c8:36:73:16:00:cd:47:ba:6d:
-                    a4:a4:74:88:83:23:0a:19:fc:09:a7:3c:4a:4b:d3:
-                    e7:1d:2d:e4:ea:4c:54:21:f3:26:db:89:37:18:d4:
-                    02:bb:40:32:5f:a4:ff:2d:1c:f7:d4:bb:ec:8e:cf:
-                    5c:82:ac:e6:7c:08:6c:48:85:61:07:7f:25:e0:5c:
-                    e0:bc:34:5f:e0:b9:04:47:75:c8:47:0b:8d:bc:d6:
-                    c8:68:5f:33:83:62:d2:20:44:35:b1:ad:81:1a:8a:
-                    cd:bc:35:b0:5c:8b:47:d6:18:e9:9c:18:97:cc:01:
-                    3c:29:cc:e8:1e:e4:e4:c1:b8:de:e7:c2:11:18:87:
-                    5a:93:34:d8:a6:25:f7:14:71:eb:e4:21:a2:d2:0f:
-                    2e:2e:d4:62:00:35:d3:d6:ef:5c:60:4b:4c:a9:14:
-                    e2:dd:15:58:46:37:33:26:b7:e7:2e:5d:ed:42:e4:
-                    c5:4d
-                Exponent: 65537 (0x10001)
-        X509v3 extensions:
-            X509v3 Subject Key Identifier: 
-                BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B
-            X509v3 Authority Key Identifier: 
-                keyid:BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B
-
-            X509v3 Basic Constraints: 
-                CA:TRUE
-    Signature Algorithm: sha1WithRSAEncryption
-         7d:0a:f5:cb:8d:d3:5d:bd:99:8e:f8:2b:0f:ba:eb:c2:d9:a6:
-         27:4f:2e:7b:2f:0e:64:d8:1c:35:50:4e:ee:fc:90:b9:8d:6d:
-         a8:c5:c6:06:b0:af:f3:2d:bf:3b:b8:42:07:dd:18:7d:6d:95:
-         54:57:85:18:60:47:2f:eb:78:1b:f9:e8:17:fd:5a:0d:87:17:
-         28:ac:4c:6a:e6:bc:29:f4:f4:55:70:29:42:de:85:ea:ab:6c:
-         23:06:64:30:75:02:8e:53:bc:5e:01:33:37:cc:1e:cd:b8:a4:
-         fd:ca:e4:5f:65:3b:83:1c:86:f1:55:02:a0:3a:8f:db:91:b7:
-         40:14:b4:e7:8d:d2:ee:73:ba:e3:e5:34:2d:bc:94:6f:4e:24:
-         06:f7:5f:8b:0e:a7:8e:6b:de:5e:75:f4:32:9a:50:b1:44:33:
-         9a:d0:05:e2:78:82:ff:db:da:8a:63:eb:a9:dd:d1:bf:a0:61:
-         ad:e3:9e:8a:24:5d:62:0e:e7:4c:91:7f:ef:df:34:36:3b:2f:
-         5d:f5:84:b2:2f:c4:6d:93:96:1a:6f:30:28:f1:da:12:9a:64:
-         b4:40:33:1d:bd:de:2b:53:a8:ea:be:d6:bc:4e:96:f5:44:fb:
-         32:18:ae:d5:1f:f6:69:af:b6:4e:7b:1d:58:ec:3b:a9:53:a3:
-         5e:58:c8:9e
------BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIJALCSZLHy2iHQMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV
-BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
-MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xMzAxMDQxOTQ3MDdaFw0yMzAxMDIx
-OTQ3MDdaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg
-Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAOfe6eMMnwC2of0rW5bSb8zgvoa5IF7sA3pV
-q+qk6flJhdJm1e3HeupWji2P50LiYiipn9Ybjuu1tJyfFKvf5pSLdh0+bSRh7Qy/
-AIphDN9cyDZzFgDNR7ptpKR0iIMjChn8Cac8SkvT5x0t5OpMVCHzJtuJNxjUArtA
-Ml+k/y0c99S77I7PXIKs5nwIbEiFYQd/JeBc4Lw0X+C5BEd1yEcLjbzWyGhfM4Ni
-0iBENbGtgRqKzbw1sFyLR9YY6ZwYl8wBPCnM6B7k5MG43ufCERiHWpM02KYl9xRx
-6+QhotIPLi7UYgA109bvXGBLTKkU4t0VWEY3Mya35y5d7ULkxU0CAwEAAaNQME4w
-HQYDVR0OBBYEFLzdYtl22hvSVGvP4GabHh57VgwLMB8GA1UdIwQYMBaAFLzdYtl2
-2hvSVGvP4GabHh57VgwLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
-AH0K9cuN0129mY74Kw+668LZpidPLnsvDmTYHDVQTu78kLmNbajFxgawr/Mtvzu4
-QgfdGH1tlVRXhRhgRy/reBv56Bf9Wg2HFyisTGrmvCn09FVwKULeheqrbCMGZDB1
-Ao5TvF4BMzfMHs24pP3K5F9lO4MchvFVAqA6j9uRt0AUtOeN0u5zuuPlNC28lG9O
-JAb3X4sOp45r3l519DKaULFEM5rQBeJ4gv/b2opj66nd0b+gYa3jnookXWIO50yR
-f+/fNDY7L131hLIvxG2TlhpvMCjx2hKaZLRAMx293itTqOq+1rxOlvVE+zIYrtUf
-9mmvtk57HVjsO6lTo15YyJ4=
------END CERTIFICATE-----
diff --git a/Lib/test/test_asyncio/ssl_cert.pem b/Lib/test/test_asyncio/ssl_cert.pem
deleted file mode 100644 (file)
index 47a7d7e..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
-BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
-IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
-MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
-Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
-YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
-gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
-6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
-pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
-FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
-BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
-lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
-CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
------END CERTIFICATE-----
diff --git a/Lib/test/test_asyncio/ssl_key.pem b/Lib/test/test_asyncio/ssl_key.pem
deleted file mode 100644 (file)
index 3fd3bbd..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm
-LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0
-ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP
-USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt
-CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq
-SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK
-UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y
-BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ
-ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5
-oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik
-eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F
-0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS
-x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/
-SPIXQuT8RMPDVNQ=
------END PRIVATE KEY-----
index 09f71f2..052a559 100644 (file)
@@ -27,7 +27,6 @@ except ImportError:
     except ImportError:
         from asyncio.test_support import assert_python_ok
 
-
 MOCK_ANY = mock.ANY
 PY34 = sys.version_info >= (3, 4)
 
@@ -288,7 +287,7 @@ class BaseEventLoopTests(test_utils.TestCase):
         loop.set_debug(debug)
         if debug:
             msg = ("Non-thread-safe operation invoked on an event loop other "
-                  "than the current one")
+                   "than the current one")
             with self.assertRaisesRegex(RuntimeError, msg):
                 loop.call_soon(cb)
             with self.assertRaisesRegex(RuntimeError, msg):
@@ -1839,5 +1838,30 @@ class RunningLoopTests(unittest.TestCase):
 
 
 
+class TestSelectorUtils(test_utils.TestCase):
+    def check_set_nodelay(self, sock):
+        opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
+        self.assertFalse(opt)
+
+        base_events._set_nodelay(sock)
+
+        opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
+        self.assertTrue(opt)
+
+    @unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'),
+                         'need socket.TCP_NODELAY')
+    def test_set_nodelay(self):
+        sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
+                             proto=socket.IPPROTO_TCP)
+        with sock:
+            self.check_set_nodelay(sock)
+
+        sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
+                             proto=socket.IPPROTO_TCP)
+        with sock:
+            sock.setblocking(False)
+            self.check_set_nodelay(sock)
+
+
 if __name__ == '__main__':
     unittest.main()
index b024ef4..91d8a96 100644 (file)
@@ -32,23 +32,13 @@ from asyncio import proactor_events
 from asyncio import selector_events
 from asyncio import sslproto
 from asyncio import test_utils
+from asyncio.test_utils import ONLYKEY, ONLYCERT, data_file
 try:
     from test import support
 except ImportError:
     from asyncio import test_support as support
 
 
-def data_file(filename):
-    if hasattr(support, 'TEST_HOME_DIR'):
-        fullname = os.path.join(support.TEST_HOME_DIR, filename)
-        if os.path.isfile(fullname):
-            return fullname
-    fullname = os.path.join(os.path.dirname(__file__), filename)
-    if os.path.isfile(fullname):
-        return fullname
-    raise FileNotFoundError(filename)
-
-
 def osx_tiger():
     """Return True if the platform is Mac OS 10.4 or older."""
     if sys.platform != 'darwin':
@@ -67,10 +57,8 @@ def _test_get_event_loop_new_process__sub_proc():
     return loop.run_until_complete(doit())
 
 
-ONLYCERT = data_file('ssl_cert.pem')
-ONLYKEY = data_file('ssl_key.pem')
-SIGNED_CERTFILE = data_file('keycert3.pem')
-SIGNING_CA = data_file('pycacert.pem')
+SIGNED_CERTFILE = test_utils.data_file('keycert3.pem')
+SIGNING_CA = test_utils.data_file('pycacert.pem')
 PEERCERT = {
     'OCSP': ('http://testca.pythontest.net/testca/ocsp/',),
     'caIssuers': ('http://testca.pythontest.net/testca/pycacert.cer',),
index 533d289..6716e89 100644 (file)
@@ -17,7 +17,6 @@ from asyncio.selector_events import _SelectorTransport
 from asyncio.selector_events import _SelectorSslTransport
 from asyncio.selector_events import _SelectorSocketTransport
 from asyncio.selector_events import _SelectorDatagramTransport
-from asyncio.selector_events import _set_nodelay
 
 
 MOCK_ANY = mock.ANY
@@ -1858,30 +1857,5 @@ class SelectorDatagramTransportTests(test_utils.TestCase):
             exc_info=(ConnectionRefusedError, MOCK_ANY, MOCK_ANY))
 
 
-class TestSelectorUtils(test_utils.TestCase):
-    def check_set_nodelay(self, sock):
-        opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
-        self.assertFalse(opt)
-
-        _set_nodelay(sock)
-
-        opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
-        self.assertTrue(opt)
-
-    @unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'),
-                         'need socket.TCP_NODELAY')
-    def test_set_nodelay(self):
-        sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
-                             proto=socket.IPPROTO_TCP)
-        with sock:
-            self.check_set_nodelay(sock)
-
-        sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
-                             proto=socket.IPPROTO_TCP)
-        with sock:
-            sock.setblocking(False)
-            self.check_set_nodelay(sock)
-
-
 if __name__ == '__main__':
     unittest.main()
index a366678..55f42e2 100644 (file)
@@ -526,13 +526,13 @@ def run_test(modules, set_list, skip=None):
     test.id = lambda : None
     test.expect_set = list(gen(repeat(()), iter(sl)))
     with create_modules(modules):
-        sys.path.append(os.getcwd())
         with TracerRun(test, skip=skip) as tracer:
             tracer.runcall(tfunc_import)
 
 @contextmanager
 def create_modules(modules):
     with test.support.temp_cwd():
+        sys.path.append(os.getcwd())
         try:
             for m in modules:
                 fname = m + '.py'
@@ -544,15 +544,16 @@ def create_modules(modules):
         finally:
             for m in modules:
                 test.support.forget(m)
+            sys.path.pop()
 
 def break_in_func(funcname, fname=__file__, temporary=False, cond=None):
     return 'break', (fname, None, temporary, cond, funcname)
 
-TEST_MODULE = 'test_module'
+TEST_MODULE = 'test_module_for_bdb'
 TEST_MODULE_FNAME = TEST_MODULE + '.py'
 def tfunc_import():
-    import test_module
-    test_module.main()
+    import test_module_for_bdb
+    test_module_for_bdb.main()
 
 def tfunc_main():
     lno = 2
@@ -970,9 +971,9 @@ class RunTestCase(BaseTestCase):
                 ('return', 3, 'main'),     ('step', ),
                 ('return', 1, '<module>'), ('quit', ),
             ]
-            import test_module
+            import test_module_for_bdb
             with TracerRun(self) as tracer:
-                tracer.runeval('test_module.main()', globals(), locals())
+                tracer.runeval('test_module_for_bdb.main()', globals(), locals())
 
 class IssuesTestCase(BaseTestCase):
     """Test fixed bdb issues."""
@@ -982,7 +983,7 @@ class IssuesTestCase(BaseTestCase):
         # Check that the tracer does step into the caller frame when the
         # trace function is not set in that frame.
         code_1 = """
-            from test_module_2 import func
+            from test_module_for_bdb_2 import func
             def main():
                 func()
                 lno = 5
@@ -993,12 +994,12 @@ class IssuesTestCase(BaseTestCase):
         """
         modules = {
             TEST_MODULE: code_1,
-            'test_module_2': code_2,
+            'test_module_for_bdb_2': code_2,
         }
         with create_modules(modules):
             self.expect_set = [
                 ('line', 2, 'tfunc_import'),
-                    break_in_func('func', 'test_module_2.py'),
+                    break_in_func('func', 'test_module_for_bdb_2.py'),
                 ('None', 2, 'tfunc_import'),      ('continue', ),
                 ('line', 3, 'func', ({1:1}, [])), ('step', ),
                 ('return', 3, 'func'),            ('step', ),
index 6fcc26a..7fa2a38 100644 (file)
@@ -69,11 +69,66 @@ class BaseBytesTest:
         self.assertRaises(IndexError, lambda: b[-sys.maxsize-2])
         self.assertRaises(IndexError, lambda: b[-10**100])
 
+    def test_from_iterable(self):
+        b = self.type2test(range(256))
+        self.assertEqual(len(b), 256)
+        self.assertEqual(list(b), list(range(256)))
+
+        # Non-sequence iterable.
+        b = self.type2test({42})
+        self.assertEqual(b, b"*")
+        b = self.type2test({43, 45})
+        self.assertIn(tuple(b), {(43, 45), (45, 43)})
+
+        # Iterator that has a __length_hint__.
+        b = self.type2test(iter(range(256)))
+        self.assertEqual(len(b), 256)
+        self.assertEqual(list(b), list(range(256)))
+
+        # Iterator that doesn't have a __length_hint__.
+        b = self.type2test(i for i in range(256) if i % 2)
+        self.assertEqual(len(b), 128)
+        self.assertEqual(list(b), list(range(256))[1::2])
+
+        # Sequence without __iter__.
+        class S:
+            def __getitem__(self, i):
+                return (1, 2, 3)[i]
+        b = self.type2test(S())
+        self.assertEqual(b, b"\x01\x02\x03")
+
+    def test_from_tuple(self):
+        # There is a special case for tuples.
+        b = self.type2test(tuple(range(256)))
+        self.assertEqual(len(b), 256)
+        self.assertEqual(list(b), list(range(256)))
+        b = self.type2test((1, 2, 3))
+        self.assertEqual(b, b"\x01\x02\x03")
+
     def test_from_list(self):
-        ints = list(range(256))
-        b = self.type2test(i for i in ints)
+        # There is a special case for lists.
+        b = self.type2test(list(range(256)))
         self.assertEqual(len(b), 256)
-        self.assertEqual(list(b), ints)
+        self.assertEqual(list(b), list(range(256)))
+        b = self.type2test([1, 2, 3])
+        self.assertEqual(b, b"\x01\x02\x03")
+
+    def test_from_mutating_list(self):
+        # Issue #34973: Crash in bytes constructor with mutating list.
+        class X:
+            def __index__(self):
+                a.clear()
+                return 42
+        a = [X(), X()]
+        self.assertEqual(bytes(a), b'*')
+
+        class Y:
+            def __index__(self):
+                if len(a) < 1000:
+                    a.append(self)
+                return 42
+        a = [Y()]
+        self.assertEqual(bytes(a), b'*' * 1000)  # should not crash
 
     def test_from_index(self):
         b = self.type2test([Indexable(), Indexable(1), Indexable(254),
@@ -85,9 +140,11 @@ class BaseBytesTest:
     def test_from_buffer(self):
         a = self.type2test(array.array('B', [1, 2, 3]))
         self.assertEqual(a, b"\x01\x02\x03")
+        a = self.type2test(b"\x01\x02\x03")
+        self.assertEqual(a, b"\x01\x02\x03")
 
-        # http://bugs.python.org/issue29159
-        # Fallback when __index__ raises exception other than OverflowError
+        # Issues #29159 and #34974.
+        # Fallback when __index__ raises a TypeError
         class B(bytes):
             def __index__(self):
                 raise TypeError
@@ -144,6 +201,20 @@ class BaseBytesTest:
         except (OverflowError, MemoryError):
             pass
 
+    def test_constructor_exceptions(self):
+        # Issue #34974: bytes and bytearray constructors replace unexpected
+        # exceptions.
+        class BadInt:
+            def __index__(self):
+                1/0
+        self.assertRaises(ZeroDivisionError, self.type2test, BadInt())
+        self.assertRaises(ZeroDivisionError, self.type2test, [BadInt()])
+
+        class BadIterable:
+            def __iter__(self):
+                1/0
+        self.assertRaises(ZeroDivisionError, self.type2test, BadIterable())
+
     def test_compare(self):
         b1 = self.type2test([1, 2, 3])
         b2 = self.type2test([1, 2, 3])
index ae3bcb9..947da8c 100644 (file)
@@ -372,6 +372,110 @@ class SubinterpreterTest(unittest.TestCase):
             self.assertNotEqual(pickle.load(f), id(builtins))
 
 
+class EmbeddingTests(unittest.TestCase):
+    def setUp(self):
+        here = os.path.abspath(__file__)
+        basepath = os.path.dirname(os.path.dirname(os.path.dirname(here)))
+        exename = "_testembed"
+        if sys.platform.startswith("win"):
+            ext = ("_d" if "_d" in sys.executable else "") + ".exe"
+            exename += ext
+            exepath = os.path.dirname(sys.executable)
+        else:
+            exepath = os.path.join(basepath, "Programs")
+        self.test_exe = exe = os.path.join(exepath, exename)
+        if not os.path.exists(exe):
+            self.skipTest("%r doesn't exist" % exe)
+        # This is needed otherwise we get a fatal error:
+        # "Py_Initialize: Unable to get the locale encoding
+        # LookupError: no codec search functions registered: can't find encoding"
+        self.oldcwd = os.getcwd()
+        os.chdir(basepath)
+
+    def tearDown(self):
+        os.chdir(self.oldcwd)
+
+    def run_embedded_interpreter(self, *args, env=None):
+        """Runs a test in the embedded interpreter"""
+        cmd = [self.test_exe]
+        cmd.extend(args)
+        if env is not None and sys.platform == 'win32':
+            # Windows requires at least the SYSTEMROOT environment variable to
+            # start Python.
+            env = env.copy()
+            env['SYSTEMROOT'] = os.environ['SYSTEMROOT']
+
+        p = subprocess.Popen(cmd,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.PIPE,
+                             universal_newlines=True,
+                             env=env)
+        (out, err) = p.communicate()
+        self.assertEqual(p.returncode, 0,
+                         "bad returncode %d, stderr is %r" %
+                         (p.returncode, err))
+        return out, err
+
+    def test_repeated_init_and_subinterpreters(self):
+        # This is just a "don't crash" test
+        out, err = self.run_embedded_interpreter('repeated_init_and_subinterpreters')
+        if support.verbose:
+            print()
+            print(out)
+            print(err)
+
+    def test_forced_io_encoding(self):
+        # Checks forced configuration of embedded interpreter IO streams
+        env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape")
+        out, err = self.run_embedded_interpreter("forced_io_encoding", env=env)
+        if support.verbose:
+            print()
+            print(out)
+            print(err)
+        expected_stream_encoding = "utf-8"
+        expected_errors = "surrogateescape"
+        expected_output = '\n'.join([
+        "--- Use defaults ---",
+        "Expected encoding: default",
+        "Expected errors: default",
+        "stdin: {in_encoding}:{errors}",
+        "stdout: {out_encoding}:{errors}",
+        "stderr: {out_encoding}:backslashreplace",
+        "--- Set errors only ---",
+        "Expected encoding: default",
+        "Expected errors: ignore",
+        "stdin: {in_encoding}:ignore",
+        "stdout: {out_encoding}:ignore",
+        "stderr: {out_encoding}:backslashreplace",
+        "--- Set encoding only ---",
+        "Expected encoding: latin-1",
+        "Expected errors: default",
+        "stdin: latin-1:{errors}",
+        "stdout: latin-1:{errors}",
+        "stderr: latin-1:backslashreplace",
+        "--- Set encoding and errors ---",
+        "Expected encoding: latin-1",
+        "Expected errors: replace",
+        "stdin: latin-1:replace",
+        "stdout: latin-1:replace",
+        "stderr: latin-1:backslashreplace"])
+        expected_output = expected_output.format(
+                                in_encoding=expected_stream_encoding,
+                                out_encoding=expected_stream_encoding,
+                                errors=expected_errors)
+        # This is useful if we ever trip over odd platform behaviour
+        self.maxDiff = None
+        self.assertEqual(out.strip(), expected_output)
+
+    def test_pre_initialization_api(self):
+        """
+        Checks the few parts of the C-API that work before the runtine
+        is initialized (via Py_Initialize()).
+        """
+        env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path))
+        out, err = self.run_embedded_interpreter("pre_initialization_api", env=env)
+        self.assertEqual(out, '')
+        self.assertEqual(err, '')
 
 
 @unittest.skipUnless(threading, 'Threading required for this test.')
@@ -430,6 +534,8 @@ class PyMemDebugTests(unittest.TestCase):
                  r"    The block was made by call #[0-9]+ to debug malloc/realloc.\n"
                  r"    Data at p: cb cb cb .*\n"
                  r"\n"
+                 r"Enable tracemalloc to get the memory block allocation traceback\n"
+                 r"\n"
                  r"Fatal Python error: bad trailing pad byte")
         regex = regex.format(ptr=self.PTR_REGEX)
         regex = re.compile(regex, flags=re.DOTALL)
@@ -444,6 +550,8 @@ class PyMemDebugTests(unittest.TestCase):
                  r"    The block was made by call #[0-9]+ to debug malloc/realloc.\n"
                  r"    Data at p: cb cb cb .*\n"
                  r"\n"
+                 r"Enable tracemalloc to get the memory block allocation traceback\n"
+                 r"\n"
                  r"Fatal Python error: bad ID: Allocated using API 'm', verified using API 'r'\n")
         regex = regex.format(ptr=self.PTR_REGEX)
         self.assertRegex(out, regex)
index 6373221..b3e2d4c 100644 (file)
@@ -373,6 +373,60 @@ Larry
         v = gen_result(data, environ)
         self.assertEqual(self._qs_result, v)
 
+    def test_max_num_fields(self):
+        # For application/x-www-form-urlencoded
+        data = '&'.join(['a=a']*11)
+        environ = {
+            'CONTENT_LENGTH': str(len(data)),
+            'CONTENT_TYPE': 'application/x-www-form-urlencoded',
+            'REQUEST_METHOD': 'POST',
+        }
+
+        with self.assertRaises(ValueError):
+            cgi.FieldStorage(
+                fp=BytesIO(data.encode()),
+                environ=environ,
+                max_num_fields=10,
+            )
+
+        # For multipart/form-data
+        data = """---123
+Content-Disposition: form-data; name="a"
+
+3
+---123
+Content-Type: application/x-www-form-urlencoded
+
+a=4
+---123
+Content-Type: application/x-www-form-urlencoded
+
+a=5
+---123--
+"""
+        environ = {
+            'CONTENT_LENGTH':   str(len(data)),
+            'CONTENT_TYPE':     'multipart/form-data; boundary=-123',
+            'QUERY_STRING':     'a=1&a=2',
+            'REQUEST_METHOD':   'POST',
+        }
+
+        # 2 GET entities
+        # 1 top level POST entities
+        # 1 entity within the second POST entity
+        # 1 entity within the third POST entity
+        with self.assertRaises(ValueError):
+            cgi.FieldStorage(
+                fp=BytesIO(data.encode()),
+                environ=environ,
+                max_num_fields=4,
+            )
+        cgi.FieldStorage(
+            fp=BytesIO(data.encode()),
+            environ=environ,
+            max_num_fields=5,
+        )
+
     def testQSAndFormData(self):
         data = """---123
 Content-Disposition: form-data; name="key2"
index eb21a39..56485de 100644 (file)
@@ -3191,6 +3191,24 @@ class CodePageTest(unittest.TestCase):
         finally:
             _bootlocale.getpreferredencoding = old_getpreferredencoding
 
+    @support.bigmemtest(size=2**31, memuse=7, dry_run=False)
+    def test_large_input(self):
+        # Test input longer than INT_MAX.
+        # Input should contain undecodable bytes before and after
+        # the INT_MAX limit.
+        encoded = (b'01234567' * (2**28-1) +
+                   b'\x85\x86\xea\xeb\xec\xef\xfc\xfd\xfe\xff')
+        self.assertEqual(len(encoded), 2**31+2)
+        decoded = codecs.code_page_decode(932, encoded, 'surrogateescape', True)
+        self.assertEqual(decoded[1], len(encoded))
+        del encoded
+        self.assertEqual(len(decoded[0]), decoded[1])
+        self.assertEqual(decoded[0][:10], '0123456701')
+        self.assertEqual(decoded[0][-20:],
+                         '6701234567'
+                         '\udc85\udc86\udcea\udceb\udcec'
+                         '\udcef\udcfc\udcfd\udcfe\udcff')
+
 
 class ASCIITest(unittest.TestCase):
     def test_encode(self):
index c9812e4..13cc882 100644 (file)
@@ -1,3 +1,4 @@
+import dis
 import math
 import os
 import unittest
@@ -285,7 +286,7 @@ if 1:
             'from sys import stdin)',
             'from sys import stdin, stdout,\nstderr',
             'from sys import stdin si',
-            'from sys import stdin,'
+            'from sys import stdin,',
             'from sys import (*)',
             'from sys import (stdin,, stdout, stderr)',
             'from sys import (stdin, stdout),',
@@ -628,6 +629,24 @@ if 1:
         self.check_constant(f1, frozenset({0}))
         self.assertTrue(f1(0))
 
+    # This is a regression test for a CPython specific peephole optimizer
+    # implementation bug present in a few releases.  It's assertion verifies
+    # that peephole optimization was actually done though that isn't an
+    # indication of the bugs presence or not (crashing is).
+    @support.cpython_only
+    def test_peephole_opt_unreachable_code_array_access_in_bounds(self):
+        """Regression test for issue35193 when run under clang msan."""
+        def unused_code_at_end():
+            return 3
+            raise RuntimeError("unreachable")
+        # The above function definition will trigger the out of bounds
+        # bug in the peephole optimizer as it scans opcodes past the
+        # RETURN_VALUE opcode.  This does not always crash an interpreter.
+        # When you build with the clang memory sanitizer it reliably aborts.
+        self.assertEqual(
+            'RETURN_VALUE',
+            list(dis.get_instructions(unused_code_at_end))[-1].opname)
+
     def test_dont_merge_constants(self):
         # Issue #25843: compile() must not merge constants which are equal
         # but have a different type.
index 2356efc..66a2004 100644 (file)
@@ -161,7 +161,7 @@ class CompileallTests(unittest.TestCase):
         self.assertRegex(line, r'Listing ([^WindowsPath|PosixPath].*)')
         self.assertTrue(os.path.isfile(self.bc_path))
 
-    @mock.patch('compileall.ProcessPoolExecutor')
+    @mock.patch('concurrent.futures.ProcessPoolExecutor')
     def test_compile_pool_called(self, pool_mock):
         compileall.compile_dir(self.directory, quiet=True, workers=5)
         self.assertTrue(pool_mock.called)
@@ -171,19 +171,19 @@ class CompileallTests(unittest.TestCase):
                                     "workers must be greater or equal to 0"):
             compileall.compile_dir(self.directory, workers=-1)
 
-    @mock.patch('compileall.ProcessPoolExecutor')
+    @mock.patch('concurrent.futures.ProcessPoolExecutor')
     def test_compile_workers_cpu_count(self, pool_mock):
         compileall.compile_dir(self.directory, quiet=True, workers=0)
         self.assertEqual(pool_mock.call_args[1]['max_workers'], None)
 
-    @mock.patch('compileall.ProcessPoolExecutor')
+    @mock.patch('concurrent.futures.ProcessPoolExecutor')
     @mock.patch('compileall.compile_file')
     def test_compile_one_worker(self, compile_file_mock, pool_mock):
         compileall.compile_dir(self.directory, quiet=True)
         self.assertFalse(pool_mock.called)
         self.assertTrue(compile_file_mock.called)
 
-    @mock.patch('compileall.ProcessPoolExecutor', new=None)
+    @mock.patch('concurrent.futures.ProcessPoolExecutor', new=None)
     @mock.patch('compileall.compile_file')
     def test_compile_missing_multiprocessing(self, compile_file_mock):
         compileall.compile_dir(self.directory, quiet=True, workers=5)
index 53f8917..0008aab 100644 (file)
@@ -1,7 +1,9 @@
 """Test suite for the cProfile module."""
 
 import sys
+import unittest
 from test.support import run_unittest, TESTFN, unlink
+from test.support.script_helper import assert_python_failure
 
 # rip off all interesting stuff from test_profile
 import cProfile
@@ -36,8 +38,15 @@ class CProfileTest(ProfileTest):
             unlink(TESTFN)
 
 
+class TestCommandLine(unittest.TestCase):
+    def test_sort(self):
+        rc, out, err = assert_python_failure('-m', 'cProfile', '-s', 'demo')
+        self.assertGreater(rc, 0)
+        self.assertIn(b"option -s: invalid choice: 'demo'", err)
+
+
 def test_main():
-    run_unittest(CProfileTest)
+    run_unittest(CProfileTest, TestCommandLine)
 
 def main():
     if '-r' not in sys.argv:
index 45d80ce..8808a67 100644 (file)
@@ -1178,10 +1178,10 @@ class FormatTest(unittest.TestCase):
         decimal_point = locale.localeconv()['decimal_point']
         thousands_sep = locale.localeconv()['thousands_sep']
         if decimal_point != '\u066b':
-            self.skipTest('inappropriate decimal point separator'
+            self.skipTest('inappropriate decimal point separator '
                           '({!a} not {!a})'.format(decimal_point, '\u066b'))
         if thousands_sep != '\u066c':
-            self.skipTest('inappropriate thousands separator'
+            self.skipTest('inappropriate thousands separator '
                           '({!a} not {!a})'.format(thousands_sep, '\u066c'))
 
         self.assertEqual(format(Decimal('100000000.123'), 'n'),
index 25f86d3..f61efa3 100644 (file)
@@ -1,5 +1,7 @@
 import os
 import signal
+import subprocess
+import sys
 import unittest
 
 from test import support
@@ -15,7 +17,20 @@ class EINTRTests(unittest.TestCase):
         # thread (for reliable signal delivery).
         tester = support.findfile("eintr_tester.py", subdir="eintrdata")
         # use -u to try to get the full output if the test hangs or crash
-        script_helper.assert_python_ok("-u", tester)
+        args = ["-u", tester, "-v"]
+        if support.verbose:
+            print()
+            print("--- run eintr_tester.py ---", flush=True)
+            # In verbose mode, the child process inherit stdout and stdout,
+            # to see output in realtime and reduce the risk of loosing output.
+            args = [sys.executable, "-E", "-X", "faulthandler", *args]
+            proc = subprocess.run(args)
+            print(f"--- eintr_tester.py completed: "
+                  f"exit code {proc.returncode} ---", flush=True)
+            if proc.returncode:
+                self.fail("eintr_tester.py failed")
+        else:
+            script_helper.assert_python_ok("-u", tester, "-v")
 
 
 if __name__ == "__main__":
index 6dcb3bb..4e3c3f3 100644 (file)
@@ -75,6 +75,7 @@ class LocaltimeTests(unittest.TestCase):
         t2 = utils.localtime(t1)
         self.assertEqual(t1, t2)
 
+    @test.support.run_with_tz('Europe/Minsk')
     def test_localtime_daylight_true_dst_true(self):
         test.support.patch(self, time, 'daylight', True)
         t0 = datetime.datetime(2012, 3, 12, 1, 1)
@@ -82,6 +83,7 @@ class LocaltimeTests(unittest.TestCase):
         t2 = utils.localtime(t1)
         self.assertEqual(t1, t2)
 
+    @test.support.run_with_tz('Europe/Minsk')
     def test_localtime_daylight_false_dst_true(self):
         test.support.patch(self, time, 'daylight', False)
         t0 = datetime.datetime(2012, 3, 12, 1, 1)
index b33d007..9c15fca 100644 (file)
@@ -5,6 +5,7 @@
 
 import locale
 import os
+import platform
 import re
 import subprocess
 import sys
@@ -54,6 +55,10 @@ if gdb_major_version < 7:
 if not sysconfig.is_python_build():
     raise unittest.SkipTest("test_gdb only works on source builds at the moment.")
 
+if 'Clang' in platform.python_compiler() and sys.platform == 'darwin':
+    raise unittest.SkipTest("test_gdb doesn't work correctly when python is"
+                            " built with LLVM clang")
+
 # Location of custom hooks file in a repository checkout.
 checkout_hook_path = os.path.join(os.path.dirname(sys.executable),
                                   'python-gdb.py')
index 6fee4df..abc625d 100644 (file)
@@ -174,12 +174,10 @@ class DateTimeTests(unittest.TestCase):
             '1980-01-01 00:61:00',
             '01-01-1980 00:00:62',
             '01-01-1980T00:00:62',
-            '19800101T250000Z'
-            '1980-01-01 00:00:00 -2500',
+            '19800101T250000Z',
             ]:
             self.assertIsNone(iso2time(test),
-                              "iso2time(%s) is not None\n"
-                              "iso2time(test) %s" % (test, iso2time(test)))
+                              "iso2time(%r)" % test)
 
 
 class HeaderTests(unittest.TestCase):
index f306917..f29c16c 100644 (file)
@@ -3547,6 +3547,16 @@ class IncrementalNewlineDecoderTest(unittest.TestCase):
         dec = self.IncrementalNewlineDecoder(None, translate=True)
         _check(dec)
 
+    def test_translate(self):
+        # issue 35062
+        for translate in (-2, -1, 1, 2):
+            decoder = codecs.getincrementaldecoder("utf-8")()
+            decoder = self.IncrementalNewlineDecoder(decoder, translate)
+            self.check_newline_decoding_utf8(decoder)
+        decoder = codecs.getincrementaldecoder("utf-8")()
+        decoder = self.IncrementalNewlineDecoder(decoder, translate=0)
+        self.assertEqual(decoder.decode(b"\r\r\n"), "\r\r\n")
+
 class CIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest):
     pass
 
index d07bb8e..fd2cc03 100644 (file)
@@ -5,12 +5,12 @@ import os
 import stat
 import sys
 import unittest
-from test.support import TESTFN, requires, unlink
+from test.support import TESTFN, requires, unlink, bigmemtest
 import io  # C implementation of io
 import _pyio as pyio # Python implementation of io
 
-# size of file to create (>2GB; 2GB == 2147483648 bytes)
-size = 2500000000
+# size of file to create (>2 GiB; 2 GiB == 2,147,483,648 bytes)
+size = 2_500_000_000
 
 class LargeFileTest:
     """Test that each file function works as expected for large
@@ -45,6 +45,15 @@ class LargeFileTest:
             raise cls.failureException('File was not truncated by opening '
                                        'with mode "wb"')
 
+    # _pyio.FileIO.readall() uses a temporary bytearray then casted to bytes,
+    # so memuse=2 is needed
+    @bigmemtest(size=size, memuse=2, dry_run=False)
+    def test_large_read(self, _size):
+        # bpo-24658: Test that a read greater than 2GB does not fail.
+        with self.open(TESTFN, "rb") as f:
+            self.assertEqual(len(f.read()), size + 1)
+            self.assertEqual(f.tell(), size + 1)
+
     def test_osstat(self):
         self.assertEqual(os.stat(TESTFN)[stat.ST_SIZE], size+1)
 
index ee8c041..d55e25e 100644 (file)
@@ -2,7 +2,7 @@
 
 import copy
 import pickle
-from test.support import findfile
+from test import support
 import unittest
 
 import xml.dom.minidom
@@ -11,7 +11,7 @@ from xml.dom.minidom import parse, Node, Document, parseString
 from xml.dom.minidom import getDOMImplementation
 
 
-tstfile = findfile("test.xml", subdir="xmltestdata")
+tstfile = support.findfile("test.xml", subdir="xmltestdata")
 sample = ("<?xml version='1.0' encoding='us-ascii'?>\n"
           "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
           " 'http://xml.python.org/system' [\n"
@@ -846,6 +846,57 @@ class MinidomTest(unittest.TestCase):
     def testClonePIDeep(self):
         self.check_clone_pi(1, "testClonePIDeep")
 
+    def check_clone_node_entity(self, clone_document):
+        # bpo-35052: Test user data handler in cloneNode() on a document with
+        # an entity
+        document = xml.dom.minidom.parseString("""
+            <?xml version="1.0" ?>
+            <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+                "http://www.w3.org/TR/html4/strict.dtd"
+                [ <!ENTITY smile "☺"> ]
+            >
+            <doc>Don't let entities make you frown &smile;</doc>
+        """.strip())
+
+        class Handler:
+            def handle(self, operation, key, data, src, dst):
+                self.operation = operation
+                self.key = key
+                self.data = data
+                self.src = src
+                self.dst = dst
+
+        handler = Handler()
+        doctype = document.doctype
+        entity = doctype.entities['smile']
+        entity.setUserData("key", "data", handler)
+
+        if clone_document:
+            # clone Document
+            clone = document.cloneNode(deep=True)
+
+            self.assertEqual(clone.documentElement.firstChild.wholeText,
+                             "Don't let entities make you frown ☺")
+            operation = xml.dom.UserDataHandler.NODE_IMPORTED
+            dst = clone.doctype.entities['smile']
+        else:
+            # clone DocumentType
+            with support.swap_attr(doctype, 'ownerDocument', None):
+                clone = doctype.cloneNode(deep=True)
+
+            operation = xml.dom.UserDataHandler.NODE_CLONED
+            dst = clone.entities['smile']
+
+        self.assertEqual(handler.operation, operation)
+        self.assertEqual(handler.key, "key")
+        self.assertEqual(handler.data, "data")
+        self.assertIs(handler.src, entity)
+        self.assertIs(handler.dst, dst)
+
+    def testCloneNodeEntity(self):
+        self.check_clone_node_entity(False)
+        self.check_clone_node_entity(True)
+
     def testNormalize(self):
         doc = parseString("<doc/>")
         root = doc.documentElement
index 9f22500..5000edb 100644 (file)
@@ -1,11 +1,17 @@
 import unittest
 import test._test_multiprocessing
 
+import sys
 from test import support
 
 if support.PGO:
     raise unittest.SkipTest("test is not helpful for PGO")
 
+if sys.platform == "win32":
+    raise unittest.SkipTest("fork is not available on Windows")
+
+if sys.platform == 'darwin':
+    raise unittest.SkipTest("test may crash on macOS (bpo-33725)")
 
 test._test_multiprocessing.install_tests_in_module_dict(globals(), 'fork')
 
index 407bb3f..6ad5faf 100644 (file)
@@ -1,11 +1,15 @@
 import unittest
 import test._test_multiprocessing
 
+import sys
 from test import support
 
 if support.PGO:
     raise unittest.SkipTest("test is not helpful for PGO")
 
+if sys.platform == "win32":
+    raise unittest.SkipTest("forkserver is not available on Windows")
+
 test._test_multiprocessing.install_tests_in_module_dict(globals(), 'forkserver')
 
 if __name__ == '__main__':
index f93d902..bba1712 100644 (file)
@@ -307,6 +307,8 @@ class TestNtpath(unittest.TestCase):
                 tester('ntpath.abspath("")', cwd_dir)
                 tester('ntpath.abspath(" ")', cwd_dir + "\\ ")
                 tester('ntpath.abspath("?")', cwd_dir + "\\?")
+                drive, _ = ntpath.splitdrive(cwd_dir)
+                tester('ntpath.abspath("/abc/")', drive + "\\abc")
         except ImportError:
             self.skipTest('nt module not available')
 
index b396426..b1d7f86 100644 (file)
@@ -697,9 +697,9 @@ class CPythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
         nodesize = calcsize('Pn2P')
 
         od = OrderedDict()
-        check(od, basicsize + 8*p + 8 + 5*entrysize)  # 8byte indicies + 8*2//3 * entry table
+        check(od, basicsize + 8 + 5*entrysize)  # 8byte indices + 8*2//3 * entry table
         od.x = 1
-        check(od, basicsize + 8*p + 8 + 5*entrysize)
+        check(od, basicsize + 8 + 5*entrysize)
         od.update([(i, i) for i in range(3)])
         check(od, basicsize + 8*p + 8 + 5*entrysize + 3*nodesize)
         od.update([(i, i) for i in range(3, 10)])
@@ -732,6 +732,23 @@ class CPythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
                 del od['c']
         self.assertEqual(list(od), list('bdeaf'))
 
+    def test_iterators_pickling(self):
+        OrderedDict = self.OrderedDict
+        pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
+        od = OrderedDict(pairs)
+
+        for method_name in ('keys', 'values', 'items'):
+            meth = getattr(od, method_name)
+            expected = list(meth())[1:]
+            for i in range(pickle.HIGHEST_PROTOCOL + 1):
+                with self.subTest(method_name=method_name, protocol=i):
+                    it = iter(meth())
+                    next(it)
+                    p = pickle.dumps(it, i)
+                    unpickled = pickle.loads(p)
+                    self.assertEqual(list(unpickled), expected)
+                    self.assertEqual(list(it), expected)
+
 
 class PurePythonOrderedDictSubclassTests(PurePythonOrderedDictTests):
 
index 8339f84..7a839c8 100644 (file)
@@ -660,6 +660,29 @@ class UtimeTests(unittest.TestCase):
         # seconds and nanoseconds parameters are mutually exclusive
         with self.assertRaises(ValueError):
             os.utime(self.fname, (5, 5), ns=(5, 5))
+        with self.assertRaises(TypeError):
+            os.utime(self.fname, [5, 5])
+        with self.assertRaises(TypeError):
+            os.utime(self.fname, (5,))
+        with self.assertRaises(TypeError):
+            os.utime(self.fname, (5, 5, 5))
+        with self.assertRaises(TypeError):
+            os.utime(self.fname, ns=[5, 5])
+        with self.assertRaises(TypeError):
+            os.utime(self.fname, ns=(5,))
+        with self.assertRaises(TypeError):
+            os.utime(self.fname, ns=(5, 5, 5))
+
+        if os.utime not in os.supports_follow_symlinks:
+            with self.assertRaises(NotImplementedError):
+                os.utime(self.fname, (5, 5), follow_symlinks=False)
+        if os.utime not in os.supports_fd:
+            with open(self.fname, 'wb', 0) as fp:
+                with self.assertRaises(TypeError):
+                    os.utime(fp.fileno(), (5, 5))
+        if os.utime not in os.supports_dir_fd:
+            with self.assertRaises(NotImplementedError):
+                os.utime(self.fname, (5, 5), dir_fd=0)
 
 
 from test import mapping_tests
@@ -1582,6 +1605,16 @@ class ExecTests(unittest.TestCase):
         with self.assertRaises(ValueError):
             os.execve(args[0], args, newenv)
 
+    @unittest.skipUnless(sys.platform == "win32", "Win32-specific test")
+    def test_execve_with_empty_path(self):
+        # bpo-32890: Check GetLastError() misuse
+        try:
+            os.execve('', ['arg'], {})
+        except OSError as e:
+            self.assertTrue(e.winerror is None or e.winerror != 0)
+        else:
+            self.fail('No OSError raised')
+
 
 @unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
 class Win32ErrorTests(unittest.TestCase):
index 9476ede..e73b31c 100644 (file)
@@ -5,6 +5,7 @@ import warnings
 from posixpath import realpath, abspath, dirname, basename
 from test import support, test_genericpath
 from test.support import FakePath
+from unittest import mock
 
 try:
     import posix
@@ -230,42 +231,61 @@ class PosixPathTest(unittest.TestCase):
     def test_expanduser(self):
         self.assertEqual(posixpath.expanduser("foo"), "foo")
         self.assertEqual(posixpath.expanduser(b"foo"), b"foo")
+
+    def test_expanduser_home_envvar(self):
         with support.EnvironmentVarGuard() as env:
+            env['HOME'] = '/home/victor'
+            self.assertEqual(posixpath.expanduser("~"), "/home/victor")
+
+            # expanduser() strips trailing slash
+            env['HOME'] = '/home/victor/'
+            self.assertEqual(posixpath.expanduser("~"), "/home/victor")
+
             for home in '/', '', '//', '///':
                 with self.subTest(home=home):
                     env['HOME'] = home
                     self.assertEqual(posixpath.expanduser("~"), "/")
                     self.assertEqual(posixpath.expanduser("~/"), "/")
                     self.assertEqual(posixpath.expanduser("~/foo"), "/foo")
-        try:
-            import pwd
-        except ImportError:
-            pass
-        else:
-            self.assertIsInstance(posixpath.expanduser("~/"), str)
-            self.assertIsInstance(posixpath.expanduser(b"~/"), bytes)
-            # if home directory == root directory, this test makes no sense
-            if posixpath.expanduser("~") != '/':
-                self.assertEqual(
-                    posixpath.expanduser("~") + "/",
-                    posixpath.expanduser("~/")
-                )
-                self.assertEqual(
-                    posixpath.expanduser(b"~") + b"/",
-                    posixpath.expanduser(b"~/")
-                )
-            self.assertIsInstance(posixpath.expanduser("~root/"), str)
-            self.assertIsInstance(posixpath.expanduser("~foo/"), str)
-            self.assertIsInstance(posixpath.expanduser(b"~root/"), bytes)
-            self.assertIsInstance(posixpath.expanduser(b"~foo/"), bytes)
-
-            with support.EnvironmentVarGuard() as env:
-                # expanduser should fall back to using the password database
-                del env['HOME']
-                home = pwd.getpwuid(os.getuid()).pw_dir
-                # $HOME can end with a trailing /, so strip it (see #17809)
-                home = home.rstrip("/") or '/'
-                self.assertEqual(posixpath.expanduser("~"), home)
+
+    def test_expanduser_pwd(self):
+        pwd = support.import_module('pwd')
+
+        self.assertIsInstance(posixpath.expanduser("~/"), str)
+        self.assertIsInstance(posixpath.expanduser(b"~/"), bytes)
+
+        # if home directory == root directory, this test makes no sense
+        if posixpath.expanduser("~") != '/':
+            self.assertEqual(
+                posixpath.expanduser("~") + "/",
+                posixpath.expanduser("~/")
+            )
+            self.assertEqual(
+                posixpath.expanduser(b"~") + b"/",
+                posixpath.expanduser(b"~/")
+            )
+        self.assertIsInstance(posixpath.expanduser("~root/"), str)
+        self.assertIsInstance(posixpath.expanduser("~foo/"), str)
+        self.assertIsInstance(posixpath.expanduser(b"~root/"), bytes)
+        self.assertIsInstance(posixpath.expanduser(b"~foo/"), bytes)
+
+        with support.EnvironmentVarGuard() as env:
+            # expanduser should fall back to using the password database
+            del env['HOME']
+
+            home = pwd.getpwuid(os.getuid()).pw_dir
+            # $HOME can end with a trailing /, so strip it (see #17809)
+            home = home.rstrip("/") or '/'
+            self.assertEqual(posixpath.expanduser("~"), home)
+
+            # bpo-10496: If the HOME environment variable is not set and the
+            # user (current identifier or name in the path) doesn't exist in
+            # the password database (pwd.getuid() or pwd.getpwnam() fail),
+            # expanduser() must return the path unchanged.
+            with mock.patch.object(pwd, 'getpwuid', side_effect=KeyError), \
+                 mock.patch.object(pwd, 'getpwnam', side_effect=KeyError):
+                for path in ('~', '~/.local', '~vstinner/'):
+                    self.assertEqual(posixpath.expanduser(path), path)
 
     def test_normpath(self):
         self.assertEqual(posixpath.normpath(""), ".")
index 0383a67..00803d3 100644 (file)
@@ -419,6 +419,7 @@ class PydocBaseTest(unittest.TestCase):
 
 
 class PydocDocTest(unittest.TestCase):
+    maxDiff = None
 
     @unittest.skipIf(sys.flags.optimize >= 2,
                      "Docstrings are omitted with -O2 and above")
@@ -650,6 +651,104 @@ class PydocDocTest(unittest.TestCase):
         methods = pydoc.allmethods(TestClass)
         self.assertDictEqual(methods, expected)
 
+    def test_method_aliases(self):
+        class A:
+            def tkraise(self, aboveThis=None):
+                """Raise this widget in the stacking order."""
+            lift = tkraise
+            def a_size(self):
+                """Return size"""
+        class B(A):
+            def itemconfigure(self, tagOrId, cnf=None, **kw):
+                """Configure resources of an item TAGORID."""
+            itemconfig = itemconfigure
+            b_size = A.a_size
+
+        doc = pydoc.render_doc(B)
+        # clean up the extra text formatting that pydoc performs
+        doc = re.sub('\b.', '', doc)
+        self.assertEqual(doc, '''\
+Python Library Documentation: class B in module %s
+
+class B(A)
+ |  Method resolution order:
+ |      B
+ |      A
+ |      builtins.object
+ |\x20\x20
+ |  Methods defined here:
+ |\x20\x20
+ |  b_size = a_size(self)
+ |\x20\x20
+ |  itemconfig = itemconfigure(self, tagOrId, cnf=None, **kw)
+ |\x20\x20
+ |  itemconfigure(self, tagOrId, cnf=None, **kw)
+ |      Configure resources of an item TAGORID.
+ |\x20\x20
+ |  ----------------------------------------------------------------------
+ |  Methods inherited from A:
+ |\x20\x20
+ |  a_size(self)
+ |      Return size
+ |\x20\x20
+ |  lift = tkraise(self, aboveThis=None)
+ |\x20\x20
+ |  tkraise(self, aboveThis=None)
+ |      Raise this widget in the stacking order.
+ |\x20\x20
+ |  ----------------------------------------------------------------------
+ |  Data descriptors inherited from A:
+ |\x20\x20
+ |  __dict__
+ |      dictionary for instance variables (if defined)
+ |\x20\x20
+ |  __weakref__
+ |      list of weak references to the object (if defined)
+''' % __name__)
+
+        doc = pydoc.render_doc(B, renderer=pydoc.HTMLDoc())
+        self.assertEqual(doc, '''\
+Python Library Documentation: class B in module %s
+
+<p>
+<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
+<tr bgcolor="#ffc8d8">
+<td colspan=3 valign=bottom>&nbsp;<br>
+<font color="#000000" face="helvetica, arial"><a name="B">class <strong>B</strong></a>(A)</font></td></tr>
+\x20\x20\x20\x20
+<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
+<td width="100%%"><dl><dt>Method resolution order:</dt>
+<dd>B</dd>
+<dd>A</dd>
+<dd><a href="builtins.html#object">builtins.object</a></dd>
+</dl>
+<hr>
+Methods defined here:<br>
+<dl><dt><a name="B-b_size"><strong>b_size</strong></a> = <a href="#B-a_size">a_size</a>(self)</dt></dl>
+
+<dl><dt><a name="B-itemconfig"><strong>itemconfig</strong></a> = <a href="#B-itemconfigure">itemconfigure</a>(self, tagOrId, cnf=None, **kw)</dt></dl>
+
+<dl><dt><a name="B-itemconfigure"><strong>itemconfigure</strong></a>(self, tagOrId, cnf=None, **kw)</dt><dd><tt>Configure&nbsp;resources&nbsp;of&nbsp;an&nbsp;item&nbsp;TAGORID.</tt></dd></dl>
+
+<hr>
+Methods inherited from A:<br>
+<dl><dt><a name="B-a_size"><strong>a_size</strong></a>(self)</dt><dd><tt>Return&nbsp;size</tt></dd></dl>
+
+<dl><dt><a name="B-lift"><strong>lift</strong></a> = <a href="#B-tkraise">tkraise</a>(self, aboveThis=None)</dt></dl>
+
+<dl><dt><a name="B-tkraise"><strong>tkraise</strong></a>(self, aboveThis=None)</dt><dd><tt>Raise&nbsp;this&nbsp;widget&nbsp;in&nbsp;the&nbsp;stacking&nbsp;order.</tt></dd></dl>
+
+<hr>
+Data descriptors inherited from A:<br>
+<dl><dt><strong>__dict__</strong></dt>
+<dd><tt>dictionary&nbsp;for&nbsp;instance&nbsp;variables&nbsp;(if&nbsp;defined)</tt></dd>
+</dl>
+<dl><dt><strong>__weakref__</strong></dt>
+<dd><tt>list&nbsp;of&nbsp;weak&nbsp;references&nbsp;to&nbsp;the&nbsp;object&nbsp;(if&nbsp;defined)</tt></dd>
+</dl>
+</td></tr></table>\
+''' % __name__)
+
 
 class PydocImportTest(PydocBaseTest):
 
index 679759e..b6f948d 100644 (file)
@@ -40,7 +40,7 @@ class RangeTest(unittest.TestCase):
                 self.fail('{}: unexpected excess element {} at '
                           'position {}'.format(test_id, x, i))
             else:
-                self.fail('{}: wrong element at position {};'
+                self.fail('{}: wrong element at position {}; '
                           'expected {}, got {}'.format(test_id, i, y, x))
 
     def test_range(self):
index 0b590ad..5347bb1 100644 (file)
@@ -66,10 +66,10 @@ class ParseArgsTestCase(unittest.TestCase):
         ns = libregrtest._parse_args(['--wait'])
         self.assertTrue(ns.wait)
 
-    def test_slaveargs(self):
-        ns = libregrtest._parse_args(['--slaveargs', '[[], {}]'])
-        self.assertEqual(ns.slaveargs, '[[], {}]')
-        self.checkError(['--slaveargs'], 'expected one argument')
+    def test_worker_args(self):
+        ns = libregrtest._parse_args(['--worker-args', '[[], {}]'])
+        self.assertEqual(ns.worker_args, '[[], {}]')
+        self.checkError(['--worker-args'], 'expected one argument')
 
     def test_start(self):
         for opt in '-S', '--start':
@@ -351,11 +351,20 @@ class BaseTestCase(unittest.TestCase):
         self.tmptestdir = tempfile.mkdtemp()
         self.addCleanup(support.rmtree, self.tmptestdir)
 
-    def create_test(self, name=None, code=''):
+    def create_test(self, name=None, code=None):
         if not name:
             name = 'noop%s' % BaseTestCase.TEST_UNIQUE_ID
             BaseTestCase.TEST_UNIQUE_ID += 1
 
+        if code is None:
+            code = textwrap.dedent("""
+                    import unittest
+
+                    class Tests(unittest.TestCase):
+                        def test_empty_test(self):
+                            pass
+                """)
+
         # test_regrtest cannot be run twice in parallel because
         # of setUp() and create_test()
         name = self.TESTNAME_PREFIX + name
@@ -390,7 +399,7 @@ class BaseTestCase(unittest.TestCase):
 
     def check_executed_tests(self, output, tests, skipped=(), failed=(),
                              env_changed=(), omitted=(),
-                             rerun=(),
+                             rerun=(), no_test_ran=(),
                              randomize=False, interrupted=False,
                              fail_env_changed=False):
         if isinstance(tests, str):
@@ -405,6 +414,8 @@ class BaseTestCase(unittest.TestCase):
             omitted = [omitted]
         if isinstance(rerun, str):
             rerun = [rerun]
+        if isinstance(no_test_ran, str):
+            no_test_ran = [no_test_ran]
 
         executed = self.parse_executed_tests(output)
         if randomize:
@@ -447,8 +458,12 @@ class BaseTestCase(unittest.TestCase):
                 regex = "Re-running test %r in verbose mode" % name
                 self.check_line(output, regex)
 
+        if no_test_ran:
+            regex = list_regex('%s test%s run no tests', no_test_ran)
+            self.check_line(output, regex)
+
         good = (len(tests) - len(skipped) - len(failed)
-                - len(omitted) - len(env_changed))
+                - len(omitted) - len(env_changed) - len(no_test_ran))
         if good:
             regex = r'%s test%s OK\.$' % (good, plural(good))
             if not skipped and not failed and good > 1:
@@ -465,12 +480,16 @@ class BaseTestCase(unittest.TestCase):
             result.append('ENV CHANGED')
         if interrupted:
             result.append('INTERRUPTED')
-        if not result:
+        if not any((good, result, failed, interrupted, skipped,
+                    env_changed, fail_env_changed)):
+            result.append("NO TEST RUN")
+        elif not result:
             result.append('SUCCESS')
         result = ', '.join(result)
         if rerun:
             self.check_line(output, 'Tests result: %s' % result)
             result = 'FAILURE then %s' % result
+
         self.check_line(output, 'Tests result: %s' % result)
 
     def parse_random_seed(self, output):
@@ -649,7 +668,14 @@ class ArgsTestCase(BaseTestCase):
         # test -u command line option
         tests = {}
         for resource in ('audio', 'network'):
-            code = 'from test import support\nsupport.requires(%r)' % resource
+            code = textwrap.dedent("""
+                        from test import support; support.requires(%r)
+                        import unittest
+                        class PassingTest(unittest.TestCase):
+                            def test_pass(self):
+                                pass
+                    """ % resource)
+
             tests[resource] = self.create_test(resource, code)
         test_names = sorted(tests.values())
 
@@ -983,6 +1009,56 @@ class ArgsTestCase(BaseTestCase):
         output = self.run_tests("-w", testname, exitcode=2)
         self.check_executed_tests(output, [testname],
                                   failed=testname, rerun=testname)
+    def test_no_tests_ran(self):
+        code = textwrap.dedent("""
+            import unittest
+
+            class Tests(unittest.TestCase):
+                def test_bug(self):
+                    pass
+        """)
+        testname = self.create_test(code=code)
+
+        output = self.run_tests(testname, "-m", "nosuchtest", exitcode=0)
+        self.check_executed_tests(output, [testname], no_test_ran=testname)
+
+    def test_no_tests_ran_multiple_tests_nonexistent(self):
+        code = textwrap.dedent("""
+            import unittest
+
+            class Tests(unittest.TestCase):
+                def test_bug(self):
+                    pass
+        """)
+        testname = self.create_test(code=code)
+        testname2 = self.create_test(code=code)
+
+        output = self.run_tests(testname, testname2, "-m", "nosuchtest", exitcode=0)
+        self.check_executed_tests(output, [testname, testname2],
+                                  no_test_ran=[testname, testname2])
+
+    def test_no_test_ran_some_test_exist_some_not(self):
+        code = textwrap.dedent("""
+            import unittest
+
+            class Tests(unittest.TestCase):
+                def test_bug(self):
+                    pass
+        """)
+        testname = self.create_test(code=code)
+        other_code = textwrap.dedent("""
+            import unittest
+
+            class Tests(unittest.TestCase):
+                def test_other_bug(self):
+                    pass
+        """)
+        testname2 = self.create_test(code=other_code)
+
+        output = self.run_tests(testname, testname2, "-m", "nosuchtest",
+                                "-m", "test_other_bug", exitcode=0)
+        self.check_executed_tests(output, [testname, testname2],
+                                  no_test_ran=[testname])
 
 
 class TestUtils(unittest.TestCase):
index afdcf36..6964a84 100644 (file)
@@ -6,6 +6,7 @@ executing have not been removed.
 """
 import unittest
 import test.support
+from test import support
 from test.support import (captured_stderr, TESTFN, EnvironmentVarGuard,
                           change_cwd)
 import builtins
@@ -18,6 +19,7 @@ import urllib.error
 import shutil
 import subprocess
 import sysconfig
+from unittest import mock
 from copy import copy
 
 # These tests are not particularly useful if Python was invoked with -S.
@@ -243,6 +245,7 @@ class HelperFunctionsTests(unittest.TestCase):
         # the call sets USER_BASE *and* USER_SITE
         self.assertEqual(site.USER_SITE, user_site)
         self.assertTrue(user_site.startswith(site.USER_BASE), user_site)
+        self.assertEqual(site.USER_BASE, site.getuserbase())
 
     def test_getsitepackages(self):
         site.PREFIXES = ['xoxo']
@@ -273,6 +276,41 @@ class HelperFunctionsTests(unittest.TestCase):
             wanted = os.path.join('xoxo', 'lib', 'site-packages')
             self.assertEqual(dirs[1], wanted)
 
+    def test_no_home_directory(self):
+        # bpo-10496: getuserbase() and getusersitepackages() must not fail if
+        # the current user has no home directory (if expanduser() returns the
+        # path unchanged).
+        site.USER_SITE = None
+        site.USER_BASE = None
+        sysconfig._CONFIG_VARS = None
+
+        with EnvironmentVarGuard() as environ, \
+             mock.patch('os.path.expanduser', lambda path: path):
+
+            del environ['PYTHONUSERBASE']
+            del environ['APPDATA']
+
+            user_base = site.getuserbase()
+            self.assertTrue(user_base.startswith('~' + os.sep),
+                            user_base)
+
+            user_site = site.getusersitepackages()
+            self.assertTrue(user_site.startswith(user_base), user_site)
+
+        with mock.patch('os.path.isdir', return_value=False) as mock_isdir, \
+             mock.patch.object(site, 'addsitedir') as mock_addsitedir, \
+             support.swap_attr(site, 'ENABLE_USER_SITE', True):
+
+            # addusersitepackages() must not add user_site to sys.path
+            # if it is not an existing directory
+            known_paths = set()
+            site.addusersitepackages(known_paths)
+
+            mock_isdir.assert_called_once_with(user_site)
+            mock_addsitedir.assert_not_called()
+            self.assertFalse(known_paths)
+
+
 class PthFile(object):
     """Helper class for handling testing of .pth files"""
 
index 1811019..8704751 100644 (file)
@@ -767,7 +767,7 @@ class SimSMTPChannel(smtpd.SMTPChannel):
             try:
                 user, hashed_pass = logpass.split()
             except ValueError as e:
-                self.push('535 Splitting response {!r} into user and password'
+                self.push('535 Splitting response {!r} into user and password '
                           'failed: {}'.format(logpass, e))
                 return False
             valid_hashed_pass = hmac.HMAC(
index fbbc9f9..56adec1 100644 (file)
@@ -32,6 +32,7 @@ except ImportError:
 
 HOST = support.HOST
 MSG = 'Michael Gilfix was here\u1234\r\n'.encode('utf-8') ## test unicode string and carriage return
+MAIN_TIMEOUT = 60.0
 
 try:
     import _thread as thread
@@ -3870,6 +3871,7 @@ class BasicSocketPairTest(SocketPairTest):
 class NonBlockingTCPTests(ThreadedTCPSocketTest):
 
     def __init__(self, methodName='runTest'):
+        self.event = threading.Event()
         ThreadedTCPSocketTest.__init__(self, methodName=methodName)
 
     def testSetBlocking(self):
@@ -3944,22 +3946,27 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest):
     def testAccept(self):
         # Testing non-blocking accept
         self.serv.setblocking(0)
-        try:
-            conn, addr = self.serv.accept()
-        except OSError:
-            pass
-        else:
-            self.fail("Error trying to do non-blocking accept.")
-        read, write, err = select.select([self.serv], [], [])
-        if self.serv in read:
+
+        # connect() didn't start: non-blocking accept() fails
+        with self.assertRaises(BlockingIOError):
             conn, addr = self.serv.accept()
-            self.assertIsNone(conn.gettimeout())
-            conn.close()
-        else:
+
+        self.event.set()
+
+        read, write, err = select.select([self.serv], [], [], MAIN_TIMEOUT)
+        if self.serv not in read:
             self.fail("Error trying to do accept after select.")
 
+        # connect() completed: non-blocking accept() doesn't block
+        conn, addr = self.serv.accept()
+        self.addCleanup(conn.close)
+        self.assertIsNone(conn.gettimeout())
+
     def _testAccept(self):
-        time.sleep(0.1)
+        # don't connect before event is set to check
+        # that non-blocking accept() raises BlockingIOError
+        self.event.wait()
+
         self.cli.connect((HOST, self.port))
 
     def testConnect(self):
@@ -3974,25 +3981,32 @@ class NonBlockingTCPTests(ThreadedTCPSocketTest):
     def testRecv(self):
         # Testing non-blocking recv
         conn, addr = self.serv.accept()
+        self.addCleanup(conn.close)
         conn.setblocking(0)
-        try:
-            msg = conn.recv(len(MSG))
-        except OSError:
-            pass
-        else:
-            self.fail("Error trying to do non-blocking recv.")
-        read, write, err = select.select([conn], [], [])
-        if conn in read:
+
+        # the server didn't send data yet: non-blocking recv() fails
+        with self.assertRaises(BlockingIOError):
             msg = conn.recv(len(MSG))
-            conn.close()
-            self.assertEqual(msg, MSG)
-        else:
+
+        self.event.set()
+
+        read, write, err = select.select([conn], [], [], MAIN_TIMEOUT)
+        if conn not in read:
             self.fail("Error during select call to non-blocking socket.")
 
+        # the server sent data yet: non-blocking recv() doesn't block
+        msg = conn.recv(len(MSG))
+        self.assertEqual(msg, MSG)
+
     def _testRecv(self):
         self.cli.connect((HOST, self.port))
-        time.sleep(0.1)
-        self.cli.send(MSG)
+
+        # don't send anything before event is set to check
+        # that non-blocking recv() raises BlockingIOError
+        self.event.wait()
+
+        # send data: recv() will no longer block
+        self.cli.sendall(MSG)
 
 @unittest.skipUnless(thread, 'Threading required for this test.')
 class FileObjectClassTestCase(SocketConnectedTest):
@@ -5577,6 +5591,24 @@ class LinuxKernelCryptoAPI(unittest.TestCase):
             with self.assertRaises(TypeError):
                 sock.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, assoclen=-1)
 
+    def test_length_restriction(self):
+        # bpo-35050, off-by-one error in length check
+        sock = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
+        self.addCleanup(sock.close)
+
+        # salg_type[14]
+        with self.assertRaises(FileNotFoundError):
+            sock.bind(("t" * 13, "name"))
+        with self.assertRaisesRegex(ValueError, "type too long"):
+            sock.bind(("t" * 14, "name"))
+
+        # salg_name[64]
+        with self.assertRaises(FileNotFoundError):
+            sock.bind(("type", "n" * 63))
+        with self.assertRaisesRegex(ValueError, "name too long"):
+            sock.bind(("type", "n" * 64))
+
+
 @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
 class TestMSWindowsTCPFlags(unittest.TestCase):
     knownTCPFlags = {
index 2f0b6a7..705f1d3 100644 (file)
@@ -408,6 +408,12 @@ class BasicSocketTests(unittest.TestCase):
             self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1)
             self.assertRaises(OSError, ss.send, b'x')
             self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0))
+            self.assertRaises(NotImplementedError, ss.dup)
+            self.assertRaises(NotImplementedError, ss.sendmsg,
+                              [b'x'], (), 0, ('0.0.0.0', 0))
+            self.assertRaises(NotImplementedError, ss.recvmsg, 100)
+            self.assertRaises(NotImplementedError, ss.recvmsg_into,
+                              [bytearray(100)])
 
     def test_timeout(self):
         # Issue #8524: when creating an SSL socket, the timeout of the
@@ -2942,11 +2948,11 @@ if _have_threads:
                 # Make sure sendmsg et al are disallowed to avoid
                 # inadvertent disclosure of data and/or corruption
                 # of the encrypted data stream
+                self.assertRaises(NotImplementedError, s.dup)
                 self.assertRaises(NotImplementedError, s.sendmsg, [b"data"])
                 self.assertRaises(NotImplementedError, s.recvmsg, 100)
                 self.assertRaises(NotImplementedError,
-                                  s.recvmsg_into, bytearray(100))
-
+                                  s.recvmsg_into, [bytearray(100)])
                 s.write(b"over\n")
 
                 self.assertRaises(ValueError, s.recv, -1)
index 2cf0926..92de811 100644 (file)
@@ -457,7 +457,7 @@ class CalculationTests(unittest.TestCase):
         self.assertTrue(result.tm_year == self.time_tuple.tm_year and
                          result.tm_mon == self.time_tuple.tm_mon and
                          result.tm_mday == self.time_tuple.tm_mday,
-                        "Calculation of Gregorian date failed;"
+                        "Calculation of Gregorian date failed; "
                          "%s-%s-%s != %s-%s-%s" %
                          (result.tm_year, result.tm_mon, result.tm_mday,
                           self.time_tuple.tm_year, self.time_tuple.tm_mon,
@@ -469,7 +469,7 @@ class CalculationTests(unittest.TestCase):
         result = _strptime._strptime_time(time.strftime(format_string, self.time_tuple),
                                     format_string)
         self.assertTrue(result.tm_wday == self.time_tuple.tm_wday,
-                        "Calculation of day of the week failed;"
+                        "Calculation of day of the week failed; "
                          "%s != %s" % (result.tm_wday, self.time_tuple.tm_wday))
 
     if support.is_android:
@@ -641,7 +641,7 @@ class CacheTests(unittest.TestCase):
         finally:
             locale.setlocale(locale.LC_TIME, locale_info)
 
-    @support.run_with_tz('STD-1DST')
+    @support.run_with_tz('STD-1DST,M4.1.0,M10.1.0')
     def test_TimeRE_recreation_timezone(self):
         # The TimeRE instance should be recreated upon changing the timezone.
         oldtzname = time.tzname
index 45cdc94..adc59b6 100644 (file)
@@ -1,13 +1,14 @@
+import errno
 import importlib
+import os
 import shutil
+import socket
 import stat
+import subprocess
 import sys
-import os
-import unittest
-import socket
 import tempfile
 import textwrap
-import errno
+import unittest
 from test import support
 from test.support import script_helper
 
@@ -394,6 +395,65 @@ class TestSupport(unittest.TestCase):
 
         self.assertRaises(AssertionError, support.check__all__, self, unittest)
 
+    def check_options(self, args, func, expected=None):
+        code = f'from test.support import {func}; print(repr({func}()))'
+        cmd = [sys.executable, *args, '-c', code]
+        env = {key: value for key, value in os.environ.items()
+               if not key.startswith('PYTHON')}
+        proc = subprocess.run(cmd,
+                              stdout=subprocess.PIPE,
+                              stderr=subprocess.DEVNULL,
+                              universal_newlines=True,
+                              env=env)
+        if expected is None:
+            expected = args
+        self.assertEqual(proc.stdout.rstrip(), repr(expected))
+        self.assertEqual(proc.returncode, 0)
+
+    def test_args_from_interpreter_flags(self):
+        # Test test.support.args_from_interpreter_flags()
+        for opts in (
+            # no option
+            [],
+            # single option
+            ['-B'],
+            ['-s'],
+            ['-S'],
+            ['-E'],
+            ['-v'],
+            ['-b'],
+            ['-q'],
+            ['-I'],
+            # same option multiple times
+            ['-bb'],
+            ['-vvv'],
+            # -W options
+            ['-Wignore'],
+            # -X options
+            ['-X', 'faulthandler'],
+            ['-X', 'showalloccount'],
+            ['-X', 'showrefcount'],
+            ['-X', 'tracemalloc'],
+            ['-X', 'tracemalloc=3'],
+        ):
+            with self.subTest(opts=opts):
+                self.check_options(opts, 'args_from_interpreter_flags')
+
+        self.check_options(['-I', '-E', '-s'], 'args_from_interpreter_flags',
+                           ['-I'])
+
+    def test_optim_args_from_interpreter_flags(self):
+        # Test test.support.optim_args_from_interpreter_flags()
+        for opts in (
+            # no option
+            [],
+            ['-O'],
+            ['-OO'],
+            ['-OOOO'],
+        ):
+            with self.subTest(opts=opts):
+                self.check_options(opts, 'optim_args_from_interpreter_flags')
+
     def test_match_test(self):
         class Test:
             def __init__(self, test_id):
@@ -485,7 +545,6 @@ class TestSupport(unittest.TestCase):
     # reap_threads
     # reap_children
     # strip_python_stderr
-    # args_from_interpreter_flags
     # can_symlink
     # skip_unless_symlink
     # SuppressCrashReport
index 43ef22b..ad54272 100644 (file)
@@ -544,6 +544,7 @@ class ThreadTests(BaseTestCase):
         self.assertEqual(err, b"")
         self.assertEqual(data, "Thread-1\nTrue\nTrue\n")
 
+    @requires_type_collecting
     def test_main_thread_during_shutdown(self):
         # bpo-31516: current_thread() should still point to the main thread
         # at shutdown
index 15f73de..1aa64cb 100644 (file)
@@ -27,6 +27,13 @@ def _wrap_with_retry_thrice(func, exc):
         return _retry_thrice(func, exc, *args, **kwargs)
     return wrapped
 
+# bpo-35411: FTP tests of test_urllib2net randomly fail
+# with "425 Security: Bad IP connecting" on Travis CI
+skip_ftp_test_on_travis = unittest.skipIf('TRAVIS' in os.environ,
+                                          'bpo-35411: skip FTP test '
+                                          'on Travis CI')
+
+
 # Connecting to remote hosts is flaky.  Make it more robust by retrying
 # the connection several times.
 _urlopen_with_retry = _wrap_with_retry_thrice(urllib.request.urlopen,
@@ -95,6 +102,7 @@ class OtherNetworkTests(unittest.TestCase):
     # XXX The rest of these tests aren't very good -- they don't check much.
     # They do sometimes catch some major disasters, though.
 
+    @skip_ftp_test_on_travis
     def test_ftp(self):
         urls = [
             'ftp://www.pythontest.net/README',
@@ -290,6 +298,7 @@ class TimeoutTest(unittest.TestCase):
 
     FTP_HOST = 'ftp://www.pythontest.net/'
 
+    @skip_ftp_test_on_travis
     def test_ftp_basic(self):
         self.assertIsNone(socket.getdefaulttimeout())
         with support.transient_internet(self.FTP_HOST, timeout=None):
@@ -297,6 +306,7 @@ class TimeoutTest(unittest.TestCase):
             self.addCleanup(u.close)
             self.assertIsNone(u.fp.fp.raw._sock.gettimeout())
 
+    @skip_ftp_test_on_travis
     def test_ftp_default_timeout(self):
         self.assertIsNone(socket.getdefaulttimeout())
         with support.transient_internet(self.FTP_HOST):
@@ -308,6 +318,7 @@ class TimeoutTest(unittest.TestCase):
                 socket.setdefaulttimeout(None)
             self.assertEqual(u.fp.fp.raw._sock.gettimeout(), 60)
 
+    @skip_ftp_test_on_travis
     def test_ftp_no_timeout(self):
         self.assertIsNone(socket.getdefaulttimeout())
         with support.transient_internet(self.FTP_HOST):
@@ -319,6 +330,7 @@ class TimeoutTest(unittest.TestCase):
                 socket.setdefaulttimeout(None)
             self.assertIsNone(u.fp.fp.raw._sock.gettimeout())
 
+    @skip_ftp_test_on_travis
     def test_ftp_timeout(self):
         with support.transient_internet(self.FTP_HOST):
             u = _urlopen_with_retry(self.FTP_HOST, timeout=60)
index ddee1c3..be50b47 100644 (file)
@@ -879,6 +879,13 @@ class UrlParseTestCase(unittest.TestCase):
                                                           errors="ignore")
         self.assertEqual(result, [('key', '\u0141-')])
 
+    def test_parse_qsl_max_num_fields(self):
+        with self.assertRaises(ValueError):
+            urllib.parse.parse_qs('&'.join(['a=a']*11), max_num_fields=10)
+        with self.assertRaises(ValueError):
+            urllib.parse.parse_qs(';'.join(['a=a']*11), max_num_fields=10)
+        urllib.parse.parse_qs('&'.join(['a=a']*10), max_num_fields=10)
+
     def test_urlencode_sequences(self):
         # Other tests incidentally urlencode things; test non-covered cases:
         # Sequence and object values.
index d1ffb81..842470f 100644 (file)
@@ -40,7 +40,7 @@ def check_output(cmd, encoding=None):
     out, err = p.communicate()
     if p.returncode:
         raise subprocess.CalledProcessError(
-            p.returncode, cmd, None, out, err)
+            p.returncode, cmd, out, err)
     return out, err
 
 class BaseTest(unittest.TestCase):
index 2b8c5e5..b01709e 100644 (file)
@@ -2145,6 +2145,21 @@ class ElementTreeTypeTest(unittest.TestCase):
         mye = MyElement('joe')
         self.assertEqual(mye.newmethod(), 'joe')
 
+    def test_Element_subclass_find(self):
+        class MyElement(ET.Element):
+            pass
+
+        e = ET.Element('foo')
+        e.text = 'text'
+        sub = MyElement('bar')
+        sub.text = 'subtext'
+        e.append(sub)
+        self.assertEqual(e.findtext('bar'), 'subtext')
+        self.assertEqual(e.find('bar').tag, 'bar')
+        found = list(e.findall('bar'))
+        self.assertEqual(len(found), 1, found)
+        self.assertEqual(found[0].tag, 'bar')
+
 
 class ElementFindTest(unittest.TestCase):
     def test_find_simple(self):
index d99b4e7..1a1f660 100644 (file)
@@ -116,6 +116,22 @@ class MiscTests(unittest.TestCase):
         elem.tail = X()
         elem.__setstate__({'tag': 42})  # shouldn't cause an assertion failure
 
+    def test_setstate_leaks(self):
+        # Test reference leaks
+        elem = cET.Element.__new__(cET.Element)
+        for i in range(100):
+            elem.__setstate__({'tag': 'foo', 'attrib': {'bar': 42},
+                               '_children': [cET.Element('child')],
+                               'text': 'text goes here',
+                               'tail': 'opposite of head'})
+
+        self.assertEqual(elem.tag, 'foo')
+        self.assertEqual(elem.text, 'text goes here')
+        self.assertEqual(elem.tail, 'opposite of head')
+        self.assertEqual(list(elem.attrib.items()), [('bar', 42)])
+        self.assertEqual(len(elem), 1)
+        self.assertEqual(elem[0].tag, 'child')
+
 
 @unittest.skipUnless(cET, 'requires _elementtree')
 class TestAliasWorking(unittest.TestCase):
index ff85f83..a6e8fb2 100644 (file)
@@ -3750,7 +3750,7 @@ class Spinbox(Widget, XView):
         select to commands. If the selection isn't currently in
         the spinbox, then a new selection is created to include
         the characters between index and the most recent selection
-        anchor point, inclusive. Returns an empty string.
+        anchor point, inclusive.
         """
         return self.selection("adjust", index)
 
@@ -3758,7 +3758,7 @@ class Spinbox(Widget, XView):
         """Clear the selection
 
         If the selection isn't in this widget then the
-        command has no effect. Returns an empty string.
+        command has no effect.
         """
         return self.selection("clear")
 
@@ -3766,9 +3766,9 @@ class Spinbox(Widget, XView):
         """Sets or gets the currently selected element.
 
         If a spinbutton element is specified, it will be
-        displayed depressed
+        displayed depressed.
         """
-        return self.selection("element", element)
+        return self.tk.call(self._w, 'selection', 'element', element)
 
 ###########################################################################
 
index 0d9a65a..467a0b6 100644 (file)
@@ -62,9 +62,9 @@ def requires_tcl(*version):
     def deco(test):
         @functools.wraps(test)
         def newtest(self):
-            if get_tk_patchlevel() < (8, 6, 5):
+            if get_tk_patchlevel() < version:
                 self.skipTest('requires Tcl version >= ' +
-                                '.'.join(map(str, get_tk_patchlevel())))
+                                '.'.join(map(str, version)))
             test(self)
         return newtest
     return deco
index e4c9d33..3fb6411 100644 (file)
@@ -474,6 +474,14 @@ class SpinboxTest(EntryTest, unittest.TestCase):
         self.assertRaises(TypeError, widget.bbox)
         self.assertRaises(TypeError, widget.bbox, 0, 1)
 
+    def test_selection_element(self):
+        widget = self.create()
+        self.assertEqual(widget.selection_element(), "none")
+        widget.selection_element("buttonup")
+        self.assertEqual(widget.selection_element(), "buttonup")
+        widget.selection_element("buttondown")
+        self.assertEqual(widget.selection_element(), "buttondown")
+
 
 @add_standard_options(StandardOptionsTests)
 class TextTest(AbstractWidgetTest, unittest.TestCase):
index d171577..e5fa94f 100755 (executable)
@@ -313,7 +313,7 @@ class CoverageResults:
         try:
             outfile = open(path, "w", encoding=encoding)
         except OSError as err:
-            print(("trace: Could not open %r for writing: %s"
+            print(("trace: Could not open %r for writing: %s "
                                   "- skipping" % (path, err)), file=sys.stderr)
             return 0, 0
 
@@ -655,7 +655,7 @@ def main():
     grp = parser.add_argument_group('Filters',
             'Can be specified multiple times')
     grp.add_argument('--ignore-module', action='append', default=[],
-            help='Ignore the given module(s) and its submodules'
+            help='Ignore the given module(s) and its submodules '
                  '(if it is a package). Accepts comma separated list of '
                  'module names.')
     grp.add_argument('--ignore-dir', action='append', default=[],
index 8036b7f..f3b92e3 100644 (file)
@@ -1352,7 +1352,7 @@ class TurtleScreen(TurtleScreenBase):
         Arguments:
         fun -- a function with two arguments, the coordinates of the
                clicked point on the canvas.
-        num -- the number of the mouse-button, defaults to 1
+        btn -- the number of the mouse-button, defaults to 1
 
         Example (for a TurtleScreen instance named screen)
 
@@ -3526,7 +3526,7 @@ class RawTurtle(TPen, TNavigator):
         Arguments:
         fun --  a function with two arguments, to which will be assigned
                 the coordinates of the clicked point on the canvas.
-        num --  number of the mouse-button defaults to 1 (left mouse button).
+        btn --  number of the mouse-button defaults to 1 (left mouse button).
         add --  True or False. If True, new binding will be added, otherwise
                 it will replace a former binding.
 
@@ -3547,7 +3547,7 @@ class RawTurtle(TPen, TNavigator):
         Arguments:
         fun -- a function with two arguments, to which will be assigned
                 the coordinates of the clicked point on the canvas.
-        num --  number of the mouse-button defaults to 1 (left mouse button).
+        btn --  number of the mouse-button defaults to 1 (left mouse button).
 
         Example (for a MyTurtle instance named joe):
         >>> class MyTurtle(Turtle):
@@ -3572,7 +3572,7 @@ class RawTurtle(TPen, TNavigator):
         Arguments:
         fun -- a function with two arguments, to which will be assigned
                the coordinates of the clicked point on the canvas.
-        num -- number of the mouse-button defaults to 1 (left mouse button).
+        btn -- number of the mouse-button defaults to 1 (left mouse button).
 
         Every sequence of mouse-move-events on a turtle is preceded by a
         mouse-click event on that turtle.
index c3634ec..402fa47 100644 (file)
@@ -509,7 +509,7 @@ class TestCase(object):
         case as failed but resumes execution at the end of the enclosed
         block, allowing further test code to be executed.
         """
-        if not self._outcome.result_supports_subtests:
+        if self._outcome is None or not self._outcome.result_supports_subtests:
             yield
             return
         parent = self._subtest
index 86183ad..645d100 100644 (file)
@@ -543,7 +543,7 @@ class NonCallableMock(Base):
             self._mock_side_effect = None
 
         for child in self._mock_children.values():
-            if isinstance(child, _SpecState):
+            if isinstance(child, _SpecState) or child is _deleted:
                 continue
             child.reset_mock(visited)
 
@@ -943,73 +943,77 @@ class CallableMixin(Base):
         self = _mock_self
         self.called = True
         self.call_count += 1
-        _new_name = self._mock_new_name
-        _new_parent = self._mock_new_parent
 
+        # handle call_args
         _call = _Call((args, kwargs), two=True)
         self.call_args = _call
         self.call_args_list.append(_call)
-        self.mock_calls.append(_Call(('', args, kwargs)))
 
         seen = set()
-        skip_next_dot = _new_name == '()'
+
+        # initial stuff for method_calls:
         do_method_calls = self._mock_parent is not None
-        name = self._mock_name
-        while _new_parent is not None:
-            this_mock_call = _Call((_new_name, args, kwargs))
-            if _new_parent._mock_new_name:
-                dot = '.'
-                if skip_next_dot:
-                    dot = ''
+        method_call_name = self._mock_name
 
-                skip_next_dot = False
-                if _new_parent._mock_new_name == '()':
-                    skip_next_dot = True
+        # initial stuff for mock_calls:
+        mock_call_name = self._mock_new_name
+        is_a_call = mock_call_name == '()'
+        self.mock_calls.append(_Call(('', args, kwargs)))
 
-                _new_name = _new_parent._mock_new_name + dot + _new_name
+        # follow up the chain of mocks:
+        _new_parent = self._mock_new_parent
+        while _new_parent is not None:
 
+            # handle method_calls:
             if do_method_calls:
-                if _new_name == name:
-                    this_method_call = this_mock_call
-                else:
-                    this_method_call = _Call((name, args, kwargs))
-                _new_parent.method_calls.append(this_method_call)
-
+                _new_parent.method_calls.append(_Call((method_call_name, args, kwargs)))
                 do_method_calls = _new_parent._mock_parent is not None
                 if do_method_calls:
-                    name = _new_parent._mock_name + '.' + name
+                    method_call_name = _new_parent._mock_name + '.' + method_call_name
 
+            # handle mock_calls:
+            this_mock_call = _Call((mock_call_name, args, kwargs))
             _new_parent.mock_calls.append(this_mock_call)
+
+            if _new_parent._mock_new_name:
+                if is_a_call:
+                    dot = ''
+                else:
+                    dot = '.'
+                is_a_call = _new_parent._mock_new_name == '()'
+                mock_call_name = _new_parent._mock_new_name + dot + mock_call_name
+
+            # follow the parental chain:
             _new_parent = _new_parent._mock_new_parent
 
-            # use ids here so as not to call __hash__ on the mocks
+            # check we're not in an infinite loop:
+            # ( use ids here so as not to call __hash__ on the mocks)
             _new_parent_id = id(_new_parent)
             if _new_parent_id in seen:
                 break
             seen.add(_new_parent_id)
 
-        ret_val = DEFAULT
         effect = self.side_effect
         if effect is not None:
             if _is_exception(effect):
                 raise effect
-
-            if not _callable(effect):
+            elif not _callable(effect):
                 result = next(effect)
                 if _is_exception(result):
                     raise result
-                if result is DEFAULT:
-                    result = self.return_value
+            else:
+                result = effect(*args, **kwargs)
+
+            if result is not DEFAULT:
                 return result
 
-            ret_val = effect(*args, **kwargs)
+        if self._mock_return_value is not DEFAULT:
+            return self.return_value
 
-        if (self._mock_wraps is not None and
-             self._mock_return_value is DEFAULT):
+        if self._mock_wraps is not None:
             return self._mock_wraps(*args, **kwargs)
-        if ret_val is DEFAULT:
-            ret_val = self.return_value
-        return ret_val
+
+        return self.return_value
 
 
 
@@ -1737,7 +1741,7 @@ _all_magics = _magics | _non_defaults
 
 _unsupported_magics = {
     '__getattr__', '__setattr__',
-    '__init__', '__new__', '__prepare__'
+    '__init__', '__new__', '__prepare__',
     '__instancecheck__', '__subclasscheck__',
     '__del__'
 }
@@ -1999,9 +2003,9 @@ class _Call(tuple):
 
     def __init__(self, value=(), name=None, parent=None, two=False,
                  from_kall=True):
-        self.name = name
-        self.parent = parent
-        self.from_kall = from_kall
+        self._mock_name = name
+        self._mock_parent = parent
+        self._mock_from_kall = from_kall
 
 
     def __eq__(self, other):
@@ -2018,6 +2022,10 @@ class _Call(tuple):
         else:
             self_name, self_args, self_kwargs = self
 
+        if (getattr(self, '_mock_parent', None) and getattr(other, '_mock_parent', None)
+                and self._mock_parent != other._mock_parent):
+            return False
+
         other_name = ''
         if len_other == 0:
             other_args, other_kwargs = (), {}
@@ -2059,17 +2067,17 @@ class _Call(tuple):
 
 
     def __call__(self, *args, **kwargs):
-        if self.name is None:
+        if self._mock_name is None:
             return _Call(('', args, kwargs), name='()')
 
-        name = self.name + '()'
-        return _Call((self.name, args, kwargs), name=name, parent=self)
+        name = self._mock_name + '()'
+        return _Call((self._mock_name, args, kwargs), name=name, parent=self)
 
 
     def __getattr__(self, attr):
-        if self.name is None:
+        if self._mock_name is None:
             return _Call(name=attr, from_kall=False)
-        name = '%s.%s' % (self.name, attr)
+        name = '%s.%s' % (self._mock_name, attr)
         return _Call(name=name, parent=self, from_kall=False)
 
 
@@ -2080,8 +2088,8 @@ class _Call(tuple):
         return self.__getattr__('index')(*args, **kwargs)
 
     def __repr__(self):
-        if not self.from_kall:
-            name = self.name or 'call'
+        if not self._mock_from_kall:
+            name = self._mock_name or 'call'
             if name.startswith('()'):
                 name = 'call%s' % name
             return name
@@ -2107,9 +2115,9 @@ class _Call(tuple):
         vals = []
         thing = self
         while thing is not None:
-            if thing.from_kall:
+            if thing._mock_from_kall:
                 vals.append(thing)
-            thing = thing.parent
+            thing = thing._mock_parent
         return _CallList(reversed(vals))
 
 
index b849591..04da9d0 100644 (file)
@@ -425,6 +425,20 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
         expected = ['a1', 'a2', 'b1']
         self.assertEqual(events, expected)
 
+    def test_subtests_debug(self):
+        # Test debug() with a test that uses subTest() (bpo-34900)
+        events = []
+
+        class Foo(unittest.TestCase):
+            def test_a(self):
+                events.append('test case')
+                with self.subTest():
+                    events.append('subtest 1')
+
+        Foo('test_a').debug()
+
+        self.assertEqual(events, ['test case', 'subtest 1'])
+
     # "This class attribute gives the exception raised by the test() method.
     # If a test framework needs to use a specialized exception, possibly to
     # carry additional information, it must subclass this exception in
index af1ce7e..34474c4 100644 (file)
@@ -128,7 +128,7 @@ class TestCallable(unittest.TestCase):
                     result.foo.assert_called_once_with(3, 2, 1)
 
 
-    def test_create_autopsec(self):
+    def test_create_autospec(self):
         mock = create_autospec(X)
         instance = mock()
         self.assertRaises(TypeError, instance)
index 7919482..0a42890 100644 (file)
@@ -269,6 +269,22 @@ class CallTest(unittest.TestCase):
         self.assertEqual(mock.mock_calls, last_call.call_list())
 
 
+    def test_extended_not_equal(self):
+        a = call(x=1).foo
+        b = call(x=2).foo
+        self.assertEqual(a, a)
+        self.assertEqual(b, b)
+        self.assertNotEqual(a, b)
+
+
+    def test_nested_calls_not_equal(self):
+        a = call(x=1).foo().bar
+        b = call(x=2).foo().bar
+        self.assertEqual(a, a)
+        self.assertEqual(b, b)
+        self.assertNotEqual(a, b)
+
+
     def test_call_list(self):
         mock = MagicMock()
         mock(1)
index b64c866..5e87356 100644 (file)
@@ -8,7 +8,7 @@ from unittest import mock
 from unittest.mock import (
     call, DEFAULT, patch, sentinel,
     MagicMock, Mock, NonCallableMock,
-    NonCallableMagicMock, _CallList,
+    NonCallableMagicMock, _Call, _CallList,
     create_autospec
 )
 
@@ -549,6 +549,16 @@ class MockTest(unittest.TestCase):
         real.assert_called_with(1, 2, fish=3)
 
 
+    def test_wraps_prevents_automatic_creation_of_mocks(self):
+        class Real(object):
+            pass
+
+        real = Real()
+        mock = Mock(wraps=real)
+
+        self.assertRaises(AttributeError, lambda: mock.new_attr())
+
+
     def test_wraps_call_with_nondefault_return_value(self):
         real = Mock()
 
@@ -575,6 +585,118 @@ class MockTest(unittest.TestCase):
         self.assertEqual(result, Real.attribute.frog())
 
 
+    def test_customize_wrapped_object_with_side_effect_iterable_with_default(self):
+        class Real(object):
+            def method(self):
+                return sentinel.ORIGINAL_VALUE
+
+        real = Real()
+        mock = Mock(wraps=real)
+        mock.method.side_effect = [sentinel.VALUE1, DEFAULT]
+
+        self.assertEqual(mock.method(), sentinel.VALUE1)
+        self.assertEqual(mock.method(), sentinel.ORIGINAL_VALUE)
+        self.assertRaises(StopIteration, mock.method)
+
+
+    def test_customize_wrapped_object_with_side_effect_iterable(self):
+        class Real(object):
+            def method(self):
+                raise NotImplementedError()
+
+        real = Real()
+        mock = Mock(wraps=real)
+        mock.method.side_effect = [sentinel.VALUE1, sentinel.VALUE2]
+
+        self.assertEqual(mock.method(), sentinel.VALUE1)
+        self.assertEqual(mock.method(), sentinel.VALUE2)
+        self.assertRaises(StopIteration, mock.method)
+
+
+    def test_customize_wrapped_object_with_side_effect_exception(self):
+        class Real(object):
+            def method(self):
+                raise NotImplementedError()
+
+        real = Real()
+        mock = Mock(wraps=real)
+        mock.method.side_effect = RuntimeError
+
+        self.assertRaises(RuntimeError, mock.method)
+
+
+    def test_customize_wrapped_object_with_side_effect_function(self):
+        class Real(object):
+            def method(self):
+                raise NotImplementedError()
+
+        def side_effect():
+            return sentinel.VALUE
+
+        real = Real()
+        mock = Mock(wraps=real)
+        mock.method.side_effect = side_effect
+
+        self.assertEqual(mock.method(), sentinel.VALUE)
+
+
+    def test_customize_wrapped_object_with_return_value(self):
+        class Real(object):
+            def method(self):
+                raise NotImplementedError()
+
+        real = Real()
+        mock = Mock(wraps=real)
+        mock.method.return_value = sentinel.VALUE
+
+        self.assertEqual(mock.method(), sentinel.VALUE)
+
+
+    def test_customize_wrapped_object_with_return_value_and_side_effect(self):
+        # side_effect should always take precedence over return_value.
+        class Real(object):
+            def method(self):
+                raise NotImplementedError()
+
+        real = Real()
+        mock = Mock(wraps=real)
+        mock.method.side_effect = [sentinel.VALUE1, sentinel.VALUE2]
+        mock.method.return_value = sentinel.WRONG_VALUE
+
+        self.assertEqual(mock.method(), sentinel.VALUE1)
+        self.assertEqual(mock.method(), sentinel.VALUE2)
+        self.assertRaises(StopIteration, mock.method)
+
+
+    def test_customize_wrapped_object_with_return_value_and_side_effect2(self):
+        # side_effect can return DEFAULT to default to return_value
+        class Real(object):
+            def method(self):
+                raise NotImplementedError()
+
+        real = Real()
+        mock = Mock(wraps=real)
+        mock.method.side_effect = lambda: DEFAULT
+        mock.method.return_value = sentinel.VALUE
+
+        self.assertEqual(mock.method(), sentinel.VALUE)
+
+
+    def test_customize_wrapped_object_with_return_value_and_side_effect_default(self):
+        class Real(object):
+            def method(self):
+                raise NotImplementedError()
+
+        real = Real()
+        mock = Mock(wraps=real)
+        mock.method.side_effect = [sentinel.VALUE1, DEFAULT]
+        mock.method.return_value = sentinel.RETURN
+
+        self.assertEqual(mock.method(), sentinel.VALUE1)
+        self.assertEqual(mock.method(), sentinel.RETURN)
+        self.assertRaises(StopIteration, mock.method)
+
+
     def test_exceptional_side_effect(self):
         mock = Mock(side_effect=AttributeError)
         self.assertRaises(AttributeError, mock)
@@ -916,6 +1038,57 @@ class MockTest(unittest.TestCase):
                              call().__int__().call_list())
 
 
+    def test_child_mock_call_equal(self):
+        m = Mock()
+        result = m()
+        result.wibble()
+        # parent looks like this:
+        self.assertEqual(m.mock_calls, [call(), call().wibble()])
+        # but child should look like this:
+        self.assertEqual(result.mock_calls, [call.wibble()])
+
+
+    def test_mock_call_not_equal_leaf(self):
+        m = Mock()
+        m.foo().something()
+        self.assertNotEqual(m.mock_calls[1], call.foo().different())
+        self.assertEqual(m.mock_calls[0], call.foo())
+
+
+    def test_mock_call_not_equal_non_leaf(self):
+        m = Mock()
+        m.foo().bar()
+        self.assertNotEqual(m.mock_calls[1], call.baz().bar())
+        self.assertNotEqual(m.mock_calls[0], call.baz())
+
+
+    def test_mock_call_not_equal_non_leaf_params_different(self):
+        m = Mock()
+        m.foo(x=1).bar()
+        # This isn't ideal, but there's no way to fix it without breaking backwards compatibility:
+        self.assertEqual(m.mock_calls[1], call.foo(x=2).bar())
+
+
+    def test_mock_call_not_equal_non_leaf_attr(self):
+        m = Mock()
+        m.foo.bar()
+        self.assertNotEqual(m.mock_calls[0], call.baz.bar())
+
+
+    def test_mock_call_not_equal_non_leaf_call_versus_attr(self):
+        m = Mock()
+        m.foo.bar()
+        self.assertNotEqual(m.mock_calls[0], call.foo().bar())
+
+
+    def test_mock_call_repr(self):
+        m = Mock()
+        m.foo().bar().baz.bob()
+        self.assertEqual(repr(m.mock_calls[0]), 'call.foo()')
+        self.assertEqual(repr(m.mock_calls[1]), 'call.foo().bar()')
+        self.assertEqual(repr(m.mock_calls[2]), 'call.foo().bar().baz.bob()')
+
+
     def test_subclassing(self):
         class Subclass(Mock):
             pass
@@ -1556,6 +1729,16 @@ class MockTest(unittest.TestCase):
             self.assertRaises(AttributeError, getattr, mock, 'f')
 
 
+    def test_reset_mock_does_not_raise_on_attr_deletion(self):
+        # bpo-31177: reset_mock should not raise AttributeError when attributes
+        # were deleted in a mock instance
+        mock = Mock()
+        mock.child = True
+        del mock.child
+        mock.reset_mock()
+        self.assertFalse(hasattr(mock, 'child'))
+
+
     def test_class_assignable(self):
         for mock in Mock(), MagicMock():
             self.assertNotIsInstance(mock, int)
@@ -1564,6 +1747,20 @@ class MockTest(unittest.TestCase):
             self.assertIsInstance(mock, int)
             mock.foo
 
+    def test_name_attribute_of_call(self):
+        # bpo-35357: _Call should not disclose any attributes whose names
+        # may clash with popular ones (such as ".name")
+        self.assertIsNotNone(call.name)
+        self.assertEqual(type(call.name), _Call)
+        self.assertEqual(type(call.name().name), _Call)
+
+    def test_parent_attribute_of_call(self):
+        # bpo-35357: _Call should not disclose any attributes whose names
+        # may clash with popular ones (such as ".parent")
+        self.assertIsNotNone(call.parent)
+        self.assertEqual(type(call.parent), _Call)
+        self.assertEqual(type(call.parent().parent), _Call)
+
 
 if __name__ == '__main__':
     unittest.main()
index fe4ecef..f052257 100644 (file)
@@ -9,6 +9,7 @@ import unittest
 from unittest.test.testmock import support
 from unittest.test.testmock.support import SomeClass, is_instance
 
+from test.test_importlib.util import uncache
 from unittest.mock import (
     NonCallableMock, CallableMixin, sentinel,
     MagicMock, Mock, NonCallableMagicMock, patch, _patch,
@@ -1660,20 +1661,19 @@ class PatchTest(unittest.TestCase):
 
 
     def test_patch_imports_lazily(self):
-        sys.modules.pop('squizz', None)
-
         p1 = patch('squizz.squozz')
         self.assertRaises(ImportError, p1.start)
 
-        squizz = Mock()
-        squizz.squozz = 6
-        sys.modules['squizz'] = squizz
-        p1 = patch('squizz.squozz')
-        squizz.squozz = 3
-        p1.start()
-        p1.stop()
-        self.assertEqual(squizz.squozz, 3)
+        with uncache('squizz'):
+            squizz = Mock()
+            sys.modules['squizz'] = squizz
 
+            squizz.squozz = 6
+            p1 = patch('squizz.squozz')
+            squizz.squozz = 3
+            p1.start()
+            p1.stop()
+        self.assertEqual(squizz.squozz, 3)
 
     def test_patch_propogrates_exc_on_exit(self):
         class holder:
@@ -1696,7 +1696,12 @@ class PatchTest(unittest.TestCase):
         def test(mock):
             raise RuntimeError
 
-        self.assertRaises(RuntimeError, test)
+        with uncache('squizz'):
+            squizz = Mock()
+            sys.modules['squizz'] = squizz
+
+            self.assertRaises(RuntimeError, test)
+
         self.assertIs(holder.exc_info[0], RuntimeError)
         self.assertIsNotNone(holder.exc_info[1],
                             'exception value not propgated')
index f959212..85e68c8 100644 (file)
@@ -624,7 +624,7 @@ def unquote(string, encoding='utf-8', errors='replace'):
 
 
 def parse_qs(qs, keep_blank_values=False, strict_parsing=False,
-             encoding='utf-8', errors='replace'):
+             encoding='utf-8', errors='replace', max_num_fields=None):
     """Parse a query given as a string argument.
 
         Arguments:
@@ -645,11 +645,15 @@ def parse_qs(qs, keep_blank_values=False, strict_parsing=False,
         encoding and errors: specify how to decode percent-encoded sequences
             into Unicode characters, as accepted by the bytes.decode() method.
 
+        max_num_fields: int. If set, then throws a ValueError if there
+            are more than n fields read by parse_qsl().
+
         Returns a dictionary.
     """
     parsed_result = {}
     pairs = parse_qsl(qs, keep_blank_values, strict_parsing,
-                      encoding=encoding, errors=errors)
+                      encoding=encoding, errors=errors,
+                      max_num_fields=max_num_fields)
     for name, value in pairs:
         if name in parsed_result:
             parsed_result[name].append(value)
@@ -659,7 +663,7 @@ def parse_qs(qs, keep_blank_values=False, strict_parsing=False,
 
 
 def parse_qsl(qs, keep_blank_values=False, strict_parsing=False,
-              encoding='utf-8', errors='replace'):
+              encoding='utf-8', errors='replace', max_num_fields=None):
     """Parse a query given as a string argument.
 
         Arguments:
@@ -679,9 +683,21 @@ def parse_qsl(qs, keep_blank_values=False, strict_parsing=False,
         encoding and errors: specify how to decode percent-encoded sequences
             into Unicode characters, as accepted by the bytes.decode() method.
 
+        max_num_fields: int. If set, then throws a ValueError
+            if there are more than n fields read by parse_qsl().
+
         Returns a list, as G-d intended.
     """
     qs, _coerce_result = _coerce_args(qs)
+
+    # If max_num_fields is defined then check that the number of fields
+    # is less than max_num_fields. This prevents a memory exhaustion DOS
+    # attack via post bodies with many fields.
+    if max_num_fields is not None:
+        num_fields = 1 + qs.count('&') + qs.count(';')
+        if max_num_fields < num_fields:
+            raise ValueError('Max number of fields exceeded')
+
     pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
     r = []
     for name_value in pairs:
index 9692144..d28f2f8 100644 (file)
@@ -199,7 +199,7 @@ def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
     global _opener
     if cafile or capath or cadefault:
         import warnings
-        warnings.warn("cafile, cpath and cadefault are deprecated, use a "
+        warnings.warn("cafile, capath and cadefault are deprecated, use a "
                       "custom context instead.", DeprecationWarning, 2)
         if context is not None:
             raise ValueError(
index 8c3d901..69c17ee 100644 (file)
@@ -6,6 +6,8 @@ registerDOMImplementation should be imported from xml.dom."""
 # should be published by posting to xml-sig@python.org, and are
 # subsequently recorded in this file.
 
+import sys
+
 well_known_implementations = {
     'minidom':'xml.dom.minidom',
     '4DOM': 'xml.dom.DOMImplementation',
@@ -55,7 +57,7 @@ def getDOMImplementation(name=None, features=()):
         return mod.getDOMImplementation()
     elif name:
         return registered[name]()
-    elif "PYTHON_DOM" in os.environ:
+    elif not sys.flags.ignore_environment and "PYTHON_DOM" in os.environ:
         return getDOMImplementation(name = os.environ["PYTHON_DOM"])
 
     # User did not specify a name, try implementations in arbitrary
index a5d813f..24957ea 100644 (file)
@@ -1318,7 +1318,7 @@ class DocumentType(Identified, Childless, Node):
                     entity.encoding = e.encoding
                     entity.version = e.version
                     clone.entities._seq.append(entity)
-                    e._call_user_data_handler(operation, n, entity)
+                    e._call_user_data_handler(operation, e, entity)
             self._call_user_data_handler(operation, self, clone)
             return clone
         else:
@@ -1921,7 +1921,7 @@ def _clone_node(node, deep, newOwnerDocument):
                 entity.ownerDocument = newOwnerDocument
                 clone.entities._seq.append(entity)
                 if hasattr(e, '_call_user_data_handler'):
-                    e._call_user_data_handler(operation, n, entity)
+                    e._call_user_data_handler(operation, e, entity)
     else:
         # Note the cloning of Document and DocumentType nodes is
         # implementation specific.  minidom handles those cases
index ef67ae6..13f6cf5 100644 (file)
@@ -58,7 +58,7 @@ if _false:
     import xml.sax.expatreader
 
 import os, sys
-if "PY_SAX_PARSER" in os.environ:
+if not sys.flags.ignore_environment and "PY_SAX_PARSER" in os.environ:
     default_parser_list = os.environ["PY_SAX_PARSER"].split(",")
 del os
 
index 5bb3587..edde0c5 100644 (file)
@@ -405,7 +405,7 @@ class ZipInfo (object):
         return ''.join(result)
 
     def FileHeader(self, zip64=None):
-        """Return the per-file header as a string."""
+        """Return the per-file header as a bytes object."""
         dt = self.date_time
         dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
         dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
@@ -1333,7 +1333,7 @@ class ZipFile:
         self._didModify = True
 
     def read(self, name, pwd=None):
-        """Return file bytes (as a string) for name."""
+        """Return file bytes for name."""
         with self.open(name, "r", pwd) as fp:
             return fp.read()
 
index b97d55b..6fc07ad 100755 (executable)
@@ -2,6 +2,8 @@
 """
 This script is used to build "official" universal installers on macOS.
 
+NEW for 3.6.8 / 2.7.16:
+- also build and use Tk 8.6 for 10.6+ installers
 NEW for 3.6.5:
 - support Intel 64-bit-only () and 32-bit-only installer builds
 - build and link with private Tcl/Tk 8.6 for 10.9+ builds
@@ -20,8 +22,8 @@ Sphinx and dependencies are installed into a venv using the python3's pip
 so will fetch them from PyPI if necessary.  Since python3 is now used for
 Sphinx, build-installer.py should also be converted to use python3!
 
-For 10.9 or greater deployment targets, build-installer builds and links
-with its own copy of Tcl/Tk 8.5 and the rest of this paragraph does not
+For 10.6 or greater deployment targets, build-installer builds and links
+with its own copy of Tcl/Tk 8.6 and the rest of this paragraph does not
 apply.  Otherwise, build-installer requires an installed third-party version
 of Tcl/Tk 8.4 (for OS X 10.4 and 10.5 deployment targets) or Tcl/TK 8.5
 (for 10.6 or later) installed in /Library/Frameworks.  When installed,
@@ -188,9 +190,9 @@ USAGE = textwrap.dedent("""\
 EXPECTED_SHARED_LIBS = {}
 
 # Are we building and linking with our own copy of Tcl/TK?
-#   For now, do so if deployment target is 10.9+.
+#   For now, do so if deployment target is 10.6+.
 def internalTk():
-    return getDeptargetTuple() >= (10, 9)
+    return getDeptargetTuple() >= (10, 6)
 
 # List of names of third party software built with this installer.
 # The names will be inserted into the rtf version of the License.
@@ -211,9 +213,9 @@ def library_recipes():
 
     result.extend([
           dict(
-              name="OpenSSL 1.0.2p",
-              url="https://www.openssl.org/source/openssl-1.0.2p.tar.gz",
-              checksum='ac5eb30bf5798aa14b1ae6d0e7da58df',
+              name="OpenSSL 1.0.2q",
+              url="https://www.openssl.org/source/openssl-1.0.2q.tar.gz",
+              checksum='7563e1ce046cb21948eeb6ba1a0eb71c',
               buildrecipe=build_universal_openssl,
               configure=None,
               install=None,
@@ -223,9 +225,9 @@ def library_recipes():
     if internalTk():
         result.extend([
           dict(
-              name="Tcl 8.6.8",
-              url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tcl8.6.8-src.tar.gz",
-              checksum='81656d3367af032e0ae6157eff134f89',
+              name="Tcl 8.6.9",
+              url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tcl8.6.9-src.tar.gz",
+              checksum='aa0a121d95a0e7b73a036f26028538d4',
               buildDir="unix",
               configure_pre=[
                     '--enable-shared',
@@ -239,12 +241,9 @@ def library_recipes():
                   },
               ),
           dict(
-              name="Tk 8.6.8",
-              url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tk8.6.8-src.tar.gz",
-              checksum='5e0faecba458ee1386078fb228d008ba',
-              patches=[
-                  "tk868_on_10_8_10_9.patch",
-                   ],
+              name="Tk 8.6.9.1",
+              url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tk8.6.9.1-src.tar.gz",
+              checksum='9efe3976468352dc894dae0c4e785a8e',
               buildDir="unix",
               configure_pre=[
                     '--enable-aqua',
@@ -706,6 +705,7 @@ def extractArchive(builddir, archiveName):
     work for current Tcl and Tk source releases where the basename of
     the archive ends with "-src" but the uncompressed directory does not.
     For now, just special case Tcl and Tk tar.gz downloads.
+    Another special case: the tk8.6.9.1 tarball extracts to tk8.6.9.
     """
     curdir = os.getcwd()
     try:
@@ -715,6 +715,8 @@ def extractArchive(builddir, archiveName):
             if ((retval.startswith('tcl') or retval.startswith('tk'))
                     and retval.endswith('-src')):
                 retval = retval[:-4]
+                if retval == 'tk8.6.9.1':
+                    retval = 'tk8.6.9'
             if os.path.exists(retval):
                 shutil.rmtree(retval)
             fp = os.popen("tar zxf %s 2>&1"%(shellQuote(archiveName),), 'r')
@@ -1531,16 +1533,27 @@ def buildDMG():
     imagepath = imagepath + '.dmg'
 
     os.mkdir(outdir)
+
+    # Try to mitigate race condition in certain versions of macOS, e.g. 10.9,
+    # when hdiutil create fails with  "Resource busy".  For now, just retry
+    # the create a few times and hope that it eventually works.
+
     volname='Python %s'%(getFullVersion())
-    runCommand("hdiutil create -format UDRW -volname %s -srcfolder %s %s"%(
+    cmd = ("hdiutil create -format UDRW -volname %s -srcfolder %s -size 100m %s"%(
             shellQuote(volname),
             shellQuote(os.path.join(WORKDIR, 'installer')),
             shellQuote(imagepath + ".tmp.dmg" )))
-
-    # Try to mitigate race condition in certain versions of macOS, e.g. 10.9,
-    # when hdiutil fails with  "Resource busy"
-
-    time.sleep(10)
+    for i in range(5):
+        fd = os.popen(cmd, 'r')
+        data = fd.read()
+        xit = fd.close()
+        if not xit:
+            break
+        sys.stdout.write(data)
+        print(" -- retrying hdiutil create")
+        time.sleep(5)
+    else:
+        raise RuntimeError("command failed: %s"%(commandline,))
 
     if not os.path.exists(os.path.join(WORKDIR, "mnt")):
         os.mkdir(os.path.join(WORKDIR, "mnt"))
index e8deea1..35a17ed 100644 (file)
@@ -1,5 +1,6 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1561\cocoasubrtf400
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;}
+{\rtf1\ansi\ansicpg1252\cocoartf1671\cocoasubrtf100
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fswiss\fcharset0 Helvetica-Oblique;
+\f3\fmodern\fcharset0 CourierNewPSMT;}
 {\colortbl;\red255\green255\blue255;}
 {\*\expandedcolortbl;;}
 \margl1440\margr1440\vieww13380\viewh14600\viewkind0
 \
 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
 
-\b \cf0 \ul \ulc0 Which installer variant should I use? [CHANGED in 3.6.6]
-\b0 \ulnone \
+\f1\b \cf0 \ul \ulc0 Which installer variant should I use? [CHANGED in 3.6.6]
+\f0\b0 \ulnone \
 \
 With Python 3.6.5, the python.org website now provides two installer variants for download: one that installs a 
-\i 64-bit-only 
-\i0 Python capable of running on 
-\i macOS 10.9 (Mavericks)
-\i0  or later; and one that installs a 
-\i 64-bit/32-bit Intel
-\i0  Python capable of running on 
-\i macOS 10.6 (Snow Leopard)
-\i0  or later.  (This ReadMe was installed with the 
-\i $MACOSX_DEPLOYMENT_TARGET
-\i0  variant.)  Previous Python 3.6.x releases only provided the 10.6 or later installer. If you are running on macOS 10.9 or later and if you have no need for compatibility with older systems, use the 10.9 variant.  Use the 10.6 variant if you are running on macOS 10.6 through 10.8, if you need to maintain compatibility with previous 3.6.x releases, or if you want to produce standalone applications that can run on systems from 10.6.  The Pythons installed by these installers are built with private copies of some third-party libraries not included with or newer than those in macOS itself.  The list of these libraries varies by installer variant and is included at the end of the License.rtf file.\
+\f2\i 64-bit-only 
+\f0\i0 Python capable of running on 
+\f2\i macOS 10.9 (Mavericks)
+\f0\i0  or later; and one that installs a 
+\f2\i 64-bit/32-bit Intel
+\f0\i0  Python capable of running on 
+\f2\i macOS 10.6 (Snow Leopard)
+\f0\i0  or later.  (This ReadMe was installed with the 
+\f2\i $MACOSX_DEPLOYMENT_TARGET
+\f0\i0  variant.)  Previous Python 3.6.x releases only provided the 10.6 or later installer. If you are running on macOS 10.9 or later and if you have no need for compatibility with older systems, use the 10.9 variant.  Use the 10.6 variant if you are running on macOS 10.6 through 10.8, if you need to maintain compatibility with previous 3.6.x releases, or if you want to produce standalone applications that can run on systems from 10.6.  The Pythons installed by these installers are built with private copies of some third-party libraries not included with or newer than those in macOS itself.  The list of these libraries varies by installer variant and is included at the end of the License.rtf file.\
 \
 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0
 
-\b \cf0 CHANGED in 3.6.6:
-\b0   the 10.9+ 64-bit-only installer variant is now the default download.  The 10.6+ variant is available from the $FULL_VERSION release page.\
+\f1\b \cf0 CHANGED in 3.6.6:
+\f0\b0   the 10.9+ 64-bit-only installer variant is now the default download.  The 10.6+ variant is available from the $FULL_VERSION release page.\
 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
 
-\b \cf0 \ul \
+\f1\b \cf0 \ul \
 Certificate verification and OpenSSL\
 
-\b0 \ulnone \
+\f0\b0 \ulnone \
 This variant of Python 3.6 now includes its own private copy of OpenSSL 1.0.2.  Unlike previous releases, the deprecated Apple-supplied OpenSSL libraries are no longer used.  This also means that the trust certificates in system and user keychains managed by the 
-\i Keychain Access 
-\i0 application and the 
-\i security
-\i0  command line utility are no longer used as defaults by the Python 
-\f1 ssl
+\f2\i Keychain Access 
+\f0\i0 application and the 
+\f2\i security
+\f0\i0  command line utility are no longer used as defaults by the Python 
+\f3 ssl
 \f0  module.  A sample command script is included in 
-\f1 /Applications/Python 3.6
+\f3 /Applications/Python 3.6
 \f0  to install a curated bundle of default root certificates from the third-party 
-\f1 certifi
+\f3 certifi
 \f0  package ({\field{\*\fldinst{HYPERLINK "https://pypi.org/project/certifi/"}}{\fldrslt https://pypi.org/project/certifi/}}).  If you choose to use 
-\f1 certifi
+\f3 certifi
 \f0 , you should consider subscribing to the{\field{\*\fldinst{HYPERLINK "https://certifi.io/en/latest/"}}{\fldrslt  project's email update service}} to be notified when the certificate bundle is updated.\
 \
 The bundled 
-\f1 pip
+\f3 pip
 \f0  included with the Python 3.6 installer has its own default certificate store for verifying download connections.\
 \
 
-\b \ul Using IDLE or other Tk applications [NEW/CHANGED in 3.6.5] 
-\b0 \ulnone \
+\f1\b \ul Using IDLE or other Tk applications [NEW/CHANGED in 3.6.5] 
+\f0\b0 \ulnone \
 \
-The 10.9+ installer variant comes with its own private version of Tcl/Tk 8.6. It does not use system-supplied or third-party supplied versions of Tcl/Tk.\
-\
-For the 10.6+ variant in 3.6.6, you continue to need to install a newer third-party version of the 
-\i Tcl/Tk
-\i0  8.5 (not 8.6) frameworks to use IDLE or other programs that use the Tkinter graphical user interface toolkit.  Visit {\field{\*\fldinst{HYPERLINK "https://www.python.org/download/mac/tcltk/"}}{\fldrslt https://www.python.org/download/mac/tcltk/}} for current information about supported and recommended versions of 
-\i Tcl/Tk
-\i0  for this version of Python and of macOS.\
+As of 3.6.5, the 10.9+ installer variant comes with its own private version of Tcl/Tk 8.6. It does not use system-supplied or third-party supplied versions of Tcl/Tk.\
 \
 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
 
-\b \cf0 NOTE
-\b0 As of the next 3.6.x release, 3.6.7, the 10.6+ variant will also include Tcl/Tk 8.6.\
+\f1\b \cf0 CHANGED in 3.6.8
+\f0\b0 The 10.6+ variant now also uses a private version of Tcl/Tk 8.6.\
 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
 
-\b \cf0 \ul \
+\f1\b \cf0 \ul \
 Other changes\
 
-\b0 \ulnone \
+\f0\b0 \ulnone \
 For other changes in this release, see the 
-\i What's new
-\i0  section in the {\field{\*\fldinst{HYPERLINK "https://www.python.org/doc/"}}{\fldrslt Documentation Set}} for this release and its 
-\i Release Notes
-\i0  link at {\field{\*\fldinst{HYPERLINK "https://www.python.org/downloads/"}}{\fldrslt https://www.python.org/downloads/}}.\
+\f2\i What's new
+\f0\i0  section in the {\field{\*\fldinst{HYPERLINK "https://www.python.org/doc/"}}{\fldrslt Documentation Set}} for this release and its 
+\f2\i Release Notes
+\f0\i0  link at {\field{\*\fldinst{HYPERLINK "https://www.python.org/downloads/"}}{\fldrslt https://www.python.org/downloads/}}.\
 
-\b \ul \
+\f1\b \ul \
 Python 3 and Python 2 Co-existence\
 
-\b0 \ulnone \
+\f0\b0 \ulnone \
 Python.org Python $VERSION and 2.7.x versions can both be installed on your system and will not conflict. Command names for Python 3 contain a 3 in them, 
-\f1 python3
+\f3 python3
 \f0  (or
-\f1  python$VERSION
+\f3  python$VERSION
 \f0 ), 
-\f1 idle3
+\f3 idle3
 \f0  (or i
-\f1 dle$VERSION
+\f3 dle$VERSION
 \f0 ), 
-\f1 pip3
+\f3 pip3
 \f0  (or 
-\f1 pip$VERSION
+\f3 pip$VERSION
 \f0 ), etc.  Python 2.7 command names contain a 2 or no digit: 
-\f1 python2
+\f3 python2
 \f0  (or 
-\f1 python2.7
+\f3 python2.7
 \f0  or 
-\f1 python
+\f3 python
 \f0 ), 
-\f1 idle2
+\f3 idle2
 \f0  (or 
-\f1 idle2.7
+\f3 idle2.7
 \f0  or 
-\f1 idle
+\f3 idle
 \f0 ), etc.\
 }
\ No newline at end of file
index 22a794a..5cd936a 100644 (file)
@@ -1,27 +1,37 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1561\cocoasubrtf400
-\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\rtf1\ansi\ansicpg1252\cocoartf1671\cocoasubrtf100
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fmodern\fcharset0 CourierNewPSMT;
+}
 {\colortbl;\red255\green255\blue255;}
 {\*\expandedcolortbl;;}
 \paperw11905\paperh16837\margl1440\margr1440\vieww12200\viewh10880\viewkind0
 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
 
 \f0\fs24 \cf0 This package will install 
-\b Python $FULL_VERSION
-\b0  for 
-\b macOS $MACOSX_DEPLOYMENT_TARGET
-\b0 .\
+\f1\b Python $FULL_VERSION
+\f0\b0  for 
+\f1\b macOS $MACOSX_DEPLOYMENT_TARGET
+\f0\b0 .\
 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0
 \cf0 \
 
-\b Python for macOS
-\b0  consists of the Python programming language interpreter, plus a set of programs to allow easy access to it for macOS users including an integrated development environment 
-\b IDLE
-\b0 .\
+\f1\b Python for macOS
+\f0\b0  consists of the Python programming language interpreter, plus a set of programs to allow easy access to it for macOS users including an integrated development environment 
+\f1\b IDLE
+\f0\b0 .\
+\
+At the end of this install, click on 
+\f2 Install Certificates
+\f0  for SSL root certificates\
+\
+
+\f1\b NEW in 3.6.5: 
+\f0\b0 two installer variants (10.9+ 64-bit-only, 10.6+ 64-/32-bit), built-in Tcl/Tk 8.6 support in the 10.9+ variant (no additional third-party downloads!)\
 \
 
-\b NEW in 3.6.5: 
-\b0 two installer variants (10.9+ 64-bit-only, 10.6+ 64-/32-bit), built-in Tcl/Tk 8.6 support in the 10.9+ variant (no additional third-party downloads!)\
+\f1\b CHANGED in 3.6.6:
+\f0\b0   the 10.9+ 64-bit-only installer variant is now the default download\
 \
 
-\b CHANGED in 3.6.6:
-\b0   the 10.9+ 64-bit-only installer variant is now the default download}
\ No newline at end of file
+\f1\b CHANGED in 3.6.8:
+\f0\b0   the 10.6+ variant now also uses a built-in Tcl/Tk 8.6\
+}
\ No newline at end of file
diff --git a/Mac/BuildScript/tk868_on_10_8_10_9.patch b/Mac/BuildScript/tk868_on_10_8_10_9.patch
deleted file mode 100644 (file)
index 8fe1060..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-Fix build failure with +quartz variant on OS X 10.8 and 10.9.
-Even though Gestalt was deprecated in OS X 10.8, it should work fine
-through OS X 10.9, and its replacement NSOperatingSystemVersion was
-not introduced until OS X 10.10.
-
-Patch from MacPorts project and reported upstream:
-https://trac.macports.org/ticket/55649
---- tk8.6.8/macosx/tkMacOSXXStubs.c.orig       2017-12-06 09:25:08.000000000 -0600
-+++ tk8.6.8-patched/macosx/tkMacOSXXStubs.c    2018-01-06 19:34:17.000000000 -0600
-@@ -175,7 +175,7 @@
-     {
-       int major, minor, patch;
--#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
-+#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
-       Gestalt(gestaltSystemVersionMajor, (SInt32*)&major);
-       Gestalt(gestaltSystemVersionMinor, (SInt32*)&minor);
-       Gestalt(gestaltSystemVersionBugFix, (SInt32*)&patch);
index d912a19..d15d935 100644 (file)
@@ -37,7 +37,6 @@ CXX=          @CXX@
 MAINCC=                @MAINCC@
 LINKCC=                @LINKCC@
 AR=            @AR@
-RANLIB=                @RANLIB@
 READELF=       @READELF@
 SOABI=         @SOABI@
 LDVERSION=     @LDVERSION@
@@ -85,6 +84,10 @@ CONFIGURE_CFLAGS=    @CFLAGS@
 # Use it when a compiler flag should _not_ be part of the distutils CFLAGS
 # once Python is installed (Issue #21121).
 CONFIGURE_CFLAGS_NODIST=@CFLAGS_NODIST@
+# LDFLAGS_NODIST is used in the same manner as CFLAGS_NODIST.
+# Use it when a linker flag should _not_ be part of the distutils LDFLAGS
+# once Python is installed (bpo-35257)
+CONFIGURE_LDFLAGS_NODIST=@LDFLAGS_NODIST@
 CONFIGURE_CPPFLAGS=    @CPPFLAGS@
 CONFIGURE_LDFLAGS=     @LDFLAGS@
 # Avoid assigning CFLAGS, LDFLAGS, etc. so users can use them on the
@@ -97,6 +100,7 @@ PY_CFLAGS_NODIST=$(CONFIGURE_CFLAGS_NODIST) $(CFLAGS_NODIST)
 # environment variables
 PY_CPPFLAGS=   $(BASECPPFLAGS) -I. -I$(srcdir)/Include $(CONFIGURE_CPPFLAGS) $(CPPFLAGS)
 PY_LDFLAGS=    $(CONFIGURE_LDFLAGS) $(LDFLAGS)
+PY_LDFLAGS_NODIST=$(CONFIGURE_LDFLAGS_NODIST) $(LDFLAGS_NODIST)
 NO_AS_NEEDED=  @NO_AS_NEEDED@
 LDLAST=                @LDLAST@
 SGI_ABI=       @SGI_ABI@
@@ -107,6 +111,8 @@ ARFLAGS=    @ARFLAGS@
 CFLAGSFORSHARED=@CFLAGSFORSHARED@
 # C flags used for building the interpreter object files
 PY_CORE_CFLAGS=        $(PY_CFLAGS) $(PY_CFLAGS_NODIST) $(PY_CPPFLAGS) $(CFLAGSFORSHARED) -DPy_BUILD_CORE
+# Linker flags used for building the interpreter object files
+PY_CORE_LDFLAGS=$(PY_LDFLAGS) $(PY_LDFLAGS_NODIST)
 # Strict or non-strict aliasing flags used to compile dtoa.c, see above
 CFLAGS_ALIASING=@CFLAGS_ALIASING@
 
@@ -146,7 +152,7 @@ CONFINCLUDEPY=      $(CONFINCLUDEDIR)/python$(LDVERSION)
 SHLIB_SUFFIX=  @SHLIB_SUFFIX@
 EXT_SUFFIX=    @EXT_SUFFIX@
 LDSHARED=      @LDSHARED@ $(PY_LDFLAGS)
-BLDSHARED=     @BLDSHARED@ $(PY_LDFLAGS)
+BLDSHARED=     @BLDSHARED@ $(PY_CORE_LDFLAGS)
 LDCXXSHARED=   @LDCXXSHARED@
 DESTSHARED=    $(BINLIBDEST)/lib-dynload
 
@@ -473,7 +479,7 @@ profile-opt:
        $(MAKE) profile-removal
 
 build_all_generate_profile:
-       $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS) $(PGO_PROF_GEN_FLAG) @LTOFLAGS@" LDFLAGS="$(LDFLAGS) $(PGO_PROF_GEN_FLAG) @LTOFLAGS@" LIBS="$(LIBS)"
+       $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LDFLAGS_NODIST="$(LDFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LIBS="$(LIBS)"
 
 run_profile_task:
        : # FIXME: can't run for a cross build
@@ -483,7 +489,7 @@ build_all_merge_profile:
        $(LLVM_PROF_MERGER)
 
 build_all_use_profile:
-       $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS) $(PGO_PROF_USE_FLAG) @LTOFLAGS@" LDFLAGS="$(LDFLAGS) @LTOFLAGS@"
+       $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_USE_FLAG)" LDFLAGS_NODIST="$(LDFLAGS_NODIST)"
 
 # Compile and run with gcov
 .PHONY=coverage coverage-lcov coverage-report
@@ -544,7 +550,7 @@ clinic: check-clean-src $(srcdir)/Modules/_blake2/blake2s_impl.c
 
 # Build the interpreter
 $(BUILDPYTHON):        Programs/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
-       $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
+       $(LINKCC) $(PY_CORE_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
 
 platform: $(BUILDPYTHON) pybuilddir.txt
        $(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import sys ; from sysconfig import get_platform ; print("%s-%d.%d" % (get_platform(), *sys.version_info[:2]))' >platform
@@ -593,16 +599,9 @@ sharedmods: $(BUILDPYTHON) pybuilddir.txt Modules/_math.o
 
 
 # Build static library
-# avoid long command lines, same as LIBRARY_OBJS
 $(LIBRARY): $(LIBRARY_OBJS)
        -rm -f $@
-       $(AR) $(ARFLAGS) $@ Modules/getbuildinfo.o
-       $(AR) $(ARFLAGS) $@ $(PARSER_OBJS)
-       $(AR) $(ARFLAGS) $@ $(OBJECT_OBJS)
-       $(AR) $(ARFLAGS) $@ $(PYTHON_OBJS) Python/frozen.o
-       $(AR) $(ARFLAGS) $@ $(MODULE_OBJS)
-       $(AR) $(ARFLAGS) $@ $(MODOBJS)
-       $(RANLIB) $@
+       $(AR) $(ARFLAGS) $@ $(LIBRARY_OBJS)
 
 libpython$(LDVERSION).so: $(LIBRARY_OBJS)
        if test $(INSTSONAME) != $(LDLIBRARY); then \
@@ -616,7 +615,7 @@ libpython3.so:      libpython$(LDVERSION).so
        $(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^
 
 libpython$(LDVERSION).dylib: $(LIBRARY_OBJS)
-        $(CC) -dynamiclib -Wl,-single_module $(PY_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \
+        $(CC) -dynamiclib -Wl,-single_module $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \
 
 
 libpython$(VERSION).sl: $(LIBRARY_OBJS)
@@ -641,7 +640,7 @@ $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK): \
                $(LIBRARY) \
                $(RESSRCDIR)/Info.plist
        $(INSTALL) -d -m $(DIRMODE) $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)
-       $(CC) -o $(LDLIBRARY) $(PY_LDFLAGS) -dynamiclib \
+       $(CC) -o $(LDLIBRARY) $(PY_CORE_LDFLAGS) -dynamiclib \
                -all_load $(LIBRARY) -Wl,-single_module \
                -install_name $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK) \
                -compatibility_version $(VERSION) \
@@ -694,7 +693,7 @@ Modules/Setup: $(srcdir)/Modules/Setup.dist
        fi
 
 Programs/_testembed: Programs/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
-       $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
+       $(LINKCC) $(PY_CORE_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
 
 ############################################################################
 # Importlib
@@ -702,7 +701,7 @@ Programs/_testembed: Programs/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
 Programs/_freeze_importlib.o: Programs/_freeze_importlib.c Makefile
 
 Programs/_freeze_importlib: Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN)
-       $(LINKCC) $(PY_LDFLAGS) -o $@ Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
+       $(LINKCC) $(PY_CORE_LDFLAGS) -o $@ Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
 
 .PHONY: regen-importlib
 regen-importlib: Programs/_freeze_importlib
@@ -784,7 +783,7 @@ Python/sysmodule.o: $(srcdir)/Python/sysmodule.c Makefile
 $(IO_OBJS): $(IO_H)
 
 $(PGEN): $(PGENOBJS)
-               $(CC) $(OPT) $(PY_LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN)
+               $(CC) $(OPT) $(PY_CORE_LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN)
 
 .PHONY: regen-grammar
 regen-grammar: $(PGEN)
@@ -1435,7 +1434,6 @@ libainstall:      @DEF_MAKE_RULE@ python-config
                                $(INSTALL_DATA) $(LDLIBRARY) $(DESTDIR)$(LIBPL) ; \
                        else \
                                $(INSTALL_DATA) $(LIBRARY) $(DESTDIR)$(LIBPL)/$(LIBRARY) ; \
-                               $(RANLIB) $(DESTDIR)$(LIBPL)/$(LIBRARY) ; \
                        fi; \
                else \
                        echo Skip install of $(LIBRARY) - use make frameworkinstall; \
index 94731b4..c78df75 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1107,6 +1107,7 @@ Samuel Nicolary
 Jonathan Niehof
 Gustavo Niemeyer
 Oscar Nierstrasz
+Lysandros Nikolaou
 Hrvoje Nikšić
 Gregory Nofi
 Jesse Noller
index 37489cd..30cc6ec 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -2,6 +2,368 @@
 Python News
 +++++++++++
 
+What's New in Python 3.6.8 final?
+=================================
+
+*Release date: 2018-12-23*
+
+Library
+-------
+
+- bpo-31715: Associate ``.mjs`` file extension with
+  ``application/javascript`` MIME Type.
+
+Build
+-----
+
+- bpo-35499: ``make profile-opt`` no longer replaces ``CFLAGS_NODIST`` with
+  ``CFLAGS``. It now adds profile-guided optimization (PGO) flags to
+  ``CFLAGS_NODIST``: existing ``CFLAGS_NODIST`` flags are kept.
+
+- bpo-35257: Avoid leaking the linker flags from Link Time Optimizations
+  (LTO) into distutils when compiling C extensions.
+
+C API
+-----
+
+- bpo-35259: Conditionally declare :c:func:`Py_FinalizeEx()` (new in 3.6)
+  based on Py_LIMITED_API. Patch by Arthur Neufeld.
+
+
+What's New in Python 3.6.8 release candidate 1?
+===============================================
+
+*Release date: 2018-12-11*
+
+Security
+--------
+
+- bpo-34812: The :option:`-I` command line option (run Python in isolated
+  mode) is now also copied by the :mod:`multiprocessing` and
+  :mod:`distutils` modules when spawning child processes. Previously, only
+  :option:`-E` and :option:`-s` options (enabled by :option:`-I`) were
+  copied.
+
+- bpo-34791: The xml.sax and xml.dom.domreg no longer use environment
+  variables to override parser implementations when
+  sys.flags.ignore_environment is set by -E or -I arguments.
+
+Core and Builtins
+-----------------
+
+- bpo-35444: Fixed error handling in pickling methods when fail to look up
+  builtin "getattr".
+
+- bpo-35436: Fix various issues with memory allocation error handling.
+  Patch by Zackery Spytz.
+
+- bpo-35357: Internal attributes' names of unittest.mock._Call and
+  unittest.mock.MagicProxy (name, parent & from_kall) are now prefixed with
+  _mock_ in order to prevent clashes with widely used object attributes.
+  Fixed minor typo in test function name.
+
+- bpo-35372: Fixed the code page decoder for input longer than 2 GiB
+  containing undecodable bytes.
+
+- bpo-33954: For :meth:`str.format`, :meth:`float.__format__` and
+  :meth:`complex.__format__` methods for non-ASCII decimal point when using
+  the "n" formatter.
+
+- bpo-35214: Fixed an out of bounds memory access when parsing a truncated
+  unicode escape sequence at the end of a string such as ``'\N'``.  It would
+  read one byte beyond the end of the memory allocation.
+
+- bpo-35214: The interpreter and extension modules have had annotations
+  added so that they work properly under clang's Memory Sanitizer.  A new
+  configure flag --with-memory-sanitizer has been added to make test builds
+  of this nature easier to perform.
+
+- bpo-35193: Fix an off by one error in the bytecode peephole optimizer
+  where it could read bytes beyond the end of bounds of an array when
+  removing unreachable code. This bug was present in every release of Python
+  3.6 until now.
+
+- bpo-29341: Clarify in the docstrings of :mod:`os` methods that path-like
+  objects are also accepted as input parameters.
+
+- bpo-35050: :mod:`socket`: Fix off-by-one bug in length check for
+  ``AF_ALG`` name and type.
+
+- bpo-34974: :class:`bytes` and :class:`bytearray` constructors no longer
+  convert unexpected exceptions (e.g. :exc:`MemoryError` and
+  :exc:`KeyboardInterrupt`) to :exc:`TypeError`.
+
+- bpo-34973: Fixed crash in :func:`bytes` when the :class:`list` argument is
+  mutated while it is iterated.
+
+- bpo-34824: Fix a possible null pointer dereference in Modules/_ssl.c.
+  Patch by Zackery Spytz.
+
+- bpo-1621: Do not assume signed integer overflow behavior (C undefined
+  behavior) when performing set hash table resizing.
+
+Library
+-------
+
+- bpo-35052: Fix xml.dom.minidom cloneNode() on a document with an entity:
+  pass the correct arguments to the user data handler of an entity.
+
+- bpo-35330: When a :class:`Mock` instance was used to wrap an object, if
+  `side_effect` is used in one of the mocks of it methods, don't call the
+  original implementation and return the result of using the side effect the
+  same way that it is done with return_value.
+
+- bpo-34172: Revert the fix for this issue previously released in 3.6.7
+  pending further investigation: Fix a reference issue inside
+  multiprocessing.Pool that caused the pool to remain alive if it was
+  deleted without being closed or terminated explicitly.
+
+- bpo-10496: :func:`posixpath.expanduser` now returns the input *path*
+  unchanged if the ``HOME`` environment variable is not set and the current
+  user has no home directory (if the current user identifier doesn't exist
+  in the password database). This change fix the :mod:`site` module if the
+  current user doesn't exist in the password database (if the user has no
+  home directory).
+
+- bpo-35310: Fix a bug in :func:`select.select` where, in some cases, the
+  file descriptor sequences were returned unmodified after a signal
+  interruption, even though the file descriptors might not be ready yet.
+  :func:`select.select` will now always return empty lists if a timeout has
+  occurred.  Patch by Oran Avraham.
+
+- bpo-35380: Enable TCP_NODELAY on Windows for proactor asyncio event loop.
+
+- bpo-35371: Fixed possible crash in ``os.utime()`` on Windows when pass
+  incorrect arguments.
+
+- bpo-27903: Fix ``ResourceWarning`` in :func:`platform.dist` on SuSE and
+  Caldera OpenLinux. Patch by Ville Skyttä.
+
+- bpo-28604: :func:`locale.localeconv` now sets temporarily the ``LC_CTYPE``
+  locale to the ``LC_MONETARY`` locale if the two locales are different and
+  monetary strings are non-ASCII. This temporary change affects other
+  threads.
+
+- bpo-35277: Update ensurepip to install pip 18.1 and setuptools 40.6.2.
+
+- bpo-35226: Recursively check arguments when testing for equality of
+  :class:`unittest.mock.call` objects and add note that tracking of
+  parameters used to create ancestors of mocks in ``mock_calls`` is not
+  possible.
+
+- bpo-35189: Modify the following fnctl function to retry if interrupted by
+  a signal (EINTR): flock, lockf, fnctl
+
+- bpo-35062: Fix incorrect parsing of
+  :class:`_io.IncrementalNewlineDecoder`'s *translate* argument.
+
+- bpo-35079: Improve difflib.SequenceManager.get_matching_blocks doc by
+  adding 'non-overlapping' and changing '!=' to '<'.
+
+- bpo-35017: :meth:`socketserver.BaseServer.serve_forever` now exits
+  immediately if it's :meth:`~socketserver.BaseServer.shutdown` method is
+  called while it is polling for new events.
+
+- bpo-31047: Fix ``ntpath.abspath`` regression where it didn't remove a
+  trailing separator on Windows. Patch by Tim Graham.
+
+- bpo-34794: Fixed a leak in Tkinter when pass the Python wrapper around
+  Tcl_Obj back to Tcl/Tk.
+
+- bpo-35008: Fixed references leaks when call the ``__setstate__()`` method
+  of :class:`xml.etree.ElementTree.Element` in the C implementation for
+  already initialized element.
+
+- bpo-23420: Verify the value for the parameter '-s' of the cProfile CLI.
+  Patch by Robert Kuska
+
+- bpo-16965: The :term:`2to3` :2to3fixer:`execfile` fixer now opens the file
+  with mode ``'rb'``.  Patch by Zackery Spytz.
+
+- bpo-34966: :mod:`pydoc` now supports aliases not only to methods defined
+  in the end class, but also to inherited methods.  The docstring is not
+  duplicated for aliases.
+
+- bpo-34941: Methods ``find()``, ``findtext()`` and ``findall()`` of the
+  ``Element`` class in the :mod:`xml.etree.ElementTree` module are now able
+  to find children which are instances of ``Element`` subclasses.
+
+- bpo-34936: Fix ``TclError`` in ``tkinter.Spinbox.selection_element()``.
+  Patch by Juliette Monsel.
+
+- bpo-34900: Fixed :meth:`unittest.TestCase.debug` when used to call test
+  methods with subtests.  Patch by Bruno Oliveira.
+
+- bpo-34866: Adding ``max_num_fields`` to ``cgi.FieldStorage`` to make DOS
+  attacks harder by limiting the number of ``MiniFieldStorage`` objects
+  created by ``FieldStorage``.
+
+- bpo-34738: ZIP files created by :mod:`distutils` will now include entries
+  for directories.
+
+- bpo-31177: Fix bug that prevented using :meth:`reset_mock
+  <unittest.mock.Mock.reset_mock>` on mock instances with deleted attributes
+
+- bpo-34604: Fix possible mojibake in the error message of `pwd.getpwnam`
+  and `grp.getgrnam` using string representation because of invisible
+  characters or trailing whitespaces. Patch by William Grzybowski.
+
+- bpo-34574: OrderedDict iterators are not exhausted during pickling
+  anymore. Patch by Sergey Fedoseev.
+
+- bpo-34052: :meth:`sqlite3.Connection.create_aggregate`,
+  :meth:`sqlite3.Connection.create_function`,
+  :meth:`sqlite3.Connection.set_authorizer`,
+  :meth:`sqlite3.Connection.set_progress_handler` methods raises TypeError
+  when unhashable objects are passed as callable. These methods now don't
+  pass such objects to SQLite API. Previous behavior could lead to
+  segfaults. Patch by Sergey Fedoseev.
+
+- bpo-29877: compileall: import ProcessPoolExecutor only when needed,
+  preventing hangs on low resource platforms
+
+- bpo-22005: Implemented unpickling instances of
+  :class:`~datetime.datetime`, :class:`~datetime.date` and
+  :class:`~datetime.time` pickled by Python 2. ``encoding='latin1'`` should
+  be used for successful decoding.
+
+Documentation
+-------------
+
+- bpo-35089: Remove mention of ``typing.io`` and ``typing.re``. Their types
+  should be imported from ``typing`` directly.
+
+- bpo-35038: Fix the documentation about an unexisting `f_restricted`
+  attribute in the frame object. Patch by Stéphane Wirtel
+
+- bpo-35035: Rename documentation for :mod:`email.utils` to
+  ``email.utils.rst``.
+
+- bpo-34967: Use app.add_object_type() instead of the deprecated Sphinx
+  function app.description_unit()
+
+- bpo-33594: Document ``getargspec``, ``from_function`` and ``from_builtin``
+  as deprecated in their respective docstring, and include version since
+  deprecation in DeprecationWarning message.
+
+- bpo-32613: Update the faq/windows.html to use the py command from PEP 397
+  instead of python.
+
+Tests
+-----
+
+- bpo-33725: test_multiprocessing_fork may crash on recent versions of
+  macOS.  Until the issue is resolved, skip the test on macOS.
+
+- bpo-35352: Modify test_asyncio to use the certificate set from the test
+  directory.
+
+- bpo-35317: Fix ``mktime()`` overflow error in ``test_email``: run
+  ``test_localtime_daylight_true_dst_true()`` and
+  ``test_localtime_daylight_false_dst_true()`` with a specific timezone.
+
+- bpo-21263: After several reports that test_gdb does not work properly on
+  macOS and since gdb is not shipped by default anymore, test_gdb is now
+  skipped on macOS when LLVM Clang has been used to compile Python. Patch by
+  Lysandros Nikolaou
+
+- bpo-34279: regrtest issue a warning when no tests have been executed in a
+  particular test file. Also, a new final result state is issued if no test
+  have been executed across all test files. Patch by Pablo Galindo.
+
+Build
+-----
+
+- bpo-35351: When building Python with clang and LTO, LTO flags are no
+  longer passed into CFLAGS to build third-party C extensions through
+  distutils.
+
+- bpo-35139: Fix a compiler error when statically linking `pyexpat` in
+  `Modules/Setup`.
+
+- bpo-35011: Restores the use of pyexpatns.h to isolate our embedded copy of
+  the expat C library so that its symbols do not conflict at link or dynamic
+  loading time with an embedding application or other extension modules with
+  their own version of libexpat.
+
+- bpo-28015: Have --with-lto works correctly with clang.
+
+- bpo-33015: Fix an undefined behaviour in the pthread implementation of
+  :c:func:`PyThread_start_new_thread`: add a function wrapper to always
+  return ``NULL``.
+
+- bpo-31625: Stop using ranlib on static libraries. Instead, we assume ar
+  supports the 's' flag.
+
+- bpo-31354: Allow --with-lto to be used on all builds, not just `make
+  profile-opt`.
+
+Windows
+-------
+
+- bpo-35401: Updates Windows build to OpenSSL 1.0.2q
+
+- bpo-32890: Fix usage of GetLastError() instead of errno in os.execve() and
+  os.truncate().
+
+macOS
+-----
+
+- bpo-15663: The macOS 10.6+ installer now provides a private copy of Tcl/Tk
+  8.6, like the 10.9+ installer does.
+
+- bpo-35402: Update macOS installer to use Tcl/Tk 8.6.9.1.
+
+- bpo-35401: Update macOS installer to use OpenSSL 1.0.2q.
+
+- bpo-35025: Properly guard the use of the ``CLOCK_GETTIME`` et al. macros
+  in ``timemodule`` on macOS.
+
+- bpo-24658: On macOS, fix reading from and writing into a file with a size
+  larger than 2 GiB.
+
+IDLE
+----
+
+- bpo-35213: Where appropriate, use 'macOS' in idlelib.
+
+- bpo-34864: On macOS, warn if the system preference "Prefer tabs when
+  opening documents" is set to "Always".
+
+- bpo-34864: Document two IDLE on MacOS issues. The System Preferences Dock
+  "prefer tabs always" setting disables some IDLE features.  Menus are a bit
+  different than as described for Windows and Linux.
+
+- bpo-35202: Remove unused imports from lib/idlelib
+
+- bpo-33000: Document that IDLE's shell has no line limit. A program that
+  runs indefinitely can overfill memory.
+
+- bpo-23220: Explain how IDLE's Shell displays output.
+
+- bpo-35099: Improve the doc about IDLE running user code.   The section is
+  renamed from "IDLE -- console differences" is renamed "Running user code".
+  It mostly covers the implications of using custom sys.stdxxx objects.
+
+- bpo-35097: Add IDLE doc subsection explaining editor windows. Topics
+  include opening, title and status bar, .py* extension, and running.
+
+- bpo-35093: Document the IDLE document viewer in the IDLE doc. Add a
+  paragraph in "Help and preferences", "Help sources" subsection.
+
+- bpo-35088: Update idlelib.help.copy_string docstring. We now use git and
+  backporting instead of hg and forward merging.
+
+- bpo-35087: Update idlelib help files for the current doc build. The main
+  change is the elimination of chapter-section numbers.
+
+Tools/Demos
+-----------
+
+- bpo-34989: python-gdb.py now handles errors on computing the line number
+  of a Python frame.
+
+
 What's New in Python 3.6.7 final?
 =================================
 
@@ -424,7 +786,7 @@ IDLE
 - bpo-34120: Fix unresponsiveness after closing certain windows and dialogs.
 
 - bpo-33975: Avoid small type when running htests. Since part of the purpose
-  of human- viewed tests is to determine that widgets look right, it is
+  of human-viewed tests is to determine that widgets look right, it is
   important that they look the same for testing as when running IDLE.
 
 - bpo-33905: Add test for idlelib.stackview.StackBrowser.
@@ -6338,10 +6700,10 @@ Library
 - bpo-10513: Fix a regression in Connection.commit().  Statements should not
   be reset after a commit.
 
-- A new version of typing.py from https://github.com/python/typing: -
-  Collection (only for 3.6) (Issue #27598) - Add FrozenSet to __all__
-  (upstream #261) - fix crash in _get_type_vars() (upstream #259) - Remove
-  the dict constraint in ForwardRef._eval_type (upstream #252)
+- A new version of typing.py from https://github.com/python/typing:
+  Collection (only for 3.6) (Issue #27598). Add FrozenSet to __all__
+  (upstream #261). Fix crash in _get_type_vars() (upstream #259). Remove the
+  dict constraint in ForwardRef._eval_type (upstream #252).
 
 - bpo-27539: Fix unnormalised ``Fraction.__pow__`` result in the case of
   negative exponent and negative base.
@@ -10060,8 +10422,10 @@ Library
 
 - bpo-5411: Added support for the "xztar" format in the shutil module.
 
-- bpo-21121: Don't force 3rd party C extensions to be built with
-  ``-Werror=declaration-after-statement``.
+- bpo-21121: Don't force 3rd party C extensions to be built with <<<<<<<
+  HEAD ``-Werror=declaration-after-statement``. =======
+  -Werror=declaration-after-statement. >>>>>>> 3f819ca138... bpo-35110: Fix
+  unintentional spaces around hyphens and dashes. (GH-10231)
 
 - bpo-21975: Fixed crash when using uninitialized sqlite3.Row (in particular
   when unpickling pickled sqlite3.Row).  sqlite3.Row is now initialized in
@@ -10796,7 +11160,10 @@ Build
 - bpo-21811: Anticipated fixes to support OS X versions > 10.9.
 
 - bpo-21166: Prevent possible segfaults and other random failures of python
-  ``--generate-posix-vars`` in pybuilddir.txt build target.
+  <<<<<<< HEAD ``--generate-posix-vars`` in pybuilddir.txt build target.
+  ======= --generate-posix-vars in pybuilddir.txt build target. >>>>>>>
+  3f819ca138... bpo-35110: Fix unintentional spaces around hyphens and
+  dashes. (GH-10231)
 
 - bpo-18096: Fix library order returned by python-config.
 
index acf4433..e469d5e 100644 (file)
@@ -368,7 +368,7 @@ _symtable symtablemodule.c
 # Interface to the Expat XML parser
 # More information on Expat can be found at www.libexpat.org.
 #
-#pyexpat expat/xmlparse.c expat/xmlrole.c expat/xmltok.c pyexpat.c -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI
+#pyexpat expat/xmlparse.c expat/xmlrole.c expat/xmltok.c pyexpat.c -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DXML_POOR_ENTROPY=1 -DUSE_PYEXPAT_CAPI
 
 # Hye-Shik Chang's CJKCodecs
 
index 2a6c16d..39786cc 100644 (file)
@@ -625,7 +625,7 @@ _asyncio_Future_done_impl(FutureObj *self)
 }
 
 static PyObject *
-FutureObj_get_blocking(FutureObj *fut)
+FutureObj_get_blocking(FutureObj *fut, void *Py_UNUSED(ignored))
 {
     if (fut->fut_blocking) {
         Py_RETURN_TRUE;
@@ -636,7 +636,7 @@ FutureObj_get_blocking(FutureObj *fut)
 }
 
 static int
-FutureObj_set_blocking(FutureObj *fut, PyObject *val)
+FutureObj_set_blocking(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored))
 {
     int is_true = PyObject_IsTrue(val);
     if (is_true < 0) {
@@ -647,7 +647,7 @@ FutureObj_set_blocking(FutureObj *fut, PyObject *val)
 }
 
 static PyObject *
-FutureObj_get_log_traceback(FutureObj *fut)
+FutureObj_get_log_traceback(FutureObj *fut, void *Py_UNUSED(ignored))
 {
     if (fut->fut_log_tb) {
         Py_RETURN_TRUE;
@@ -658,7 +658,7 @@ FutureObj_get_log_traceback(FutureObj *fut)
 }
 
 static int
-FutureObj_set_log_traceback(FutureObj *fut, PyObject *val)
+FutureObj_set_log_traceback(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored))
 {
     int is_true = PyObject_IsTrue(val);
     if (is_true < 0) {
@@ -669,7 +669,7 @@ FutureObj_set_log_traceback(FutureObj *fut, PyObject *val)
 }
 
 static PyObject *
-FutureObj_get_loop(FutureObj *fut)
+FutureObj_get_loop(FutureObj *fut, void *Py_UNUSED(ignored))
 {
     if (fut->fut_loop == NULL) {
         Py_RETURN_NONE;
@@ -679,7 +679,7 @@ FutureObj_get_loop(FutureObj *fut)
 }
 
 static PyObject *
-FutureObj_get_callbacks(FutureObj *fut)
+FutureObj_get_callbacks(FutureObj *fut, void *Py_UNUSED(ignored))
 {
     if (fut->fut_callbacks == NULL) {
         Py_RETURN_NONE;
@@ -689,7 +689,7 @@ FutureObj_get_callbacks(FutureObj *fut)
 }
 
 static PyObject *
-FutureObj_get_result(FutureObj *fut)
+FutureObj_get_result(FutureObj *fut, void *Py_UNUSED(ignored))
 {
     if (fut->fut_result == NULL) {
         Py_RETURN_NONE;
@@ -699,7 +699,7 @@ FutureObj_get_result(FutureObj *fut)
 }
 
 static PyObject *
-FutureObj_get_exception(FutureObj *fut)
+FutureObj_get_exception(FutureObj *fut, void *Py_UNUSED(ignored))
 {
     if (fut->fut_exception == NULL) {
         Py_RETURN_NONE;
@@ -709,7 +709,7 @@ FutureObj_get_exception(FutureObj *fut)
 }
 
 static PyObject *
-FutureObj_get_source_traceback(FutureObj *fut)
+FutureObj_get_source_traceback(FutureObj *fut, void *Py_UNUSED(ignored))
 {
     if (fut->fut_source_tb == NULL) {
         Py_RETURN_NONE;
@@ -719,7 +719,7 @@ FutureObj_get_source_traceback(FutureObj *fut)
 }
 
 static PyObject *
-FutureObj_get_state(FutureObj *fut)
+FutureObj_get_state(FutureObj *fut, void *Py_UNUSED(ignored))
 {
     _Py_IDENTIFIER(PENDING);
     _Py_IDENTIFIER(CANCELLED);
@@ -1207,7 +1207,7 @@ TaskStepMethWrapper_traverse(TaskStepMethWrapper *o,
 }
 
 static PyObject *
-TaskStepMethWrapper_get___self__(TaskStepMethWrapper *o)
+TaskStepMethWrapper_get___self__(TaskStepMethWrapper *o, void *Py_UNUSED(ignored))
 {
     if (o->sw_task) {
         Py_INCREF(o->sw_task);
@@ -1387,7 +1387,7 @@ TaskObj_traverse(TaskObj *task, visitproc visit, void *arg)
 }
 
 static PyObject *
-TaskObj_get_log_destroy_pending(TaskObj *task)
+TaskObj_get_log_destroy_pending(TaskObj *task, void *Py_UNUSED(ignored))
 {
     if (task->task_log_destroy_pending) {
         Py_RETURN_TRUE;
@@ -1398,7 +1398,7 @@ TaskObj_get_log_destroy_pending(TaskObj *task)
 }
 
 static int
-TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val)
+TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val, void *Py_UNUSED(ignored))
 {
     int is_true = PyObject_IsTrue(val);
     if (is_true < 0) {
@@ -1409,7 +1409,7 @@ TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val)
 }
 
 static PyObject *
-TaskObj_get_must_cancel(TaskObj *task)
+TaskObj_get_must_cancel(TaskObj *task, void *Py_UNUSED(ignored))
 {
     if (task->task_must_cancel) {
         Py_RETURN_TRUE;
@@ -1420,7 +1420,7 @@ TaskObj_get_must_cancel(TaskObj *task)
 }
 
 static PyObject *
-TaskObj_get_coro(TaskObj *task)
+TaskObj_get_coro(TaskObj *task, void *Py_UNUSED(ignored))
 {
     if (task->task_coro) {
         Py_INCREF(task->task_coro);
@@ -1431,7 +1431,7 @@ TaskObj_get_coro(TaskObj *task)
 }
 
 static PyObject *
-TaskObj_get_fut_waiter(TaskObj *task)
+TaskObj_get_fut_waiter(TaskObj *task, void *Py_UNUSED(ignored))
 {
     if (task->task_fut_waiter) {
         Py_INCREF(task->task_fut_waiter);
index 3f55599..fe06953 100644 (file)
@@ -288,11 +288,11 @@ BZ2_Malloc(void* ctx, int items, int size)
 {
     if (items < 0 || size < 0)
         return NULL;
-    if ((size_t)items > (size_t)PY_SSIZE_T_MAX / (size_t)size)
+    if (size != 0 && (size_t)items > (size_t)PY_SSIZE_T_MAX / (size_t)size)
         return NULL;
     /* PyMem_Malloc() cannot be used: compress() and decompress()
        release the GIL */
-    return PyMem_RawMalloc(items * size);
+    return PyMem_RawMalloc((size_t)items * (size_t)size);
 }
 
 static void
index 85037d0..25006fa 100644 (file)
@@ -1341,7 +1341,7 @@ deque_traverse(dequeobject *deque, visitproc visit, void *arg)
 }
 
 static PyObject *
-deque_reduce(dequeobject *deque)
+deque_reduce(dequeobject *deque, PyObject *Py_UNUSED(ignored))
 {
     PyObject *dict, *it;
     _Py_IDENTIFIER(__dict__);
@@ -1539,7 +1539,7 @@ deque_bool(dequeobject *deque)
 }
 
 static PyObject *
-deque_get_maxlen(dequeobject *deque)
+deque_get_maxlen(dequeobject *deque, void *Py_UNUSED(ignored))
 {
     if (deque->maxlen < 0)
         Py_RETURN_NONE;
index 5d0044a..5324fa6 100644 (file)
@@ -160,31 +160,31 @@ get_nullchar_as_None(Py_UCS4 c)
 }
 
 static PyObject *
-Dialect_get_lineterminator(DialectObj *self)
+Dialect_get_lineterminator(DialectObj *self, void *Py_UNUSED(ignored))
 {
     return get_string(self->lineterminator);
 }
 
 static PyObject *
-Dialect_get_delimiter(DialectObj *self)
+Dialect_get_delimiter(DialectObj *self, void *Py_UNUSED(ignored))
 {
     return get_nullchar_as_None(self->delimiter);
 }
 
 static PyObject *
-Dialect_get_escapechar(DialectObj *self)
+Dialect_get_escapechar(DialectObj *self, void *Py_UNUSED(ignored))
 {
     return get_nullchar_as_None(self->escapechar);
 }
 
 static PyObject *
-Dialect_get_quotechar(DialectObj *self)
+Dialect_get_quotechar(DialectObj *self, void *Py_UNUSED(ignored))
 {
     return get_nullchar_as_None(self->quotechar);
 }
 
 static PyObject *
-Dialect_get_quoting(DialectObj *self)
+Dialect_get_quoting(DialectObj *self, void *Py_UNUSED(ignored))
 {
     return PyLong_FromLong(self->quoting);
 }
index 69d73f5..24d6485 100644 (file)
@@ -306,8 +306,10 @@ _ctypes_alloc_format_string_for_type(char code, int big_endian)
     }
 
     result = PyMem_Malloc(3);
-    if (result == NULL)
+    if (result == NULL) {
+        PyErr_NoMemory();
         return NULL;
+    }
 
     result[0] = big_endian ? '>' : '<';
     result[1] = pep_code;
@@ -367,8 +369,10 @@ _ctypes_alloc_format_string_with_shape(int ndim, const Py_ssize_t *shape,
     if (prefix)
         prefix_len += strlen(prefix);
     new_prefix = PyMem_Malloc(prefix_len);
-    if (new_prefix == NULL)
+    if (new_prefix == NULL) {
+        PyErr_NoMemory();
         return NULL;
+    }
     new_prefix[0] = '\0';
     if (prefix)
         strcpy(new_prefix, prefix);
@@ -1163,7 +1167,7 @@ PyTypeObject PyCPointerType_Type = {
 */
 
 static int
-CharArray_set_raw(CDataObject *self, PyObject *value)
+CharArray_set_raw(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
 {
     char *ptr;
     Py_ssize_t size;
@@ -1189,13 +1193,13 @@ CharArray_set_raw(CDataObject *self, PyObject *value)
 }
 
 static PyObject *
-CharArray_get_raw(CDataObject *self)
+CharArray_get_raw(CDataObject *self, void *Py_UNUSED(ignored))
 {
     return PyBytes_FromStringAndSize(self->b_ptr, self->b_size);
 }
 
 static PyObject *
-CharArray_get_value(CDataObject *self)
+CharArray_get_value(CDataObject *self, void *Py_UNUSED(ignored))
 {
     Py_ssize_t i;
     char *ptr = self->b_ptr;
@@ -1206,7 +1210,7 @@ CharArray_get_value(CDataObject *self)
 }
 
 static int
-CharArray_set_value(CDataObject *self, PyObject *value)
+CharArray_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
 {
     char *ptr;
     Py_ssize_t size;
@@ -1251,7 +1255,7 @@ static PyGetSetDef CharArray_getsets[] = {
 
 #ifdef CTYPES_UNICODE
 static PyObject *
-WCharArray_get_value(CDataObject *self)
+WCharArray_get_value(CDataObject *self, void *Py_UNUSED(ignored))
 {
     Py_ssize_t i;
     wchar_t *ptr = (wchar_t *)self->b_ptr;
@@ -1262,7 +1266,7 @@ WCharArray_get_value(CDataObject *self)
 }
 
 static int
-WCharArray_set_value(CDataObject *self, PyObject *value)
+WCharArray_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
 {
     Py_ssize_t result = 0;
     Py_UNICODE *wstr;
@@ -1856,6 +1860,10 @@ static PyObject *CreateSwappedType(PyTypeObject *type, PyObject *args, PyObject
 #else
         suffix = PyUnicode_InternFromString("_be");
 #endif
+    if (suffix == NULL) {
+        Py_DECREF(swapped_args);
+        return NULL;
+    }
 
     newname = PyUnicode_Concat(name, suffix);
     if (newname == NULL) {
@@ -3049,7 +3057,7 @@ GenericPyCData_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 */
 
 static int
-PyCFuncPtr_set_errcheck(PyCFuncPtrObject *self, PyObject *ob)
+PyCFuncPtr_set_errcheck(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored))
 {
     if (ob && !PyCallable_Check(ob)) {
         PyErr_SetString(PyExc_TypeError,
@@ -3062,7 +3070,7 @@ PyCFuncPtr_set_errcheck(PyCFuncPtrObject *self, PyObject *ob)
 }
 
 static PyObject *
-PyCFuncPtr_get_errcheck(PyCFuncPtrObject *self)
+PyCFuncPtr_get_errcheck(PyCFuncPtrObject *self, void *Py_UNUSED(ignored))
 {
     if (self->errcheck) {
         Py_INCREF(self->errcheck);
@@ -3073,7 +3081,7 @@ PyCFuncPtr_get_errcheck(PyCFuncPtrObject *self)
 }
 
 static int
-PyCFuncPtr_set_restype(PyCFuncPtrObject *self, PyObject *ob)
+PyCFuncPtr_set_restype(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored))
 {
     if (ob == NULL) {
         Py_CLEAR(self->restype);
@@ -3094,7 +3102,7 @@ PyCFuncPtr_set_restype(PyCFuncPtrObject *self, PyObject *ob)
 }
 
 static PyObject *
-PyCFuncPtr_get_restype(PyCFuncPtrObject *self)
+PyCFuncPtr_get_restype(PyCFuncPtrObject *self, void *Py_UNUSED(ignored))
 {
     StgDictObject *dict;
     if (self->restype) {
@@ -3113,7 +3121,7 @@ PyCFuncPtr_get_restype(PyCFuncPtrObject *self)
 }
 
 static int
-PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob)
+PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored))
 {
     PyObject *converters;
 
@@ -3132,7 +3140,7 @@ PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob)
 }
 
 static PyObject *
-PyCFuncPtr_get_argtypes(PyCFuncPtrObject *self)
+PyCFuncPtr_get_argtypes(PyCFuncPtrObject *self, void *Py_UNUSED(ignored))
 {
     StgDictObject *dict;
     if (self->argtypes) {
@@ -4678,7 +4686,7 @@ PyCArrayType_from_ctype(PyObject *itemtype, Py_ssize_t length)
 */
 
 static int
-Simple_set_value(CDataObject *self, PyObject *value)
+Simple_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
 {
     PyObject *result;
     StgDictObject *dict = PyObject_stgdict((PyObject *)self);
@@ -4705,12 +4713,12 @@ Simple_init(CDataObject *self, PyObject *args, PyObject *kw)
     if (!PyArg_UnpackTuple(args, "__init__", 0, 1, &value))
         return -1;
     if (value)
-        return Simple_set_value(self, value);
+        return Simple_set_value(self, value, NULL);
     return 0;
 }
 
 static PyObject *
-Simple_get_value(CDataObject *self)
+Simple_get_value(CDataObject *self, void *Py_UNUSED(ignored))
 {
     StgDictObject *dict;
     dict = PyObject_stgdict((PyObject *)self);
@@ -4733,7 +4741,7 @@ Simple_from_outparm(PyObject *self, PyObject *args)
         return self;
     }
     /* call stgdict->getfunc */
-    return Simple_get_value((CDataObject *)self);
+    return Simple_get_value((CDataObject *)self, NULL);
 }
 
 static PyMethodDef Simple_methods[] = {
@@ -4770,7 +4778,7 @@ Simple_repr(CDataObject *self)
                                    Py_TYPE(self)->tp_name, self);
     }
 
-    val = Simple_get_value(self);
+    val = Simple_get_value(self, NULL);
     if (val == NULL)
         return NULL;
 
index b958f30..c8773a1 100644 (file)
@@ -309,7 +309,6 @@ static CThunkObject* CThunkObject_new(Py_ssize_t nArgs)
 
     p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nArgs);
     if (p == NULL) {
-        PyErr_NoMemory();
         return NULL;
     }
 
@@ -347,7 +346,7 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
     assert(CThunk_CheckExact((PyObject *)p));
 
     p->pcl_write = ffi_closure_alloc(sizeof(ffi_closure),
-                                                                        &p->pcl_exec);
+                                                                         &p->pcl_exec);
     if (p->pcl_write == NULL) {
         PyErr_NoMemory();
         goto error;
@@ -397,8 +396,8 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
     result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p);
 #else
     result = ffi_prep_closure_loc(p->pcl_write, &p->cif, closure_fcn,
-                                 p,
-                                 p->pcl_exec);
+                                  p,
+                                  p->pcl_exec);
 #endif
     if (result != FFI_OK) {
         PyErr_Format(PyExc_RuntimeError,
index b8c2c74..d1c190f 100644 (file)
 #include <alloca.h>
 #endif
 
+#ifdef _Py_MEMORY_SANITIZER
+#include <sanitizer/msan_interface.h>
+#endif
+
 #if defined(_DEBUG) || defined(__MINGW32__)
 /* Don't use structured exception handling on Windows if this is defined.
    MingW, AFAIK, doesn't support it.
@@ -448,6 +452,12 @@ PyCArg_dealloc(PyCArgObject *self)
     PyObject_Del(self);
 }
 
+static int
+is_literal_char(unsigned char c)
+{
+    return c < 128 && _PyUnicode_IsPrintable(c) && c != '\\' && c != '\'';
+}
+
 static PyObject *
 PyCArg_repr(PyCArgObject *self)
 {
@@ -480,7 +490,7 @@ PyCArg_repr(PyCArgObject *self)
 #ifdef MS_WIN32
             "<cparam '%c' (%I64d)>",
 #else
-            "<cparam '%c' (%qd)>",
+            "<cparam '%c' (%lld)>",
 #endif
             self->tag, self->value.q);
         break;
@@ -494,8 +504,14 @@ PyCArg_repr(PyCArgObject *self)
         break;
 
     case 'c':
-        sprintf(buffer, "<cparam '%c' (%c)>",
-            self->tag, self->value.c);
+        if (is_literal_char((unsigned char)self->value.c)) {
+            sprintf(buffer, "<cparam '%c' ('%c')>",
+                self->tag, self->value.c);
+        }
+        else {
+            sprintf(buffer, "<cparam '%c' ('\\x%02x')>",
+                self->tag, (unsigned char)self->value.c);
+        }
         break;
 
 /* Hm, are these 'z' and 'Z' codes useful at all?
@@ -510,8 +526,14 @@ PyCArg_repr(PyCArgObject *self)
         break;
 
     default:
-        sprintf(buffer, "<cparam '%c' at %p>",
-            self->tag, self);
+        if (is_literal_char((unsigned char)self->tag)) {
+            sprintf(buffer, "<cparam '%c' at %p>",
+                (unsigned char)self->tag, self);
+        }
+        else {
+            sprintf(buffer, "<cparam 0x%02x at %p>",
+                (unsigned char)self->tag, self);
+        }
         break;
     }
     return PyUnicode_FromString(buffer);
@@ -1136,6 +1158,13 @@ PyObject *_ctypes_callproc(PPROC pProc,
     rtype = _ctypes_get_ffi_type(restype);
     resbuf = alloca(max(rtype->size, sizeof(ffi_arg)));
 
+#ifdef _Py_MEMORY_SANITIZER
+    /* ffi_call actually initializes resbuf, but from asm, which
+     * MemorySanitizer can't detect. Avoid false positives from MSan. */
+    if (resbuf != NULL) {
+        __msan_unpoison(resbuf, max(rtype->size, sizeof(ffi_arg)));
+    }
+#endif
     avalues = (void **)alloca(sizeof(void *) * argcount);
     atypes = (ffi_type **)alloca(sizeof(ffi_type *) * argcount);
     if (!resbuf || !avalues || !atypes) {
index 4ac702a..c048a7d 100644 (file)
@@ -414,27 +414,27 @@ PyTypeObject PyCursesWindow_Type;
    PARSESTR - format string for argument parsing
 */
 
-#define Window_NoArgNoReturnFunction(X)                 \
-    static PyObject *PyCursesWindow_ ## X               \
-    (PyCursesWindowObject *self, PyObject *args)        \
+#define Window_NoArgNoReturnFunction(X)                         \
+    static PyObject *PyCursesWindow_ ## X                       \
+    (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored))  \
     { return PyCursesCheckERR(X(self->win), # X); }
 
 #define Window_NoArgTrueFalseFunction(X)                                \
     static PyObject * PyCursesWindow_ ## X                              \
-    (PyCursesWindowObject *self)                                        \
+    (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored))          \
     {                                                                   \
         if (X (self->win) == FALSE) { Py_INCREF(Py_False); return Py_False; } \
         else { Py_INCREF(Py_True); return Py_True; } }
 
 #define Window_NoArgNoReturnVoidFunction(X)                     \
     static PyObject * PyCursesWindow_ ## X                      \
-    (PyCursesWindowObject *self)                                \
+    (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored))  \
     {                                                           \
         X(self->win); Py_INCREF(Py_None); return Py_None; }
 
 #define Window_NoArg2TupleReturnFunction(X, TYPE, ERGSTR)               \
     static PyObject * PyCursesWindow_ ## X                              \
-    (PyCursesWindowObject *self)                                        \
+    (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored))          \
     {                                                                   \
         TYPE arg1, arg2;                                                \
         X(self->win,arg1,arg2); return Py_BuildValue(ERGSTR, arg1, arg2); }
@@ -1976,7 +1976,7 @@ PyCursesWindow_get_encoding(PyCursesWindowObject *self, void *closure)
 }
 
 static int
-PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value)
+PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value, void *Py_UNUSED(ignored))
 {
     PyObject *ascii;
     char *encoding;
index 64928b1..397b898 100644 (file)
@@ -1542,6 +1542,29 @@ Done:
     return result;
 }
 
+static PyObject *
+checked_divmod(PyObject *a, PyObject *b)
+{
+    PyObject *result = PyNumber_Divmod(a, b);
+    if (result != NULL) {
+        if (!PyTuple_Check(result)) {
+            PyErr_Format(PyExc_TypeError,
+                         "divmod() returned non-tuple (type %.200s)",
+                         result->ob_type->tp_name);
+            Py_DECREF(result);
+            return NULL;
+        }
+        if (PyTuple_GET_SIZE(result) != 2) {
+            PyErr_Format(PyExc_TypeError,
+                         "divmod() returned a tuple of size %zd",
+                         PyTuple_GET_SIZE(result));
+            Py_DECREF(result);
+            return NULL;
+        }
+    }
+    return result;
+}
+
 /* Convert a number of us (as a Python int) to a timedelta.
  */
 static PyObject *
@@ -1550,70 +1573,49 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type)
     int us;
     int s;
     int d;
-    long temp;
 
     PyObject *tuple = NULL;
     PyObject *num = NULL;
     PyObject *result = NULL;
 
-    assert(PyLong_CheckExact(pyus));
-    tuple = PyNumber_Divmod(pyus, us_per_second);
-    if (tuple == NULL)
+    tuple = checked_divmod(pyus, us_per_second);
+    if (tuple == NULL) {
         goto Done;
+    }
 
-    num = PyTuple_GetItem(tuple, 1);            /* us */
-    if (num == NULL)
-        goto Done;
-    temp = PyLong_AsLong(num);
+    num = PyTuple_GET_ITEM(tuple, 1);           /* us */
+    us = _PyLong_AsInt(num);
     num = NULL;
-    if (temp == -1 && PyErr_Occurred())
-        goto Done;
-    assert(0 <= temp && temp < 1000000);
-    us = (int)temp;
-    if (us < 0) {
-        /* The divisor was positive, so this must be an error. */
-        assert(PyErr_Occurred());
+    if (us == -1 && PyErr_Occurred()) {
         goto Done;
     }
+    if (!(0 <= us && us < 1000000)) {
+        goto BadDivmod;
+    }
 
-    num = PyTuple_GetItem(tuple, 0);            /* leftover seconds */
-    if (num == NULL)
-        goto Done;
+    num = PyTuple_GET_ITEM(tuple, 0);           /* leftover seconds */
     Py_INCREF(num);
     Py_DECREF(tuple);
 
-    tuple = PyNumber_Divmod(num, seconds_per_day);
+    tuple = checked_divmod(num, seconds_per_day);
     if (tuple == NULL)
         goto Done;
     Py_DECREF(num);
 
-    num = PyTuple_GetItem(tuple, 1);            /* seconds */
-    if (num == NULL)
-        goto Done;
-    temp = PyLong_AsLong(num);
+    num = PyTuple_GET_ITEM(tuple, 1);           /* seconds */
+    s = _PyLong_AsInt(num);
     num = NULL;
-    if (temp == -1 && PyErr_Occurred())
-        goto Done;
-    assert(0 <= temp && temp < 24*3600);
-    s = (int)temp;
-
-    if (s < 0) {
-        /* The divisor was positive, so this must be an error. */
-        assert(PyErr_Occurred());
+    if (s == -1 && PyErr_Occurred()) {
         goto Done;
     }
+    if (!(0 <= s && s < 24*3600)) {
+        goto BadDivmod;
+    }
 
-    num = PyTuple_GetItem(tuple, 0);            /* leftover days */
-    if (num == NULL)
-        goto Done;
+    num = PyTuple_GET_ITEM(tuple, 0);           /* leftover days */
     Py_INCREF(num);
-    temp = PyLong_AsLong(num);
-    if (temp == -1 && PyErr_Occurred())
-        goto Done;
-    d = (int)temp;
-    if ((long)d != temp) {
-        PyErr_SetString(PyExc_OverflowError, "normalized days too "
-                        "large to fit in a C int");
+    d = _PyLong_AsInt(num);
+    if (d == -1 && PyErr_Occurred()) {
         goto Done;
     }
     result = new_delta_ex(d, s, us, 0, type);
@@ -1622,6 +1624,11 @@ Done:
     Py_XDECREF(tuple);
     Py_XDECREF(num);
     return result;
+
+BadDivmod:
+    PyErr_SetString(PyExc_TypeError,
+                    "divmod() returned a value out of range");
+    goto Done;
 }
 
 #define microseconds_to_delta(pymicros) \
@@ -1638,7 +1645,7 @@ multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta)
     if (pyus_in == NULL)
         return NULL;
 
-    pyus_out = PyNumber_Multiply(pyus_in, intobj);
+    pyus_out = PyNumber_Multiply(intobj, pyus_in);
     Py_DECREF(pyus_in);
     if (pyus_out == NULL)
         return NULL;
@@ -2073,13 +2080,12 @@ delta_divmod(PyObject *left, PyObject *right)
         return NULL;
     }
 
-    divmod = PyNumber_Divmod(pyus_left, pyus_right);
+    divmod = checked_divmod(pyus_left, pyus_right);
     Py_DECREF(pyus_left);
     Py_DECREF(pyus_right);
     if (divmod == NULL)
         return NULL;
 
-    assert(PyTuple_Size(divmod) == 2);
     delta = microseconds_to_delta(PyTuple_GET_ITEM(divmod, 1));
     if (delta == NULL) {
         Py_DECREF(divmod);
@@ -2110,13 +2116,11 @@ accum(const char* tag, PyObject *sofar, PyObject *num, PyObject *factor,
     assert(num != NULL);
 
     if (PyLong_Check(num)) {
-        prod = PyNumber_Multiply(factor, num);
+        prod = PyNumber_Multiply(num, factor);
         if (prod == NULL)
             return NULL;
-        assert(PyLong_CheckExact(prod));
         sum = PyNumber_Add(sofar, prod);
         Py_DECREF(prod);
-        assert(sum == NULL || PyLong_CheckExact(sum));
         return sum;
     }
 
@@ -2174,7 +2178,6 @@ accum(const char* tag, PyObject *sofar, PyObject *num, PyObject *factor,
         Py_DECREF(sum);
         Py_DECREF(x);
         *leftover += fracpart;
-        assert(y == NULL || PyLong_CheckExact(y));
         return y;
     }
 
@@ -2413,7 +2416,11 @@ static PyMethodDef delta_methods[] = {
 };
 
 static const char delta_doc[] =
-PyDoc_STR("Difference between two datetime values.");
+PyDoc_STR("Difference between two datetime values.\n\n"
+          "timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, "
+          "minutes=0, hours=0, weeks=0)\n\n"
+          "All arguments are optional and default to 0.\n"
+          "Arguments may be integers or floats, and may be positive or negative.");
 
 static PyNumberMethods delta_as_number = {
     delta_add,                                  /* nb_add */
@@ -2529,29 +2536,60 @@ static PyGetSetDef date_getset[] = {
 static char *date_kws[] = {"year", "month", "day", NULL};
 
 static PyObject *
+date_from_pickle(PyTypeObject *type, PyObject *state)
+{
+    PyDateTime_Date *me;
+
+    me = (PyDateTime_Date *) (type->tp_alloc(type, 0));
+    if (me != NULL) {
+        const char *pdata = PyBytes_AS_STRING(state);
+        memcpy(me->data, pdata, _PyDateTime_DATE_DATASIZE);
+        me->hashcode = -1;
+    }
+    return (PyObject *)me;
+}
+
+static PyObject *
 date_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 {
     PyObject *self = NULL;
-    PyObject *state;
     int year;
     int month;
     int day;
 
     /* Check for invocation from pickle with __getstate__ state */
-    if (PyTuple_GET_SIZE(args) == 1 &&
-        PyBytes_Check(state = PyTuple_GET_ITEM(args, 0)) &&
-        PyBytes_GET_SIZE(state) == _PyDateTime_DATE_DATASIZE &&
-        MONTH_IS_SANE(PyBytes_AS_STRING(state)[2]))
-    {
-        PyDateTime_Date *me;
-
-        me = (PyDateTime_Date *) (type->tp_alloc(type, 0));
-        if (me != NULL) {
-            char *pdata = PyBytes_AS_STRING(state);
-            memcpy(me->data, pdata, _PyDateTime_DATE_DATASIZE);
-            me->hashcode = -1;
+    if (PyTuple_GET_SIZE(args) == 1) {
+        PyObject *state = PyTuple_GET_ITEM(args, 0);
+        if (PyBytes_Check(state)) {
+            if (PyBytes_GET_SIZE(state) == _PyDateTime_DATE_DATASIZE &&
+                MONTH_IS_SANE(PyBytes_AS_STRING(state)[2]))
+            {
+                return date_from_pickle(type, state);
+            }
+        }
+        else if (PyUnicode_Check(state)) {
+            if (PyUnicode_READY(state)) {
+                return NULL;
+            }
+            if (PyUnicode_GET_LENGTH(state) == _PyDateTime_DATE_DATASIZE &&
+                MONTH_IS_SANE(PyUnicode_READ_CHAR(state, 2)))
+            {
+                state = PyUnicode_AsLatin1String(state);
+                if (state == NULL) {
+                    if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
+                        /* More informative error message. */
+                        PyErr_SetString(PyExc_ValueError,
+                            "Failed to encode latin1 string when unpickling "
+                            "a date object. "
+                            "pickle.load(data, encoding='latin1') is assumed.");
+                    }
+                    return NULL;
+                }
+                self = date_from_pickle(type, state);
+                Py_DECREF(state);
+                return self;
+            }
         }
-        return (PyObject *)me;
     }
 
     if (PyArg_ParseTupleAndKeywords(args, kw, "iii", date_kws,
@@ -3154,7 +3192,7 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt)
     return result;
 
 Inconsistent:
-    PyErr_SetString(PyExc_ValueError, "fromutc: tz.dst() gave"
+    PyErr_SetString(PyExc_ValueError, "fromutc: tz.dst() gave "
                     "inconsistent results; cannot convert");
 
     /* fall through to failure */
@@ -3585,10 +3623,42 @@ static char *time_kws[] = {"hour", "minute", "second", "microsecond",
                            "tzinfo", "fold", NULL};
 
 static PyObject *
+time_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo)
+{
+    PyDateTime_Time *me;
+    char aware = (char)(tzinfo != Py_None);
+
+    if (aware && check_tzinfo_subclass(tzinfo) < 0) {
+        PyErr_SetString(PyExc_TypeError, "bad tzinfo state arg");
+        return NULL;
+    }
+
+    me = (PyDateTime_Time *) (type->tp_alloc(type, aware));
+    if (me != NULL) {
+        const char *pdata = PyBytes_AS_STRING(state);
+
+        memcpy(me->data, pdata, _PyDateTime_TIME_DATASIZE);
+        me->hashcode = -1;
+        me->hastzinfo = aware;
+        if (aware) {
+            Py_INCREF(tzinfo);
+            me->tzinfo = tzinfo;
+        }
+        if (pdata[0] & (1 << 7)) {
+            me->data[0] -= 128;
+            me->fold = 1;
+        }
+        else {
+            me->fold = 0;
+        }
+    }
+    return (PyObject *)me;
+}
+
+static PyObject *
 time_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 {
     PyObject *self = NULL;
-    PyObject *state;
     int hour = 0;
     int minute = 0;
     int second = 0;
@@ -3597,44 +3667,42 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw)
     int fold = 0;
 
     /* Check for invocation from pickle with __getstate__ state */
-    if (PyTuple_GET_SIZE(args) >= 1 &&
-        PyTuple_GET_SIZE(args) <= 2 &&
-        PyBytes_Check(state = PyTuple_GET_ITEM(args, 0)) &&
-        PyBytes_GET_SIZE(state) == _PyDateTime_TIME_DATASIZE &&
-        (0x7F & ((unsigned char) (PyBytes_AS_STRING(state)[0]))) < 24)
-    {
-        PyDateTime_Time *me;
-        char aware;
-
+    if (PyTuple_GET_SIZE(args) >= 1 && PyTuple_GET_SIZE(args) <= 2) {
+        PyObject *state = PyTuple_GET_ITEM(args, 0);
         if (PyTuple_GET_SIZE(args) == 2) {
             tzinfo = PyTuple_GET_ITEM(args, 1);
-            if (check_tzinfo_subclass(tzinfo) < 0) {
-                PyErr_SetString(PyExc_TypeError, "bad "
-                    "tzinfo state arg");
-                return NULL;
-            }
         }
-        aware = (char)(tzinfo != Py_None);
-        me = (PyDateTime_Time *) (type->tp_alloc(type, aware));
-        if (me != NULL) {
-            char *pdata = PyBytes_AS_STRING(state);
-
-            memcpy(me->data, pdata, _PyDateTime_TIME_DATASIZE);
-            me->hashcode = -1;
-            me->hastzinfo = aware;
-            if (aware) {
-                Py_INCREF(tzinfo);
-                me->tzinfo = tzinfo;
+        if (PyBytes_Check(state)) {
+            if (PyBytes_GET_SIZE(state) == _PyDateTime_TIME_DATASIZE &&
+                (0x7F & ((unsigned char) (PyBytes_AS_STRING(state)[0]))) < 24)
+            {
+                return time_from_pickle(type, state, tzinfo);
             }
-            if (pdata[0] & (1 << 7)) {
-                me->data[0] -= 128;
-                me->fold = 1;
+        }
+        else if (PyUnicode_Check(state)) {
+            if (PyUnicode_READY(state)) {
+                return NULL;
             }
-            else {
-                me->fold = 0;
+            if (PyUnicode_GET_LENGTH(state) == _PyDateTime_TIME_DATASIZE &&
+                (0x7F & PyUnicode_READ_CHAR(state, 2)) < 24)
+            {
+                state = PyUnicode_AsLatin1String(state);
+                if (state == NULL) {
+                    if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
+                        /* More informative error message. */
+                        PyErr_SetString(PyExc_ValueError,
+                            "Failed to encode latin1 string when unpickling "
+                            "a time object. "
+                            "pickle.load(data, encoding='latin1') is assumed.");
+                    }
+                    return NULL;
+                }
+                self = time_from_pickle(type, state, tzinfo);
+                Py_DECREF(state);
+                return self;
             }
         }
-        return (PyObject *)me;
+        tzinfo = Py_None;
     }
 
     if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i", time_kws,
@@ -4168,10 +4236,42 @@ static char *datetime_kws[] = {
 };
 
 static PyObject *
+datetime_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo)
+{
+    PyDateTime_DateTime *me;
+    char aware = (char)(tzinfo != Py_None);
+
+    if (aware && check_tzinfo_subclass(tzinfo) < 0) {
+        PyErr_SetString(PyExc_TypeError, "bad tzinfo state arg");
+        return NULL;
+    }
+
+    me = (PyDateTime_DateTime *) (type->tp_alloc(type , aware));
+    if (me != NULL) {
+        const char *pdata = PyBytes_AS_STRING(state);
+
+        memcpy(me->data, pdata, _PyDateTime_DATETIME_DATASIZE);
+        me->hashcode = -1;
+        me->hastzinfo = aware;
+        if (aware) {
+            Py_INCREF(tzinfo);
+            me->tzinfo = tzinfo;
+        }
+        if (pdata[2] & (1 << 7)) {
+            me->data[2] -= 128;
+            me->fold = 1;
+        }
+        else {
+            me->fold = 0;
+        }
+    }
+    return (PyObject *)me;
+}
+
+static PyObject *
 datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 {
     PyObject *self = NULL;
-    PyObject *state;
     int year;
     int month;
     int day;
@@ -4183,44 +4283,42 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
     PyObject *tzinfo = Py_None;
 
     /* Check for invocation from pickle with __getstate__ state */
-    if (PyTuple_GET_SIZE(args) >= 1 &&
-        PyTuple_GET_SIZE(args) <= 2 &&
-        PyBytes_Check(state = PyTuple_GET_ITEM(args, 0)) &&
-        PyBytes_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE &&
-        MONTH_IS_SANE(PyBytes_AS_STRING(state)[2] & 0x7F))
-    {
-        PyDateTime_DateTime *me;
-        char aware;
-
+    if (PyTuple_GET_SIZE(args) >= 1 && PyTuple_GET_SIZE(args) <= 2) {
+        PyObject *state = PyTuple_GET_ITEM(args, 0);
         if (PyTuple_GET_SIZE(args) == 2) {
             tzinfo = PyTuple_GET_ITEM(args, 1);
-            if (check_tzinfo_subclass(tzinfo) < 0) {
-                PyErr_SetString(PyExc_TypeError, "bad "
-                    "tzinfo state arg");
-                return NULL;
-            }
         }
-        aware = (char)(tzinfo != Py_None);
-        me = (PyDateTime_DateTime *) (type->tp_alloc(type , aware));
-        if (me != NULL) {
-            char *pdata = PyBytes_AS_STRING(state);
-
-            memcpy(me->data, pdata, _PyDateTime_DATETIME_DATASIZE);
-            me->hashcode = -1;
-            me->hastzinfo = aware;
-            if (aware) {
-                Py_INCREF(tzinfo);
-                me->tzinfo = tzinfo;
+        if (PyBytes_Check(state)) {
+            if (PyBytes_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE &&
+                MONTH_IS_SANE(PyBytes_AS_STRING(state)[2] & 0x7F))
+            {
+                return datetime_from_pickle(type, state, tzinfo);
             }
-            if (pdata[2] & (1 << 7)) {
-                me->data[2] -= 128;
-                me->fold = 1;
+        }
+        else if (PyUnicode_Check(state)) {
+            if (PyUnicode_READY(state)) {
+                return NULL;
             }
-            else {
-                me->fold = 0;
+            if (PyUnicode_GET_LENGTH(state) == _PyDateTime_DATETIME_DATASIZE &&
+                MONTH_IS_SANE(PyUnicode_READ_CHAR(state, 2) & 0x7F))
+            {
+                state = PyUnicode_AsLatin1String(state);
+                if (state == NULL) {
+                    if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
+                        /* More informative error message. */
+                        PyErr_SetString(PyExc_ValueError,
+                            "Failed to encode latin1 string when unpickling "
+                            "a datetime object. "
+                            "pickle.load(data, encoding='latin1') is assumed.");
+                    }
+                    return NULL;
+                }
+                self = datetime_from_pickle(type, state, tzinfo);
+                Py_DECREF(state);
+                return self;
             }
         }
-        return (PyObject *)me;
+        tzinfo = Py_None;
     }
 
     if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO$i", datetime_kws,
index daf2b9d..a67dd9b 100644 (file)
@@ -818,12 +818,12 @@ void *mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size);
 mpd_t *mpd_qnew(void);
 mpd_t *mpd_new(mpd_context_t *ctx);
 mpd_t *mpd_qnew_size(mpd_ssize_t size);
-void mpd_del(mpd_t *dec);
+EXTINLINE void mpd_del(mpd_t *dec);
 
-void mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len);
-int mpd_qresize(mpd_t *result, mpd_ssize_t size, uint32_t *status);
-int mpd_qresize_zero(mpd_t *result, mpd_ssize_t size, uint32_t *status);
-void mpd_minalloc(mpd_t *result);
+EXTINLINE void mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len);
+EXTINLINE int mpd_qresize(mpd_t *result, mpd_ssize_t size, uint32_t *status);
+EXTINLINE int mpd_qresize_zero(mpd_t *result, mpd_ssize_t size, uint32_t *status);
+EXTINLINE void mpd_minalloc(mpd_t *result);
 
 int mpd_resize(mpd_t *result, mpd_ssize_t size, mpd_context_t *ctx);
 int mpd_resize_zero(mpd_t *result, mpd_ssize_t size, mpd_context_t *ctx);
index 53f05f9..30e382d 100644 (file)
@@ -204,6 +204,8 @@ typedef struct {
 
 
 #define Element_CheckExact(op) (Py_TYPE(op) == &Element_Type)
+#define Element_Check(op) PyObject_TypeCheck(op, &Element_Type)
+
 
 /* -------------------------------------------------------------------- */
 /* Element constructors and destructor */
@@ -231,11 +233,29 @@ create_extra(ElementObject* self, PyObject* attrib)
 }
 
 LOCAL(void)
-dealloc_extra(ElementObject* self)
+dealloc_extra(ElementObjectExtra *extra)
 {
-    ElementObjectExtra *myextra;
     Py_ssize_t i;
 
+    if (!extra)
+        return;
+
+    Py_DECREF(extra->attrib);
+
+    for (i = 0; i < extra->length; i++)
+        Py_DECREF(extra->children[i]);
+
+    if (extra->children != extra->_children)
+        PyObject_Free(extra->children);
+
+    PyObject_Free(extra);
+}
+
+LOCAL(void)
+clear_extra(ElementObject* self)
+{
+    ElementObjectExtra *myextra;
+
     if (!self->extra)
         return;
 
@@ -244,15 +264,7 @@ dealloc_extra(ElementObject* self)
     myextra = self->extra;
     self->extra = NULL;
 
-    Py_DECREF(myextra->attrib);
-
-    for (i = 0; i < myextra->length; i++)
-        Py_DECREF(myextra->children[i]);
-
-    if (myextra->children != myextra->_children)
-        PyObject_Free(myextra->children);
-
-    PyObject_Free(myextra);
+    dealloc_extra(myextra);
 }
 
 /* Convenience internal function to create new Element objects with the given
@@ -324,6 +336,9 @@ static PyObject*
 get_attrib_from_keywords(PyObject *kwds)
 {
     PyObject *attrib_str = PyUnicode_FromString("attrib");
+    if (attrib_str == NULL) {
+        return NULL;
+    }
     PyObject *attrib = PyDict_GetItem(kwds, attrib_str);
 
     if (attrib) {
@@ -337,17 +352,20 @@ get_attrib_from_keywords(PyObject *kwds)
             return NULL;
         }
         attrib = PyDict_Copy(attrib);
-        PyDict_DelItem(kwds, attrib_str);
+        if (attrib && PyDict_DelItem(kwds, attrib_str) < 0) {
+            Py_DECREF(attrib);
+            attrib = NULL;
+        }
     } else {
         attrib = PyDict_New();
     }
 
     Py_DECREF(attrib_str);
 
-    /* attrib can be NULL if PyDict_New failed */
-    if (attrib)
-        if (PyDict_Update(attrib, kwds) < 0)
-            return NULL;
+    if (attrib != NULL && PyDict_Update(attrib, kwds) < 0) {
+        Py_DECREF(attrib);
+        return NULL;
+    }
     return attrib;
 }
 
@@ -418,6 +436,7 @@ element_resize(ElementObject* self, Py_ssize_t extra)
     Py_ssize_t size;
     PyObject* *children;
 
+    assert(extra >= 0);
     /* make sure self->children can hold the given number of extra
        elements.  set an exception and return -1 if allocation failed */
 
@@ -566,10 +585,9 @@ subelement(PyObject *self, PyObject *args, PyObject *kwds)
         attrib = PyDict_Copy(attrib);
         if (!attrib)
             return NULL;
-        if (kwds) {
-            if (PyDict_Update(attrib, kwds) < 0) {
-                return NULL;
-            }
+        if (kwds != NULL && PyDict_Update(attrib, kwds) < 0) {
+            Py_DECREF(attrib);
+            return NULL;
         }
     } else if (kwds) {
         /* have keyword args */
@@ -622,7 +640,7 @@ element_gc_clear(ElementObject *self)
     /* After dropping all references from extra, it's no longer valid anyway,
      * so fully deallocate it.
     */
-    dealloc_extra(self);
+    clear_extra(self);
     return 0;
 }
 
@@ -674,7 +692,7 @@ static PyObject *
 _elementtree_Element_clear_impl(ElementObject *self)
 /*[clinic end generated code: output=8bcd7a51f94cfff6 input=3c719ff94bf45dd6]*/
 {
-    dealloc_extra(self);
+    clear_extra(self);
 
     Py_INCREF(Py_None);
     _set_joined_ptr(&self->text, Py_None);
@@ -708,6 +726,7 @@ _elementtree_Element___copy___impl(ElementObject *self)
     Py_INCREF(JOIN_OBJ(self->tail));
     _set_joined_ptr(&element->tail, self->tail);
 
+    assert(!element->extra || !element->extra->length);
     if (self->extra) {
         if (element_resize(element, self->extra->length) < 0) {
             Py_DECREF(element);
@@ -719,6 +738,7 @@ _elementtree_Element___copy___impl(ElementObject *self)
             element->extra->children[i] = self->extra->children[i];
         }
 
+        assert(!element->extra->length);
         element->extra->length = self->extra->length;
     }
 
@@ -781,6 +801,7 @@ _elementtree_Element___deepcopy__(ElementObject *self, PyObject *memo)
         goto error;
     _set_joined_ptr(&element->tail, JOIN_SET(tail, JOIN_GET(self->tail)));
 
+    assert(!element->extra || !element->extra->length);
     if (self->extra) {
         if (element_resize(element, self->extra->length) < 0)
             goto error;
@@ -794,6 +815,7 @@ _elementtree_Element___deepcopy__(ElementObject *self, PyObject *memo)
             element->extra->children[i] = child;
         }
 
+        assert(!element->extra->length);
         element->extra->length = self->extra->length;
     }
 
@@ -954,6 +976,7 @@ element_setstate_from_attributes(ElementObject *self,
                                  PyObject *children)
 {
     Py_ssize_t i, nchildren;
+    ElementObjectExtra *oldextra = NULL;
 
     if (!tag) {
         PyErr_SetString(PyExc_TypeError, "tag may not be NULL");
@@ -972,8 +995,9 @@ element_setstate_from_attributes(ElementObject *self,
     _set_joined_ptr(&self->tail, tail);
 
     /* Handle ATTRIB and CHILDREN. */
-    if (!children && !attrib)
+    if (!children && !attrib) {
         Py_RETURN_NONE;
+    }
 
     /* Compute 'nchildren'. */
     if (children) {
@@ -981,32 +1005,48 @@ element_setstate_from_attributes(ElementObject *self,
             PyErr_SetString(PyExc_TypeError, "'_children' is not a list");
             return NULL;
         }
-        nchildren = PyList_Size(children);
-    }
-    else {
-        nchildren = 0;
-    }
+        nchildren = PyList_GET_SIZE(children);
 
-    /* Allocate 'extra'. */
-    if (element_resize(self, nchildren)) {
-        return NULL;
-    }
-    assert(self->extra && self->extra->allocated >= nchildren);
+        /* (Re-)allocate 'extra'.
+           Avoid DECREFs calling into this code again (cycles, etc.)
+         */
+        oldextra = self->extra;
+        self->extra = NULL;
+        if (element_resize(self, nchildren)) {
+            assert(!self->extra || !self->extra->length);
+            clear_extra(self);
+            self->extra = oldextra;
+            return NULL;
+        }
+        assert(self->extra);
+        assert(self->extra->allocated >= nchildren);
+        if (oldextra) {
+            assert(self->extra->attrib == Py_None);
+            self->extra->attrib = oldextra->attrib;
+            oldextra->attrib = Py_None;
+        }
 
-    /* Copy children */
-    for (i = 0; i < nchildren; i++) {
-        self->extra->children[i] = PyList_GET_ITEM(children, i);
-        Py_INCREF(self->extra->children[i]);
-    }
+        /* Copy children */
+        for (i = 0; i < nchildren; i++) {
+            self->extra->children[i] = PyList_GET_ITEM(children, i);
+            Py_INCREF(self->extra->children[i]);
+        }
 
-    self->extra->length = nchildren;
-    self->extra->allocated = nchildren;
+        assert(!self->extra->length);
+        self->extra->length = nchildren;
+    }
+    else {
+        if (element_resize(self, 0)) {
+            return NULL;
+        }
+    }
 
     /* Stash attrib. */
     if (attrib) {
         Py_INCREF(attrib);
         Py_XSETREF(self->extra->attrib, attrib);
     }
+    dealloc_extra(oldextra);
 
     Py_RETURN_NONE;
 }
@@ -1131,7 +1171,7 @@ _elementtree_Element_extend(ElementObject *self, PyObject *elements)
     for (i = 0; i < PySequence_Fast_GET_SIZE(seq); i++) {
         PyObject* element = PySequence_Fast_GET_ITEM(seq, i);
         Py_INCREF(element);
-        if (!PyObject_TypeCheck(element, (PyTypeObject *)&Element_Type)) {
+        if (!Element_Check(element)) {
             PyErr_Format(
                 PyExc_TypeError,
                 "expected an Element, not \"%.200s\"",
@@ -1183,7 +1223,7 @@ _elementtree_Element_find_impl(ElementObject *self, PyObject *path,
     for (i = 0; i < self->extra->length; i++) {
         PyObject* item = self->extra->children[i];
         int rc;
-        if (!Element_CheckExact(item))
+        if (!Element_Check(item))
             continue;
         Py_INCREF(item);
         rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ);
@@ -1227,14 +1267,14 @@ _elementtree_Element_findtext_impl(ElementObject *self, PyObject *path,
     }
 
     for (i = 0; i < self->extra->length; i++) {
-        ElementObject* item = (ElementObject*) self->extra->children[i];
+        PyObject *item = self->extra->children[i];
         int rc;
-        if (!Element_CheckExact(item))
+        if (!Element_Check(item))
             continue;
         Py_INCREF(item);
-        rc = PyObject_RichCompareBool(item->tag, path, Py_EQ);
+        rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ);
         if (rc > 0) {
-            PyObject* text = element_get_text(item);
+            PyObject* text = element_get_text((ElementObject*)item);
             if (text == Py_None) {
                 Py_DECREF(item);
                 return PyUnicode_New(0, 0);
@@ -1267,13 +1307,12 @@ _elementtree_Element_findall_impl(ElementObject *self, PyObject *path,
 {
     Py_ssize_t i;
     PyObject* out;
-    PyObject* tag = path;
     elementtreestate *st = ET_STATE_GLOBAL;
 
-    if (checkpath(tag) || namespaces != Py_None) {
+    if (checkpath(path) || namespaces != Py_None) {
         _Py_IDENTIFIER(findall);
         return _PyObject_CallMethodId(
-            st->elementpath_obj, &PyId_findall, "OOO", self, tag, namespaces
+            st->elementpath_obj, &PyId_findall, "OOO", self, path, namespaces
             );
     }
 
@@ -1287,10 +1326,10 @@ _elementtree_Element_findall_impl(ElementObject *self, PyObject *path,
     for (i = 0; i < self->extra->length; i++) {
         PyObject* item = self->extra->children[i];
         int rc;
-        if (!Element_CheckExact(item))
+        if (!Element_Check(item))
             continue;
         Py_INCREF(item);
-        rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, tag, Py_EQ);
+        rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ);
         if (rc != 0 && (rc < 0 || PyList_Append(out, item) < 0)) {
             Py_DECREF(item);
             Py_DECREF(out);
@@ -1794,7 +1833,6 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
              * scheduled for removal.
             */
             if (!(recycle = PyList_New(slicelen))) {
-                PyErr_NoMemory();
                 return -1;
             }
 
@@ -1834,7 +1872,7 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
             self->extra->length -= slicelen;
 
             /* Discard the recycle list with all the deleted sub-elements */
-            Py_XDECREF(recycle);
+            Py_DECREF(recycle);
             return 0;
         }
 
@@ -2145,7 +2183,7 @@ elementiter_next(ElementIterObject *it)
                 continue;
             }
 
-            if (!PyObject_TypeCheck(extra->children[child_index], &Element_Type)) {
+            if (!Element_Check(extra->children[child_index])) {
                 PyErr_Format(PyExc_AttributeError,
                              "'%.100s' object has no attribute 'iter'",
                              Py_TYPE(extra->children[child_index])->tp_name);
@@ -3274,7 +3312,6 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *html,
         if (!target) {
             Py_CLEAR(self->entity);
             Py_CLEAR(self->names);
-            EXPAT(ParserFree)(self->parser);
             return -1;
         }
     }
index 9e3a286..84edd72 100644 (file)
@@ -192,7 +192,7 @@ EVP_copy(EVPobject *self, PyObject *unused)
 }
 
 PyDoc_STRVAR(EVP_digest__doc__,
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
 
 static PyObject *
 EVP_digest(EVPobject *self, PyObject *unused)
index 6c54de7..d5884fa 100644 (file)
@@ -201,7 +201,7 @@ write_bytes(bytesio *self, const char *bytes, Py_ssize_t len)
 }
 
 static PyObject *
-bytesio_get_closed(bytesio *self)
+bytesio_get_closed(bytesio *self, void *Py_UNUSED(ignored))
 {
     if (self->buf == NULL) {
         Py_RETURN_TRUE;
index 52cbb94..e014552 100644 (file)
@@ -799,11 +799,9 @@ _io_FileIO_read_impl(fileio *self, Py_ssize_t size)
     if (size < 0)
         return _io_FileIO_readall_impl(self);
 
-#ifdef MS_WINDOWS
-    /* On Windows, the count parameter of read() is an int */
-    if (size > INT_MAX)
-        size = INT_MAX;
-#endif
+    if (size > _PY_READ_MAX) {
+        size = _PY_READ_MAX;
+    }
 
     bytes = PyBytes_FromStringAndSize(NULL, size);
     if (bytes == NULL)
index d582d3f..ebc3c04 100644 (file)
@@ -268,7 +268,7 @@ _io_IncrementalNewlineDecoder___init___impl(nldecoder_object *self,
         self->errors = errors;
     }
 
-    self->translate = translate;
+    self->translate = translate ? 1 : 0;
     self->seennl = 0;
     self->pendingcr = 0;
 
index 979bcfc..2f36806 100644 (file)
@@ -832,11 +832,13 @@ _io__WindowsConsoleIO_readall_impl(winconsoleio *self)
             }
             bufsize = newsize;
 
-            buf = PyMem_Realloc(buf, (bufsize + 1) * sizeof(wchar_t));
-            if (!buf) {
+            wchar_t *tmp = PyMem_Realloc(buf,
+                                         (bufsize + 1) * sizeof(wchar_t));
+            if (tmp == NULL) {
                 PyMem_Free(buf);
                 return NULL;
             }
+            buf = tmp;
         }
 
         subbuf = read_console_w(self->handle, bufsize - len, &n);
index 95b370b..eba8289 100644 (file)
@@ -70,20 +70,13 @@ copy_grouping(const char* s)
     do {
         i++;
         val = PyLong_FromLong(s[i]);
-        if (!val)
-            break;
-        if (PyList_SetItem(result, i, val)) {
-            Py_DECREF(val);
-            val = NULL;
-            break;
+        if (val == NULL) {
+            Py_DECREF(result);
+            return NULL;
         }
+        PyList_SET_ITEM(result, i, val);
     } while (s[i] != '\0' && s[i] != CHAR_MAX);
 
-    if (!val) {
-        Py_DECREF(result);
-        return NULL;
-    }
-
     return result;
 }
 
@@ -128,6 +121,82 @@ PyLocale_setlocale(PyObject* self, PyObject* args)
     return result_object;
 }
 
+static int
+locale_is_ascii(const char *str)
+{
+    return (strlen(str) == 1 && ((unsigned char)str[0]) <= 127);
+}
+
+static int
+locale_decode_monetary(PyObject *dict, struct lconv *lc)
+{
+    int change_locale;
+    change_locale = (!locale_is_ascii(lc->int_curr_symbol)
+                     || !locale_is_ascii(lc->currency_symbol)
+                     || !locale_is_ascii(lc->mon_decimal_point)
+                     || !locale_is_ascii(lc->mon_thousands_sep));
+
+    /* Keep a copy of the LC_CTYPE locale */
+    char *oldloc = NULL, *loc = NULL;
+    if (change_locale) {
+        oldloc = setlocale(LC_CTYPE, NULL);
+        if (!oldloc) {
+            PyErr_SetString(PyExc_RuntimeWarning,
+                            "failed to get LC_CTYPE locale");
+            return -1;
+        }
+
+        oldloc = _PyMem_Strdup(oldloc);
+        if (!oldloc) {
+            PyErr_NoMemory();
+            return -1;
+        }
+
+        loc = setlocale(LC_MONETARY, NULL);
+        if (loc != NULL && strcmp(loc, oldloc) == 0) {
+            loc = NULL;
+        }
+
+        if (loc != NULL) {
+            /* Only set the locale temporarily the LC_CTYPE locale
+               to the LC_MONETARY locale if the two locales are different and
+               at least one string is non-ASCII. */
+            setlocale(LC_CTYPE, loc);
+        }
+    }
+
+    int res = -1;
+
+#define RESULT_STRING(ATTR) \
+    do { \
+        PyObject *obj; \
+        obj = PyUnicode_DecodeLocale(lc->ATTR, NULL); \
+        if (obj == NULL) { \
+            goto done; \
+        } \
+        if (PyDict_SetItemString(dict, Py_STRINGIFY(ATTR), obj) < 0) { \
+            Py_DECREF(obj); \
+            goto done; \
+        } \
+        Py_DECREF(obj); \
+    } while (0)
+
+    RESULT_STRING(int_curr_symbol);
+    RESULT_STRING(currency_symbol);
+    RESULT_STRING(mon_decimal_point);
+    RESULT_STRING(mon_thousands_sep);
+#undef RESULT_STRING
+
+    res = 0;
+
+done:
+    if (loc != NULL) {
+        setlocale(LC_CTYPE, oldloc);
+    }
+    PyMem_Free(oldloc);
+    return res;
+}
+
 PyDoc_STRVAR(localeconv__doc__,
 "() -> dict. Returns numeric and monetary locale-specific parameters.");
 
@@ -171,11 +240,10 @@ PyLocale_localeconv(PyObject* self)
         RESULT(#i, x); \
     } while (0)
 
-    /* Monetary information */
-    RESULT_STRING(int_curr_symbol);
-    RESULT_STRING(currency_symbol);
-    RESULT_STRING(mon_decimal_point);
-    RESULT_STRING(mon_thousands_sep);
+    /* Monetary information: LC_MONETARY encoding */
+    if (locale_decode_monetary(result, l) < 0) {
+        goto failed;
+    }
     x = copy_grouping(l->mon_grouping);
     RESULT("mon_grouping", x);
 
@@ -190,7 +258,7 @@ PyLocale_localeconv(PyObject* self)
     RESULT_INT(p_sign_posn);
     RESULT_INT(n_sign_posn);
 
-    /* Numeric information */
+    /* Numeric information: LC_NUMERIC encoding */
     PyObject *decimal_point, *thousands_sep;
     const char *grouping;
     if (_Py_GetLocaleconvNumeric(&decimal_point,
@@ -220,6 +288,10 @@ PyLocale_localeconv(PyObject* self)
   failed:
     Py_XDECREF(result);
     return NULL;
+
+#undef RESULT
+#undef RESULT_STRING
+#undef RESULT_INT
 }
 
 #if defined(HAVE_WCSCOLL)
index c265507..3d3645a 100644 (file)
@@ -119,7 +119,7 @@ catch_lzma_error(lzma_ret lzret)
 static void*
 PyLzma_Malloc(void *opaque, size_t items, size_t size)
 {
-    if (items > (size_t)PY_SSIZE_T_MAX / size)
+    if (size != 0 && items > (size_t)PY_SSIZE_T_MAX / size)
         return NULL;
     /* PyMem_Malloc() cannot be used:
        the GIL is not held when lzma_code() is called */
index cea962a..4ff454f 100644 (file)
@@ -439,8 +439,9 @@ semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 
     if (!unlink) {
         name_copy = PyMem_Malloc(strlen(name) + 1);
-        if (name_copy == NULL)
-            goto failure;
+        if (name_copy == NULL) {
+            return PyErr_NoMemory();
+        }
         strcpy(name_copy, name);
     }
 
@@ -463,7 +464,9 @@ semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     if (handle != SEM_FAILED)
         SEM_CLOSE(handle);
     PyMem_Free(name_copy);
-    _PyMp_SetError(NULL, MP_STANDARD_ERROR);
+    if (!PyErr_Occurred()) {
+        _PyMp_SetError(NULL, MP_STANDARD_ERROR);
+    }
     return NULL;
 }
 
index fb8eafc..af05f1c 100644 (file)
@@ -1057,6 +1057,7 @@ methodcaller_repr(methodcallerobject *mc)
                 goto done;
             if (i >= numtotalargs) {
                 i = -1;
+                Py_DECREF(onerepr);
                 break;
             }
             PyTuple_SET_ITEM(argreprs, i, onerepr);
index 0a7e20e..41b8fa7 100644 (file)
@@ -200,19 +200,15 @@ _Pickle_ClearState(PickleState *st)
 static int
 _Pickle_InitState(PickleState *st)
 {
-    PyObject *builtins;
     PyObject *copyreg = NULL;
     PyObject *compat_pickle = NULL;
     PyObject *codecs = NULL;
     PyObject *functools = NULL;
+    _Py_IDENTIFIER(getattr);
 
-    builtins = PyEval_GetBuiltins();
-    if (builtins == NULL)
-        goto error;
-    st->getattr = PyDict_GetItemString(builtins, "getattr");
+    st->getattr = _PyEval_GetBuiltinId(&PyId_getattr);
     if (st->getattr == NULL)
         goto error;
-    Py_INCREF(st->getattr);
 
     copyreg = PyImport_ImportModule("copyreg");
     if (!copyreg)
@@ -3743,7 +3739,10 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj)
 
         if (obj != NULL) {
             obj_class = get_class(obj);
-            p = obj_class != cls;    /* true iff a problem */
+            if (obj_class == NULL) {
+                return -1;
+            }
+            p = obj_class != cls;
             Py_DECREF(obj_class);
             if (p) {
                 PyErr_SetString(st->PicklingError, "args[0] from "
@@ -4476,13 +4475,13 @@ PicklerMemoProxy_New(PicklerObject *pickler)
 /*****************************************************************************/
 
 static PyObject *
-Pickler_get_memo(PicklerObject *self)
+Pickler_get_memo(PicklerObject *self, void *Py_UNUSED(ignored))
 {
     return PicklerMemoProxy_New(self);
 }
 
 static int
-Pickler_set_memo(PicklerObject *self, PyObject *obj)
+Pickler_set_memo(PicklerObject *self, PyObject *obj, void *Py_UNUSED(ignored))
 {
     PyMemoTable *new_memo = NULL;
 
@@ -4527,7 +4526,7 @@ Pickler_set_memo(PicklerObject *self, PyObject *obj)
     }
     else {
         PyErr_Format(PyExc_TypeError,
-                     "'memo' attribute must be a PicklerMemoProxy object"
+                     "'memo' attribute must be a PicklerMemoProxy object "
                      "or dict, not %.200s", Py_TYPE(obj)->tp_name);
         return -1;
     }
@@ -4544,7 +4543,7 @@ Pickler_set_memo(PicklerObject *self, PyObject *obj)
 }
 
 static PyObject *
-Pickler_get_persid(PicklerObject *self)
+Pickler_get_persid(PicklerObject *self, void *Py_UNUSED(ignored))
 {
     if (self->pers_func == NULL) {
         PyErr_SetString(PyExc_AttributeError, "persistent_id");
@@ -4554,7 +4553,7 @@ Pickler_get_persid(PicklerObject *self)
 }
 
 static int
-Pickler_set_persid(PicklerObject *self, PyObject *value)
+Pickler_set_persid(PicklerObject *self, PyObject *value, void *Py_UNUSED(ignored))
 {
     if (value == NULL) {
         PyErr_SetString(PyExc_TypeError,
@@ -6908,13 +6907,13 @@ UnpicklerMemoProxy_New(UnpicklerObject *unpickler)
 
 
 static PyObject *
-Unpickler_get_memo(UnpicklerObject *self)
+Unpickler_get_memo(UnpicklerObject *self, void *Py_UNUSED(ignored))
 {
     return UnpicklerMemoProxy_New(self);
 }
 
 static int
-Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
+Unpickler_set_memo(UnpicklerObject *self, PyObject *obj, void *Py_UNUSED(ignored))
 {
     PyObject **new_memo;
     size_t new_memo_size = 0;
@@ -6969,7 +6968,7 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
     }
     else {
         PyErr_Format(PyExc_TypeError,
-                     "'memo' attribute must be an UnpicklerMemoProxy object"
+                     "'memo' attribute must be an UnpicklerMemoProxy object "
                      "or dict, not %.200s", Py_TYPE(obj)->tp_name);
         return -1;
     }
@@ -6991,7 +6990,7 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
 }
 
 static PyObject *
-Unpickler_get_persload(UnpicklerObject *self)
+Unpickler_get_persload(UnpicklerObject *self, void *Py_UNUSED(ignored))
 {
     if (self->pers_func == NULL) {
         PyErr_SetString(PyExc_AttributeError, "persistent_load");
@@ -7001,7 +7000,7 @@ Unpickler_get_persload(UnpicklerObject *self)
 }
 
 static int
-Unpickler_set_persload(UnpicklerObject *self, PyObject *value)
+Unpickler_set_persload(UnpicklerObject *self, PyObject *value, void *Py_UNUSED(ignored))
 {
     if (value == NULL) {
         PyErr_SetString(PyExc_TypeError,
index fe0e554..07dd54d 100644 (file)
 #include <dirent.h>
 #endif
 
+#ifdef _Py_MEMORY_SANITIZER
+# include <sanitizer/msan_interface.h>
+#endif
+
 #if defined(__ANDROID__) && __ANDROID_API__ < 21 && !defined(SYS_getdents64)
 # include <sys/linux-syscalls.h>
 # define SYS_getdents64  __NR_getdents64
@@ -287,6 +291,9 @@ _close_open_fds_safe(int start_fd, PyObject* py_fds_to_keep)
                                 sizeof(buffer))) > 0) {
             struct linux_dirent64 *entry;
             int offset;
+#ifdef _Py_MEMORY_SANITIZER
+            __msan_unpoison(buffer, bytes);
+#endif
             for (offset = 0; offset < bytes; offset += entry->d_reclen) {
                 int fd;
                 entry = (struct linux_dirent64 *)(buffer + offset);
@@ -791,11 +798,11 @@ static PyMethodDef module_methods[] = {
 
 
 static struct PyModuleDef _posixsubprocessmodule = {
-       PyModuleDef_HEAD_INIT,
-       "_posixsubprocess",
-       module_doc,
-       -1,  /* No memory is needed. */
-       module_methods,
+        PyModuleDef_HEAD_INIT,
+        "_posixsubprocess",
+        module_doc,
+        -1,  /* No memory is needed. */
+        module_methods,
 };
 
 PyMODINIT_FUNC
index f503288..326d268 100644 (file)
@@ -51,7 +51,7 @@ static const char * const begin_statements[] = {
     NULL
 };
 
-static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level);
+static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level, void *Py_UNUSED(ignored));
 static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
 
 
@@ -136,7 +136,7 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
         Py_INCREF(isolation_level);
     }
     self->isolation_level = NULL;
-    if (pysqlite_connection_set_isolation_level(self, isolation_level) < 0) {
+    if (pysqlite_connection_set_isolation_level(self, isolation_level, NULL) < 0) {
         Py_DECREF(isolation_level);
         return -1;
     }
@@ -836,18 +836,17 @@ PyObject* pysqlite_connection_create_function(pysqlite_Connection* self, PyObjec
         return NULL;
     }
 
+    if (PyDict_SetItem(self->function_pinboard, func, Py_None) == -1) {
+        return NULL;
+    }
     rc = sqlite3_create_function(self->db, name, narg, SQLITE_UTF8, (void*)func, _pysqlite_func_callback, NULL, NULL);
 
     if (rc != SQLITE_OK) {
         /* Workaround for SQLite bug: no error code or string is available here */
         PyErr_SetString(pysqlite_OperationalError, "Error creating function");
         return NULL;
-    } else {
-        if (PyDict_SetItem(self->function_pinboard, func, Py_None) == -1)
-            return NULL;
-
-        Py_RETURN_NONE;
     }
+    Py_RETURN_NONE;
 }
 
 PyObject* pysqlite_connection_create_aggregate(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
@@ -868,17 +867,16 @@ PyObject* pysqlite_connection_create_aggregate(pysqlite_Connection* self, PyObje
         return NULL;
     }
 
+    if (PyDict_SetItem(self->function_pinboard, aggregate_class, Py_None) == -1) {
+        return NULL;
+    }
     rc = sqlite3_create_function(self->db, name, n_arg, SQLITE_UTF8, (void*)aggregate_class, 0, &_pysqlite_step_callback, &_pysqlite_final_callback);
     if (rc != SQLITE_OK) {
         /* Workaround for SQLite bug: no error code or string is available here */
         PyErr_SetString(pysqlite_OperationalError, "Error creating aggregate");
         return NULL;
-    } else {
-        if (PyDict_SetItem(self->function_pinboard, aggregate_class, Py_None) == -1)
-            return NULL;
-
-        Py_RETURN_NONE;
     }
+    Py_RETURN_NONE;
 }
 
 static int _authorizer_callback(void* user_arg, int action, const char* arg1, const char* arg2 , const char* dbname, const char* access_attempt_source)
@@ -1003,17 +1001,15 @@ static PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, P
         return NULL;
     }
 
+    if (PyDict_SetItem(self->function_pinboard, authorizer_cb, Py_None) == -1) {
+        return NULL;
+    }
     rc = sqlite3_set_authorizer(self->db, _authorizer_callback, (void*)authorizer_cb);
-
     if (rc != SQLITE_OK) {
         PyErr_SetString(pysqlite_OperationalError, "Error setting authorizer callback");
         return NULL;
-    } else {
-        if (PyDict_SetItem(self->function_pinboard, authorizer_cb, Py_None) == -1)
-            return NULL;
-
-        Py_RETURN_NONE;
     }
+    Py_RETURN_NONE;
 }
 
 static PyObject* pysqlite_connection_set_progress_handler(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
@@ -1036,9 +1032,9 @@ static PyObject* pysqlite_connection_set_progress_handler(pysqlite_Connection* s
         /* None clears the progress handler previously set */
         sqlite3_progress_handler(self->db, 0, 0, (void*)0);
     } else {
-        sqlite3_progress_handler(self->db, n, _progress_handler, progress_handler);
         if (PyDict_SetItem(self->function_pinboard, progress_handler, Py_None) == -1)
             return NULL;
+        sqlite3_progress_handler(self->db, n, _progress_handler, progress_handler);
     }
 
     Py_RETURN_NONE;
@@ -1162,7 +1158,8 @@ static PyObject* pysqlite_connection_get_in_transaction(pysqlite_Connection* sel
     Py_RETURN_FALSE;
 }
 
-static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level)
+static int
+pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level, void *Py_UNUSED(ignored))
 {
     if (isolation_level == Py_None) {
         PyObject *res = pysqlite_connection_commit(self, NULL);
index 53342f3..8c53f89 100644 (file)
@@ -150,7 +150,8 @@ PyObject* pysqlite_row_subscript(pysqlite_Row* self, PyObject* idx)
     }
 }
 
-Py_ssize_t pysqlite_row_length(pysqlite_Row* self, PyObject* args, PyObject* kwargs)
+static Py_ssize_t
+pysqlite_row_length(pysqlite_Row* self)
 {
     return PyTuple_GET_SIZE(self->data);
 }
index d092496..a4b7e72 100644 (file)
@@ -1424,7 +1424,7 @@ PyDoc_STRVAR(pattern_doc, "Compiled regular expression objects");
 
 /* PatternObject's 'groupindex' method. */
 static PyObject *
-pattern_groupindex(PatternObject *self)
+pattern_groupindex(PatternObject *self, void *Py_UNUSED(ignored))
 {
     return PyDictProxy_New(self->groupindex);
 }
@@ -2426,7 +2426,7 @@ PyDoc_STRVAR(match_group_doc,
     For 0 returns the entire match.");
 
 static PyObject *
-match_lastindex_get(MatchObject *self)
+match_lastindex_get(MatchObject *self, void *Py_UNUSED(ignored))
 {
     if (self->lastindex >= 0)
         return PyLong_FromSsize_t(self->lastindex);
@@ -2435,7 +2435,7 @@ match_lastindex_get(MatchObject *self)
 }
 
 static PyObject *
-match_lastgroup_get(MatchObject *self)
+match_lastgroup_get(MatchObject *self, void *Py_UNUSED(ignored))
 {
     if (self->pattern->indexgroup && self->lastindex >= 0) {
         PyObject* result = PySequence_GetItem(
@@ -2450,7 +2450,7 @@ match_lastgroup_get(MatchObject *self)
 }
 
 static PyObject *
-match_regs_get(MatchObject *self)
+match_regs_get(MatchObject *self, void *Py_UNUSED(ignored))
 {
     if (self->regs) {
         Py_INCREF(self->regs);
index b0cfbdc..a188d6a 100644 (file)
@@ -685,6 +685,11 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
     PySSL_BEGIN_ALLOW_THREADS
     self->ssl = SSL_new(ctx);
     PySSL_END_ALLOW_THREADS
+    if (self->ssl == NULL) {
+        Py_DECREF(self);
+        _setSSLError(NULL, 0, __FILE__, __LINE__);
+        return NULL;
+    }
     SSL_set_app_data(self->ssl, self);
     if (sock) {
         SSL_set_fd(self->ssl, Py_SAFE_DOWNCAST(sock->sock_fd, SOCKET_T, int));
@@ -1040,6 +1045,10 @@ _get_peer_alt_names (X509 *certificate) {
 
     /* get a memory buffer */
     biobuf = BIO_new(BIO_s_mem());
+    if (biobuf == NULL) {
+        PyErr_SetString(PySSLErrorObject, "failed to allocate BIO");
+        return NULL;
+    }
 
     i = -1;
     while ((i = X509_get_ext_by_NID(
@@ -1415,6 +1424,10 @@ _decode_certificate(X509 *certificate) {
 
     /* get a memory buffer */
     biobuf = BIO_new(BIO_s_mem());
+    if (biobuf == NULL) {
+        PyErr_SetString(PySSLErrorObject, "failed to allocate BIO");
+        goto fail0;
+    }
 
     (void) BIO_reset(biobuf);
     serialNumber = X509_get_serialNumber(certificate);
@@ -4365,12 +4378,17 @@ _ssl_MemoryBIO_read_impl(PySSLMemoryBIO *self, int len)
         return result;
 
     nbytes = BIO_read(self->bio, PyBytes_AS_STRING(result), len);
-    /* There should never be any short reads but check anyway. */
-    if ((nbytes < len) && (_PyBytes_Resize(&result, len) < 0)) {
+    if (nbytes < 0) {
         Py_DECREF(result);
+        _setSSLError(NULL, 0, __FILE__, __LINE__);
         return NULL;
     }
 
+    /* There should never be any short reads but check anyway. */
+    if (nbytes < len) {
+        _PyBytes_Resize(&result, nbytes);
+    }
+
     return result;
 }
 
index 669794d..a16b96d 100644 (file)
@@ -1531,7 +1531,7 @@ ndarray_getbuf(NDArrayObject *self, Py_buffer *view, int flags)
     return 0;
 }
 
-static int
+static void
 ndarray_releasebuf(NDArrayObject *self, Py_buffer *view)
 {
     if (!ND_IS_CONSUMER(self)) {
@@ -1539,8 +1539,6 @@ ndarray_releasebuf(NDArrayObject *self, Py_buffer *view)
         if (--ndbuf->exports == 0 && ndbuf != self->head)
             ndbuf_delete(self, ndbuf);
     }
-
-    return 0;
 }
 
 static PyBufferProcs ndarray_as_buffer = {
index 556d49b..067d463 100644 (file)
@@ -952,7 +952,7 @@ test_buildvalue_N_error(const char *fmt)
 }
 
 static PyObject *
-test_buildvalue_N(PyObject *self, PyObject *noargs)
+test_buildvalue_N(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
     PyObject *arg, *res;
 
@@ -2351,7 +2351,7 @@ pending_threadfunc(PyObject *self, PyObject *arg)
 
 /* Some tests of PyUnicode_FromFormat().  This needs more tests. */
 static PyObject *
-test_string_from_format(PyObject *self, PyObject *args)
+test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
     PyObject *result;
     char *msg;
@@ -2491,7 +2491,7 @@ typedef struct {
 } known_capsule;
 
 static PyObject *
-test_capsule(PyObject *self, PyObject *args)
+test_capsule(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
     PyObject *object;
     const char *error = NULL;
@@ -2863,7 +2863,7 @@ make_memoryview_from_NULL_pointer(PyObject *self)
 }
 
 static PyObject *
-test_from_contiguous(PyObject* self, PyObject *noargs)
+test_from_contiguous(PyObject* self, PyObject *Py_UNUSED(ignored))
 {
     int data[9] = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
     int init[5] = {0, 1, 2, 3, 4};
@@ -2916,7 +2916,7 @@ test_from_contiguous(PyObject* self, PyObject *noargs)
 extern PyTypeObject _PyBytesIOBuffer_Type;
 
 static PyObject *
-test_pep3118_obsolete_write_locks(PyObject* self, PyObject *noargs)
+test_pep3118_obsolete_write_locks(PyObject* self, PyObject *Py_UNUSED(ignored))
 {
     PyTypeObject *type = &_PyBytesIOBuffer_Type;
     PyObject *b;
index c504b57..a13b2e0 100644 (file)
@@ -785,9 +785,11 @@ local_clear(localobject *self)
         for(tstate = PyInterpreterState_ThreadHead(tstate->interp);
             tstate;
             tstate = PyThreadState_Next(tstate))
-            if (tstate->dict &&
-                PyDict_GetItem(tstate->dict, self->key))
-                PyDict_DelItem(tstate->dict, self->key);
+            if (tstate->dict && PyDict_GetItem(tstate->dict, self->key)) {
+                if (PyDict_DelItem(tstate->dict, self->key)) {
+                    PyErr_Clear();
+                }
+            }
     }
     return 0;
 }
index 68ee26e..473e601 100644 (file)
@@ -864,7 +864,7 @@ PyTclObject_string(PyTclObject *self, void *ignored)
 }
 
 static PyObject *
-PyTclObject_str(PyTclObject *self, void *ignored)
+PyTclObject_str(PyTclObject *self)
 {
     if (self->string) {
         Py_INCREF(self->string);
@@ -877,7 +877,7 @@ PyTclObject_str(PyTclObject *self, void *ignored)
 static PyObject *
 PyTclObject_repr(PyTclObject *self)
 {
-    PyObject *repr, *str = PyTclObject_str(self, NULL);
+    PyObject *repr, *str = PyTclObject_str(self);
     if (str == NULL)
         return NULL;
     repr = PyUnicode_FromFormat("<%s object: %R>",
@@ -1153,9 +1153,7 @@ AsObj(PyObject *value)
     }
 
     if (PyTclObject_Check(value)) {
-        Tcl_Obj *v = ((PyTclObject*)value)->value;
-        Tcl_IncrRefCount(v);
-        return v;
+        return ((PyTclObject*)value)->value;
     }
 
     {
index 4f3bb54..a61bdb6 100644 (file)
@@ -1492,6 +1492,12 @@ _PyMem_DumpTraceback(int fd, const void *ptr)
     traceback_t *traceback;
     int i;
 
+    if (!tracemalloc_config.tracing) {
+        PUTS(fd, "Enable tracemalloc to get the memory block "
+                 "allocation traceback\n\n");
+        return;
+    }
+
     traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
     if (traceback == NULL)
         return;
index 9254af5..bc3f62d 100644 (file)
@@ -1499,12 +1499,18 @@ array_array_fromlist(arrayobject *self, PyObject *list)
         if (array_resize(self, old_size + n) == -1)
             return NULL;
         for (i = 0; i < n; i++) {
-            PyObject *v = PyList_GetItem(list, i);
+            PyObject *v = PyList_GET_ITEM(list, i);
             if ((*self->ob_descr->setitem)(self,
                             Py_SIZE(self) - n + i, v) != 0) {
                 array_resize(self, old_size);
                 return NULL;
             }
+            if (n != PyList_GET_SIZE(list)) {
+                PyErr_SetString(PyExc_RuntimeError,
+                                "list changed size during iteration");
+                array_resize(self, old_size);
+                return NULL;
+            }
         }
     }
     Py_INCREF(Py_None);
@@ -1530,8 +1536,7 @@ array_array_tolist_impl(arrayobject *self)
         PyObject *v = getarrayitem((PyObject *)self, i);
         if (v == NULL)
             goto error;
-        if (PyList_SetItem(list, i, v) < 0)
-            goto error;
+        PyList_SET_ITEM(list, i, v);
     }
     return list;
 
index 2c7788a..3a33295 100644 (file)
@@ -40,7 +40,7 @@ ENCODER(cp932)
             if (c == 0xf8f0)
                 OUTBYTE1(0xa0);
             else
-                OUTBYTE1(c - 0xfef1 + 0xfd);
+                OUTBYTE1(c - 0xf8f1 + 0xfd);
             NEXT(1, 1);
             continue;
         }
index d6efc77..e85ec56 100644 (file)
@@ -108,7 +108,7 @@ call_error_callback(PyObject *errors, PyObject *exc)
 }
 
 static PyObject *
-codecctx_errors_get(MultibyteStatefulCodecContext *self)
+codecctx_errors_get(MultibyteStatefulCodecContext *self, void *Py_UNUSED(ignored))
 {
     const char *errors;
 
index a841fe5..8a10860 100644 (file)
@@ -24,7 +24,7 @@ PyDoc_STRVAR(MD5Type_digest__doc__,
 "digest($self, /)\n"
 "--\n"
 "\n"
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
 
 #define MD5TYPE_DIGEST_METHODDEF    \
     {"digest", (PyCFunction)MD5Type_digest, METH_NOARGS, MD5Type_digest__doc__},
@@ -94,4 +94,4 @@ _md5_md5(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=54cd50db050f2589 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=1761d10cec19a4c2 input=a9049054013a1b77]*/
index 0d3ce6e..e615e00 100644 (file)
@@ -9,7 +9,7 @@ PyDoc_STRVAR(os_stat__doc__,
 "Perform a stat system call on the given path.\n"
 "\n"
 "  path\n"
-"    Path to be examined; can be string, bytes, path-like object or\n"
+"    Path to be examined; can be string, bytes, path-like object or\n"
 "    open-file-descriptor int.\n"
 "  dir_fd\n"
 "    If not None, it should be a file descriptor open to a directory,\n"
@@ -101,7 +101,7 @@ PyDoc_STRVAR(os_access__doc__,
 "Use the real uid/gid to test for access to a path.\n"
 "\n"
 "  path\n"
-"    Path to be tested; can be string or bytes\n"
+"    Path to be tested; can be string, bytes, or a path-like object.\n"
 "  mode\n"
 "    Operating-system mode bitfield.  Can be F_OK to test existence,\n"
 "    or the inclusive-OR of R_OK, W_OK, and X_OK.\n"
@@ -304,7 +304,7 @@ PyDoc_STRVAR(os_chmod__doc__,
 "Change the access permissions of a file.\n"
 "\n"
 "  path\n"
-"    Path to be modified.  May always be specified as a str or bytes.\n"
+"    Path to be modified.  May always be specified as a str, bytes, or a path-like object.\n"
 "    On some platforms, path may also be specified as an open file descriptor.\n"
 "    If this functionality is unavailable, using it raises an exception.\n"
 "  mode\n"
@@ -655,7 +655,7 @@ PyDoc_STRVAR(os_chown__doc__,
 "Change the owner and group id of path to the numeric uid and gid.\\\n"
 "\n"
 "  path\n"
-"    Path to be examined; can be string, bytes, or open-file-descriptor int.\n"
+"    Path to be examined; can be string, bytes, a path-like object, or open-file-descriptor int.\n"
 "  dir_fd\n"
 "    If not None, it should be a file descriptor open to a directory,\n"
 "    and path should be relative; path will then be relative to that\n"
@@ -889,7 +889,7 @@ PyDoc_STRVAR(os_listdir__doc__,
 "\n"
 "Return a list containing the names of the files in the directory.\n"
 "\n"
-"path can be specified as either str or bytes.  If path is bytes,\n"
+"path can be specified as either str, bytes, or a path-like object.  If path is bytes,\n"
 "  the filenames returned will also be bytes; in all other circumstances\n"
 "  the filenames returned will be str.\n"
 "If path is None, uses the path=\'.\'.\n"
@@ -5234,7 +5234,7 @@ PyDoc_STRVAR(os_getxattr__doc__,
 "\n"
 "Return the value of extended attribute attribute on path.\n"
 "\n"
-"path may be either a string or an open file descriptor.\n"
+"path may be either a string, a path-like object, or an open file descriptor.\n"
 "If follow_symlinks is False, and the last element of the path is a symbolic\n"
 "  link, getxattr will examine the symbolic link itself instead of the file\n"
 "  the link points to.");
@@ -5282,7 +5282,7 @@ PyDoc_STRVAR(os_setxattr__doc__,
 "\n"
 "Set extended attribute attribute on path to value.\n"
 "\n"
-"path may be either a string or an open file descriptor.\n"
+"path may be either a string, a path-like object,  or an open file descriptor.\n"
 "If follow_symlinks is False, and the last element of the path is a symbolic\n"
 "  link, setxattr will modify the symbolic link itself instead of the file\n"
 "  the link points to.");
@@ -5335,7 +5335,7 @@ PyDoc_STRVAR(os_removexattr__doc__,
 "\n"
 "Remove extended attribute attribute on path.\n"
 "\n"
-"path may be either a string or an open file descriptor.\n"
+"path may be either a string, a path-like object, or an open file descriptor.\n"
 "If follow_symlinks is False, and the last element of the path is a symbolic\n"
 "  link, removexattr will modify the symbolic link itself instead of the file\n"
 "  the link points to.");
@@ -5382,7 +5382,7 @@ PyDoc_STRVAR(os_listxattr__doc__,
 "\n"
 "Return a list of extended attributes on path.\n"
 "\n"
-"path may be either None, a string, or an open file descriptor.\n"
+"path may be either None, a string, a path-like object, or an open file descriptor.\n"
 "if path is None, listxattr will examine the current directory.\n"
 "If follow_symlinks is False, and the last element of the path is a symbolic\n"
 "  link, listxattr will examine the symbolic link itself instead of the file\n"
@@ -6150,4 +6150,4 @@ exit:
 #ifndef OS_GETRANDOM_METHODDEF
     #define OS_GETRANDOM_METHODDEF
 #endif /* !defined(OS_GETRANDOM_METHODDEF) */
-/*[clinic end generated code: output=455def991740915a input=a9049054013a1b77]*/
+/*[clinic end generated code: output=92026f29ec925950 input=a9049054013a1b77]*/
index b08e92d..71b4a34 100644 (file)
@@ -24,7 +24,7 @@ PyDoc_STRVAR(SHA1Type_digest__doc__,
 "digest($self, /)\n"
 "--\n"
 "\n"
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
 
 #define SHA1TYPE_DIGEST_METHODDEF    \
     {"digest", (PyCFunction)SHA1Type_digest, METH_NOARGS, SHA1Type_digest__doc__},
@@ -94,4 +94,4 @@ _sha1_sha1(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwname
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=1430450f3f806895 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=34e9cee5761f2a36 input=a9049054013a1b77]*/
index 115db50..bf609be 100644 (file)
@@ -24,7 +24,7 @@ PyDoc_STRVAR(SHA256Type_digest__doc__,
 "digest($self, /)\n"
 "--\n"
 "\n"
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
 
 #define SHA256TYPE_DIGEST_METHODDEF    \
     {"digest", (PyCFunction)SHA256Type_digest, METH_NOARGS, SHA256Type_digest__doc__},
@@ -124,4 +124,4 @@ _sha256_sha224(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kw
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=19439d70db7ead5c input=a9049054013a1b77]*/
+/*[clinic end generated code: output=3babbe1e753c1a38 input=a9049054013a1b77]*/
index a2b57f7..264c9f4 100644 (file)
@@ -24,7 +24,7 @@ PyDoc_STRVAR(SHA512Type_digest__doc__,
 "digest($self, /)\n"
 "--\n"
 "\n"
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
 
 #define SHA512TYPE_DIGEST_METHODDEF    \
     {"digest", (PyCFunction)SHA512Type_digest, METH_NOARGS, SHA512Type_digest__doc__},
@@ -124,4 +124,4 @@ _sha512_sha384(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kw
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=18f15598c3487045 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=59a43fa6eb3b5f4f input=a9049054013a1b77]*/
index 629483a..2d96b4f 100644 (file)
 
 /* External API definitions */
 
+/* Namespace external symbols to allow multiple libexpat version to
+   co-exist. */
+#include "pyexpatns.h"
+
 #if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
 # define XML_USE_MSC_EXTENSIONS 1
 #endif
index 6b415d8..6371a35 100644 (file)
@@ -30,6 +30,9 @@
    USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
+#if !defined(_WIN32) && defined(HAVE_EXPAT_CONFIG_H)
+#  include <pyconfig.h>
+#endif
 #include <stddef.h>
 #include <string.h>  /* memcpy */
 
index 227424f..890c645 100644 (file)
@@ -1393,7 +1393,7 @@ void _PyFaulthandler_Fini(void)
 #ifdef HAVE_SIGALTSTACK
     if (stack.ss_sp != NULL) {
         /* Fetch the current alt stack */
-        stack_t current_stack;
+        stack_t current_stack = {};
         if (sigaltstack(NULL, &current_stack) == 0) {
             if (current_stack.ss_sp == stack.ss_sp) {
                 /* The current alt stack is the one that we installed.
index 8875b26..b5eea49 100644 (file)
@@ -64,6 +64,7 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
     char *str;
     Py_ssize_t len;
     char buf[1024];
+    int async_err = 0;
 
     if (arg != NULL) {
         int parse_result;
@@ -75,12 +76,13 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
                 return NULL;
             }
             memcpy(buf, str, len);
-            Py_BEGIN_ALLOW_THREADS
-            ret = fcntl(fd, code, buf);
-            Py_END_ALLOW_THREADS
+            do {
+                Py_BEGIN_ALLOW_THREADS
+                ret = fcntl(fd, code, buf);
+                Py_END_ALLOW_THREADS
+            } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
             if (ret < 0) {
-                PyErr_SetFromErrno(PyExc_IOError);
-                return NULL;
+                return !async_err ? PyErr_SetFromErrno(PyExc_IOError) : NULL;
             }
             return PyBytes_FromStringAndSize(buf, len);
         }
@@ -95,12 +97,13 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
         }
     }
 
-    Py_BEGIN_ALLOW_THREADS
-    ret = fcntl(fd, code, (int)int_arg);
-    Py_END_ALLOW_THREADS
+    do {
+        Py_BEGIN_ALLOW_THREADS
+        ret = fcntl(fd, code, (int)int_arg);
+        Py_END_ALLOW_THREADS
+    } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
     if (ret < 0) {
-        PyErr_SetFromErrno(PyExc_IOError);
-        return NULL;
+        return !async_err ? PyErr_SetFromErrno(PyExc_IOError) : NULL;
     }
     return PyLong_FromLong((long)ret);
 }
@@ -283,11 +286,14 @@ fcntl_flock_impl(PyObject *module, int fd, int code)
 /*[clinic end generated code: output=84059e2b37d2fc64 input=b70a0a41ca22a8a0]*/
 {
     int ret;
+    int async_err = 0;
 
 #ifdef HAVE_FLOCK
-    Py_BEGIN_ALLOW_THREADS
-    ret = flock(fd, code);
-    Py_END_ALLOW_THREADS
+    do {
+        Py_BEGIN_ALLOW_THREADS
+        ret = flock(fd, code);
+        Py_END_ALLOW_THREADS
+    } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
 #else
 
 #ifndef LOCK_SH
@@ -310,14 +316,15 @@ fcntl_flock_impl(PyObject *module, int fd, int code)
             return NULL;
         }
         l.l_whence = l.l_start = l.l_len = 0;
-        Py_BEGIN_ALLOW_THREADS
-        ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
-        Py_END_ALLOW_THREADS
+        do {
+            Py_BEGIN_ALLOW_THREADS
+            ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
+            Py_END_ALLOW_THREADS
+        } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
     }
 #endif /* HAVE_FLOCK */
     if (ret < 0) {
-        PyErr_SetFromErrno(PyExc_IOError);
-        return NULL;
+        return !async_err ? PyErr_SetFromErrno(PyExc_IOError) : NULL;
     }
     Py_RETURN_NONE;
 }
@@ -363,6 +370,7 @@ fcntl_lockf_impl(PyObject *module, int fd, int code, PyObject *lenobj,
 /*[clinic end generated code: output=4985e7a172e7461a input=3a5dc01b04371f1a]*/
 {
     int ret;
+    int async_err = 0;
 
 #ifndef LOCK_SH
 #define LOCK_SH         1       /* shared lock */
@@ -407,13 +415,14 @@ fcntl_lockf_impl(PyObject *module, int fd, int code, PyObject *lenobj,
                 return NULL;
         }
         l.l_whence = whence;
-        Py_BEGIN_ALLOW_THREADS
-        ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
-        Py_END_ALLOW_THREADS
+        do {
+            Py_BEGIN_ALLOW_THREADS
+            ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
+            Py_END_ALLOW_THREADS
+        } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
     }
     if (ret < 0) {
-        PyErr_SetFromErrno(PyExc_IOError);
-        return NULL;
+        return !async_err ? PyErr_SetFromErrno(PyExc_IOError) : NULL;
     }
     Py_RETURN_NONE;
 }
index 43e45ef..8a724b6 100644 (file)
@@ -156,7 +156,7 @@ grp_getgrnam_impl(PyObject *module, PyObject *name)
         goto out;
 
     if ((p = getgrnam(name_chars)) == NULL) {
-        PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %S", name);
+        PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
         goto out;
     }
     retval = mkgrent(p);
index 01d2118..5d46c68 100644 (file)
@@ -361,12 +361,12 @@ MD5Type_copy_impl(MD5object *self)
 /*[clinic input]
 MD5Type.digest
 
-Return the digest value as a string of binary data.
+Return the digest value as a bytes object.
 [clinic start generated code]*/
 
 static PyObject *
 MD5Type_digest_impl(MD5object *self)
-/*[clinic end generated code: output=eb691dc4190a07ec input=7b96e65389412a34]*/
+/*[clinic end generated code: output=eb691dc4190a07ec input=bc0c4397c2994be6]*/
 {
     unsigned char digest[MD5_DIGESTSIZE];
     struct md5_state temp;
index 721e5ed..dec670f 100644 (file)
@@ -681,7 +681,7 @@ mmap_move_method(mmap_object *self, PyObject *args)
 }
 
 static PyObject *
-mmap_closed_get(mmap_object *self)
+mmap_closed_get(mmap_object *self, void *Py_UNUSED(ignored))
 {
 #ifdef MS_WINDOWS
     return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
index a9028bb..11df679 100644 (file)
@@ -412,6 +412,7 @@ nis_maps (PyObject *self, PyObject *args, PyObject *kwdict)
         PyObject *str = PyUnicode_FromString(maps->map);
         if (!str || PyList_Append(list, str) < 0)
         {
+            Py_XDECREF(str);
             Py_DECREF(list);
             list = NULL;
             break;
index af6b9dc..776a3d2 100644 (file)
@@ -1341,13 +1341,19 @@ win32_error_object(const char* function, PyObject* filename)
 #endif /* MS_WINDOWS */
 
 static PyObject *
+posix_path_object_error(PyObject *path)
+{
+    return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
+}
+
+static PyObject *
 path_object_error(PyObject *path)
 {
 #ifdef MS_WINDOWS
     return PyErr_SetExcFromWindowsErrWithFilenameObject(
                 PyExc_OSError, 0, path);
 #else
-    return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
+    return posix_path_object_error(path);
 #endif
 }
 
@@ -1369,6 +1375,12 @@ path_error(path_t *path)
 }
 
 static PyObject *
+posix_path_error(path_t *path)
+{
+    return posix_path_object_error(path->object);
+}
+
+static PyObject *
 path_error2(path_t *path, path_t *path2)
 {
     return path_object_error2(path->object, path2->object);
@@ -2379,7 +2391,7 @@ class sched_param_converter(CConverter):
 os.stat
 
     path : path_t(allow_fd=True)
-        Path to be examined; can be string, bytes, path-like object or
+        Path to be examined; can be string, bytes, path-like object or
         open-file-descriptor int.
 
     *
@@ -2407,7 +2419,7 @@ It's an error to use dir_fd or follow_symlinks when specifying path as
 
 static PyObject *
 os_stat_impl(PyObject *module, path_t *path, int dir_fd, int follow_symlinks)
-/*[clinic end generated code: output=7d4976e6f18a59c5 input=270bd64e7bb3c8f7]*/
+/*[clinic end generated code: output=7d4976e6f18a59c5 input=01d362ebcc06996b]*/
 {
     return posix_do_stat("stat", path, dir_fd, follow_symlinks);
 }
@@ -2441,7 +2453,7 @@ os_lstat_impl(PyObject *module, path_t *path, int dir_fd)
 os.access -> bool
 
     path: path_t
-        Path to be tested; can be string or bytes
+        Path to be tested; can be string, bytes, or a path-like object.
 
     mode: int
         Operating-system mode bitfield.  Can be F_OK to test existence,
@@ -2479,7 +2491,7 @@ Note that most operations will use the effective uid/gid, therefore this
 static int
 os_access_impl(PyObject *module, path_t *path, int mode, int dir_fd,
                int effective_ids, int follow_symlinks)
-/*[clinic end generated code: output=cf84158bc90b1a77 input=8e8c3a6ba791fee3]*/
+/*[clinic end generated code: output=cf84158bc90b1a77 input=3ffe4e650ee3bf20]*/
 {
     int return_value;
 
@@ -2671,7 +2683,7 @@ os_fchdir_impl(PyObject *module, int fd)
 os.chmod
 
     path: path_t(allow_fd='PATH_HAVE_FCHMOD')
-        Path to be modified.  May always be specified as a str or bytes.
+        Path to be modified.  May always be specified as a str, bytes, or a path-like object.
         On some platforms, path may also be specified as an open file descriptor.
         If this functionality is unavailable, using it raises an exception.
 
@@ -2702,7 +2714,7 @@ dir_fd and follow_symlinks may not be implemented on your platform.
 static PyObject *
 os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd,
               int follow_symlinks)
-/*[clinic end generated code: output=5cf6a94915cc7bff input=7f1618e5e15cc196]*/
+/*[clinic end generated code: output=5cf6a94915cc7bff input=989081551c00293b]*/
 {
     int result;
 
@@ -3022,7 +3034,7 @@ os_fdatasync_impl(PyObject *module, int fd)
 os.chown
 
     path : path_t(allow_fd='PATH_HAVE_FCHOWN')
-        Path to be examined; can be string, bytes, or open-file-descriptor int.
+        Path to be examined; can be string, bytes, a path-like object, or open-file-descriptor int.
 
     uid: uid_t
 
@@ -3060,7 +3072,7 @@ dir_fd and follow_symlinks may not be implemented on your platform.
 static PyObject *
 os_chown_impl(PyObject *module, path_t *path, uid_t uid, gid_t gid,
               int dir_fd, int follow_symlinks)
-/*[clinic end generated code: output=4beadab0db5f70cd input=a61cc35574814d5d]*/
+/*[clinic end generated code: output=4beadab0db5f70cd input=b08c5ec67996a97d]*/
 {
     int result;
 
@@ -3587,7 +3599,7 @@ os.listdir
 
 Return a list containing the names of the files in the directory.
 
-path can be specified as either str or bytes.  If path is bytes,
+path can be specified as either str, bytes, or a path-like object.  If path is bytes,
   the filenames returned will also be bytes; in all other circumstances
   the filenames returned will be str.
 If path is None, uses the path='.'.
@@ -3603,7 +3615,7 @@ entries '.' and '..' even if they are present in the directory.
 
 static PyObject *
 os_listdir_impl(PyObject *module, path_t *path)
-/*[clinic end generated code: output=293045673fcd1a75 input=09e300416e3cd729]*/
+/*[clinic end generated code: output=293045673fcd1a75 input=e3f58030f538295d]*/
 {
 #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR)
     return _listdir_windows_no_opendir(path, NULL);
@@ -4577,7 +4589,6 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns,
     int result;
 #endif
 
-    PyObject *return_value = NULL;
     utime_t utime;
 
     memset(&utime, 0, sizeof(utime_t));
@@ -4586,7 +4597,7 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns,
         PyErr_SetString(PyExc_ValueError,
                      "utime: you may specify either 'times'"
                      " or 'ns' but not both");
-        goto exit;
+        return NULL;
     }
 
     if (times && (times != Py_None)) {
@@ -4596,14 +4607,14 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns,
             PyErr_SetString(PyExc_TypeError,
                          "utime: 'times' must be either"
                          " a tuple of two ints or None");
-            goto exit;
+            return NULL;
         }
         utime.now = 0;
         if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 0),
                                      &a_sec, &a_nsec, _PyTime_ROUND_FLOOR) == -1 ||
             _PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 1),
                                      &m_sec, &m_nsec, _PyTime_ROUND_FLOOR) == -1) {
-            goto exit;
+            return NULL;
         }
         utime.atime_s = a_sec;
         utime.atime_ns = a_nsec;
@@ -4614,14 +4625,14 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns,
         if (!PyTuple_CheckExact(ns) || (PyTuple_Size(ns) != 2)) {
             PyErr_SetString(PyExc_TypeError,
                          "utime: 'ns' must be a tuple of two ints");
-            goto exit;
+            return NULL;
         }
         utime.now = 0;
         if (!split_py_long_to_s_and_ns(PyTuple_GET_ITEM(ns, 0),
                                       &utime.atime_s, &utime.atime_ns) ||
             !split_py_long_to_s_and_ns(PyTuple_GET_ITEM(ns, 1),
                                        &utime.mtime_s, &utime.mtime_ns)) {
-            goto exit;
+            return NULL;
         }
     }
     else {
@@ -4631,20 +4642,20 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns,
 
 #if !defined(UTIME_HAVE_NOFOLLOW_SYMLINKS)
     if (follow_symlinks_specified("utime", follow_symlinks))
-        goto exit;
+        return NULL;
 #endif
 
     if (path_and_dir_fd_invalid("utime", path, dir_fd) ||
         dir_fd_and_fd_invalid("utime", dir_fd, path->fd) ||
         fd_and_follow_symlinks_invalid("utime", path->fd, follow_symlinks))
-        goto exit;
+        return NULL;
 
 #if !defined(HAVE_UTIMENSAT)
     if ((dir_fd != DEFAULT_DIR_FD) && (!follow_symlinks)) {
         PyErr_SetString(PyExc_ValueError,
                      "utime: cannot use dir_fd and follow_symlinks "
                      "together on this platform");
-        goto exit;
+        return NULL;
     }
 #endif
 
@@ -4656,7 +4667,7 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns,
     Py_END_ALLOW_THREADS
     if (hFile == INVALID_HANDLE_VALUE) {
         path_error(path);
-        goto exit;
+        return NULL;
     }
 
     if (utime.now) {
@@ -4673,8 +4684,10 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns,
            something is wrong with the file, when it also
            could be the time stamp that gives a problem. */
         PyErr_SetFromWindowsErr(0);
-        goto exit;
+        CloseHandle(hFile);
+        return NULL;
     }
+    CloseHandle(hFile);
 #else /* MS_WINDOWS */
     Py_BEGIN_ALLOW_THREADS
 
@@ -4702,21 +4715,13 @@ os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns,
 
     if (result < 0) {
         /* see previous comment about not putting filename in error here */
-        return_value = posix_error();
-        goto exit;
+        posix_error();
+        return NULL;
     }
 
 #endif /* MS_WINDOWS */
 
-    Py_INCREF(Py_None);
-    return_value = Py_None;
-
-exit:
-#ifdef MS_WINDOWS
-    if (hFile != INVALID_HANDLE_VALUE)
-        CloseHandle(hFile);
-#endif
-    return return_value;
+    Py_RETURN_NONE;
 }
 
 /* Process operations */
@@ -5041,7 +5046,7 @@ os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
 
     /* If we get here it's definitely an error */
 
-    path_error(path);
+    posix_path_error(path);
 
     free_string_array(envlist, envc);
   fail:
@@ -6122,8 +6127,7 @@ os_getgroups_impl(PyObject *module)
     } else {
         alt_grouplist = PyMem_New(gid_t, n);
         if (alt_grouplist == NULL) {
-            errno = EINVAL;
-            return posix_error();
+            return PyErr_NoMemory();
         }
     }
 
@@ -6148,8 +6152,7 @@ os_getgroups_impl(PyObject *module)
             } else {
                 alt_grouplist = PyMem_New(gid_t, n);
                 if (alt_grouplist == NULL) {
-                    errno = EINVAL;
-                    return posix_error();
+                    return PyErr_NoMemory();
                 }
                 n = getgroups(n, alt_grouplist);
                 if (n == -1) {
@@ -7900,11 +7903,7 @@ os_read_impl(PyObject *module, int fd, Py_ssize_t length)
         return posix_error();
     }
 
-#ifdef MS_WINDOWS
-    /* On Windows, the count parameter of read() is an int */
-    if (length > INT_MAX)
-        length = INT_MAX;
-#endif
+    length = Py_MIN(length, _PY_READ_MAX);
 
     buffer = PyBytes_FromStringAndSize((char *)NULL, length);
     if (buffer == NULL)
@@ -8770,7 +8769,7 @@ os_truncate_impl(PyObject *module, path_t *path, Py_off_t length)
     _Py_END_SUPPRESS_IPH
     Py_END_ALLOW_THREADS
     if (result < 0)
-        return path_error(path);
+        return posix_path_error(path);
 
     Py_RETURN_NONE;
 }
@@ -10655,7 +10654,7 @@ os.getxattr
 
 Return the value of extended attribute attribute on path.
 
-path may be either a string or an open file descriptor.
+path may be either a string, a path-like object, or an open file descriptor.
 If follow_symlinks is False, and the last element of the path is a symbolic
   link, getxattr will examine the symbolic link itself instead of the file
   the link points to.
@@ -10665,7 +10664,7 @@ If follow_symlinks is False, and the last element of the path is a symbolic
 static PyObject *
 os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute,
                  int follow_symlinks)
-/*[clinic end generated code: output=5f2f44200a43cff2 input=8c8ea3bab78d89c2]*/
+/*[clinic end generated code: output=5f2f44200a43cff2 input=025789491708f7eb]*/
 {
     Py_ssize_t i;
     PyObject *buffer = NULL;
@@ -10727,7 +10726,7 @@ os.setxattr
 
 Set extended attribute attribute on path to value.
 
-path may be either a string or an open file descriptor.
+path may be either a string, a path-like object,  or an open file descriptor.
 If follow_symlinks is False, and the last element of the path is a symbolic
   link, setxattr will modify the symbolic link itself instead of the file
   the link points to.
@@ -10737,7 +10736,7 @@ If follow_symlinks is False, and the last element of the path is a symbolic
 static PyObject *
 os_setxattr_impl(PyObject *module, path_t *path, path_t *attribute,
                  Py_buffer *value, int flags, int follow_symlinks)
-/*[clinic end generated code: output=98b83f63fdde26bb input=f0d26833992015c2]*/
+/*[clinic end generated code: output=98b83f63fdde26bb input=c17c0103009042f0]*/
 {
     ssize_t result;
 
@@ -10775,7 +10774,7 @@ os.removexattr
 
 Remove extended attribute attribute on path.
 
-path may be either a string or an open file descriptor.
+path may be either a string, a path-like object, or an open file descriptor.
 If follow_symlinks is False, and the last element of the path is a symbolic
   link, removexattr will modify the symbolic link itself instead of the file
   the link points to.
@@ -10785,7 +10784,7 @@ If follow_symlinks is False, and the last element of the path is a symbolic
 static PyObject *
 os_removexattr_impl(PyObject *module, path_t *path, path_t *attribute,
                     int follow_symlinks)
-/*[clinic end generated code: output=521a51817980cda6 input=cdb54834161e3329]*/
+/*[clinic end generated code: output=521a51817980cda6 input=3d9a7d36fe2f7c4e]*/
 {
     ssize_t result;
 
@@ -10818,7 +10817,7 @@ os.listxattr
 
 Return a list of extended attributes on path.
 
-path may be either None, a string, or an open file descriptor.
+path may be either None, a string, a path-like object, or an open file descriptor.
 if path is None, listxattr will examine the current directory.
 If follow_symlinks is False, and the last element of the path is a symbolic
   link, listxattr will examine the symbolic link itself instead of the file
@@ -10827,7 +10826,7 @@ If follow_symlinks is False, and the last element of the path is a symbolic
 
 static PyObject *
 os_listxattr_impl(PyObject *module, path_t *path, int follow_symlinks)
-/*[clinic end generated code: output=bebdb4e2ad0ce435 input=08cca53ac0b07c13]*/
+/*[clinic end generated code: output=bebdb4e2ad0ce435 input=9826edf9fdb90869]*/
 {
     Py_ssize_t i;
     PyObject *result = NULL;
index 21c2b54..810427a 100644 (file)
@@ -163,7 +163,7 @@ pwd_getpwnam_impl(PyObject *module, PyObject *arg)
         goto out;
     if ((p = getpwnam(name)) == NULL) {
         PyErr_Format(PyExc_KeyError,
-                     "getpwnam(): name not found: %S", arg);
+                     "getpwnam(): name not found: %R", arg);
         goto out;
     }
     retval = mkpwent(p);
index aa21d93..2e69f61 100644 (file)
@@ -245,8 +245,10 @@ string_intern(xmlparseobject *self, const char* str)
     if (!value) {
         if (PyDict_SetItem(self->intern, result, result) == 0)
             return result;
-        else
+        else {
+            Py_DECREF(result);
             return NULL;
+        }
     }
     Py_INCREF(value);
     Py_DECREF(result);
@@ -395,6 +397,7 @@ my_StartElementHandler(void *userData,
                 flag_error(self);
                 Py_DECREF(n);
                 Py_DECREF(v);
+                Py_DECREF(container);
                 return;
             }
             else {
@@ -403,12 +406,14 @@ my_StartElementHandler(void *userData,
             }
         }
         args = string_intern(self, name);
-        if (args != NULL)
-            args = Py_BuildValue("(NN)", args, container);
         if (args == NULL) {
             Py_DECREF(container);
             return;
         }
+        args = Py_BuildValue("(NN)", args, container);
+        if (args == NULL) {
+            return;
+        }
         /* Container is now a borrowed reference; ignore it. */
         self->in_callback = 1;
         rv = call_with_frame("StartElement", __LINE__,
@@ -567,7 +572,6 @@ my_ElementDeclHandler(void *userData,
         }
         args = Py_BuildValue("NN", nameobj, modelobj);
         if (args == NULL) {
-            Py_DECREF(modelobj);
             flag_error(self);
             goto finally;
         }
index 575479c..0965715 100644 (file)
@@ -947,8 +947,7 @@ on_completion_display_matches_hook(char **matches,
         s = decode(matches[i+1]);
         if (s == NULL)
             goto error;
-        if (PyList_SetItem(m, i, s) == -1)
-            goto error;
+        PyList_SET_ITEM(m, i, s);
     }
     sub = decode(matches[0]);
     r = PyObject_CallFunction(readlinestate_global->completion_display_matches_hook,
index 5438b69..2bc7b9f 100644 (file)
@@ -279,6 +279,10 @@ select_select(PyObject *self, PyObject *args)
         if (tvp) {
             timeout = deadline - _PyTime_GetMonotonicClock();
             if (timeout < 0) {
+                /* bpo-35310: lists were unmodified -- clear them explicitly */
+                FD_ZERO(&ifdset);
+                FD_ZERO(&ofdset);
+                FD_ZERO(&efdset);
                 n = 0;
                 break;
             }
@@ -651,10 +655,7 @@ poll_poll(pollObject *self, PyObject *args)
             goto error;
         }
         PyTuple_SET_ITEM(value, 1, num);
-        if ((PyList_SetItem(result_list, j, value)) == -1) {
-            Py_DECREF(value);
-            goto error;
-        }
+        PyList_SET_ITEM(result_list, j, value);
         i++;
     }
     return result_list;
@@ -980,10 +981,7 @@ devpoll_poll(devpollObject *self, PyObject *args)
         Py_DECREF(num2);
         if (value == NULL)
             goto error;
-        if ((PyList_SetItem(result_list, i, value)) == -1) {
-            Py_DECREF(value);
-            goto error;
-        }
+        PyList_SET_ITEM(result_list, i, value);
     }
 
     return result_list;
@@ -1026,7 +1024,7 @@ Close the devpoll file descriptor. Further operations on the devpoll\n\
 object will raise an exception.");
 
 static PyObject*
-devpoll_get_closed(devpollObject *self)
+devpoll_get_closed(devpollObject *self, void *Py_UNUSED(ignored))
 {
     if (self->fd_devpoll < 0)
         Py_RETURN_TRUE;
@@ -1345,7 +1343,7 @@ Close the epoll control file descriptor. Further operations on the epoll\n\
 object will raise an exception.");
 
 static PyObject*
-pyepoll_get_closed(pyEpoll_Object *self)
+pyepoll_get_closed(pyEpoll_Object *self, void *Py_UNUSED(ignored))
 {
     if (self->epfd < 0)
         Py_RETURN_TRUE;
@@ -2091,7 +2089,7 @@ Close the kqueue control file descriptor. Further operations on the kqueue\n\
 object will raise an exception.");
 
 static PyObject*
-kqueue_queue_get_closed(kqueue_queue_Object *self)
+kqueue_queue_get_closed(kqueue_queue_Object *self, void *Py_UNUSED(ignored))
 {
     if (self->kqfd < 0)
         Py_RETURN_TRUE;
index cd12358..f58d7e4 100644 (file)
@@ -338,12 +338,12 @@ SHA1Type_copy_impl(SHA1object *self)
 /*[clinic input]
 SHA1Type.digest
 
-Return the digest value as a string of binary data.
+Return the digest value as a bytes object.
 [clinic start generated code]*/
 
 static PyObject *
 SHA1Type_digest_impl(SHA1object *self)
-/*[clinic end generated code: output=2f05302a7aa2b5cb input=205d47e1927fd009]*/
+/*[clinic end generated code: output=2f05302a7aa2b5cb input=13824b35407444bd]*/
 {
     unsigned char digest[SHA1_DIGESTSIZE];
     struct sha1_state temp;
index 70c49b5..ecd98e6 100644 (file)
@@ -428,12 +428,12 @@ SHA256Type_copy_impl(SHAobject *self)
 /*[clinic input]
 SHA256Type.digest
 
-Return the digest value as a string of binary data.
+Return the digest value as a bytes object.
 [clinic start generated code]*/
 
 static PyObject *
 SHA256Type_digest_impl(SHAobject *self)
-/*[clinic end generated code: output=46616a5e909fbc3d input=1fb752e58954157d]*/
+/*[clinic end generated code: output=46616a5e909fbc3d input=f1f4cfea5cbde35c]*/
 {
     unsigned char digest[SHA_DIGESTSIZE];
     SHAobject temp;
index da0cb57..891493c 100644 (file)
@@ -493,12 +493,12 @@ SHA512Type_copy_impl(SHAobject *self)
 /*[clinic input]
 SHA512Type.digest
 
-Return the digest value as a string of binary data.
+Return the digest value as a bytes object.
 [clinic start generated code]*/
 
 static PyObject *
 SHA512Type_digest_impl(SHAobject *self)
-/*[clinic end generated code: output=1080bbeeef7dde1b input=60c2cede9e023018]*/
+/*[clinic end generated code: output=1080bbeeef7dde1b input=f6470dd359071f4b]*/
 {
     unsigned char digest[SHA_DIGESTSIZE];
     SHAobject temp;
index ed31667..5208674 100644 (file)
@@ -356,7 +356,7 @@ remove_unusable_flags(PyObject *m)
 
     for (int i=0; i<sizeof(win_runtime_flags)/sizeof(FlagRuntimeInfo); i++) {
         info.dwBuildNumber = win_runtime_flags[i].build_number;
-        /* greater than or equal to the specified version? 
+        /* greater than or equal to the specified version?
            Compatibility Mode will not cheat VerifyVersionInfo(...) */
         if (VerifyVersionInfo(
                 &info,
@@ -367,10 +367,14 @@ remove_unusable_flags(PyObject *m)
         else {
             if (PyDict_GetItemString(
                     dict,
-                    win_runtime_flags[i].flag_name) != NULL) {
-                PyDict_DelItemString(
-                    dict,
-                    win_runtime_flags[i].flag_name);
+                    win_runtime_flags[i].flag_name) != NULL)
+            {
+                if (PyDict_DelItemString(
+                        dict,
+                        win_runtime_flags[i].flag_name))
+                {
+                    PyErr_Clear();
+                }
             }
         }
     }
@@ -2058,14 +2062,18 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
 
         if (!PyArg_ParseTuple(args, "ss|HH:getsockaddrarg",
                                 &type, &name, &sa->salg_feat, &sa->salg_mask))
+        {
             return 0;
-        /* sockaddr_alg has fixed-sized char arrays for type and name */
-        if (strlen(type) > sizeof(sa->salg_type)) {
+        }
+        /* sockaddr_alg has fixed-sized char arrays for type, and name
+         * both must be NULL terminated.
+         */
+        if (strlen(type) >= sizeof(sa->salg_type)) {
             PyErr_SetString(PyExc_ValueError, "AF_ALG type too long.");
             return 0;
         }
         strncpy((char *)sa->salg_type, type, sizeof(sa->salg_type));
-        if (strlen(name) > sizeof(sa->salg_name)) {
+        if (strlen(name) >= sizeof(sa->salg_name)) {
             PyErr_SetString(PyExc_ValueError, "AF_ALG name too long.");
             return 0;
         }
@@ -6075,9 +6083,11 @@ socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs)
         if (single == NULL)
             goto err;
 
-        if (PyList_Append(all, single))
+        if (PyList_Append(all, single)) {
+            Py_DECREF(single);
             goto err;
-        Py_XDECREF(single);
+        }
+        Py_DECREF(single);
     }
     Py_XDECREF(idna);
     if (res0)
index b78d33e..945d8e0 100644 (file)
@@ -113,11 +113,11 @@ termios_tcgetattr(PyObject *self, PyObject *args)
     PyList_SetItem(v, 3, PyLong_FromLong((long)mode.c_lflag));
     PyList_SetItem(v, 4, PyLong_FromLong((long)ispeed));
     PyList_SetItem(v, 5, PyLong_FromLong((long)ospeed));
-    PyList_SetItem(v, 6, cc);
-    if (PyErr_Occurred()){
+    if (PyErr_Occurred()) {
         Py_DECREF(v);
         goto err;
     }
+    PyList_SetItem(v, 6, cc);
     return v;
   err:
     Py_DECREF(cc);
index f66f098..a963bb1 100644 (file)
@@ -860,7 +860,7 @@ of the timezone or altzone attributes on the time module.");
 #endif /* HAVE_MKTIME */
 
 #ifdef HAVE_WORKING_TZSET
-static void PyInit_timezone(PyObject *module);
+static int init_timezone(PyObject *module);
 
 static PyObject *
 time_tzset(PyObject *self, PyObject *unused)
@@ -875,7 +875,9 @@ time_tzset(PyObject *self, PyObject *unused)
     tzset();
 
     /* Reset timezone, altzone, daylight and tzname */
-    PyInit_timezone(m);
+    if (init_timezone(m) < 0) {
+         return NULL;
+    }
     Py_DECREF(m);
     if (PyErr_Occurred())
         return NULL;
@@ -1174,7 +1176,7 @@ get_zone(char *zone, int n, struct tm *p)
 #endif
 }
 
-static int
+static time_t
 get_gmtoff(time_t t, struct tm *p)
 {
 #ifdef HAVE_STRUCT_TM_TM_ZONE
@@ -1184,8 +1186,11 @@ get_gmtoff(time_t t, struct tm *p)
 #endif
 }
 
-static void
-PyInit_timezone(PyObject *m) {
+static int
+init_timezone(PyObject *m)
+{
+    assert(!PyErr_Occurred());
+
     /* This code moved from PyInit_time wholesale to allow calling it from
     time_tzset. In the future, some parts of it can be moved back
     (for platforms that don't HAVE_WORKING_TZSET, when we know what they
@@ -1213,26 +1218,49 @@ PyInit_timezone(PyObject *m) {
 #endif
     PyModule_AddIntConstant(m, "daylight", daylight);
     otz0 = PyUnicode_DecodeLocale(tzname[0], "surrogateescape");
+    if (otz0 == NULL) {
+        return -1;
+    }
     otz1 = PyUnicode_DecodeLocale(tzname[1], "surrogateescape");
-    PyModule_AddObject(m, "tzname", Py_BuildValue("(NN)", otz0, otz1));
+    if (otz1 == NULL) {
+        Py_DECREF(otz0);
+        return -1;
+    }
+    PyObject *tzname_obj = Py_BuildValue("(NN)", otz0, otz1);
+    if (tzname_obj == NULL) {
+        return -1;
+    }
+    PyModule_AddObject(m, "tzname", tzname_obj);
 #else /* !HAVE_TZNAME || __GLIBC__ || __CYGWIN__*/
     {
 #define YEAR ((time_t)((365 * 24 + 6) * 3600))
         time_t t;
         struct tm p;
-        long janzone, julyzone;
+        time_t janzone_t, julyzone_t;
         char janname[10], julyname[10];
         t = (time((time_t *)0) / YEAR) * YEAR;
         _PyTime_localtime(t, &p);
         get_zone(janname, 9, &p);
-        janzone = -get_gmtoff(t, &p);
+        janzone_t = -get_gmtoff(t, &p);
         janname[9] = '\0';
         t += YEAR/2;
         _PyTime_localtime(t, &p);
         get_zone(julyname, 9, &p);
-        julyzone = -get_gmtoff(t, &p);
+        julyzone_t = -get_gmtoff(t, &p);
         julyname[9] = '\0';
 
+        /* Sanity check, don't check for the validity of timezones.
+           In practice, it should be more in range -12 hours .. +14 hours. */
+#define MAX_TIMEZONE (48 * 3600)
+        if (janzone_t < -MAX_TIMEZONE || janzone_t > MAX_TIMEZONE
+            || julyzone_t < -MAX_TIMEZONE || julyzone_t > MAX_TIMEZONE)
+        {
+            PyErr_SetString(PyExc_RuntimeError, "invalid GMT offset");
+            return -1;
+        }
+        int janzone = (int)janzone_t;
+        int julyzone = (int)julyzone_t;
+
         if( janzone < julyzone ) {
             /* DST is reversed in the southern hemisphere */
             PyModule_AddIntConstant(m, "timezone", julyzone);
@@ -1261,6 +1289,11 @@ PyInit_timezone(PyObject *m) {
                        Py_BuildValue("(zz)", _tzname[0], _tzname[1]));
 #endif /* __CYGWIN__ */
 #endif /* !HAVE_TZNAME || __GLIBC__ || __CYGWIN__*/
+
+    if (PyErr_Occurred()) {
+        return -1;
+    }
+    return 0;
 }
 
 
@@ -1348,7 +1381,11 @@ PyInit_time(void)
         return NULL;
 
     /* Set, or reset, module variables like time.timezone */
-    PyInit_timezone(m);
+    if (init_timezone(m) < 0) {
+        return NULL;
+    }
+
+#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_CLOCK_GETRES)
 
 #ifdef CLOCK_REALTIME
     PyModule_AddIntMacro(m, CLOCK_REALTIME);
@@ -1369,6 +1406,8 @@ PyInit_time(void)
     PyModule_AddIntMacro(m, CLOCK_THREAD_CPUTIME_ID);
 #endif
 
+#endif  /* defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_CLOCK_GETRES) */
+
     if (!initialized) {
         if (PyStructSequence_InitType2(&StructTimeType,
                                        &struct_time_type_desc) < 0)
@@ -1378,6 +1417,10 @@ PyInit_time(void)
     PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 11);
     PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType);
     initialized = 1;
+
+    if (PyErr_Occurred()) {
+        return NULL;
+    }
     return m;
 }
 
index 11242d7..d2593b1 100644 (file)
@@ -89,7 +89,7 @@ spamlist_init(spamlistobject *self, PyObject *args, PyObject *kwds)
 }
 
 static PyObject *
-spamlist_state_get(spamlistobject *self)
+spamlist_state_get(spamlistobject *self, void *Py_UNUSED(ignored))
 {
     return PyLong_FromLong(self->state);
 }
index a20dcd6..dd7eb4f 100644 (file)
@@ -126,11 +126,11 @@ newcompobject(PyTypeObject *type)
 static void*
 PyZlib_Malloc(voidpf ctx, uInt items, uInt size)
 {
-    if (items > (size_t)PY_SSIZE_T_MAX / size)
+    if (size != 0 && items > (size_t)PY_SSIZE_T_MAX / size)
         return NULL;
     /* PyMem_Malloc() cannot be used: the GIL is not held when
        inflate() and deflate() are called */
-    return PyMem_RawMalloc(items * size);
+    return PyMem_RawMalloc((size_t)items * (size_t)size);
 }
 
 static void
index 1552457..673dd0c 100644 (file)
@@ -39,7 +39,6 @@ _getbytevalue(PyObject* arg, int *value)
     } else {
         PyObject *index = PyNumber_Index(arg);
         if (index == NULL) {
-            PyErr_Format(PyExc_TypeError, "an integer is required");
             *value = -1;
             return 0;
         }
@@ -819,7 +818,7 @@ bytearray_init(PyByteArrayObject *self, PyObject *args, PyObject *kwds)
     if (PyIndex_Check(arg)) {
         count = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
         if (count == -1 && PyErr_Occurred()) {
-            if (PyErr_ExceptionMatches(PyExc_OverflowError))
+            if (!PyErr_ExceptionMatches(PyExc_TypeError))
                 return -1;
             PyErr_Clear();  /* fall through */
         }
index 04ebe0b..8fcc0b3 100644 (file)
@@ -2606,7 +2606,7 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     if (PyIndex_Check(x)) {
         size = PyNumber_AsSsize_t(x, PyExc_OverflowError);
         if (size == -1 && PyErr_Occurred()) {
-            if (PyErr_ExceptionMatches(PyExc_OverflowError))
+            if (!PyErr_ExceptionMatches(PyExc_TypeError))
                 return NULL;
             PyErr_Clear();  /* fall through */
         }
@@ -2649,49 +2649,83 @@ fail:
     return NULL;
 }
 
-#define _PyBytes_FROM_LIST_BODY(x, GET_ITEM)                                \
-    do {                                                                    \
-        PyObject *bytes;                                                    \
-        Py_ssize_t i;                                                       \
-        Py_ssize_t value;                                                   \
-        char *str;                                                          \
-        PyObject *item;                                                     \
-                                                                            \
-        bytes = PyBytes_FromStringAndSize(NULL, Py_SIZE(x));                \
-        if (bytes == NULL)                                                  \
-            return NULL;                                                    \
-        str = ((PyBytesObject *)bytes)->ob_sval;                            \
-                                                                            \
-        for (i = 0; i < Py_SIZE(x); i++) {                                  \
-            item = GET_ITEM((x), i);                                        \
-            value = PyNumber_AsSsize_t(item, NULL);                         \
-            if (value == -1 && PyErr_Occurred())                            \
-                goto error;                                                 \
-                                                                            \
-            if (value < 0 || value >= 256) {                                \
-                PyErr_SetString(PyExc_ValueError,                           \
-                                "bytes must be in range(0, 256)");          \
-                goto error;                                                 \
-            }                                                               \
-            *str++ = (char) value;                                          \
-        }                                                                   \
-        return bytes;                                                       \
-                                                                            \
-    error:                                                                  \
-        Py_DECREF(bytes);                                                   \
-        return NULL;                                                        \
-    } while (0)
-
 static PyObject*
 _PyBytes_FromList(PyObject *x)
 {
-    _PyBytes_FROM_LIST_BODY(x, PyList_GET_ITEM);
+    Py_ssize_t i, size = PyList_GET_SIZE(x);
+    Py_ssize_t value;
+    char *str;
+    PyObject *item;
+    _PyBytesWriter writer;
+
+    _PyBytesWriter_Init(&writer);
+    str = _PyBytesWriter_Alloc(&writer, size);
+    if (str == NULL)
+        return NULL;
+    writer.overallocate = 1;
+    size = writer.allocated;
+
+    for (i = 0; i < PyList_GET_SIZE(x); i++) {
+        item = PyList_GET_ITEM(x, i);
+        Py_INCREF(item);
+        value = PyNumber_AsSsize_t(item, NULL);
+        Py_DECREF(item);
+        if (value == -1 && PyErr_Occurred())
+            goto error;
+
+        if (value < 0 || value >= 256) {
+            PyErr_SetString(PyExc_ValueError,
+                            "bytes must be in range(0, 256)");
+            goto error;
+        }
+
+        if (i >= size) {
+            str = _PyBytesWriter_Resize(&writer, str, size+1);
+            if (str == NULL)
+                return NULL;
+            size = writer.allocated;
+        }
+        *str++ = (char) value;
+    }
+    return _PyBytesWriter_Finish(&writer, str);
+
+  error:
+    _PyBytesWriter_Dealloc(&writer);
+    return NULL;
 }
 
 static PyObject*
 _PyBytes_FromTuple(PyObject *x)
 {
-    _PyBytes_FROM_LIST_BODY(x, PyTuple_GET_ITEM);
+    PyObject *bytes;
+    Py_ssize_t i, size = PyTuple_GET_SIZE(x);
+    Py_ssize_t value;
+    char *str;
+    PyObject *item;
+
+    bytes = PyBytes_FromStringAndSize(NULL, size);
+    if (bytes == NULL)
+        return NULL;
+    str = ((PyBytesObject *)bytes)->ob_sval;
+
+    for (i = 0; i < size; i++) {
+        item = PyTuple_GET_ITEM(x, i);
+        value = PyNumber_AsSsize_t(item, NULL);
+        if (value == -1 && PyErr_Occurred())
+            goto error;
+
+        if (value < 0 || value >= 256) {
+            PyErr_SetString(PyExc_ValueError,
+                            "bytes must be in range(0, 256)");
+            goto error;
+        }
+        *str++ = (char) value;
+    }
+    return bytes;
+
+  error:
+    Py_DECREF(bytes);
+    return NULL;
 }
 
 static PyObject *
@@ -2788,6 +2822,9 @@ PyBytes_FromObject(PyObject *x)
             Py_DECREF(it);
             return result;
         }
+        if (!PyErr_ExceptionMatches(PyExc_TypeError)) {
+            return NULL;
+        }
     }
 
     PyErr_Format(PyExc_TypeError,
index acd3de6..4e15b44 100644 (file)
@@ -201,7 +201,7 @@ PyCapsule_Import(const char *name, int no_block)
     char *name_dup = (char *)PyMem_MALLOC(name_length);
 
     if (!name_dup) {
-        return NULL;
+        return PyErr_NoMemory();
     }
 
     memcpy(name_dup, name, name_length);
index b0ed023..7071016 100644 (file)
@@ -75,8 +75,6 @@ method_reduce(PyMethodObject *im)
 {
     PyObject *self = PyMethod_GET_SELF(im);
     PyObject *func = PyMethod_GET_FUNCTION(im);
-    PyObject *builtins;
-    PyObject *getattr;
     PyObject *funcname;
     _Py_IDENTIFIER(getattr);
 
@@ -84,9 +82,8 @@ method_reduce(PyMethodObject *im)
     if (funcname == NULL) {
         return NULL;
     }
-    builtins = PyEval_GetBuiltins();
-    getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
-    return Py_BuildValue("O(ON)", getattr, self, funcname);
+    return Py_BuildValue("N(ON)", _PyEval_GetBuiltinId(&PyId_getattr),
+                         self, funcname);
 }
 
 static PyMethodDef method_methods[] = {
index 9020ccd..e897b10 100644 (file)
@@ -378,7 +378,7 @@ calculate_qualname(PyDescrObject *descr)
 }
 
 static PyObject *
-descr_get_qualname(PyDescrObject *descr)
+descr_get_qualname(PyDescrObject *descr, void *Py_UNUSED(ignored))
 {
     if (descr->d_qualname == NULL)
         descr->d_qualname = calculate_qualname(descr);
@@ -389,14 +389,9 @@ descr_get_qualname(PyDescrObject *descr)
 static PyObject *
 descr_reduce(PyDescrObject *descr)
 {
-    PyObject *builtins;
-    PyObject *getattr;
     _Py_IDENTIFIER(getattr);
-
-    builtins = PyEval_GetBuiltins();
-    getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
-    return Py_BuildValue("O(OO)", getattr, PyDescr_TYPE(descr),
-                         PyDescr_NAME(descr));
+    return Py_BuildValue("N(OO)", _PyEval_GetBuiltinId(&PyId_getattr),
+                         PyDescr_TYPE(descr), PyDescr_NAME(descr));
 }
 
 static PyMethodDef descr_methods[] = {
@@ -1098,13 +1093,9 @@ wrapper_repr(wrapperobject *wp)
 static PyObject *
 wrapper_reduce(wrapperobject *wp)
 {
-    PyObject *builtins;
-    PyObject *getattr;
     _Py_IDENTIFIER(getattr);
-
-    builtins = PyEval_GetBuiltins();
-    getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
-    return Py_BuildValue("O(OO)", getattr, wp->self, PyDescr_NAME(wp->descr));
+    return Py_BuildValue("N(OO)", _PyEval_GetBuiltinId(&PyId_getattr),
+                         wp->self, PyDescr_NAME(wp->descr));
 }
 
 static PyMethodDef wrapper_methods[] = {
@@ -1118,7 +1109,7 @@ static PyMemberDef wrapper_members[] = {
 };
 
 static PyObject *
-wrapper_objclass(wrapperobject *wp)
+wrapper_objclass(wrapperobject *wp, void *Py_UNUSED(ignored))
 {
     PyObject *c = (PyObject *)PyDescr_TYPE(wp->descr);
 
@@ -1127,7 +1118,7 @@ wrapper_objclass(wrapperobject *wp)
 }
 
 static PyObject *
-wrapper_name(wrapperobject *wp)
+wrapper_name(wrapperobject *wp, void *Py_UNUSED(ignored))
 {
     const char *s = wp->descr->d_base->name;
 
@@ -1135,21 +1126,21 @@ wrapper_name(wrapperobject *wp)
 }
 
 static PyObject *
-wrapper_doc(wrapperobject *wp, void *closure)
+wrapper_doc(wrapperobject *wp, void *Py_UNUSED(ignored))
 {
     return _PyType_GetDocFromInternalDoc(wp->descr->d_base->name, wp->descr->d_base->doc);
 }
 
 static PyObject *
-wrapper_text_signature(wrapperobject *wp, void *closure)
+wrapper_text_signature(wrapperobject *wp, void *Py_UNUSED(ignored))
 {
     return _PyType_GetTextSignatureFromInternalDoc(wp->descr->d_base->name, wp->descr->d_base->doc);
 }
 
 static PyObject *
-wrapper_qualname(wrapperobject *wp)
+wrapper_qualname(wrapperobject *wp, void *Py_UNUSED(ignored))
 {
-    return descr_get_qualname((PyDescrObject *)wp->descr);
+    return descr_get_qualname((PyDescrObject *)wp->descr, NULL);
 }
 
 static PyGetSetDef wrapper_getsets[] = {
index 3bec50e..6f3b986 100644 (file)
@@ -181,7 +181,7 @@ static PyMethodDef BaseException_methods[] = {
 };
 
 static PyObject *
-BaseException_get_args(PyBaseExceptionObject *self)
+BaseException_get_args(PyBaseExceptionObject *self, void *Py_UNUSED(ignored))
 {
     if (self->args == NULL) {
         Py_INCREF(Py_None);
@@ -192,7 +192,7 @@ BaseException_get_args(PyBaseExceptionObject *self)
 }
 
 static int
-BaseException_set_args(PyBaseExceptionObject *self, PyObject *val)
+BaseException_set_args(PyBaseExceptionObject *self, PyObject *val, void *Py_UNUSED(ignored))
 {
     PyObject *seq;
     if (val == NULL) {
@@ -207,7 +207,7 @@ BaseException_set_args(PyBaseExceptionObject *self, PyObject *val)
 }
 
 static PyObject *
-BaseException_get_tb(PyBaseExceptionObject *self)
+BaseException_get_tb(PyBaseExceptionObject *self, void *Py_UNUSED(ignored))
 {
     if (self->traceback == NULL) {
         Py_INCREF(Py_None);
@@ -218,7 +218,7 @@ BaseException_get_tb(PyBaseExceptionObject *self)
 }
 
 static int
-BaseException_set_tb(PyBaseExceptionObject *self, PyObject *tb)
+BaseException_set_tb(PyBaseExceptionObject *self, PyObject *tb, void *Py_UNUSED(ignored))
 {
     if (tb == NULL) {
         PyErr_SetString(PyExc_TypeError, "__traceback__ may not be deleted");
@@ -236,7 +236,8 @@ BaseException_set_tb(PyBaseExceptionObject *self, PyObject *tb)
 }
 
 static PyObject *
-BaseException_get_context(PyObject *self) {
+BaseException_get_context(PyObject *self, void *Py_UNUSED(ignored))
+{
     PyObject *res = PyException_GetContext(self);
     if (res)
         return res;  /* new reference already returned above */
@@ -244,7 +245,8 @@ BaseException_get_context(PyObject *self) {
 }
 
 static int
-BaseException_set_context(PyObject *self, PyObject *arg) {
+BaseException_set_context(PyObject *self, PyObject *arg, void *Py_UNUSED(ignored))
+{
     if (arg == NULL) {
         PyErr_SetString(PyExc_TypeError, "__context__ may not be deleted");
         return -1;
@@ -263,7 +265,8 @@ BaseException_set_context(PyObject *self, PyObject *arg) {
 }
 
 static PyObject *
-BaseException_get_cause(PyObject *self) {
+BaseException_get_cause(PyObject *self, void *Py_UNUSED(ignored))
+{
     PyObject *res = PyException_GetCause(self);
     if (res)
         return res;  /* new reference already returned above */
@@ -271,7 +274,8 @@ BaseException_get_cause(PyObject *self) {
 }
 
 static int
-BaseException_set_cause(PyObject *self, PyObject *arg) {
+BaseException_set_cause(PyObject *self, PyObject *arg, void *Py_UNUSED(ignored))
+{
     if (arg == NULL) {
         PyErr_SetString(PyExc_TypeError, "__cause__ may not be deleted");
         return -1;
@@ -294,10 +298,10 @@ static PyGetSetDef BaseException_getset[] = {
     {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
     {"args", (getter)BaseException_get_args, (setter)BaseException_set_args},
     {"__traceback__", (getter)BaseException_get_tb, (setter)BaseException_set_tb},
-    {"__context__", (getter)BaseException_get_context,
-     (setter)BaseException_set_context, PyDoc_STR("exception context")},
-    {"__cause__", (getter)BaseException_get_cause,
-     (setter)BaseException_set_cause, PyDoc_STR("exception cause")},
+    {"__context__", BaseException_get_context,
+     BaseException_set_context, PyDoc_STR("exception context")},
+    {"__cause__", BaseException_get_cause,
+     BaseException_set_cause, PyDoc_STR("exception cause")},
     {NULL},
 };
 
@@ -312,7 +316,7 @@ PyException_GetTraceback(PyObject *self) {
 
 int
 PyException_SetTraceback(PyObject *self, PyObject *tb) {
-    return BaseException_set_tb((PyBaseExceptionObject *)self, tb);
+    return BaseException_set_tb((PyBaseExceptionObject *)self, tb, NULL);
 }
 
 PyObject *
index f442418..f8b47fc 100644 (file)
@@ -3,7 +3,8 @@
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
 
-#ifdef HAVE_GETC_UNLOCKED
+#if defined(HAVE_GETC_UNLOCKED) && !defined(_Py_MEMORY_SANITIZER)
+/* clang MemorySanitizer doesn't yet understand getc_unlocked. */
 #define GETC(f) getc_unlocked(f)
 #define FLOCKFILE(f) flockfile(f)
 #define FUNLOCKFILE(f) funlockfile(f)
index b7a16ad..535ec46 100644 (file)
@@ -61,7 +61,7 @@ frame_getlineno(PyFrameObject *f, void *closure)
  *    that time.
  */
 static int
-frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno)
+frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignored))
 {
     int new_lineno = 0;                 /* The new value of f_lineno */
     long l_new_lineno;
@@ -521,7 +521,7 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
     return 0;
 }
 
-static void
+static int
 frame_tp_clear(PyFrameObject *f)
 {
     PyObject **fastlocals, **p, **oldtop;
@@ -552,6 +552,7 @@ frame_tp_clear(PyFrameObject *f)
         for (p = f->f_valuestack; p < oldtop; p++)
             Py_CLEAR(*p);
     }
+    return 0;
 }
 
 static PyObject *
@@ -566,7 +567,7 @@ frame_clear(PyFrameObject *f)
         _PyGen_Finalize(f->f_gen);
         assert(f->f_gen == NULL);
     }
-    frame_tp_clear(f);
+    (void)frame_tp_clear(f);
     Py_RETURN_NONE;
 }
 
index 6ce0cb4..e66fda3 100644 (file)
@@ -240,14 +240,14 @@ static PyMemberDef func_memberlist[] = {
 };
 
 static PyObject *
-func_get_code(PyFunctionObject *op)
+func_get_code(PyFunctionObject *op, void *Py_UNUSED(ignored))
 {
     Py_INCREF(op->func_code);
     return op->func_code;
 }
 
 static int
-func_set_code(PyFunctionObject *op, PyObject *value)
+func_set_code(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
 {
     Py_ssize_t nfree, nclosure;
 
@@ -275,14 +275,14 @@ func_set_code(PyFunctionObject *op, PyObject *value)
 }
 
 static PyObject *
-func_get_name(PyFunctionObject *op)
+func_get_name(PyFunctionObject *op, void *Py_UNUSED(ignored))
 {
     Py_INCREF(op->func_name);
     return op->func_name;
 }
 
 static int
-func_set_name(PyFunctionObject *op, PyObject *value)
+func_set_name(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
 {
     /* Not legal to del f.func_name or to set it to anything
      * other than a string object. */
@@ -297,14 +297,14 @@ func_set_name(PyFunctionObject *op, PyObject *value)
 }
 
 static PyObject *
-func_get_qualname(PyFunctionObject *op)
+func_get_qualname(PyFunctionObject *op, void *Py_UNUSED(ignored))
 {
     Py_INCREF(op->func_qualname);
     return op->func_qualname;
 }
 
 static int
-func_set_qualname(PyFunctionObject *op, PyObject *value)
+func_set_qualname(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
 {
     /* Not legal to del f.__qualname__ or to set it to anything
      * other than a string object. */
@@ -319,7 +319,7 @@ func_set_qualname(PyFunctionObject *op, PyObject *value)
 }
 
 static PyObject *
-func_get_defaults(PyFunctionObject *op)
+func_get_defaults(PyFunctionObject *op, void *Py_UNUSED(ignored))
 {
     if (op->func_defaults == NULL) {
         Py_INCREF(Py_None);
@@ -330,7 +330,7 @@ func_get_defaults(PyFunctionObject *op)
 }
 
 static int
-func_set_defaults(PyFunctionObject *op, PyObject *value)
+func_set_defaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
 {
     /* Legal to del f.func_defaults.
      * Can only set func_defaults to NULL or a tuple. */
@@ -347,7 +347,7 @@ func_set_defaults(PyFunctionObject *op, PyObject *value)
 }
 
 static PyObject *
-func_get_kwdefaults(PyFunctionObject *op)
+func_get_kwdefaults(PyFunctionObject *op, void *Py_UNUSED(ignored))
 {
     if (op->func_kwdefaults == NULL) {
         Py_INCREF(Py_None);
@@ -358,7 +358,7 @@ func_get_kwdefaults(PyFunctionObject *op)
 }
 
 static int
-func_set_kwdefaults(PyFunctionObject *op, PyObject *value)
+func_set_kwdefaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
 {
     if (value == Py_None)
         value = NULL;
@@ -375,7 +375,7 @@ func_set_kwdefaults(PyFunctionObject *op, PyObject *value)
 }
 
 static PyObject *
-func_get_annotations(PyFunctionObject *op)
+func_get_annotations(PyFunctionObject *op, void *Py_UNUSED(ignored))
 {
     if (op->func_annotations == NULL) {
         op->func_annotations = PyDict_New();
@@ -387,7 +387,7 @@ func_get_annotations(PyFunctionObject *op)
 }
 
 static int
-func_set_annotations(PyFunctionObject *op, PyObject *value)
+func_set_annotations(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
 {
     if (value == Py_None)
         value = NULL;
index f226dbe..d113630 100644 (file)
@@ -665,14 +665,14 @@ gen_repr(PyGenObject *gen)
 }
 
 static PyObject *
-gen_get_name(PyGenObject *op)
+gen_get_name(PyGenObject *op, void *Py_UNUSED(ignored))
 {
     Py_INCREF(op->gi_name);
     return op->gi_name;
 }
 
 static int
-gen_set_name(PyGenObject *op, PyObject *value)
+gen_set_name(PyGenObject *op, PyObject *value, void *Py_UNUSED(ignored))
 {
     /* Not legal to del gen.gi_name or to set it to anything
      * other than a string object. */
@@ -687,14 +687,14 @@ gen_set_name(PyGenObject *op, PyObject *value)
 }
 
 static PyObject *
-gen_get_qualname(PyGenObject *op)
+gen_get_qualname(PyGenObject *op, void *Py_UNUSED(ignored))
 {
     Py_INCREF(op->gi_qualname);
     return op->gi_qualname;
 }
 
 static int
-gen_set_qualname(PyGenObject *op, PyObject *value)
+gen_set_qualname(PyGenObject *op, PyObject *value, void *Py_UNUSED(ignored))
 {
     /* Not legal to del gen.__qualname__ or to set it to anything
      * other than a string object. */
@@ -709,7 +709,7 @@ gen_set_qualname(PyGenObject *op, PyObject *value)
 }
 
 static PyObject *
-gen_getyieldfrom(PyGenObject *gen)
+gen_getyieldfrom(PyGenObject *gen, void *Py_UNUSED(ignored))
 {
     PyObject *yf = _PyGen_yf(gen);
     if (yf == NULL)
@@ -944,7 +944,7 @@ coro_await(PyCoroObject *coro)
 }
 
 static PyObject *
-coro_get_cr_await(PyCoroObject *coro)
+coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored))
 {
     PyObject *yf = _PyGen_yf((PyGenObject *) coro);
     if (yf == NULL)
index e1ac728..30e0055 100644 (file)
@@ -2903,7 +2903,7 @@ _IntTupleFromSsizet(int len, Py_ssize_t *vals)
 }
 
 static PyObject *
-memory_obj_get(PyMemoryViewObject *self)
+memory_obj_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
 {
     Py_buffer *view = &self->view;
 
@@ -2916,56 +2916,56 @@ memory_obj_get(PyMemoryViewObject *self)
 }
 
 static PyObject *
-memory_nbytes_get(PyMemoryViewObject *self)
+memory_nbytes_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
 {
     CHECK_RELEASED(self);
     return PyLong_FromSsize_t(self->view.len);
 }
 
 static PyObject *
-memory_format_get(PyMemoryViewObject *self)
+memory_format_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
 {
     CHECK_RELEASED(self);
     return PyUnicode_FromString(self->view.format);
 }
 
 static PyObject *
-memory_itemsize_get(PyMemoryViewObject *self)
+memory_itemsize_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
 {
     CHECK_RELEASED(self);
     return PyLong_FromSsize_t(self->view.itemsize);
 }
 
 static PyObject *
-memory_shape_get(PyMemoryViewObject *self)
+memory_shape_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
 {
     CHECK_RELEASED(self);
     return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
 }
 
 static PyObject *
-memory_strides_get(PyMemoryViewObject *self)
+memory_strides_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
 {
     CHECK_RELEASED(self);
     return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
 }
 
 static PyObject *
-memory_suboffsets_get(PyMemoryViewObject *self)
+memory_suboffsets_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
 {
     CHECK_RELEASED(self);
     return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
 }
 
 static PyObject *
-memory_readonly_get(PyMemoryViewObject *self)
+memory_readonly_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
 {
     CHECK_RELEASED(self);
     return PyBool_FromLong(self->view.readonly);
 }
 
 static PyObject *
-memory_ndim_get(PyMemoryViewObject *self)
+memory_ndim_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
 {
     CHECK_RELEASED(self);
     return PyLong_FromLong(self->view.ndim);
index fe52545..6794bf2 100644 (file)
@@ -320,16 +320,13 @@ meth_dealloc(PyCFunctionObject *m)
 static PyObject *
 meth_reduce(PyCFunctionObject *m)
 {
-    PyObject *builtins;
-    PyObject *getattr;
     _Py_IDENTIFIER(getattr);
 
     if (m->m_self == NULL || PyModule_Check(m->m_self))
         return PyUnicode_FromString(m->m_ml->ml_name);
 
-    builtins = PyEval_GetBuiltins();
-    getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
-    return Py_BuildValue("O(Os)", getattr, m->m_self, m->m_ml->ml_name);
+    return Py_BuildValue("N(Os)", _PyEval_GetBuiltinId(&PyId_getattr),
+                         m->m_self, m->m_ml->ml_name);
 }
 
 static PyMethodDef meth_methods[] = {
index 6307ee0..a810eff 100644 (file)
@@ -109,15 +109,15 @@ namespace_repr(PyObject *ns)
             PyObject *value, *item;
 
             value = PyDict_GetItem(d, key);
-            assert(value != NULL);
-
-            item = PyUnicode_FromFormat("%S=%R", key, value);
-            if (item == NULL) {
-                loop_error = 1;
-            }
-            else {
-                loop_error = PyList_Append(pairs, item);
-                Py_DECREF(item);
+            if (value != NULL) {
+                item = PyUnicode_FromFormat("%S=%R", key, value);
+                if (item == NULL) {
+                    loop_error = 1;
+                }
+                else {
+                    loop_error = PyList_Append(pairs, item);
+                    Py_DECREF(item);
+                }
             }
         }
 
index fdd41a6..e1a0569 100644 (file)
@@ -422,40 +422,71 @@ _Py_BreakPoint(void)
 }
 
 
+/* Heuristic checking if the object memory has been deallocated.
+   Rely on the debug hooks on Python memory allocators which fills the memory
+   with DEADBYTE (0xDB) when memory is deallocated.
+
+   The function can be used to prevent segmentation fault on dereferencing
+   pointers like 0xdbdbdbdbdbdbdbdb. Such pointer is very unlikely to be mapped
+   in memory. */
+int
+_PyObject_IsFreed(PyObject *op)
+{
+    uintptr_t ptr = (uintptr_t)op;
+    if (_PyMem_IsFreed(&ptr, sizeof(ptr))) {
+        return 1;
+    }
+    int freed = _PyMem_IsFreed(&op->ob_type, sizeof(op->ob_type));
+    /* ignore op->ob_ref: the value can have be modified
+       by Py_INCREF() and Py_DECREF(). */
+#ifdef Py_TRACE_REFS
+    freed &= _PyMem_IsFreed(&op->_ob_next, sizeof(op->_ob_next));
+    freed &= _PyMem_IsFreed(&op->_ob_prev, sizeof(op->_ob_prev));
+#endif
+    return freed;
+}
+
+
 /* For debugging convenience.  See Misc/gdbinit for some useful gdb hooks */
 void
 _PyObject_Dump(PyObject* op)
 {
-    if (op == NULL)
-        fprintf(stderr, "NULL\n");
-    else {
-#ifdef WITH_THREAD
-        PyGILState_STATE gil;
-#endif
-        PyObject *error_type, *error_value, *error_traceback;
+    if (op == NULL) {
+        fprintf(stderr, "<NULL object>\n");
+        fflush(stderr);
+        return;
+    }
 
-        fprintf(stderr, "object  : ");
-#ifdef WITH_THREAD
-        gil = PyGILState_Ensure();
-#endif
+    if (_PyObject_IsFreed(op)) {
+        /* It seems like the object memory has been freed:
+           don't access it to prevent a segmentation fault. */
+        fprintf(stderr, "<freed object>\n");
+        return;
+    }
 
-        PyErr_Fetch(&error_type, &error_value, &error_traceback);
-        (void)PyObject_Print(op, stderr, 0);
-        PyErr_Restore(error_type, error_value, error_traceback);
+    PyGILState_STATE gil;
+    PyObject *error_type, *error_value, *error_traceback;
 
-#ifdef WITH_THREAD
-        PyGILState_Release(gil);
-#endif
-        /* XXX(twouters) cast refcount to long until %zd is
-           universally available */
-        fprintf(stderr, "\n"
-            "type    : %s\n"
-            "refcount: %ld\n"
-            "address : %p\n",
-            Py_TYPE(op)==NULL ? "NULL" : Py_TYPE(op)->tp_name,
-            (long)op->ob_refcnt,
-            op);
-    }
+    fprintf(stderr, "object  : ");
+    fflush(stderr);
+    gil = PyGILState_Ensure();
+
+    PyErr_Fetch(&error_type, &error_value, &error_traceback);
+    (void)PyObject_Print(op, stderr, 0);
+    fflush(stderr);
+    PyErr_Restore(error_type, error_value, error_traceback);
+
+    PyGILState_Release(gil);
+    /* XXX(twouters) cast refcount to long until %zd is
+       universally available */
+    fprintf(stderr, "\n"
+        "type    : %s\n"
+        "refcount: %ld\n"
+        "address : %p\n",
+        Py_TYPE(op)==NULL ? "NULL" : Py_TYPE(op)->tp_name,
+        (long)op->ob_refcnt,
+        op);
+    fflush(stderr);
 }
 
 PyObject *
index 38f267e..d46d149 100644 (file)
@@ -27,19 +27,36 @@ static void _PyObject_DebugDumpAddress(const void *p);
 static void _PyMem_DebugCheckAddress(char api_id, const void *p);
 
 #if defined(__has_feature)  /* Clang */
- #if __has_feature(address_sanitizer)  /* is ASAN enabled? */
-  #define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS \
+#  if __has_feature(address_sanitizer) /* is ASAN enabled? */
+#    define _Py_NO_ADDRESS_SAFETY_ANALYSIS \
         __attribute__((no_address_safety_analysis))
- #else
-  #define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
- #endif
-#else
- #if defined(__SANITIZE_ADDRESS__)  /* GCC 4.8.x, is ASAN enabled? */
-  #define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS \
+#  endif
+#  if __has_feature(thread_sanitizer)  /* is TSAN enabled? */
+#    define _Py_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
+#  endif
+#  if __has_feature(memory_sanitizer)  /* is MSAN enabled? */
+#    define _Py_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
+#  endif
+#elif defined(__GNUC__)
+#  if defined(__SANITIZE_ADDRESS__)    /* GCC 4.8+, is ASAN enabled? */
+#    define _Py_NO_ADDRESS_SAFETY_ANALYSIS \
         __attribute__((no_address_safety_analysis))
- #else
-  #define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
- #endif
+#  endif
+   // TSAN is supported since GCC 4.8, but __SANITIZE_THREAD__ macro
+   // is provided only since GCC 7.
+#  if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
+#    define _Py_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
+#  endif
+#endif
+
+#ifndef _Py_NO_ADDRESS_SAFETY_ANALYSIS
+#  define _Py_NO_ADDRESS_SAFETY_ANALYSIS
+#endif
+#ifndef _Py_NO_SANITIZE_THREAD
+#  define _Py_NO_SANITIZE_THREAD
+#endif
+#ifndef _Py_NO_SANITIZE_MEMORY
+#  define _Py_NO_SANITIZE_MEMORY
 #endif
 
 #ifdef WITH_PYMALLOC
@@ -1188,7 +1205,9 @@ obmalloc controls.  Since this test is needed at every entry point, it's
 extremely desirable that it be this fast.
 */
 
-static bool ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
+static bool _Py_NO_ADDRESS_SAFETY_ANALYSIS
+            _Py_NO_SANITIZE_THREAD
+            _Py_NO_SANITIZE_MEMORY
 address_in_range(void *p, poolp pool)
 {
     // Since address_in_range may be reading from memory which was not allocated
@@ -1888,6 +1907,23 @@ _PyMem_DebugRawCalloc(void *ctx, size_t nelem, size_t elsize)
     return _PyMem_DebugRawAlloc(1, ctx, nbytes);
 }
 
+
+/* Heuristic checking if the memory has been freed. Rely on the debug hooks on
+   Python memory allocators which fills the memory with DEADBYTE (0xDB) when
+   memory is deallocated. */
+int
+_PyMem_IsFreed(void *ptr, size_t size)
+{
+    unsigned char *bytes = ptr;
+    for (size_t i=0; i < size; i++) {
+        if (bytes[i] != DEADBYTE) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+
 /* The debug free first checks the 2*SST bytes on each end for sanity (in
    particular, that the FORBIDDENBYTEs with the api ID are still intact).
    Then fills the original bytes with DEADBYTE.
index 26f1579..fdeda43 100644 (file)
@@ -101,10 +101,6 @@ Others:
 * _odict_find_node(od, key)
 * _odict_keys_equal(od1, od2)
 
-Used, but specific to the linked-list implementation:
-
-* _odict_free_fast_nodes(od)
-
 And here's a look at how the linked-list relates to the OrderedDict API:
 
 ============ === === ==== ==== ==== === ==== ===== ==== ==== === ==== === ===
@@ -378,7 +374,6 @@ tp_iter           odict_iter
 tp_dictoffset     (offset)
 tp_init           odict_init
 tp_alloc          (repeated)
-tp_new            odict_new
 ================= ================
 
 ================= ================
@@ -522,15 +517,6 @@ struct _odictnode {
 #define _odict_FOREACH(od, node) \
     for (node = _odict_FIRST(od); node != NULL; node = _odictnode_NEXT(node))
 
-#define _odict_FAST_SIZE(od) ((PyDictObject *)od)->ma_keys->dk_size
-
-static void
-_odict_free_fast_nodes(PyODictObject *od) {
-    if (od->od_fast_nodes) {
-        PyMem_FREE(od->od_fast_nodes);
-    }
-}
-
 /* Return the index into the hash table, regardless of a valid node. */
 static Py_ssize_t
 _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
@@ -551,7 +537,8 @@ _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
 
 /* Replace od->od_fast_nodes with a new table matching the size of dict's. */
 static int
-_odict_resize(PyODictObject *od) {
+_odict_resize(PyODictObject *od)
+{
     Py_ssize_t size, i;
     _ODictNode **fast_nodes, *node;
 
@@ -577,7 +564,7 @@ _odict_resize(PyODictObject *od) {
     }
 
     /* Replace the old fast nodes table. */
-    _odict_free_fast_nodes(od);
+    PyMem_FREE(od->od_fast_nodes);
     od->od_fast_nodes = fast_nodes;
     od->od_fast_nodes_size = size;
     od->od_resize_sentinel = ((PyDictObject *)od)->ma_keys;
@@ -615,6 +602,7 @@ _odict_find_node_hash(PyODictObject *od, PyObject *key, Py_hash_t hash)
     index = _odict_get_index(od, key, hash);
     if (index < 0)
         return NULL;
+    assert(od->od_fast_nodes != NULL);
     return od->od_fast_nodes[index];
 }
 
@@ -632,6 +620,7 @@ _odict_find_node(PyODictObject *od, PyObject *key)
     index = _odict_get_index(od, key, hash);
     if (index < 0)
         return NULL;
+    assert(od->od_fast_nodes != NULL);
     return od->od_fast_nodes[index];
 }
 
@@ -676,7 +665,8 @@ _odict_add_new_node(PyODictObject *od, PyObject *key, Py_hash_t hash)
         Py_DECREF(key);
         return -1;
     }
-    else if (od->od_fast_nodes[i] != NULL) {
+    assert(od->od_fast_nodes != NULL);
+    if (od->od_fast_nodes[i] != NULL) {
         /* We already have a node for the key so there's no need to add one. */
         Py_DECREF(key);
         return 0;
@@ -755,6 +745,7 @@ _odict_clear_node(PyODictObject *od, _ODictNode *node, PyObject *key,
     if (i < 0)
         return PyErr_Occurred() ? -1 : 0;
 
+    assert(od->od_fast_nodes != NULL);
     if (node == NULL)
         node = od->od_fast_nodes[i];
     assert(node == od->od_fast_nodes[i]);
@@ -775,8 +766,10 @@ _odict_clear_nodes(PyODictObject *od)
 {
     _ODictNode *node, *next;
 
-    _odict_free_fast_nodes(od);
+    PyMem_FREE(od->od_fast_nodes);
     od->od_fast_nodes = NULL;
+    od->od_fast_nodes_size = 0;
+    od->od_resize_sentinel = NULL;
 
     node = _odict_FIRST(od);
     _odict_FIRST(od) = NULL;
@@ -941,7 +934,7 @@ static PyObject *
 odict_sizeof(PyODictObject *od)
 {
     Py_ssize_t res = _PyDict_SizeOf((PyDictObject *)od);
-    res += sizeof(_ODictNode *) * _odict_FAST_SIZE(od);  /* od_fast_nodes */
+    res += sizeof(_ODictNode *) * od->od_fast_nodes_size;  /* od_fast_nodes */
     if (!_odict_EMPTY(od)) {
         res += sizeof(_ODictNode) * PyODict_SIZE(od);  /* linked-list */
     }
@@ -1231,12 +1224,10 @@ PyDoc_STRVAR(odict_clear__doc__,
              "od.clear() -> None.  Remove all items from od.");
 
 static PyObject *
-odict_clear(register PyODictObject *od)
+odict_clear(register PyODictObject *od, PyObject *Py_UNUSED(ignored))
 {
     PyDict_Clear((PyObject *)od);
     _odict_clear_nodes(od);
-    if (_odict_resize(od) < 0)
-        return NULL;
     Py_RETURN_NONE;
 }
 
@@ -1570,13 +1561,10 @@ odict_traverse(PyODictObject *od, visitproc visit, void *arg)
 static int
 odict_tp_clear(PyODictObject *od)
 {
-    PyObject *res;
     Py_CLEAR(od->od_inst_dict);
     Py_CLEAR(od->od_weakreflist);
-    res = odict_clear(od);
-    if (res == NULL)
-        return -1;
-    Py_DECREF(res);
+    PyDict_Clear((PyObject *)od);
+    _odict_clear_nodes(od);
     return 0;
 }
 
@@ -1651,27 +1639,6 @@ odict_init(PyObject *self, PyObject *args, PyObject *kwds)
     }
 }
 
-/* tp_new */
-
-static PyObject *
-odict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
-    PyODictObject *od;
-
-    od = (PyODictObject *)PyDict_Type.tp_new(type, args, kwds);
-    if (od == NULL)
-        return NULL;
-
-    /* type constructor fills the memory with zeros (see
-       PyType_GenericAlloc()), there is no need to set them to zero again */
-    if (_odict_resize(od) < 0) {
-        Py_DECREF(od);
-        return NULL;
-    }
-
-    return (PyObject*)od;
-}
-
 /* PyODict_Type */
 
 PyTypeObject PyODict_Type = {
@@ -1712,7 +1679,7 @@ PyTypeObject PyODict_Type = {
     offsetof(PyODictObject, od_inst_dict),      /* tp_dictoffset */
     (initproc)odict_init,                       /* tp_init */
     PyType_GenericAlloc,                        /* tp_alloc */
-    (newfunc)odict_new,                         /* tp_new */
+    0,                                          /* tp_new */
     0,                                          /* tp_free */
 };
 
@@ -1722,8 +1689,9 @@ PyTypeObject PyODict_Type = {
  */
 
 PyObject *
-PyODict_New(void) {
-    return odict_new(&PyODict_Type, NULL, NULL);
+PyODict_New(void)
+{
+    return PyDict_Type.tp_new(&PyODict_Type, NULL, NULL);
 }
 
 static int
@@ -1921,40 +1889,21 @@ done:
 PyDoc_STRVAR(reduce_doc, "Return state information for pickling");
 
 static PyObject *
-odictiter_reduce(odictiterobject *di)
+odictiter_reduce(odictiterobject *di, PyObject *Py_UNUSED(ignored))
 {
-    PyObject *list, *iter;
-
-    list = PyList_New(0);
-    if (!list)
-        return NULL;
+    /* copy the iterator state */
+    odictiterobject tmp = *di;
+    Py_XINCREF(tmp.di_odict);
+    Py_XINCREF(tmp.di_current);
 
     /* iterate the temporary into a list */
-    for(;;) {
-        PyObject *element = odictiter_iternext(di);
-        if (element) {
-            if (PyList_Append(list, element)) {
-                Py_DECREF(element);
-                Py_DECREF(list);
-                return NULL;
-            }
-            Py_DECREF(element);
-        }
-        else {
-            /* done iterating? */
-            break;
-        }
-    }
-    if (PyErr_Occurred()) {
-        Py_DECREF(list);
-        return NULL;
-    }
-    iter = _PyObject_GetBuiltin("iter");
-    if (iter == NULL) {
-        Py_DECREF(list);
+    PyObject *list = PySequence_List((PyObject*)&tmp);
+    Py_XDECREF(tmp.di_odict);
+    Py_XDECREF(tmp.di_current);
+    if (list == NULL) {
         return NULL;
     }
-    return Py_BuildValue("N(N)", iter, list);
+    return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), list);
 }
 
 static PyMethodDef odictiter_methods[] = {
index 2fc70cd..4f392a4 100644 (file)
@@ -1256,6 +1256,7 @@ long_range:
     it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
     if (it == NULL)
         return NULL;
+    it->index = it->start = it->step = NULL;
 
     /* start + (len - 1) * step */
     it->len = range->length;
index 96485f8..27836c0 100644 (file)
@@ -294,7 +294,6 @@ actually be smaller than the old one.
 static int
 set_table_resize(PySetObject *so, Py_ssize_t minused)
 {
-    Py_ssize_t newsize;
     setentry *oldtable, *newtable, *entry;
     Py_ssize_t oldfill = so->fill;
     Py_ssize_t oldused = so->used;
@@ -307,13 +306,9 @@ set_table_resize(PySetObject *so, Py_ssize_t minused)
 
     /* Find the smallest table size > minused. */
     /* XXX speed-up with intrinsics */
-    for (newsize = PySet_MINSIZE;
-         newsize <= minused && newsize > 0;
-         newsize <<= 1)
-        ;
-    if (newsize <= 0) {
-        PyErr_NoMemory();
-        return -1;
+    size_t newsize = PySet_MINSIZE;
+    while (newsize <= (size_t)minused) {
+        newsize <<= 1; // The largest possible value is PY_SSIZE_T_MAX + 1.
     }
 
     /* Get space for a new table. */
index df501ed..31fed34 100644 (file)
@@ -1,28 +1,24 @@
-/* stringlib: locale related helpers implementation */
-
-#include <locale.h>
-
-#if !STRINGLIB_IS_UNICODE
-#   error "localeutil.h is specific to Unicode"
-#endif
+/* _PyUnicode_InsertThousandsGrouping() helper functions */
 
 typedef struct {
     const char *grouping;
     char previous;
     Py_ssize_t i; /* Where we're currently pointing in grouping. */
-} STRINGLIB(GroupGenerator);
+} GroupGenerator;
+
 
 static void
-STRINGLIB(GroupGenerator_init)(STRINGLIB(GroupGenerator) *self, const char *grouping)
+GroupGenerator_init(GroupGenerator *self, const char *grouping)
 {
     self->grouping = grouping;
     self->i = 0;
     self->previous = 0;
 }
 
+
 /* Returns the next grouping, or 0 to signify end. */
 static Py_ssize_t
-STRINGLIB(GroupGenerator_next)(STRINGLIB(GroupGenerator) *self)
+GroupGenerator_next(GroupGenerator *self)
 {
     /* Note that we don't really do much error checking here. If a
        grouping string contains just CHAR_MAX, for example, then just
@@ -43,138 +39,44 @@ STRINGLIB(GroupGenerator_next)(STRINGLIB(GroupGenerator) *self)
     }
 }
 
+
 /* Fill in some digits, leading zeros, and thousands separator. All
    are optional, depending on when we're called. */
 static void
-STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end,
-     Py_ssize_t n_chars, Py_ssize_t n_zeros, STRINGLIB_CHAR* thousands_sep,
-     Py_ssize_t thousands_sep_len)
+InsertThousandsGrouping_fill(_PyUnicodeWriter *writer, Py_ssize_t *buffer_pos,
+                             PyObject *digits, Py_ssize_t *digits_pos,
+                             Py_ssize_t n_chars, Py_ssize_t n_zeros,
+                             PyObject *thousands_sep, Py_ssize_t thousands_sep_len,
+                             Py_UCS4 *maxchar)
 {
-    Py_ssize_t i;
+    if (!writer) {
+        /* if maxchar > 127, maxchar is already set */
+        if (*maxchar == 127 && thousands_sep) {
+            Py_UCS4 maxchar2 = PyUnicode_MAX_CHAR_VALUE(thousands_sep);
+            *maxchar = Py_MAX(*maxchar, maxchar2);
+        }
+        return;
+    }
 
     if (thousands_sep) {
-        *buffer_end -= thousands_sep_len;
+        *buffer_pos -= thousands_sep_len;
 
         /* Copy the thousands_sep chars into the buffer. */
-        memcpy(*buffer_end, thousands_sep,
-               thousands_sep_len * STRINGLIB_SIZEOF_CHAR);
-    }
-
-    *buffer_end -= n_chars;
-    *digits_end -= n_chars;
-    memcpy(*buffer_end, *digits_end, n_chars * sizeof(STRINGLIB_CHAR));
-
-    *buffer_end -= n_zeros;
-    for (i = 0; i < n_zeros; i++)
-        (*buffer_end)[i] = '0';
-}
-
-/**
- * InsertThousandsGrouping:
- * @buffer: A pointer to the start of a string.
- * @n_buffer: Number of characters in @buffer.
- * @digits: A pointer to the digits we're reading from. If count
- *          is non-NULL, this is unused.
- * @n_digits: The number of digits in the string, in which we want
- *            to put the grouping chars.
- * @min_width: The minimum width of the digits in the output string.
- *             Output will be zero-padded on the left to fill.
- * @grouping: see definition in localeconv().
- * @thousands_sep: see definition in localeconv().
- *
- * There are 2 modes: counting and filling. If @buffer is NULL,
- *  we are in counting mode, else filling mode.
- * If counting, the required buffer size is returned.
- * If filling, we know the buffer will be large enough, so we don't
- *  need to pass in the buffer size.
- * Inserts thousand grouping characters (as defined by grouping and
- *  thousands_sep) into the string between buffer and buffer+n_digits.
- *
- * Return value: 0 on error, else 1.  Note that no error can occur if
- *  count is non-NULL.
- *
- * This name won't be used, the includer of this file should define
- *  it to be the actual function name, based on unicode or string.
- *
- * As closely as possible, this code mimics the logic in decimal.py's
-    _insert_thousands_sep().
- **/
-static Py_ssize_t
-STRINGLIB(InsertThousandsGrouping)(
-    STRINGLIB_CHAR *buffer,
-    Py_ssize_t n_buffer,
-    STRINGLIB_CHAR *digits,
-    Py_ssize_t n_digits,
-    Py_ssize_t min_width,
-    const char *grouping,
-    STRINGLIB_CHAR *thousands_sep,
-    Py_ssize_t thousands_sep_len)
-{
-    Py_ssize_t count = 0;
-    Py_ssize_t n_zeros;
-    int loop_broken = 0;
-    int use_separator = 0; /* First time through, don't append the
-                              separator. They only go between
-                              groups. */
-    STRINGLIB_CHAR *buffer_end = NULL;
-    STRINGLIB_CHAR *digits_end = NULL;
-    Py_ssize_t l;
-    Py_ssize_t n_chars;
-    Py_ssize_t remaining = n_digits; /* Number of chars remaining to
-                                        be looked at */
-    /* A generator that returns all of the grouping widths, until it
-       returns 0. */
-    STRINGLIB(GroupGenerator) groupgen;
-    STRINGLIB(GroupGenerator_init)(&groupgen, grouping);
-
-    if (buffer) {
-        buffer_end = buffer + n_buffer;
-        digits_end = digits + n_digits;
-    }
-
-    while ((l = STRINGLIB(GroupGenerator_next)(&groupgen)) > 0) {
-        l = Py_MIN(l, Py_MAX(Py_MAX(remaining, min_width), 1));
-        n_zeros = Py_MAX(0, l - remaining);
-        n_chars = Py_MAX(0, Py_MIN(remaining, l));
-
-        /* Use n_zero zero's and n_chars chars */
-
-        /* Count only, don't do anything. */
-        count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
-
-        if (buffer) {
-            /* Copy into the output buffer. */
-            STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros,
-                 use_separator ? thousands_sep : NULL, thousands_sep_len);
-        }
-
-        /* Use a separator next time. */
-        use_separator = 1;
-
-        remaining -= n_chars;
-        min_width -= l;
-
-        if (remaining <= 0 && min_width <= 0) {
-            loop_broken = 1;
-            break;
-        }
-        min_width -= thousands_sep_len;
+        _PyUnicode_FastCopyCharacters(writer->buffer, *buffer_pos,
+                                      thousands_sep, 0,
+                                      thousands_sep_len);
     }
-    if (!loop_broken) {
-        /* We left the loop without using a break statement. */
 
-        l = Py_MAX(Py_MAX(remaining, min_width), 1);
-        n_zeros = Py_MAX(0, l - remaining);
-        n_chars = Py_MAX(0, Py_MIN(remaining, l));
-
-        /* Use n_zero zero's and n_chars chars */
-        count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
-        if (buffer) {
-            /* Copy into the output buffer. */
-            STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros,
-                 use_separator ? thousands_sep : NULL, thousands_sep_len);
-        }
+    *buffer_pos -= n_chars;
+    *digits_pos -= n_chars;
+    _PyUnicode_FastCopyCharacters(writer->buffer, *buffer_pos,
+                                  digits, *digits_pos,
+                                  n_chars);
+
+    if (n_zeros) {
+        *buffer_pos -= n_zeros;
+        enum PyUnicode_Kind kind = PyUnicode_KIND(writer->buffer);
+        void *data = PyUnicode_DATA(writer->buffer);
+        FILL(kind, data, '0', *buffer_pos, n_zeros);
     }
-    return count;
 }
-
index ed2d400..a811eaa 100644 (file)
@@ -6596,7 +6596,7 @@ static slotdef slotdefs[] = {
            "__repr__($self, /)\n--\n\nReturn repr(self)."),
     TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc,
            "__hash__($self, /)\n--\n\nReturn hash(self)."),
-    FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call,
+    FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)(void(*)(void))wrap_call,
            "__call__($self, /, *args, **kwargs)\n--\n\nCall self as a function.",
            PyWrapperFlag_KEYWORDS),
     TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc,
@@ -6632,7 +6632,7 @@ static slotdef slotdefs[] = {
     TPSLOT("__delete__", tp_descr_set, slot_tp_descr_set,
            wrap_descr_delete,
            "__delete__($self, instance, /)\n--\n\nDelete an attribute of instance."),
-    FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init,
+    FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)(void(*)(void))wrap_init,
            "__init__($self, /, *args, **kwargs)\n--\n\n"
            "Initialize self.  See help(type(self)) for accurate signature.",
            PyWrapperFlag_KEYWORDS),
index 972423e..0e64bf9 100644 (file)
@@ -203,6 +203,39 @@ static PyObject *unicode_empty = NULL;
         return unicode_empty;                           \
     } while (0)
 
+#define FILL(kind, data, value, start, length) \
+    do { \
+        assert(0 <= start); \
+        assert(kind != PyUnicode_WCHAR_KIND); \
+        switch (kind) { \
+        case PyUnicode_1BYTE_KIND: { \
+            assert(value <= 0xff); \
+            Py_UCS1 ch = (unsigned char)value; \
+            Py_UCS1 *to = (Py_UCS1 *)data + start; \
+            memset(to, ch, length); \
+            break; \
+        } \
+        case PyUnicode_2BYTE_KIND: { \
+            assert(value <= 0xffff); \
+            Py_UCS2 ch = (Py_UCS2)value; \
+            Py_UCS2 *to = (Py_UCS2 *)data + start; \
+            const Py_UCS2 *end = to + length; \
+            for (; to < end; ++to) *to = ch; \
+            break; \
+        } \
+        case PyUnicode_4BYTE_KIND: { \
+            assert(value <= MAX_UNICODE); \
+            Py_UCS4 ch = value; \
+            Py_UCS4 * to = (Py_UCS4 *)data + start; \
+            const Py_UCS4 *end = to + length; \
+            for (; to < end; ++to) *to = ch; \
+            break; \
+        } \
+        default: assert(0); \
+        } \
+    } while (0)
+
+
 /* Forward declaration */
 static inline int
 _PyUnicodeWriter_WriteCharInline(_PyUnicodeWriter *writer, Py_UCS4 ch);
@@ -779,7 +812,6 @@ ensure_unicode(PyObject *obj)
 #include "stringlib/count.h"
 #include "stringlib/find.h"
 #include "stringlib/find_max_char.h"
-#include "stringlib/localeutil.h"
 #include "stringlib/undef.h"
 
 #include "stringlib/ucs1lib.h"
@@ -790,7 +822,6 @@ ensure_unicode(PyObject *obj)
 #include "stringlib/find.h"
 #include "stringlib/replace.h"
 #include "stringlib/find_max_char.h"
-#include "stringlib/localeutil.h"
 #include "stringlib/undef.h"
 
 #include "stringlib/ucs2lib.h"
@@ -801,7 +832,6 @@ ensure_unicode(PyObject *obj)
 #include "stringlib/find.h"
 #include "stringlib/replace.h"
 #include "stringlib/find_max_char.h"
-#include "stringlib/localeutil.h"
 #include "stringlib/undef.h"
 
 #include "stringlib/ucs4lib.h"
@@ -812,7 +842,6 @@ ensure_unicode(PyObject *obj)
 #include "stringlib/find.h"
 #include "stringlib/replace.h"
 #include "stringlib/find_max_char.h"
-#include "stringlib/localeutil.h"
 #include "stringlib/undef.h"
 
 #include "stringlib/unicodedefs.h"
@@ -6133,7 +6162,7 @@ _PyUnicode_DecodeUnicodeEscape(const char *s,
             }
 
             message = "malformed \\N character escape";
-            if (*s == '{') {
+            if (s < end && *s == '{') {
                 const char *start = ++s;
                 size_t namelen;
                 /* look for the closing brace */
@@ -7256,7 +7285,7 @@ decode_code_page_errors(UINT code_page,
                          "in the target code page.";
     /* each step cannot decode more than 1 character, but a character can be
        represented as a surrogate pair */
-    wchar_t buffer[2], *startout, *out;
+    wchar_t buffer[2], *out;
     int insize;
     Py_ssize_t outsize;
     PyObject *errorHandler = NULL;
@@ -7293,7 +7322,7 @@ decode_code_page_errors(UINT code_page,
         *v = (PyObject*)_PyUnicode_New(size * Py_ARRAY_LENGTH(buffer));
         if (*v == NULL)
             goto error;
-        startout = PyUnicode_AS_UNICODE(*v);
+        out = PyUnicode_AS_UNICODE(*v);
     }
     else {
         /* Extend unicode object */
@@ -7304,11 +7333,10 @@ decode_code_page_errors(UINT code_page,
         }
         if (unicode_resize(v, n + size * Py_ARRAY_LENGTH(buffer)) < 0)
             goto error;
-        startout = PyUnicode_AS_UNICODE(*v) + n;
+        out = PyUnicode_AS_UNICODE(*v) + n;
     }
 
     /* Decode the byte string character per character */
-    out = startout;
     while (in < endin)
     {
         /* Decode a character */
@@ -7363,7 +7391,7 @@ decode_code_page_errors(UINT code_page,
     *out = 0;
 
     /* Extend unicode object */
-    outsize = out - startout;
+    outsize = out - PyUnicode_AS_UNICODE(*v);
     assert(outsize <= PyUnicode_WSTR_LENGTH(*v));
     if (unicode_resize(v, outsize) < 0)
         goto error;
@@ -9407,87 +9435,149 @@ any_find_slice(PyObject* s1, PyObject* s2,
     return result;
 }
 
+/* _PyUnicode_InsertThousandsGrouping() helper functions */
+#include "stringlib/localeutil.h"
+
+/**
+ * InsertThousandsGrouping:
+ * @writer: Unicode writer.
+ * @n_buffer: Number of characters in @buffer.
+ * @digits: Digits we're reading from. If count is non-NULL, this is unused.
+ * @d_pos: Start of digits string.
+ * @n_digits: The number of digits in the string, in which we want
+ *            to put the grouping chars.
+ * @min_width: The minimum width of the digits in the output string.
+ *             Output will be zero-padded on the left to fill.
+ * @grouping: see definition in localeconv().
+ * @thousands_sep: see definition in localeconv().
+ *
+ * There are 2 modes: counting and filling. If @writer is NULL,
+ *  we are in counting mode, else filling mode.
+ * If counting, the required buffer size is returned.
+ * If filling, we know the buffer will be large enough, so we don't
+ *  need to pass in the buffer size.
+ * Inserts thousand grouping characters (as defined by grouping and
+ *  thousands_sep) into @writer.
+ *
+ * Return value: -1 on error, number of characters otherwise.
+ **/
 Py_ssize_t
 _PyUnicode_InsertThousandsGrouping(
-    PyObject *unicode, Py_ssize_t index,
+    _PyUnicodeWriter *writer,
     Py_ssize_t n_buffer,
-    void *digits, Py_ssize_t n_digits,
+    PyObject *digits,
+    Py_ssize_t d_pos,
+    Py_ssize_t n_digits,
     Py_ssize_t min_width,
-    const char *grouping, PyObject *thousands_sep,
+    const char *grouping,
+    PyObject *thousands_sep,
     Py_UCS4 *maxchar)
 {
-    unsigned int kind, thousands_sep_kind;
-    char *data, *thousands_sep_data;
-    Py_ssize_t thousands_sep_len;
-    Py_ssize_t len;
-
-    if (unicode != NULL) {
-        kind = PyUnicode_KIND(unicode);
-        data = (char *) PyUnicode_DATA(unicode) + index * kind;
+    if (writer) {
+        assert(digits != NULL);
+        assert(maxchar == NULL);
     }
     else {
-        kind = PyUnicode_1BYTE_KIND;
-        data = NULL;
-    }
-    thousands_sep_kind = PyUnicode_KIND(thousands_sep);
-    thousands_sep_data = PyUnicode_DATA(thousands_sep);
-    thousands_sep_len = PyUnicode_GET_LENGTH(thousands_sep);
-    if (unicode != NULL && thousands_sep_kind != kind) {
-        if (thousands_sep_kind < kind) {
-            thousands_sep_data = _PyUnicode_AsKind(thousands_sep, kind);
-            if (!thousands_sep_data)
-                return -1;
-        }
-        else {
-            data = _PyUnicode_AsKind(unicode, thousands_sep_kind);
-            if (!data)
-                return -1;
-        }
+        assert(digits == NULL);
+        assert(maxchar != NULL);
     }
+    assert(0 <= d_pos);
+    assert(0 <= n_digits);
+    assert(0 <= min_width);
+    assert(grouping != NULL);
 
-    switch (kind) {
-    case PyUnicode_1BYTE_KIND:
-        if (unicode != NULL && PyUnicode_IS_ASCII(unicode))
-            len = asciilib_InsertThousandsGrouping(
-                (Py_UCS1 *) data, n_buffer, (Py_UCS1 *) digits, n_digits,
-                min_width, grouping,
-                (Py_UCS1 *) thousands_sep_data, thousands_sep_len);
-        else
-            len = ucs1lib_InsertThousandsGrouping(
-                (Py_UCS1*)data, n_buffer, (Py_UCS1*)digits, n_digits,
-                min_width, grouping,
-                (Py_UCS1 *) thousands_sep_data, thousands_sep_len);
-        break;
-    case PyUnicode_2BYTE_KIND:
-        len = ucs2lib_InsertThousandsGrouping(
-            (Py_UCS2 *) data, n_buffer, (Py_UCS2 *) digits, n_digits,
-            min_width, grouping,
-            (Py_UCS2 *) thousands_sep_data, thousands_sep_len);
-        break;
-    case PyUnicode_4BYTE_KIND:
-        len = ucs4lib_InsertThousandsGrouping(
-            (Py_UCS4 *) data, n_buffer, (Py_UCS4 *) digits, n_digits,
-            min_width, grouping,
-            (Py_UCS4 *) thousands_sep_data, thousands_sep_len);
-        break;
-    default:
-        assert(0);
+    if (digits != NULL) {
+        if (PyUnicode_READY(digits) == -1) {
+            return -1;
+        }
+    }
+    if (PyUnicode_READY(thousands_sep) == -1) {
         return -1;
     }
-    if (unicode != NULL && thousands_sep_kind != kind) {
-        if (thousands_sep_kind < kind)
-            PyMem_Free(thousands_sep_data);
-        else
-            PyMem_Free(data);
+
+    Py_ssize_t count = 0;
+    Py_ssize_t n_zeros;
+    int loop_broken = 0;
+    int use_separator = 0; /* First time through, don't append the
+                              separator. They only go between
+                              groups. */
+    Py_ssize_t buffer_pos;
+    Py_ssize_t digits_pos;
+    Py_ssize_t len;
+    Py_ssize_t n_chars;
+    Py_ssize_t remaining = n_digits; /* Number of chars remaining to
+                                        be looked at */
+    /* A generator that returns all of the grouping widths, until it
+       returns 0. */
+    GroupGenerator groupgen;
+    GroupGenerator_init(&groupgen, grouping);
+    const Py_ssize_t thousands_sep_len = PyUnicode_GET_LENGTH(thousands_sep);
+
+    /* if digits are not grouped, thousands separator
+       should be an empty string */
+    assert(!(grouping[0] == CHAR_MAX && thousands_sep_len != 0));
+
+    digits_pos = d_pos + n_digits;
+    if (writer) {
+        buffer_pos = writer->pos + n_buffer;
+        assert(buffer_pos <= PyUnicode_GET_LENGTH(writer->buffer));
+        assert(digits_pos <= PyUnicode_GET_LENGTH(digits));
     }
-    if (unicode == NULL) {
+    else {
+        buffer_pos = n_buffer;
+    }
+
+    if (!writer) {
         *maxchar = 127;
-        if (len != n_digits) {
-            *maxchar = Py_MAX(*maxchar,
-                                   PyUnicode_MAX_CHAR_VALUE(thousands_sep));
+    }
+
+    while ((len = GroupGenerator_next(&groupgen)) > 0) {
+        len = Py_MIN(len, Py_MAX(Py_MAX(remaining, min_width), 1));
+        n_zeros = Py_MAX(0, len - remaining);
+        n_chars = Py_MAX(0, Py_MIN(remaining, len));
+
+        /* Use n_zero zero's and n_chars chars */
+
+        /* Count only, don't do anything. */
+        count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
+
+        /* Copy into the writer. */
+        InsertThousandsGrouping_fill(writer, &buffer_pos,
+                                     digits, &digits_pos,
+                                     n_chars, n_zeros,
+                                     use_separator ? thousands_sep : NULL,
+                                     thousands_sep_len, maxchar);
+
+        /* Use a separator next time. */
+        use_separator = 1;
+
+        remaining -= n_chars;
+        min_width -= len;
+
+        if (remaining <= 0 && min_width <= 0) {
+            loop_broken = 1;
+            break;
         }
+        min_width -= thousands_sep_len;
     }
-    return len;
+    if (!loop_broken) {
+        /* We left the loop without using a break statement. */
+
+        len = Py_MAX(Py_MAX(remaining, min_width), 1);
+        n_zeros = Py_MAX(0, len - remaining);
+        n_chars = Py_MAX(0, Py_MIN(remaining, len));
+
+        /* Use n_zero zero's and n_chars chars */
+        count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
+
+        /* Copy into the writer. */
+        InsertThousandsGrouping_fill(writer, &buffer_pos,
+                                     digits, &digits_pos,
+                                     n_chars, n_zeros,
+                                     use_separator ? thousands_sep : NULL,
+                                     thousands_sep_len, maxchar);
+    }
+    return count;
 }
 
 
@@ -10174,36 +10264,12 @@ _PyUnicode_JoinArray(PyObject *separator, PyObject **items, Py_ssize_t seqlen)
     return NULL;
 }
 
-#define FILL(kind, data, value, start, length) \
-    do { \
-        Py_ssize_t i_ = 0; \
-        assert(kind != PyUnicode_WCHAR_KIND); \
-        switch ((kind)) { \
-        case PyUnicode_1BYTE_KIND: { \
-            unsigned char * to_ = (unsigned char *)((data)) + (start); \
-            memset(to_, (unsigned char)value, (length)); \
-            break; \
-        } \
-        case PyUnicode_2BYTE_KIND: { \
-            Py_UCS2 * to_ = (Py_UCS2 *)((data)) + (start); \
-            for (; i_ < (length); ++i_, ++to_) *to_ = (value); \
-            break; \
-        } \
-        case PyUnicode_4BYTE_KIND: { \
-            Py_UCS4 * to_ = (Py_UCS4 *)((data)) + (start); \
-            for (; i_ < (length); ++i_, ++to_) *to_ = (value); \
-            break; \
-        } \
-        default: assert(0); \
-        } \
-    } while (0)
-
 void
 _PyUnicode_FastFill(PyObject *unicode, Py_ssize_t start, Py_ssize_t length,
                     Py_UCS4 fill_char)
 {
     const enum PyUnicode_Kind kind = PyUnicode_KIND(unicode);
-    const void *data = PyUnicode_DATA(unicode);
+    void *data = PyUnicode_DATA(unicode);
     assert(PyUnicode_IS_READY(unicode));
     assert(unicode_modifiable(unicode));
     assert(fill_char <= PyUnicode_MAX_CHAR_VALUE(unicode));
index af4af76..880ea7b 100644 (file)
@@ -586,6 +586,9 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
     size_t prefixlen = wcslen(prefix);
 
     wchar_t *buf = (wchar_t*)PyMem_RawMalloc(bufsiz * sizeof(wchar_t));
+    if (buf == NULL) {
+        goto error;
+    }
     buf[0] = '\0';
 
     while (!feof(sp_file)) {
@@ -611,17 +614,22 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
 
         DWORD wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, NULL, 0);
         wchar_t *wline = (wchar_t*)PyMem_RawMalloc((wn + 1) * sizeof(wchar_t));
+        if (wline == NULL) {
+            goto error;
+        }
         wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1);
         wline[wn] = '\0';
 
         size_t usedsiz = wcslen(buf);
         while (usedsiz + wn + prefixlen + 4 > bufsiz) {
             bufsiz += MAXPATHLEN;
-            buf = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) * sizeof(wchar_t));
-            if (!buf) {
+            wchar_t *tmp = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) *
+                                                            sizeof(wchar_t));
+            if (tmp == NULL) {
                 PyMem_RawFree(wline);
                 goto error;
             }
+            buf = tmp;
         }
 
         if (usedsiz) {
index 5efdc5e..3fde04d 100644 (file)
@@ -757,9 +757,13 @@ Reg2Py(BYTE *retDataBuf, DWORD retDataSize, DWORD typ)
                         PyMem_Free(str);
                         return NULL;
                     }
-                    PyList_SetItem(obData,
-                                   index,
-                                   PyUnicode_FromWideChar(str[index], len));
+                    PyObject *uni = PyUnicode_FromWideChar(str[index], len);
+                    if (uni == NULL) {
+                        Py_DECREF(obData);
+                        PyMem_Free(str);
+                        return NULL;
+                    }
+                    PyList_SET_ITEM(obData, index, uni);
                 }
                 PyMem_Free(str);
 
index 18a9931..df965b6 100644 (file)
@@ -141,4 +141,5 @@ goto :eof
 \r
 :Version\r
 rem Display the current build version information\r
-%MSBUILD% "%dir%python.props" /t:ShowVersionInfo /v:m /nologo %1 %2 %3 %4 %5 %6 %7 %8 %9\r
+call "%dir%find_msbuild.bat" %MSBUILD%\r
+if not ERRORLEVEL 1 %MSBUILD% "%dir%pythoncore.vcxproj" /t:ShowVersionInfo /v:m /nologo %1 %2 %3 %4 %5 %6 %7 %8 %9\r
index 639bf86..4f04318 100644 (file)
@@ -41,7 +41,7 @@ echo.Fetching external libraries...
 \r
 set libraries=\r
 set libraries=%libraries%                                    bzip2-1.0.6\r
-if NOT "%IncludeSSL%"=="false" set libraries=%libraries%     openssl-1.0.2p\r
+if NOT "%IncludeSSL%"=="false" set libraries=%libraries%     openssl-1.0.2q\r
 set libraries=%libraries%                                    sqlite-3.21.0.0\r
 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tcl-core-8.6.6.0\r
 if NOT "%IncludeTkinter%"=="false" set libraries=%libraries% tk-8.6.6.0\r
index cd59401..4957fba 100644 (file)
     <!--\r
     <ClCompile Include="$(opensslDir)crypto\fips_ers.c" />\r
     -->\r
+    <ClCompile Include="$(opensslDir)crypto\getenv.c" />\r
     <ClCompile Include="$(opensslDir)crypto\hmac\hm_ameth.c" />\r
     <ClCompile Include="$(opensslDir)crypto\hmac\hm_pmeth.c" />\r
     <ClCompile Include="$(opensslDir)crypto\hmac\hmac.c" />\r
     <ClCompile Include="$(opensslDir)crypto\ui\ui_lib.c" />\r
     <ClCompile Include="$(opensslDir)crypto\ui\ui_openssl.c" />\r
     <ClCompile Include="$(opensslDir)crypto\ui\ui_util.c" />\r
-    <!--\r
     <ClCompile Include="$(opensslDir)crypto\uid.c" />\r
-    -->\r
     <ClCompile Include="$(opensslDir)crypto\whrlpool\wp_dgst.c" />\r
     <ClCompile Include="$(opensslDir)crypto\x509\by_dir.c" />\r
     <ClCompile Include="$(opensslDir)crypto\x509\by_file.c" />\r
index 20538c1..a297b4f 100644 (file)
       <FileName Required="true" />\r
     </ParameterGroup>\r
     <Task>\r
-      <Code Type="Fragment" Language="cs">\r
+      <Using Namespace="System.Diagnostics"/>\r
+      <Using Namespace="System.IO"/>\r
+      <Using Namespace="System.Runtime.InteropServices"/>\r
+      <Using Namespace="System.Text"/>\r
+      <Code Type="Method" Language="cs">\r
 <![CDATA[\r
-string fullPath = System.IO.Path.GetFullPath(FileName);\r
-Log.LogMessage("Looking for " + fullPath, MessageImportance.Normal);\r
-foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses()) {\r
-    try {\r
-        Log.LogMessage("Found running process: " + p.MainModule.FileName, MessageImportance.Low);\r
-        if (fullPath.Equals(System.IO.Path.GetFullPath(p.MainModule.FileName), StringComparison.OrdinalIgnoreCase)) {\r
-            Log.LogMessage("Terminating " + p.MainModule.FileName, MessageImportance.High);\r
-            p.Kill();\r
+[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]\r
+public static extern bool QueryFullProcessImageName([In]IntPtr hProcess, [In]int dwFlags,\r
+                                                    [Out]StringBuilder lpExeName, ref int lpdwSize);\r
+public override bool Execute() {\r
+    string fullPath = Path.GetFullPath(FileName);\r
+    Log.LogMessage("Looking for " + fullPath, MessageImportance.Normal);\r
+    foreach (Process p in Process.GetProcesses()) {\r
+        try {\r
+            int pathLength = 32768;\r
+            StringBuilder pathBuilder = new StringBuilder(pathLength);\r
+            if (QueryFullProcessImageName(p.Handle, 0, pathBuilder, ref pathLength)) {\r
+                string exeName = Path.GetFullPath(pathBuilder.ToString());\r
+                Log.LogMessage("Found running process: " + exeName, MessageImportance.Low);\r
+                if (fullPath.Equals(exeName, StringComparison.OrdinalIgnoreCase)) {\r
+                    Log.LogMessage("Terminating " + exeName, MessageImportance.High);\r
+                    p.Kill();\r
+                }\r
+            }\r
+        } catch {\r
         }\r
-    } catch {\r
     }\r
+    return true;\r
 }\r
 ]]>\r
       </Code>\r
index 59162fc..eefbdc4 100644 (file)
@@ -49,7 +49,7 @@
     <sqlite3Dir>$(ExternalsDir)sqlite-3.21.0.0\</sqlite3Dir>\r
     <bz2Dir>$(ExternalsDir)bzip2-1.0.6\</bz2Dir>\r
     <lzmaDir>$(ExternalsDir)xz-5.2.2\</lzmaDir>\r
-    <opensslDir>$(ExternalsDir)openssl-1.0.2p\</opensslDir>\r
+    <opensslDir>$(ExternalsDir)openssl-1.0.2q\</opensslDir>\r
     <opensslIncludeDir>$(opensslDir)include32</opensslIncludeDir>\r
     <opensslIncludeDir Condition="'$(ArchName)' == 'amd64'">$(opensslDir)include64</opensslIncludeDir>\r
     <nasmDir>$(ExternalsDir)\nasm-2.11.06\</nasmDir>\r
     possible version). Since we limit WINVER to Windows 7 anyway, it doesn't really\r
     matter which WinSDK version we use.\r
     -->\r
-    <_RegistryVersion>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion)</_RegistryVersion>\r
-    <_RegistryVersion Condition="$(_RegistryVersion) == ''">$(Registry:HKEY_LOCAL_MACHINE\WOW6432Node\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion)</_RegistryVersion>\r
-    <DefaultWindowsSDKVersion>10.0.15063.0</DefaultWindowsSDKVersion>\r
-    <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == '10.0.14393'">10.0.14393.0</DefaultWindowsSDKVersion>\r
-    <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == '10.0.10586'">10.0.10586.0</DefaultWindowsSDKVersion>\r
-    <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == '10.0.10240'">10.0.10240.0</DefaultWindowsSDKVersion>\r
+    <_KitsRoot>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder)</_KitsRoot>\r
+    <_KitsRoot Condition="$(_KitsRoot) == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0@InstallationFolder)</_KitsRoot>\r
+\r
+    <!-- The minimum allowed SDK version to use for building -->\r
+    <DefaultWindowsSDKVersion>10.0.10586.0</DefaultWindowsSDKVersion>\r
+    <DefaultWindowsSDKVersion Condition="Exists('$(_KitsRoot)\Platforms\UAP\10.0.14393.0')">10.0.14393.0</DefaultWindowsSDKVersion>\r
+    <DefaultWindowsSDKVersion Condition="Exists('$(_KitsRoot)\Platforms\UAP\10.0.15063.0')">10.0.15063.0</DefaultWindowsSDKVersion>\r
+  </PropertyGroup>\r
+  \r
+  <PropertyGroup Condition="$(WindowsTargetPlatformVersion) == ''">\r
+    <WindowsTargetPlatformVersion>$(DefaultWindowsSDKVersion)</WindowsTargetPlatformVersion>\r
   </PropertyGroup>\r
 \r
   <PropertyGroup Condition="'$(OverrideVersion)' == ''">\r
     <Message Importance="high" Text="Field3Value:         $(Field3Value)" />\r
     <Message Importance="high" Text="SysWinVer:           $(SysWinVer)" />\r
     <Message Importance="high" Text="PyDllName:           $(PyDllName)" />\r
+    <Message Importance="high" Text="WindowsSdkVersion:   $(TargetPlatformVersion)" />\r
   </Target>\r
 </Project>\r
index 476af71..34a6f8b 100644 (file)
@@ -162,20 +162,37 @@ _PyOS_WindowsConsoleReadline(HANDLE hStdIn)
             wbuf = (wchar_t*)PyMem_RawMalloc(wbuflen * sizeof(wchar_t));
             if (wbuf)
                 wcscpy_s(wbuf, wbuflen, wbuf_local);
+            else {
+                PyErr_NoMemory();
+                goto exit;
+            }
+        }
+        else {
+            wchar_t *tmp = PyMem_RawRealloc(wbuf, wbuflen * sizeof(wchar_t));
+            if (tmp == NULL) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+            wbuf = tmp;
         }
-        else
-            wbuf = (wchar_t*)PyMem_RawRealloc(wbuf, wbuflen * sizeof(wchar_t));
     }
 
     if (wbuf[0] == '\x1a') {
         buf = PyMem_RawMalloc(1);
         if (buf)
             buf[0] = '\0';
+        else {
+            PyErr_NoMemory();
+        }
         goto exit;
     }
 
     u8len = WideCharToMultiByte(CP_UTF8, 0, wbuf, total_read, NULL, 0, NULL, NULL);
     buf = PyMem_RawMalloc(u8len + 1);
+    if (buf == NULL) {
+        PyErr_NoMemory();
+        goto exit;
+    }
     u8len = WideCharToMultiByte(CP_UTF8, 0, wbuf, total_read, buf, u8len, NULL, NULL);
     buf[u8len] = '\0';
 
@@ -224,8 +241,12 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
                     int wlen;
                     wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1,
                             NULL, 0);
-                    if (wlen &&
-                        (wbuf = PyMem_RawMalloc(wlen * sizeof(wchar_t)))) {
+                    if (wlen) {
+                        wbuf = PyMem_RawMalloc(wlen * sizeof(wchar_t));
+                        if (wbuf == NULL) {
+                            PyErr_NoMemory();
+                            return NULL;
+                        }
                         wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1,
                                 wbuf, wlen);
                         if (wlen) {
@@ -249,8 +270,10 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
 
     n = 100;
     p = (char *)PyMem_RawMalloc(n);
-    if (p == NULL)
+    if (p == NULL) {
+        PyErr_NoMemory();
         return NULL;
+    }
 
     fflush(sys_stdout);
     if (prompt)
@@ -328,6 +351,10 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
 #ifdef WITH_THREAD
     if (_PyOS_ReadlineLock == NULL) {
         _PyOS_ReadlineLock = PyThread_allocate_lock();
+        if (_PyOS_ReadlineLock == NULL) {
+            PyErr_SetString(PyExc_MemoryError, "can't allocate lock");
+            return NULL;
+        }
     }
 #endif
 
@@ -360,8 +387,12 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt)
 
     len = strlen(rv) + 1;
     res = PyMem_Malloc(len);
-    if (res != NULL)
+    if (res != NULL) {
         memcpy(res, rv, len);
+    }
+    else {
+        PyErr_NoMemory();
+    }
     PyMem_RawFree(rv);
 
     return res;
index ab72f61..0d3ad4d 100644 (file)
@@ -956,6 +956,11 @@ tok_nextc(struct tok_state *tok)
                 buflen = PyBytes_GET_SIZE(u);
                 buf = PyBytes_AS_STRING(u);
                 newtok = PyMem_MALLOC(buflen+1);
+                if (newtok == NULL) {
+                    Py_DECREF(u);
+                    tok->done = E_NOMEM;
+                    return EOF;
+                }
                 strcpy(newtok, buf);
                 Py_DECREF(u);
             }
index e96e154..3ae68bb 100644 (file)
@@ -248,7 +248,11 @@ already_warned(PyObject *registry, PyObject *key, int should_set)
     version_obj = _PyDict_GetItemId(registry, &PyId_version);
     if (version_obj == NULL
         || !PyLong_CheckExact(version_obj)
-        || PyLong_AsLong(version_obj) != _filters_version) {
+        || PyLong_AsLong(version_obj) != _filters_version)
+    {
+        if (PyErr_Occurred()) {
+            return -1;
+        }
         PyDict_Clear(registry);
         version_obj = PyLong_FromLong(_filters_version);
         if (version_obj == NULL)
index 51175cd..675063e 100644 (file)
@@ -4104,6 +4104,9 @@ parsenumber(struct compiling *c, const char *s)
     }
     /* Create a duplicate without underscores. */
     dup = PyMem_Malloc(strlen(s) + 1);
+    if (dup == NULL) {
+        return PyErr_NoMemory();
+    }
     end = dup;
     for (; *s; s++) {
         if (*s != '_') {
@@ -4338,8 +4341,10 @@ fstring_compile_expr(const char *expr_start, const char *expr_end,
     len = expr_end - expr_start;
     /* Allocate 3 extra bytes: open paren, close paren, null byte. */
     str = PyMem_RawMalloc(len + 3);
-    if (str == NULL)
+    if (str == NULL) {
+        PyErr_NoMemory();
         return NULL;
+    }
 
     str[0] = '(';
     memcpy(str+1, expr_start, len);
index 50834f8..0b30cc1 100644 (file)
@@ -4667,6 +4667,20 @@ PyEval_GetBuiltins(void)
         return current_frame->f_builtins;
 }
 
+/* Convenience function to get a builtin from its name */
+PyObject *
+_PyEval_GetBuiltinId(_Py_Identifier *name)
+{
+    PyObject *attr = _PyDict_GetItemIdWithError(PyEval_GetBuiltins(), name);
+    if (attr) {
+        Py_INCREF(attr);
+    }
+    else if (!PyErr_Occurred()) {
+        PyErr_SetObject(PyExc_AttributeError, _PyUnicode_FromId(name));
+    }
+    return attr;
+}
+
 PyObject *
 PyEval_GetLocals(void)
 {
@@ -5471,7 +5485,7 @@ unicode_concatenate(PyObject *v, PyObject *w,
             PyObject *names = f->f_code->co_names;
             PyObject *name = GETITEM(names, oparg);
             PyObject *locals = f->f_locals;
-            if (PyDict_CheckExact(locals) &&
+            if (locals && PyDict_CheckExact(locals) &&
                 PyDict_GetItem(locals, name) == v) {
                 if (PyDict_DelItem(locals, name) != 0) {
                     PyErr_Clear();
@@ -5500,7 +5514,7 @@ getarray(long a[256])
             Py_DECREF(l);
             return NULL;
         }
-        PyList_SetItem(l, i, x);
+        PyList_SET_ITEM(l, i, x);
     }
     for (i = 0; i < 256; i++)
         a[i] = 0;
@@ -5522,7 +5536,7 @@ _Py_GetDXProfile(PyObject *self, PyObject *args)
             Py_DECREF(l);
             return NULL;
         }
-        PyList_SetItem(l, i, x);
+        PyList_SET_ITEM(l, i, x);
     }
     return l;
 #endif
index 4ff8301..584c1ef 100644 (file)
@@ -129,8 +129,10 @@ PyObject *_PyCodec_Lookup(const char *encoding)
 
     /* Next, scan the search functions in order of registration */
     args = PyTuple_New(1);
-    if (args == NULL)
-        goto onError;
+    if (args == NULL) {
+        Py_DECREF(v);
+        return NULL;
+    }
     PyTuple_SET_ITEM(args,0,v);
 
     len = PyList_Size(interp->codec_search_path);
index c1df7e8..fac1c5b 100644 (file)
@@ -2492,8 +2492,9 @@ compiler_try_except(struct compiler *c, stmt_ty s)
 
             cleanup_end = compiler_new_block(c);
             cleanup_body = compiler_new_block(c);
-            if (!(cleanup_end || cleanup_body))
+            if (cleanup_end == NULL || cleanup_body == NULL) {
                 return 0;
+            }
 
             compiler_nameop(c, handler->v.ExceptHandler.name, Store);
             ADDOP(c, POP_TOP);
index b8e4891..d1a9ca0 100644 (file)
@@ -1263,18 +1263,9 @@ _Py_read(int fd, void *buf, size_t count)
      * handler raised an exception. */
     assert(!PyErr_Occurred());
 
-#ifdef MS_WINDOWS
-    if (count > INT_MAX) {
-        /* On Windows, the count parameter of read() is an int */
-        count = INT_MAX;
-    }
-#else
-    if (count > PY_SSIZE_T_MAX) {
-        /* if count is greater than PY_SSIZE_T_MAX,
-         * read() result is undefined */
-        count = PY_SSIZE_T_MAX;
+    if (count > _PY_READ_MAX) {
+        count = _PY_READ_MAX;
     }
-#endif
 
     _Py_BEGIN_SUPPRESS_IPH
     do {
@@ -1325,15 +1316,10 @@ _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
            depending on heap usage). */
         count = 32767;
     }
-    else if (count > INT_MAX)
-        count = INT_MAX;
-#else
-    if (count > PY_SSIZE_T_MAX) {
-        /* write() should truncate count to PY_SSIZE_T_MAX, but it's safer
-         * to do it ourself to have a portable behaviour. */
-        count = PY_SSIZE_T_MAX;
-    }
 #endif
+    if (count > _PY_WRITE_MAX) {
+        count = _PY_WRITE_MAX;
+    }
 
     if (gil_held) {
         do {
@@ -1701,7 +1687,7 @@ _Py_GetLocaleconvNumeric(PyObject **decimal_point, PyObject **thousands_sep,
     if (change_locale) {
         oldloc = setlocale(LC_CTYPE, NULL);
         if (!oldloc) {
-            PyErr_SetString(PyExc_RuntimeWarning, "faild to get LC_CTYPE locale");
+            PyErr_SetString(PyExc_RuntimeWarning, "failed to get LC_CTYPE locale");
             return -1;
         }
 
@@ -1717,7 +1703,7 @@ _Py_GetLocaleconvNumeric(PyObject **decimal_point, PyObject **thousands_sep,
         }
 
         if (loc != NULL) {
-            /* Only set the locale temporarilty the LC_CTYPE locale
+            /* Only set the locale temporarily the LC_CTYPE locale
                if LC_NUMERIC locale is different than LC_CTYPE locale and
                decimal_point and/or thousands_sep are non-ASCII or longer than
                1 byte */
index d6772c5..4a38f7a 100644 (file)
@@ -397,9 +397,10 @@ typedef struct {
     PyObject *decimal_point;
     PyObject *thousands_sep;
     const char *grouping;
+    char *grouping_buffer;
 } LocaleInfo;
 
-#define STATIC_LOCALE_INFO_INIT {0, 0, 0}
+#define STATIC_LOCALE_INFO_INIT {0, 0, 0, 0}
 
 /* describes the layout for an integer, see the comment in
    calc_number_widths() for details */
@@ -461,7 +462,8 @@ parse_number(PyObject *s, Py_ssize_t pos, Py_ssize_t end,
 /* not all fields of format are used.  for example, precision is
    unused.  should this take discrete params in order to be more clear
    about what it does?  or is passing a single format parameter easier
-   and more efficient enough to justify a little obfuscation? */
+   and more efficient enough to justify a little obfuscation?
+   Return -1 on error. */
 static Py_ssize_t
 calc_number_widths(NumberFieldWidths *spec, Py_ssize_t n_prefix,
                    Py_UCS4 sign_char, PyObject *number, Py_ssize_t n_start,
@@ -540,9 +542,12 @@ calc_number_widths(NumberFieldWidths *spec, Py_ssize_t n_prefix,
         Py_UCS4 grouping_maxchar;
         spec->n_grouped_digits = _PyUnicode_InsertThousandsGrouping(
             NULL, 0,
-            0, NULL,
-            spec->n_digits, spec->n_min_width,
+            NULL, 0, spec->n_digits,
+            spec->n_min_width,
             locale->grouping, locale->thousands_sep, &grouping_maxchar);
+        if (spec->n_grouped_digits == -1) {
+            return -1;
+        }
         *maxchar = Py_MAX(*maxchar, grouping_maxchar);
     }
 
@@ -636,26 +641,14 @@ fill_number(_PyUnicodeWriter *writer, const NumberFieldWidths *spec,
     /* Only for type 'c' special case, it has no digits. */
     if (spec->n_digits != 0) {
         /* Fill the digits with InsertThousandsGrouping. */
-        char *pdigits;
-        if (PyUnicode_READY(digits))
-            return -1;
-        pdigits = PyUnicode_DATA(digits);
-        if (PyUnicode_KIND(digits) < kind) {
-            pdigits = _PyUnicode_AsKind(digits, kind);
-            if (pdigits == NULL)
-                return -1;
-        }
         r = _PyUnicode_InsertThousandsGrouping(
-                writer->buffer, writer->pos,
-                spec->n_grouped_digits,
-                pdigits + kind * d_pos,
-                spec->n_digits, spec->n_min_width,
+                writer, spec->n_grouped_digits,
+                digits, d_pos, spec->n_digits,
+                spec->n_min_width,
                 locale->grouping, locale->thousands_sep, NULL);
         if (r == -1)
             return -1;
         assert(r == spec->n_grouped_digits);
-        if (PyUnicode_KIND(digits) < kind)
-            PyMem_Free(pdigits);
         d_pos += spec->n_digits;
     }
     if (toupper) {
@@ -708,11 +701,22 @@ get_locale_info(enum LocaleType type, LocaleInfo *locale_info)
 {
     switch (type) {
     case LT_CURRENT_LOCALE: {
+        const char *grouping;
         if (_Py_GetLocaleconvNumeric(&locale_info->decimal_point,
                                      &locale_info->thousands_sep,
-                                     &locale_info->grouping) < 0) {
+                                     &grouping) < 0) {
+            return -1;
+        }
+
+        /* localeconv() grouping can become a dangling pointer or point
+           to a different string if another thread calls localeconv() during
+           the string formatting. Copy the string to avoid this risk. */
+        locale_info->grouping_buffer = _PyMem_Strdup(grouping);
+        if (locale_info->grouping_buffer == NULL) {
+            PyErr_NoMemory();
             return -1;
         }
+        locale_info->grouping = locale_info->grouping_buffer;
         break;
     }
     case LT_DEFAULT_LOCALE:
@@ -746,6 +750,7 @@ free_locale_info(LocaleInfo *locale_info)
 {
     Py_XDECREF(locale_info->decimal_point);
     Py_XDECREF(locale_info->thousands_sep);
+    PyMem_Free(locale_info->grouping_buffer);
 }
 
 /************************************************************************/
@@ -983,6 +988,9 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format,
     n_total = calc_number_widths(&spec, n_prefix, sign_char, tmp, inumeric_chars,
                                  inumeric_chars + n_digits, n_remainder, 0,
                                  &locale, format, &maxchar);
+    if (n_total == -1) {
+        goto done;
+    }
 
     /* Allocate the memory. */
     if (_PyUnicodeWriter_Prepare(writer, n_total, maxchar) == -1)
@@ -1128,6 +1136,9 @@ format_float_internal(PyObject *value,
     n_total = calc_number_widths(&spec, 0, sign_char, unicode_tmp, index,
                                  index + n_digits, n_remainder, has_decimal,
                                  &locale, format, &maxchar);
+    if (n_total == -1) {
+        goto done;
+    }
 
     /* Allocate the memory. */
     if (_PyUnicodeWriter_Prepare(writer, n_total, maxchar) == -1)
@@ -1311,6 +1322,9 @@ format_complex_internal(PyObject *value,
                                     i_re, i_re + n_re_digits, n_re_remainder,
                                     re_has_decimal, &locale, &tmp_format,
                                     &maxchar);
+    if (n_re_total == -1) {
+        goto done;
+    }
 
     /* Same formatting, but always include a sign, unless the real part is
      * going to be omitted, in which case we use whatever sign convention was
@@ -1321,6 +1335,9 @@ format_complex_internal(PyObject *value,
                                     i_im, i_im + n_im_digits, n_im_remainder,
                                     im_has_decimal, &locale, &tmp_format,
                                     &maxchar);
+    if (n_im_total == -1) {
+        goto done;
+    }
 
     if (skip_re)
         n_re_total = 0;
index fa0a9e1..cb19270 100644 (file)
@@ -715,7 +715,7 @@ remove_module(PyObject *name)
     if (PyDict_GetItem(modules, name) == NULL)
         return;
     if (PyDict_DelItem(modules, name) < 0)
-        Py_FatalError("import:  deleting existing key in"
+        Py_FatalError("import:  deleting existing key in "
                       "sys.modules failed");
 }
 
@@ -1973,10 +1973,10 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
     }
 
     mod = _PyImport_FindExtensionObject(name, path);
-    if (mod != NULL) {
+    if (mod != NULL || PyErr_Occurred()) {
         Py_DECREF(name);
         Py_DECREF(path);
-        Py_INCREF(mod);
+        Py_XINCREF(mod);
         return mod;
     }
 
index 91a57c2..dbe75e3 100644 (file)
@@ -677,11 +677,12 @@ r_string(Py_ssize_t n, RFILE *p)
         p->buf_size = n;
     }
     else if (p->buf_size < n) {
-        p->buf = PyMem_REALLOC(p->buf, n);
-        if (p->buf == NULL) {
+        char *tmp = PyMem_REALLOC(p->buf, n);
+        if (tmp == NULL) {
             PyErr_NoMemory();
             return NULL;
         }
+        p->buf = tmp;
         p->buf_size = n;
     }
 
index 31d4e92..3fa3b7f 100644 (file)
@@ -96,9 +96,9 @@ lastn_const_start(const _Py_CODEUNIT *codestr, Py_ssize_t i, Py_ssize_t n)
 
 /* Scans through EXTENDED ARGs, seeking the index of the effective opcode */
 static Py_ssize_t
-find_op(const _Py_CODEUNIT *codestr, Py_ssize_t i)
+find_op(const _Py_CODEUNIT *codestr, Py_ssize_t codelen, Py_ssize_t i)
 {
-    while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
+    while (i < codelen && _Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
         i++;
     }
     return i;
@@ -590,7 +590,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
 
     CONST_STACK_CREATE();
 
-    for (i=find_op(codestr, 0) ; i<codelen ; i=nexti) {
+    for (i=find_op(codestr, codelen, 0) ; i<codelen ; i=nexti) {
         opcode = _Py_OPCODE(codestr[i]);
         op_start = i;
         while (op_start >= 1 && _Py_OPCODE(codestr[op_start-1]) == EXTENDED_ARG) {
@@ -755,7 +755,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
             case JUMP_IF_FALSE_OR_POP:
             case JUMP_IF_TRUE_OR_POP:
                 h = get_arg(codestr, i) / sizeof(_Py_CODEUNIT);
-                tgt = find_op(codestr, h);
+                tgt = find_op(codestr, codelen, h);
 
                 j = _Py_OPCODE(codestr[tgt]);
                 if (CONDITIONAL_JUMP(j)) {
@@ -796,7 +796,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
             case SETUP_WITH:
             case SETUP_ASYNC_WITH:
                 h = GETJUMPTGT(codestr, i);
-                tgt = find_op(codestr, h);
+                tgt = find_op(codestr, codelen, h);
                 /* Replace JUMP_* to a RETURN into just a RETURN */
                 if (UNCONDITIONAL_JUMP(opcode) &&
                     _Py_OPCODE(codestr[tgt]) == RETURN_VALUE) {
@@ -825,7 +825,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
                 }
                 if (h > i + 1) {
                     fill_nops(codestr, i + 1, h);
-                    nexti = find_op(codestr, h);
+                    nexti = find_op(codestr, codelen, h);
                 }
                 break;
         }
index ecfdfee..0ebf9c7 100644 (file)
@@ -797,6 +797,9 @@ Py_NewInterpreter(void)
             goto handle_error;
         Py_INCREF(interp->builtins);
     }
+    else if (PyErr_Occurred()) {
+        goto handle_error;
+    }
 
     /* initialize builtin exceptions */
     _PyExc_Init(bimod);
@@ -1356,12 +1359,6 @@ _Py_FatalError_PrintExc(int fd)
     PyObject *exception, *v, *tb;
     int has_tb;
 
-    if (PyThreadState_GET() == NULL) {
-        /* The GIL is released: trying to acquire it is likely to deadlock,
-           just give up. */
-        return 0;
-    }
-
     PyErr_Fetch(&exception, &v, &tb);
     if (exception == NULL) {
         /* No current exception */
@@ -1425,10 +1422,32 @@ Py_FatalError(const char *msg)
     fprintf(stderr, "Fatal Python error: %s\n", msg);
     fflush(stderr); /* it helps in Windows debug build */
 
-    /* Print the exception (if an exception is set) with its traceback,
-     * or display the current Python stack. */
-    if (!_Py_FatalError_PrintExc(fd))
+    /* Check if the current thread has a Python thread state
+       and holds the GIL */
+    PyThreadState *tss_tstate = PyGILState_GetThisThreadState();
+    if (tss_tstate != NULL) {
+        PyThreadState *tstate = PyThreadState_GET();
+        if (tss_tstate != tstate) {
+            /* The Python thread does not hold the GIL */
+            tss_tstate = NULL;
+        }
+    }
+    else {
+        /* Py_FatalError() has been called from a C thread
+           which has no Python thread state. */
+    }
+    int has_tstate_and_gil = (tss_tstate != NULL);
+
+    if (has_tstate_and_gil) {
+        /* If an exception is set, print the exception with its traceback */
+        if (!_Py_FatalError_PrintExc(fd)) {
+            /* No exception is set, or an exception is set without traceback */
+            _Py_FatalError_DumpTracebacks(fd);
+        }
+    }
+    else {
         _Py_FatalError_DumpTracebacks(fd);
+    }
 
     /* The main purpose of faulthandler is to display the traceback. We already
      * did our best to display it. So faulthandler can now be disabled.
@@ -1436,7 +1455,7 @@ Py_FatalError(const char *msg)
     _PyFaulthandler_Fini();
 
     /* Check if the current Python thread hold the GIL */
-    if (PyThreadState_GET() != NULL) {
+    if (has_tstate_and_gil) {
         /* Flush sys.stdout and sys.stderr */
         flush_std_files();
     }
index 6799d20..24b8042 100644 (file)
@@ -17,7 +17,9 @@ double _Py_force_double(double x)
 
 /* inline assembly for getting and setting the 387 FPU control word on
    gcc/x86 */
-
+#ifdef _Py_MEMORY_SANITIZER
+__attribute__((no_sanitize_memory))
+#endif
 unsigned short _Py_get_387controlword(void) {
     unsigned short cw;
     __asm__ __volatile__ ("fnstcw %0" : "=m" (cw));
index c0e0880..71494da 100644 (file)
@@ -377,6 +377,7 @@ PyState_RemoveModule(struct PyModuleDef* def)
         Py_FatalError("PyState_RemoveModule: Module index out of bounds.");
         return -1;
     }
+    Py_INCREF(Py_None);
     return PyList_SetItem(state->modules_by_index, index, Py_None);
 }
 
index 1c63560..509048c 100644 (file)
@@ -398,6 +398,9 @@ _Py_string_to_number_with_underscores(
     }
 
     dup = PyMem_Malloc(orig_len + 1);
+    if (dup == NULL) {
+        return PyErr_NoMemory();
+    }
     end = dup;
     prev = '\0';
     last = s + orig_len;
@@ -433,8 +436,8 @@ _Py_string_to_number_with_underscores(
   error:
     PyMem_Free(dup);
     PyErr_Format(PyExc_ValueError,
-                "could not convert string to %s: "
-                "%R", what, obj);
+                 "could not convert string to %s: "
+                 "%R", what, obj);
     return NULL;
 }
 
index c62cbeb..d4747d6 100644 (file)
 #  endif
 #endif
 
+#ifdef _Py_MEMORY_SANITIZER
+#  include <sanitizer/msan_interface.h>
+#endif
+
 #ifdef Py_DEBUG
 int _Py_HashSecret_Initialized = 0;
 #else
@@ -143,6 +147,11 @@ py_getrandom(void *buffer, Py_ssize_t size, int blocking, int raise)
         else {
             n = syscall(SYS_getrandom, dest, n, flags);
         }
+#  ifdef _Py_MEMORY_SANITIZER
+        if (n > 0) {
+             __msan_unpoison(dest, n);
+        }
+#  endif
 #endif
 
         if (n < 0) {
index 90b07ef..aef845b 100644 (file)
@@ -206,8 +206,10 @@ symtable_new(void)
     struct symtable *st;
 
     st = (struct symtable *)PyMem_Malloc(sizeof(struct symtable));
-    if (st == NULL)
+    if (st == NULL) {
+        PyErr_NoMemory();
         return NULL;
+    }
 
     st->st_filename = NULL;
     st->st_blocks = NULL;
index b09268b..7d1493c 100644 (file)
@@ -2109,7 +2109,7 @@ makepathobject(const wchar_t *path, wchar_t delim)
             Py_DECREF(v);
             return NULL;
         }
-        PyList_SetItem(v, i, w);
+        PyList_SET_ITEM(v, i, w);
         if (*p == '\0')
             break;
         path = p+1;
index 3607341..baea71f 100644 (file)
@@ -183,6 +183,28 @@ PyThread__init_thread(void)
  * Thread support.
  */
 
+/* bpo-33015: pythread_callback struct and pythread_wrapper() cast
+   "void func(void *)" to "void* func(void *)": always return NULL.
+
+   PyThread_start_new_thread() uses "void func(void *)" type, whereas
+   pthread_create() requires a void* return value. */
+typedef struct {
+    void (*func) (void *);
+    void *arg;
+} pythread_callback;
+
+static void *
+pythread_wrapper(void *arg)
+{
+    /* copy func and func_arg and free the temporary structure */
+    pythread_callback *callback = arg;
+    void (*func)(void *) = callback->func;
+    void *func_arg = callback->arg;
+    PyMem_RawFree(arg);
+
+    func(func_arg);
+    return NULL;
+}
 
 long
 PyThread_start_new_thread(void (*func)(void *), void *arg)
@@ -218,21 +240,31 @@ PyThread_start_new_thread(void (*func)(void *), void *arg)
     pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM);
 #endif
 
+    pythread_callback *callback = PyMem_RawMalloc(sizeof(pythread_callback));
+
+    if (callback == NULL) {
+      return -1;
+    }
+
+    callback->func = func;
+    callback->arg = arg;
+
     status = pthread_create(&th,
 #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
                              &attrs,
 #else
                              (pthread_attr_t*)NULL,
 #endif
-                             (void* (*)(void *))func,
-                             (void *)arg
-                             );
+                             pythread_wrapper, callback);
 
 #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
     pthread_attr_destroy(&attrs);
 #endif
-    if (status != 0)
+
+    if (status != 0) {
+        PyMem_RawFree(callback);
         return -1;
+    }
 
     pthread_detach(th);
 
index 145d028..f489a47 100644 (file)
@@ -65,11 +65,12 @@ tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)
     return 0;
 }
 
-static void
+static int
 tb_clear(PyTracebackObject *tb)
 {
     Py_CLEAR(tb->tb_next);
     Py_CLEAR(tb->tb_frame);
+    return 0;
 }
 
 PyTypeObject PyTraceBack_Type = {
index 698d9db..0531cb5 100644 (file)
@@ -1,4 +1,4 @@
-This is Python version 3.6.7
+This is Python version 3.6.8
 ============================
 
 .. image:: https://travis-ci.org/python/cpython.svg?branch=3.6
index 6d3d52f..073aca8 100755 (executable)
@@ -934,35 +934,50 @@ class PyFrameObjectPtr(PyObjectPtr):
         if long(f_trace) != 0:
             # we have a non-NULL f_trace:
             return self.f_lineno
-        else:
-            #try:
+
+        try:
             return self.co.addr2line(self.f_lasti)
-            #except ValueError:
-            #    return self.f_lineno
+        except Exception:
+            # bpo-34989: addr2line() is a complex function, it can fail in many
+            # ways. For example, it fails with a TypeError on "FakeRepr" if
+            # gdb fails to load debug symbols. Use a catch-all "except
+            # Exception" to make the whole function safe. The caller has to
+            # handle None anyway for optimized Python.
+            return None
 
     def current_line(self):
         '''Get the text of the current source line as a string, with a trailing
         newline character'''
         if self.is_optimized_out():
             return '(frame information optimized out)'
+
+        lineno = self.current_line_num()
+        if lineno is None:
+            return '(failed to get frame line number)'
+
         filename = self.filename()
         try:
-            f = open(os_fsencode(filename), 'r')
+            with open(os_fsencode(filename), 'r') as fp:
+                lines = fp.readlines()
         except IOError:
             return None
-        with f:
-            all_lines = f.readlines()
-            # Convert from 1-based current_line_num to 0-based list offset:
-            return all_lines[self.current_line_num()-1]
+
+        try:
+            # Convert from 1-based current_line_num to 0-based list offset
+            return lines[lineno - 1]
+        except IndexError:
+            return None
 
     def write_repr(self, out, visited):
         if self.is_optimized_out():
             out.write('(frame information optimized out)')
             return
-        out.write('Frame 0x%x, for file %s, line %i, in %s ('
+        lineno = self.current_line_num()
+        lineno = str(lineno) if lineno is not None else "?"
+        out.write('Frame 0x%x, for file %s, line %s, in %s ('
                   % (self.as_address(),
                      self.co_filename.proxyval(visited),
-                     self.current_line_num(),
+                     lineno,
                      self.co_name.proxyval(visited)))
         first = True
         for pyop_name, pyop_value in self.iter_locals():
@@ -981,9 +996,11 @@ class PyFrameObjectPtr(PyObjectPtr):
             sys.stdout.write('  (frame information optimized out)\n')
             return
         visited = set()
-        sys.stdout.write('  File "%s", line %i, in %s\n'
+        lineno = self.current_line_num()
+        lineno = str(lineno) if lineno is not None else "?"
+        sys.stdout.write('  File "%s", line %s, in %s\n'
                   % (self.co_filename.proxyval(visited),
-                     self.current_line_num(),
+                     lineno,
                      self.co_name.proxyval(visited)))
 
 class PySetObjectPtr(PyObjectPtr):
@@ -1742,6 +1759,9 @@ class PyList(gdb.Command):
 
         filename = pyop.filename()
         lineno = pyop.current_line_num()
+        if lineno is None:
+            print('Unable to read python frame line number')
+            return
 
         if start is None:
             start = lineno - 5
index 4ab6b77..e5214ab 100755 (executable)
@@ -49,7 +49,9 @@ def get_git_branch():
     """Get the symbolic name for the current git branch"""
     cmd = "git rev-parse --abbrev-ref HEAD".split()
     try:
-        return subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
+        return subprocess.check_output(cmd,
+                                       stderr=subprocess.DEVNULL,
+                                       cwd=SRCDIR)
     except subprocess.CalledProcessError:
         return None
 
@@ -61,7 +63,9 @@ def get_git_upstream_remote():
     """
     cmd = "git remote get-url upstream".split()
     try:
-        subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
+        subprocess.check_output(cmd,
+                                stderr=subprocess.DEVNULL,
+                                cwd=SRCDIR)
     except subprocess.CalledProcessError:
         return "origin"
     return "upstream"
@@ -99,7 +103,9 @@ def changed_files(base_branch=None):
         else:
             cmd = 'git status --porcelain'
         filenames = []
-        with subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) as st:
+        with subprocess.Popen(cmd.split(),
+                              stdout=subprocess.PIPE,
+                              cwd=SRCDIR) as st:
             for line in st.stdout:
                 line = line.decode().rstrip()
                 status_text, filename = line.split(maxsplit=1)
index 9c1e9fe..5565c21 100755 (executable)
@@ -1806,7 +1806,7 @@ class HTMLHelp:
             print('<!-- This file defines the table of contents -->', file=fp)
             print('<HTML>', file=fp)
             print('<HEAD>', file=fp)
-            print('<meta name="GENERATOR"'
+            print('<meta name="GENERATOR" '
                         'content="Microsoft&reg; HTML Help Workshop 4.1">', file=fp)
             print('<!-- Sitemap 1.0 -->', file=fp)
             print('</HEAD>', file=fp)
@@ -1831,7 +1831,7 @@ class HTMLHelp:
             print('<!-- This file defines the index -->', file=fp)
             print('<HTML>', file=fp)
             print('<HEAD>', file=fp)
-            print('<meta name="GENERATOR"'
+            print('<meta name="GENERATOR" '
                         'content="Microsoft&reg; HTML Help Workshop 4.1">', file=fp)
             print('<!-- Sitemap 1.0 -->', file=fp)
             print('</HEAD>', file=fp)
index 5e29449..61b2539 100644 (file)
@@ -13,7 +13,7 @@
 
 m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
 dnl pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
-dnl serial 11 (pkg-config-0.29.1)
+dnl serial 11 (pkg-config-0.29)
 dnl
 dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
 dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
@@ -55,7 +55,7 @@ dnl
 dnl See the "Since" comment for each macro you use to see what version
 dnl of the macros you require.
 m4_defun([PKG_PREREQ],
-[m4_define([PKG_MACROS_VERSION], [0.29.1])
+[m4_define([PKG_MACROS_VERSION], [0.29])
 m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
     [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
 ])dnl PKG_PREREQ
index bfa4b83..e39c16e 100755 (executable)
--- a/configure
+++ b/configure
@@ -666,22 +666,24 @@ SHLIB_SUFFIX
 LIBTOOL_CRUFT
 OTHER_LIBTOOL_OPT
 UNIVERSAL_ARCH_FLAGS
+LDFLAGS_NODIST
 CFLAGS_NODIST
 BASECFLAGS
 CFLAGS_ALIASING
 OPT
 LLVM_PROF_FOUND
-target_os
-target_vendor
-target_cpu
-target
 LLVM_PROFDATA
 LLVM_PROF_ERR
 LLVM_PROF_FILE
 LLVM_PROF_MERGER
 PGO_PROF_USE_FLAG
 PGO_PROF_GEN_FLAG
-LTOFLAGS
+LLVM_AR_FOUND
+target_os
+target_vendor
+target_cpu
+target
+LLVM_AR
 DEF_MAKE_RULE
 DEF_MAKE_ALL_RULE
 ABIFLAGS
@@ -695,7 +697,6 @@ READELF
 ARFLAGS
 ac_ct_AR
 AR
-RANLIB
 USE_INLINE
 GNULD
 LINKCC
@@ -784,7 +785,6 @@ infodir
 docdir
 oldincludedir
 includedir
-runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -823,6 +823,8 @@ enable_optimizations
 with_lto
 with_hash_algorithm
 with_address_sanitizer
+with_memory_sanitizer
+with_undefined_behavior_sanitizer
 with_libs
 with_system_expat
 with_system_ffi
@@ -896,7 +898,6 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
-runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1149,15 +1150,6 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
-  -runstatedir | --runstatedir | --runstatedi | --runstated \
-  | --runstate | --runstat | --runsta | --runst | --runs \
-  | --run | --ru | --r)
-    ac_prev=runstatedir ;;
-  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
-  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
-  | --run=* | --ru=* | --r=*)
-    runstatedir=$ac_optarg ;;
-
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1295,7 +1287,7 @@ fi
 for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
                datadir sysconfdir sharedstatedir localstatedir includedir \
                oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-               libdir localedir mandir runstatedir
+               libdir localedir mandir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1448,7 +1440,6 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
-  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -1516,12 +1507,15 @@ Optional Packages:
   --with-suffix=.exe      set executable suffix
   --with-pydebug          build with Py_DEBUG defined
   --with-assertions       build with C assertions enabled
-  --with-lto              Enable Link Time Optimization in PGO builds.
-                          Disabled by default.
+  --with-lto              Enable Link Time Optimization in any build. Disabled
+                          by default.
   --with-hash-algorithm=[fnv|siphash24]
                           select hash algorithm
   --with-address-sanitizer
-                          enable AddressSanitizer
+                          enable AddressSanitizer (asan)
+  --with-memory-sanitizer enable MemorySanitizer (msan)
+  --with-undefined-behavior-sanitizer
+                          enable UndefinedBehaviorSanitizer (ubsan)
   --with-libs='lib1 ...'  link against additional libs
   --with-system-expat     build pyexpat module using an installed expat
                           library
@@ -6025,98 +6019,6 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LDLIBRARY" >&5
 $as_echo "$LDLIBRARY" >&6; }
 
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_RANLIB+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$RANLIB"; then
-  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-RANLIB=$ac_cv_prog_RANLIB
-if test -n "$RANLIB"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
-$as_echo "$RANLIB" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_RANLIB"; then
-  ac_ct_RANLIB=$RANLIB
-  # Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_RANLIB"; then
-  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_RANLIB="ranlib"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
-if test -n "$ac_ct_RANLIB"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
-$as_echo "$ac_ct_RANLIB" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_RANLIB" = x; then
-    RANLIB=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    RANLIB=$ac_ct_RANLIB
-  fi
-else
-  RANLIB="$ac_cv_prog_RANLIB"
-fi
-
 
 if test -n "$ac_tool_prefix"; then
   for ac_prog in ar aal
@@ -6223,7 +6125,7 @@ fi
 
 if test -z "$ARFLAGS"
 then
-        ARFLAGS="rc"
+        ARFLAGS="rcs"
 fi
 
 if test -n "$ac_tool_prefix"; then
@@ -6583,8 +6485,27 @@ else
   DEF_MAKE_RULE="all"
 fi
 
-# Enable LTO flags
+# Make llvm-relatec checks work on systems where llvm tools are not installed with their
+# normal names in the default $PATH (ie: Ubuntu).  They exist under the
+# non-suffixed name in their versioned llvm directory.
+
+llvm_bin_dir=''
+llvm_path="${PATH}"
+if test "${CC}" = "clang"
+then
+  clang_bin=`which clang`
+  # Some systems install clang elsewhere as a symlink to the real path
+  # which is where the related llvm tools are located.
+  if test -L "${clang_bin}"
+  then
+    clang_dir=`dirname "${clang_bin}"`
+    clang_bin=`readlink "${clang_bin}"`
+    llvm_bin_dir="${clang_dir}/"`dirname "${clang_bin}"`
+    llvm_path="${llvm_path}${PATH_SEPARATOR}${llvm_bin_dir}"
+  fi
+fi
 
+# Enable LTO flags
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-lto" >&5
 $as_echo_n "checking for --with-lto... " >&6; }
 
@@ -6609,62 +6530,8 @@ fi
 if test "$Py_LTO" = 'true' ; then
   case $CC in
     *clang*)
-      case $ac_sys_system in
-        Darwin*)
-          # Any changes made here should be reflected in the GCC+Darwin case below
-          LTOFLAGS="-flto -Wl,-export_dynamic"
-          ;;
-        *)
-          LTOFLAGS="-flto"
-          ;;
-      esac
-      ;;
-    *gcc*)
-      case $ac_sys_system in
-        Darwin*)
-          LTOFLAGS="-flto -Wl,-export_dynamic"
-          ;;
-        *)
-          LTOFLAGS="-flto -fuse-linker-plugin -ffat-lto-objects -flto-partition=none"
-          ;;
-      esac
-      ;;
-  esac
-
-  if test "$ac_cv_prog_cc_g" = "yes"
-  then
-      # bpo-30345: Add -g to LDFLAGS when compiling with LTO
-      # to get debug symbols.
-      LTOFLAGS="$LTOFLAGS -g"
-  fi
-fi
-
-# Enable PGO flags.
-
-
-
-
-
-# Make this work on systems where llvm tools are not installed with their
-# normal names in the default $PATH (ie: Ubuntu).  They exist under the
-# non-suffixed name in their versioned llvm directory.
-llvm_bin_dir=''
-llvm_path="${PATH}"
-if test "${CC}" = "clang"
-then
-  clang_bin=`which clang`
-  # Some systems install clang elsewhere as a symlink to the real path
-  # which is where the related llvm tools are located.
-  if test -L "${clang_bin}"
-  then
-    clang_dir=`dirname "${clang_bin}"`
-    clang_bin=`readlink "${clang_bin}"`
-    llvm_bin_dir="${clang_dir}/"`dirname "${clang_bin}"`
-    llvm_path="${llvm_path}${PATH_SEPARATOR}${llvm_bin_dir}"
-  fi
-fi
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
 $as_echo_n "checking target system type... " >&6; }
 if ${ac_cv_target+:} false; then :
   $as_echo_n "(cached) " >&6
@@ -6703,6 +6570,163 @@ test -n "$target_alias" &&
   test "$program_prefix$program_suffix$program_transform_name" = \
     NONENONEs,x,x, &&
   program_prefix=${target_alias}-
+# Extract the first word of "$target_alias-llvm-ar", so it can be a program name with args.
+set dummy $target_alias-llvm-ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_LLVM_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $LLVM_AR in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_LLVM_AR="$LLVM_AR" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in ${llvm_path}
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_LLVM_AR="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+LLVM_AR=$ac_cv_path_LLVM_AR
+if test -n "$LLVM_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LLVM_AR" >&5
+$as_echo "$LLVM_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+if test -z "$ac_cv_path_LLVM_AR"; then
+  if test "$build" = "$target"; then
+    ac_pt_LLVM_AR=$LLVM_AR
+    # Extract the first word of "llvm-ar", so it can be a program name with args.
+set dummy llvm-ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_LLVM_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_LLVM_AR in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_LLVM_AR="$ac_pt_LLVM_AR" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in ${llvm_path}
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_LLVM_AR="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_ac_pt_LLVM_AR" && ac_cv_path_ac_pt_LLVM_AR="''"
+  ;;
+esac
+fi
+ac_pt_LLVM_AR=$ac_cv_path_ac_pt_LLVM_AR
+if test -n "$ac_pt_LLVM_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LLVM_AR" >&5
+$as_echo "$ac_pt_LLVM_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+    LLVM_AR=$ac_pt_LLVM_AR
+  else
+    LLVM_AR="''"
+  fi
+else
+  LLVM_AR="$ac_cv_path_LLVM_AR"
+fi
+
+
+      if test -n "${LLVM_AR}" -a -x "${LLVM_AR}"
+      then
+        LLVM_AR_FOUND="found"
+      else
+        LLVM_AR_FOUND="not-found"
+      fi
+      if test "$ac_sys_system" = "Darwin" -a "${LLVM_AR_FOUND}" = "not-found"
+      then
+        found_llvm_ar=`/usr/bin/xcrun -find llvm-ar 2>/dev/null`
+        if test -n "${found_llvm_ar}"
+        then
+          LLVM_AR='/usr/bin/xcrun llvm-ar'
+          LLVM_AR_FOUND=found
+          { $as_echo "$as_me:${as_lineno-$LINENO}: llvm-ar found via xcrun: ${LLVM_AR}" >&5
+$as_echo "$as_me: llvm-ar found via xcrun: ${LLVM_AR}" >&6;}
+        fi
+      fi
+      if test $LLVM_AR_FOUND = not-found
+      then
+        LLVM_PROFR_ERR=yes
+        as_fn_error $? "llvm-ar is required for a --with-lto build with clang but could not be found." "$LINENO" 5
+      else
+        LLVM_AR_ERR=no
+      fi
+      AR="${LLVM_AR}"
+      case $ac_sys_system in
+        Darwin*)
+          # Any changes made here should be reflected in the GCC+Darwin case below
+          LTOFLAGS="-flto -Wl,-export_dynamic"
+          ;;
+        *)
+          LTOFLAGS="-flto"
+          ;;
+      esac
+      ;;
+    *gcc*)
+      case $ac_sys_system in
+        Darwin*)
+          LTOFLAGS="-flto -Wl,-export_dynamic"
+          ;;
+        *)
+          LTOFLAGS="-flto -fuse-linker-plugin -ffat-lto-objects -flto-partition=none"
+          ;;
+      esac
+      ;;
+  esac
+
+  if test "$ac_cv_prog_cc_g" = "yes"
+  then
+      # bpo-30345: Add -g to LDFLAGS when compiling with LTO
+      # to get debug symbols.
+      LTOFLAGS="$LTOFLAGS -g"
+  fi
+
+  CFLAGS_NODIST="$CFLAGS_NODIST $LTOFLAGS"
+  LDFLAGS_NODIST="$LDFLAGS_NODIST $LTOFLAGS"
+fi
+
+# Enable PGO flags.
+
+
+
+
+
+
 # Extract the first word of "$target_alias-llvm-profdata", so it can be a program name with args.
 set dummy $target_alias-llvm-profdata; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
@@ -6945,6 +6969,7 @@ fi
 
 
 
+
 # The -arch flags for universal builds on OSX
 UNIVERSAL_ARCH_FLAGS=
 
@@ -9925,6 +9950,44 @@ if test "${with_address_sanitizer+set}" = set; then :
 $as_echo "$withval" >&6; }
 BASECFLAGS="-fsanitize=address -fno-omit-frame-pointer $BASECFLAGS"
 LDFLAGS="-fsanitize=address $LDFLAGS"
+# ASan works by controlling memory allocation, our own malloc interferes.
+with_pymalloc="no"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-memory-sanitizer" >&5
+$as_echo_n "checking for --with-memory-sanitizer... " >&6; }
+
+# Check whether --with-memory_sanitizer was given.
+if test "${with_memory_sanitizer+set}" = set; then :
+  withval=$with_memory_sanitizer;
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5
+$as_echo "$withval" >&6; }
+BASECFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer $BASECFLAGS"
+LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 $LDFLAGS"
+# MSan works by controlling memory allocation, our own malloc interferes.
+with_pymalloc="no"
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-undefined-behavior-sanitizer" >&5
+$as_echo_n "checking for --with-undefined-behavior-sanitizer... " >&6; }
+
+# Check whether --with-undefined_behavior_sanitizer was given.
+if test "${with_undefined_behavior_sanitizer+set}" = set; then :
+  withval=$with_undefined_behavior_sanitizer;
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5
+$as_echo "$withval" >&6; }
+BASECFLAGS="-fsanitize=undefined $BASECFLAGS"
+LDFLAGS="-fsanitize=undefined $LDFLAGS"
 
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
index 3f2459a..cf28050 100644 (file)
@@ -1196,7 +1196,6 @@ fi
 
 AC_MSG_RESULT($LDLIBRARY)
 
-AC_PROG_RANLIB
 AC_SUBST(AR)
 AC_CHECK_TOOLS(AR, ar aal, ar)
 
@@ -1204,7 +1203,7 @@ AC_CHECK_TOOLS(AR, ar aal, ar)
 AC_SUBST(ARFLAGS)
 if test -z "$ARFLAGS"
 then
-        ARFLAGS="rc"
+        ARFLAGS="rcs"
 fi
 
 AC_CHECK_TOOLS([READELF], [readelf], [:])
@@ -1309,10 +1308,29 @@ else
   DEF_MAKE_RULE="all"
 fi
 
+# Make llvm-relatec checks work on systems where llvm tools are not installed with their
+# normal names in the default $PATH (ie: Ubuntu).  They exist under the
+# non-suffixed name in their versioned llvm directory.
+
+llvm_bin_dir=''
+llvm_path="${PATH}"
+if test "${CC}" = "clang"
+then
+  clang_bin=`which clang`
+  # Some systems install clang elsewhere as a symlink to the real path
+  # which is where the related llvm tools are located.
+  if test -L "${clang_bin}"
+  then
+    clang_dir=`dirname "${clang_bin}"`
+    clang_bin=`readlink "${clang_bin}"`
+    llvm_bin_dir="${clang_dir}/"`dirname "${clang_bin}"`
+    llvm_path="${llvm_path}${PATH_SEPARATOR}${llvm_bin_dir}"
+  fi
+fi
+
 # Enable LTO flags
-AC_SUBST(LTOFLAGS)
 AC_MSG_CHECKING(for --with-lto)
-AC_ARG_WITH(lto, AS_HELP_STRING([--with-lto], [Enable Link Time Optimization in PGO builds. Disabled by default.]),
+AC_ARG_WITH(lto, AS_HELP_STRING([--with-lto], [Enable Link Time Optimization in any build. Disabled by default.]),
 [
 if test "$withval" != no
 then
@@ -1326,6 +1344,33 @@ fi],
 if test "$Py_LTO" = 'true' ; then
   case $CC in
     *clang*)
+      AC_SUBST(LLVM_AR)
+      AC_PATH_TARGET_TOOL(LLVM_AR, llvm-ar, '', ${llvm_path})
+      AC_SUBST(LLVM_AR_FOUND)
+      if test -n "${LLVM_AR}" -a -x "${LLVM_AR}"
+      then
+        LLVM_AR_FOUND="found"
+      else
+        LLVM_AR_FOUND="not-found"
+      fi
+      if test "$ac_sys_system" = "Darwin" -a "${LLVM_AR_FOUND}" = "not-found"
+      then
+        found_llvm_ar=`/usr/bin/xcrun -find llvm-ar 2>/dev/null`
+        if test -n "${found_llvm_ar}"
+        then
+          LLVM_AR='/usr/bin/xcrun llvm-ar'
+          LLVM_AR_FOUND=found
+          AC_MSG_NOTICE([llvm-ar found via xcrun: ${LLVM_AR}])
+        fi
+      fi
+      if test $LLVM_AR_FOUND = not-found
+      then
+        LLVM_PROFR_ERR=yes
+        AC_MSG_ERROR([llvm-ar is required for a --with-lto build with clang but could not be found.])
+      else
+        LLVM_AR_ERR=no
+      fi
+      AR="${LLVM_AR}"
       case $ac_sys_system in
         Darwin*)
           # Any changes made here should be reflected in the GCC+Darwin case below
@@ -1354,6 +1399,9 @@ if test "$Py_LTO" = 'true' ; then
       # to get debug symbols.
       LTOFLAGS="$LTOFLAGS -g"
   fi
+
+  CFLAGS_NODIST="$CFLAGS_NODIST $LTOFLAGS"
+  LDFLAGS_NODIST="$LDFLAGS_NODIST $LTOFLAGS"
 fi
 
 # Enable PGO flags.
@@ -1362,24 +1410,6 @@ AC_SUBST(PGO_PROF_USE_FLAG)
 AC_SUBST(LLVM_PROF_MERGER)
 AC_SUBST(LLVM_PROF_FILE)
 AC_SUBST(LLVM_PROF_ERR)
-# Make this work on systems where llvm tools are not installed with their
-# normal names in the default $PATH (ie: Ubuntu).  They exist under the
-# non-suffixed name in their versioned llvm directory.
-llvm_bin_dir=''
-llvm_path="${PATH}"
-if test "${CC}" = "clang"
-then
-  clang_bin=`which clang`
-  # Some systems install clang elsewhere as a symlink to the real path
-  # which is where the related llvm tools are located.
-  if test -L "${clang_bin}"
-  then
-    clang_dir=`dirname "${clang_bin}"`
-    clang_bin=`readlink "${clang_bin}"`
-    llvm_bin_dir="${clang_dir}/"`dirname "${clang_bin}"`
-    llvm_path="${llvm_path}${PATH_SEPARATOR}${llvm_bin_dir}"
-  fi
-fi
 AC_SUBST(LLVM_PROFDATA)
 AC_PATH_TARGET_TOOL(LLVM_PROFDATA, llvm-profdata, '', ${llvm_path})
 AC_SUBST(LLVM_PROF_FOUND)
@@ -1531,6 +1561,7 @@ fi
 
 AC_SUBST(BASECFLAGS)
 AC_SUBST(CFLAGS_NODIST)
+AC_SUBST(LDFLAGS_NODIST)
 
 # The -arch flags for universal builds on OSX
 UNIVERSAL_ARCH_FLAGS=
@@ -2831,11 +2862,37 @@ esac
 AC_MSG_CHECKING(for --with-address-sanitizer)
 AC_ARG_WITH(address_sanitizer,
             AS_HELP_STRING([--with-address-sanitizer],
-                           [enable AddressSanitizer]),
+                           [enable AddressSanitizer (asan)]),
 [
 AC_MSG_RESULT($withval)
 BASECFLAGS="-fsanitize=address -fno-omit-frame-pointer $BASECFLAGS"
 LDFLAGS="-fsanitize=address $LDFLAGS"
+# ASan works by controlling memory allocation, our own malloc interferes.
+with_pymalloc="no"
+],
+[AC_MSG_RESULT(no)])
+
+AC_MSG_CHECKING(for --with-memory-sanitizer)
+AC_ARG_WITH(memory_sanitizer,
+            AS_HELP_STRING([--with-memory-sanitizer],
+                           [enable MemorySanitizer (msan)]),
+[
+AC_MSG_RESULT($withval)
+BASECFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer $BASECFLAGS"
+LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 $LDFLAGS"
+# MSan works by controlling memory allocation, our own malloc interferes.
+with_pymalloc="no"
+],
+[AC_MSG_RESULT(no)])
+
+AC_MSG_CHECKING(for --with-undefined-behavior-sanitizer)
+AC_ARG_WITH(undefined_behavior_sanitizer,
+            AS_HELP_STRING([--with-undefined-behavior-sanitizer],
+                           [enable UndefinedBehaviorSanitizer (ubsan)]),
+[
+AC_MSG_RESULT($withval)
+BASECFLAGS="-fsanitize=undefined $BASECFLAGS"
+LDFLAGS="-fsanitize=undefined $LDFLAGS"
 ],
 [AC_MSG_RESULT(no)])
 
index 49193f6..fb95fb5 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -18,11 +18,16 @@ from distutils.spawn import find_executable
 
 cross_compiling = "_PYTHON_HOST_PLATFORM" in os.environ
 
-# Add special CFLAGS reserved for building the interpreter and the stdlib
-# modules (Issue #21121).
-cflags = sysconfig.get_config_var('CFLAGS')
-py_cflags_nodist = sysconfig.get_config_var('PY_CFLAGS_NODIST')
-sysconfig.get_config_vars()['CFLAGS'] = cflags + ' ' + py_cflags_nodist
+# Set common compiler and linker flags derived from the Makefile,
+# reserved for building the interpreter and the stdlib modules.
+# See bpo-21121 and bpo-35257
+def set_compiler_flags(compiler_flags, compiler_py_flags_nodist):
+    flags = sysconfig.get_config_var(compiler_flags)
+    py_flags_nodist = sysconfig.get_config_var(compiler_py_flags_nodist)
+    sysconfig.get_config_vars()[compiler_flags] = flags + ' ' + py_flags_nodist
+
+set_compiler_flags('CFLAGS', 'PY_CFLAGS_NODIST')
+set_compiler_flags('LDFLAGS', 'PY_LDFLAGS_NODIST')
 
 class Dummy:
     """Hack for parallel build"""