Merge branch '3.6.1' of github.com:ned-deily/cpython into 3.6
diff --git a/.github/appveyor.yml b/.github/appveyor.yml
new file mode 100644
index 0000000..a369e52
--- /dev/null
+++ b/.github/appveyor.yml
@@ -0,0 +1,23 @@
+version: 3.6.1rc1+.{build}
+clone_depth: 5
+build_script:
+- cmd: PCbuild\build.bat -e
+test_script:
+- cmd: PCbuild\rt.bat -q -uall -rwW --slowest --timeout=1200 -j0
+
+# Only trigger AppVeyor if actual code or its configuration changes
+only_commits:
+ files:
+ - .github/appveyor.yml
+ - .gitattributes
+ - Grammar/
+ - Include/
+ - Lib/
+ - Modules/
+ - Objects/
+ - PC/
+ - PCBuild/
+ - Parser/
+ - Programs/
+ - Python/
+ - Tools/
diff --git a/.gitignore b/.gitignore
index ed4ebfb..db27597 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@
.gdb_history
Doc/build/
Doc/venv/
+Include/pydtrace_probes.h
Lib/distutils/command/*.pdb
Lib/lib2to3/*.pickle
Lib/test/data/*
diff --git a/.travis.yml b/.travis.yml
index 27b63c6..66f03dc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -64,15 +64,6 @@
# Make the `coverage` command available to Codecov w/ a version of Python that can parse all source files.
- source ./venv/bin/activate
- bash <(curl -s https://codecov.io/bash)
- - os: linux
- language: cpp
- compiler: clang
- env:
- - TESTING="C++ header compatibility"
- before_script:
- - ./configure
- script:
- - echo '#include "Python.h"' > test.cc && $CXX -c test.cc -o /dev/null -I ./Include -I .
# Travis provides only 2 cores, so don't overdue the parallelism and waste memory.
before_script:
diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst
index a6d0f46..c6d1d02 100644
--- a/Doc/c-api/marshal.rst
+++ b/Doc/c-api/marshal.rst
@@ -34,7 +34,7 @@
.. c:function:: PyObject* PyMarshal_WriteObjectToString(PyObject *value, int version)
- Return a string object containing the marshalled representation of *value*.
+ Return a bytes object containing the marshalled representation of *value*.
*version* indicates the file format.
@@ -88,10 +88,10 @@
:exc:`TypeError`) and returns *NULL*.
-.. c:function:: PyObject* PyMarshal_ReadObjectFromString(const char *string, Py_ssize_t len)
+.. c:function:: PyObject* PyMarshal_ReadObjectFromString(const char *data, Py_ssize_t len)
- Return a Python object from the data stream in a character buffer
- containing *len* bytes pointed to by *string*.
+ Return a Python object from the data stream in a byte buffer
+ containing *len* bytes pointed to by *data*.
On error, sets the appropriate exception (:exc:`EOFError` or
:exc:`TypeError`) and returns *NULL*.
diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst
index 3ff5452..873fb2a 100644
--- a/Doc/c-api/memory.rst
+++ b/Doc/c-api/memory.rst
@@ -391,7 +391,7 @@
:c:func:`PyMem_RawRealloc` for allocations larger than 512 bytes.
*pymalloc* is the default allocator of the :c:data:`PYMEM_DOMAIN_MEM` (ex:
-:c:func:`PyObject_Malloc`) and :c:data:`PYMEM_DOMAIN_OBJ` (ex:
+:c:func:`PyMem_Malloc`) and :c:data:`PYMEM_DOMAIN_OBJ` (ex:
:c:func:`PyObject_Malloc`) domains.
The arena allocator uses the following functions:
diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst
index 02f7ada..6e91576 100644
--- a/Doc/c-api/unicode.rst
+++ b/Doc/c-api/unicode.rst
@@ -1393,72 +1393,45 @@
This codec is special in that it can be used to implement many different codecs
(and this is in fact what was done to obtain most of the standard codecs
included in the :mod:`encodings` package). The codec uses mapping to encode and
-decode characters.
-
-Decoding mappings must map single string characters to single Unicode
-characters, integers (which are then interpreted as Unicode ordinals) or ``None``
-(meaning "undefined mapping" and causing an error).
-
-Encoding mappings must map single Unicode characters to single string
-characters, integers (which are then interpreted as Latin-1 ordinals) or ``None``
-(meaning "undefined mapping" and causing an error).
-
-The mapping objects provided must only support the __getitem__ mapping
-interface.
-
-If a character lookup fails with a LookupError, the character is copied as-is
-meaning that its ordinal value will be interpreted as Unicode or Latin-1 ordinal
-resp. Because of this, mappings only need to contain those mappings which map
-characters to different code points.
+decode characters. The mapping objects provided must support the
+:meth:`__getitem__` mapping interface; dictionaries and sequences work well.
These are the mapping codec APIs:
-.. c:function:: PyObject* PyUnicode_DecodeCharmap(const char *s, Py_ssize_t size, \
+.. c:function:: PyObject* PyUnicode_DecodeCharmap(const char *data, Py_ssize_t size, \
PyObject *mapping, const char *errors)
- Create a Unicode object by decoding *size* bytes of the encoded string *s* using
- the given *mapping* object. Return *NULL* if an exception was raised by the
- codec. If *mapping* is *NULL* latin-1 decoding will be done. Else it can be a
- dictionary mapping byte or a unicode string, which is treated as a lookup table.
- Byte values greater that the length of the string and U+FFFE "characters" are
- treated as "undefined mapping".
+ Create a Unicode object by decoding *size* bytes of the encoded string *s*
+ using the given *mapping* object. Return *NULL* if an exception was raised
+ by the codec.
+
+ If *mapping* is *NULL*, Latin-1 decoding will be applied. Else
+ *mapping* must map bytes ordinals (integers in the range from 0 to 255)
+ to Unicode strings, integers (which are then interpreted as Unicode
+ ordinals) or ``None``. Unmapped data bytes -- ones which cause a
+ :exc:`LookupError`, as well as ones which get mapped to ``None``,
+ ``0xFFFE`` or ``'\ufffe'``, are treated as undefined mappings and cause
+ an error.
.. c:function:: PyObject* PyUnicode_AsCharmapString(PyObject *unicode, PyObject *mapping)
- Encode a Unicode object using the given *mapping* object and return the result
- as Python string object. Error handling is "strict". Return *NULL* if an
+ Encode a Unicode object using the given *mapping* object and return the
+ result as a bytes object. Error handling is "strict". Return *NULL* if an
exception was raised by the codec.
-The following codec API is special in that maps Unicode to Unicode.
-
-
-.. c:function:: PyObject* PyUnicode_TranslateCharmap(const Py_UNICODE *s, Py_ssize_t size, \
- PyObject *table, const char *errors)
-
- Translate a :c:type:`Py_UNICODE` buffer of the given *size* by applying a
- character mapping *table* to it and return the resulting Unicode object. Return
- *NULL* when an exception was raised by the codec.
-
- The *mapping* table must map Unicode ordinal integers to Unicode ordinal
- integers or ``None`` (causing deletion of the character).
-
- Mapping tables need only provide the :meth:`__getitem__` interface; dictionaries
- and sequences work well. Unmapped character ordinals (ones which cause a
- :exc:`LookupError`) are left untouched and are copied as-is.
-
- .. deprecated-removed:: 3.3 4.0
- Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using
- :c:func:`PyUnicode_Translate`. or :ref:`generic codec based API
- <codec-registry>`
+ The *mapping* object must map Unicode ordinal integers to bytes objects,
+ integers in the range from 0 to 255 or ``None``. Unmapped character
+ ordinals (ones which cause a :exc:`LookupError`) as well as mapped to
+ ``None`` are treated as "undefined mapping" and cause an error.
.. c:function:: PyObject* PyUnicode_EncodeCharmap(const Py_UNICODE *s, Py_ssize_t size, \
PyObject *mapping, const char *errors)
Encode the :c:type:`Py_UNICODE` buffer of the given *size* using the given
- *mapping* object and return a Python string object. Return *NULL* if an
- exception was raised by the codec.
+ *mapping* object and return the result as a bytes object. Return *NULL* if
+ an exception was raised by the codec.
.. deprecated-removed:: 3.3 4.0
Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using
@@ -1466,6 +1439,34 @@
:c:func:`PyUnicode_AsEncodedString`.
+The following codec API is special in that maps Unicode to Unicode.
+
+.. c:function:: PyObject* PyUnicode_Translate(PyObject *unicode, \
+ PyObject *mapping, const char *errors)
+
+ Translate a Unicode object using the given *mapping* object and return the
+ resulting Unicode object. Return *NULL* if an exception was raised by the
+ codec.
+
+ The *mapping* object must map Unicode ordinal integers to Unicode strings,
+ integers (which are then interpreted as Unicode ordinals) or ``None``
+ (causing deletion of the character). Unmapped character ordinals (ones
+ which cause a :exc:`LookupError`) are left untouched and are copied as-is.
+
+
+.. c:function:: PyObject* PyUnicode_TranslateCharmap(const Py_UNICODE *s, Py_ssize_t size, \
+ PyObject *mapping, const char *errors)
+
+ Translate a :c:type:`Py_UNICODE` buffer of the given *size* by applying a
+ character *mapping* table to it and return the resulting Unicode object.
+ Return *NULL* when an exception was raised by the codec.
+
+ .. deprecated-removed:: 3.3 4.0
+ Part of the old-style :c:type:`Py_UNICODE` API; please migrate to using
+ :c:func:`PyUnicode_Translate`. or :ref:`generic codec based API
+ <codec-registry>`
+
+
MBCS codecs for Windows
"""""""""""""""""""""""
diff --git a/Doc/distutils/examples.rst b/Doc/distutils/examples.rst
index 1f5be9c..4e2761d 100644
--- a/Doc/distutils/examples.rst
+++ b/Doc/distutils/examples.rst
@@ -321,7 +321,7 @@
>>> metadata.description
'Easily download, build, install, upgrade, and uninstall Python packages'
-Notice that the class can also be instanciated with a metadata file path to
+Notice that the class can also be instantiated with a metadata file path to
loads its values::
>>> pkg_info_path = 'distribute-0.6.8-py2.7.egg-info'
diff --git a/Doc/glossary.rst b/Doc/glossary.rst
index 41ee3d8..495934a 100644
--- a/Doc/glossary.rst
+++ b/Doc/glossary.rst
@@ -131,6 +131,10 @@
binary file
A :term:`file object` able to read and write
:term:`bytes-like objects <bytes-like object>`.
+ Examples of binary files are files opened in binary mode (``'rb'``,
+ ``'wb'`` or ``'rb+'``), :data:`sys.stdin.buffer`,
+ :data:`sys.stdout.buffer`, and instances of :class:`io.BytesIO` and
+ :class:`gzip.GzipFile`.
.. seealso::
A :term:`text file` reads and writes :class:`str` objects.
@@ -155,7 +159,7 @@
bytecode
Python source code is compiled into bytecode, the internal representation
of a Python program in the CPython interpreter. The bytecode is also
- cached in ``.pyc`` and ``.pyo`` files so that executing the same file is
+ cached in ``.pyc`` files so that executing the same file is
faster the second time (recompilation from source to bytecode can be
avoided). This "intermediate language" is said to run on a
:term:`virtual machine` that executes the machine code corresponding to
@@ -966,6 +970,9 @@
A :term:`file object` able to read and write :class:`str` objects.
Often, a text file actually accesses a byte-oriented datastream
and handles the :term:`text encoding` automatically.
+ Examples of text files are files opened in text mode (``'r'`` or ``'w'``),
+ :data:`sys.stdin`, :data:`sys.stdout`, and instances of
+ :class:`io.StringIO`.
.. seealso::
A :term:`binary file` reads and write :class:`bytes` objects.
diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst
index dc93a74..16ba9a3 100644
--- a/Doc/library/asyncio-subprocess.rst
+++ b/Doc/library/asyncio-subprocess.rst
@@ -80,7 +80,7 @@
however, where :class:`~subprocess.Popen` takes a single argument which is
list of strings, :func:`subprocess_exec` takes multiple string arguments.
- The *protocol_factory* must instanciate a subclass of the
+ The *protocol_factory* must instantiate a subclass of the
:class:`asyncio.SubprocessProtocol` class.
Other parameters:
@@ -123,7 +123,7 @@
using the platform's "shell" syntax. This is similar to the standard library
:class:`subprocess.Popen` class called with ``shell=True``.
- The *protocol_factory* must instanciate a subclass of the
+ The *protocol_factory* must instantiate a subclass of the
:class:`asyncio.SubprocessProtocol` class.
See :meth:`~AbstractEventLoop.subprocess_exec` for more details about
diff --git a/Doc/library/binhex.rst b/Doc/library/binhex.rst
index 359ab23..2966e0d 100644
--- a/Doc/library/binhex.rst
+++ b/Doc/library/binhex.rst
@@ -55,5 +55,3 @@
If you code or decode textfiles on non-Macintosh platforms they will still use
the old Macintosh newline convention (carriage-return as end of line).
-As of this writing, :func:`hexbin` appears to not work in all cases.
-
diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst
index f0742ce..469a3ee 100644
--- a/Doc/library/constants.rst
+++ b/Doc/library/constants.rst
@@ -46,7 +46,7 @@
.. note::
- ``NotImplentedError`` and ``NotImplemented`` are not interchangeable,
+ ``NotImplementedError`` and ``NotImplemented`` are not interchangeable,
even though they have similar names and purposes.
See :exc:`NotImplementedError` for details on when to use it.
diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst
index d746eaf..d510855 100644
--- a/Doc/library/curses.rst
+++ b/Doc/library/curses.rst
@@ -1443,7 +1443,7 @@
+-------------------+--------------------------------------------+
| ``KEY_SEOL`` | Shifted Clear line |
+-------------------+--------------------------------------------+
-| ``KEY_SEXIT`` | Shifted Dxit |
+| ``KEY_SEXIT`` | Shifted Exit |
+-------------------+--------------------------------------------+
| ``KEY_SFIND`` | Shifted Find |
+-------------------+--------------------------------------------+
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
index 1c1e1a2..11d0569 100644
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -807,6 +807,15 @@
.. versionadded:: 3.5
+.. opcode:: BUILD_TUPLE_UNPACK_WITH_CALL (count)
+
+ This is similar to :opcode:`BUILD_TUPLE_UNPACK`,
+ but is used for ``f(*x, *y, *z)`` call syntax. The stack item at position
+ ``count + 1`` should be the corresponding callable ``f``.
+
+ .. versionadded:: 3.6
+
+
.. opcode:: BUILD_LIST_UNPACK (count)
This is similar to :opcode:`BUILD_TUPLE_UNPACK`, but pushes a list
@@ -834,14 +843,16 @@
.. versionadded:: 3.5
-.. opcode:: BUILD_MAP_UNPACK_WITH_CALL (oparg)
+.. opcode:: BUILD_MAP_UNPACK_WITH_CALL (count)
This is similar to :opcode:`BUILD_MAP_UNPACK`,
- but is used for ``f(**x, **y, **z)`` call syntax. The lowest byte of
- *oparg* is the count of mappings, the relative position of the
- corresponding callable ``f`` is encoded in the second byte of *oparg*.
+ but is used for ``f(**x, **y, **z)`` call syntax. The stack item at
+ position ``count + 2`` should be the corresponding callable ``f``.
.. versionadded:: 3.5
+ .. versionchanged:: 3.6
+ The position of the callable is determined by adding 2 to the opcode
+ argument instead of encoding it in the second byte of the argument.
.. opcode:: LOAD_ATTR (namei)
@@ -998,14 +1009,45 @@
.. opcode:: CALL_FUNCTION (argc)
- Calls a function. The low byte of *argc* indicates the number of positional
- parameters, the high byte the number of keyword parameters. On the stack, the
- opcode finds the keyword parameters first. For each keyword argument, the
- value is on top of the key. Below the keyword parameters, the positional
- parameters are on the stack, with the right-most parameter on top. Below the
- parameters, the function object to call is on the stack. Pops all function
- arguments, and the function itself off the stack, and pushes the return
- value.
+ Calls a function. *argc* indicates the number of positional arguments.
+ The positional arguments are on the stack, with the right-most argument
+ on top. Below the arguments, the function object to call is on the stack.
+ Pops all function arguments, and the function itself off the stack, and
+ pushes the return value.
+
+ .. versionchanged:: 3.6
+ This opcode is used only for calls with positional arguments.
+
+
+.. opcode:: CALL_FUNCTION_KW (argc)
+
+ Calls a function. *argc* indicates the number of arguments (positional
+ and keyword). The top element on the stack contains a tuple of keyword
+ argument names. Below the tuple, keyword arguments are on the stack, in
+ the order corresponding to the tuple. Below the keyword arguments, the
+ positional arguments are on the stack, with the right-most parameter on
+ top. Below the arguments, the function object to call is on the stack.
+ Pops all function arguments, and the function itself off the stack, and
+ pushes the return value.
+
+ .. versionchanged:: 3.6
+ Keyword arguments are packed in a tuple instead of a dictionary,
+ *argc* indicates the total number of arguments
+
+
+.. opcode:: CALL_FUNCTION_EX (flags)
+
+ Calls a function. The lowest bit of *flags* indicates whether the
+ var-keyword argument is placed at the top of the stack. Below the
+ var-keyword argument, the var-positional argument is on the stack.
+ Below the arguments, the function object to call is placed.
+ Pops all function arguments, and the function itself off the stack, and
+ pushes the return value. Note that this opcode pops at most three items
+ from the stack. Var-positional and var-keyword arguments are packed
+ by :opcode:`BUILD_MAP_UNPACK_WITH_CALL` and
+ :opcode:`BUILD_MAP_UNPACK_WITH_CALL`.
+
+ .. versionadded:: 3.6
.. opcode:: MAKE_FUNCTION (argc)
@@ -1038,28 +1080,6 @@
two most-significant bytes.
-.. opcode:: CALL_FUNCTION_VAR (argc)
-
- Calls a function. *argc* is interpreted as in :opcode:`CALL_FUNCTION`. The
- top element on the stack contains the variable argument list, followed by
- keyword and positional arguments.
-
-
-.. opcode:: CALL_FUNCTION_KW (argc)
-
- Calls a function. *argc* is interpreted as in :opcode:`CALL_FUNCTION`. The
- top element on the stack contains the keyword arguments dictionary, followed
- by explicit keyword and positional arguments.
-
-
-.. opcode:: CALL_FUNCTION_VAR_KW (argc)
-
- Calls a function. *argc* is interpreted as in :opcode:`CALL_FUNCTION`. The
- top element on the stack contains the keyword arguments dictionary, followed
- by the variable-arguments tuple, followed by explicit keyword and positional
- arguments.
-
-
.. opcode:: FORMAT_VALUE (flags)
Used for implementing formatted literal strings (f-strings). Pops
diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst
index b8c1dcf..7291dfe8 100644
--- a/Doc/library/ftplib.rst
+++ b/Doc/library/ftplib.rst
@@ -235,7 +235,7 @@
Retrieve a file in binary transfer mode. *cmd* should be an appropriate
``RETR`` command: ``'RETR filename'``. The *callback* function is called for
- each block of data received, with a single string argument giving the data
+ each block of data received, with a single bytes argument giving the data
block. The optional *blocksize* argument specifies the maximum chunk size to
read on the low-level socket object created to do the actual transfer (which
will also be the largest size of the data blocks passed to *callback*). A
@@ -255,9 +255,9 @@
prints the line to ``sys.stdout``.
-.. method:: FTP.set_pasv(boolean)
+.. method:: FTP.set_pasv(val)
- Enable "passive" mode if *boolean* is true, other disable passive mode.
+ Enable "passive" mode if *val* is true, otherwise disable passive mode.
Passive mode is on by default.
diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst
index 3fa44a0..4ff2187 100644
--- a/Doc/library/inspect.rst
+++ b/Doc/library/inspect.rst
@@ -442,7 +442,9 @@
Return in a single string any lines of comments immediately preceding the
object's source code (for a class, function, or method), or at the top of the
- Python source file (if the object is a module).
+ Python source file (if the object is a module). If the object's source code
+ is unavailable, return ``None``. This could happen if the object has been
+ defined in C or the interactive shell.
.. function:: getfile(object)
diff --git a/Doc/library/marshal.rst b/Doc/library/marshal.rst
index 1ffc6ef..d65afc2 100644
--- a/Doc/library/marshal.rst
+++ b/Doc/library/marshal.rst
@@ -49,7 +49,7 @@
be written (see below).
There are functions that read/write files as well as functions operating on
-strings.
+bytes-like objects.
The module defines these functions:
@@ -57,9 +57,7 @@
.. function:: dump(value, file[, version])
Write the value on the open file. The value must be a supported type. The
- file must be an open file object such as ``sys.stdout`` or returned by
- :func:`open` or :func:`os.popen`. It must be opened in binary mode (``'wb'``
- or ``'w+b'``).
+ file must be a writeable :term:`binary file`.
If the value has (or contains an object that has) an unsupported type, a
:exc:`ValueError` exception is raised --- but garbage data will also be written
@@ -74,8 +72,7 @@
Read one value from the open file and return it. If no valid value is read
(e.g. because the data has a different Python version's incompatible marshal
format), raise :exc:`EOFError`, :exc:`ValueError` or :exc:`TypeError`. The
- file must be an open file object opened in binary mode (``'rb'`` or
- ``'r+b'``).
+ file must be a readable :term:`binary file`.
.. note::
@@ -85,7 +82,7 @@
.. function:: dumps(value[, version])
- Return the string that would be written to a file by ``dump(value, file)``. The
+ Return the bytes object that would be written to a file by ``dump(value, file)``. The
value must be a supported type. Raise a :exc:`ValueError` exception if value
has (or contains an object that has) an unsupported type.
@@ -93,11 +90,11 @@
(see below).
-.. function:: loads(string)
+.. function:: loads(bytes)
- Convert the string to a value. If no valid value is found, raise
- :exc:`EOFError`, :exc:`ValueError` or :exc:`TypeError`. Extra characters in the
- string are ignored.
+ Convert the :term:`bytes-like object` to a value. If no valid value is found, raise
+ :exc:`EOFError`, :exc:`ValueError` or :exc:`TypeError`. Extra bytes in the
+ input are ignored.
In addition, the following constants are defined:
diff --git a/Doc/library/othergui.rst b/Doc/library/othergui.rst
index ee1ce50..d40abe1 100644
--- a/Doc/library/othergui.rst
+++ b/Doc/library/othergui.rst
@@ -9,14 +9,15 @@
.. seealso::
`PyGObject <https://wiki.gnome.org/Projects/PyGObject>`_
- provides introspection bindings for C libraries using
+ PyGObject provides introspection bindings for C libraries using
`GObject <https://developer.gnome.org/gobject/stable/>`_. One of
these libraries is the `GTK+ 3 <http://www.gtk.org/>`_ widget set.
GTK+ comes with many more widgets than Tkinter provides. An online
`Python GTK+ 3 Tutorial <https://python-gtk-3-tutorial.readthedocs.org/en/latest/>`_
is available.
- `PyGTK <http://www.pygtk.org/>`_ provides bindings for an older version
+ `PyGTK <http://www.pygtk.org/>`_
+ PyGTK provides bindings for an older version
of the library, GTK+ 2. It provides an object oriented interface that
is slightly higher level than the C one. There are also bindings to
`GNOME <https://www.gnome.org/>`_. An online `tutorial
@@ -27,15 +28,10 @@
extensive C++ GUI application development framework that is
available for Unix, Windows and Mac OS X. :program:`sip` is a tool
for generating bindings for C++ libraries as Python classes, and
- is specifically designed for Python. The *PyQt3* bindings have a
- book, `GUI Programming with Python: QT Edition
- <https://www.commandprompt.com/community/pyqt/>`_ by Boudewijn
- Rempt. The *PyQt4* bindings also have a book, `Rapid GUI Programming
- with Python and Qt <https://www.qtrac.eu/pyqtbook.html>`_, by Mark
- Summerfield.
+ is specifically designed for Python.
`PySide <https://wiki.qt.io/PySide>`_
- is a newer binding to the Qt toolkit, provided by Nokia.
+ PySide is a newer binding to the Qt toolkit, provided by Nokia.
Compared to PyQt, its licensing scheme is friendlier to non-open source
applications.
@@ -49,9 +45,7 @@
documentation and context sensitive help, printing, HTML viewing,
low-level device context drawing, drag and drop, system clipboard access,
an XML-based resource format and more, including an ever growing library
- of user-contributed modules. wxPython has a book, `wxPython in Action
- <https://www.manning.com/books/wxpython-in-action>`_, by Noel Rappin and
- Robin Dunn.
+ of user-contributed modules.
PyGTK, PyQt, and wxPython, all have a modern look and feel and more
widgets than Tkinter. In addition, there are many other GUI toolkits for
diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst
index a85bf33..41e5baf 100644
--- a/Doc/library/shutil.rst
+++ b/Doc/library/shutil.rst
@@ -153,7 +153,7 @@
is true and *src* is a symbolic link, *dst* will be a copy of
the file *src* refers to.
- :func:`copy` copies the file data and the file's permission
+ :func:`~shutil.copy` copies the file data and the file's permission
mode (see :func:`os.chmod`). Other metadata, like the
file's creation and modification times, is not preserved.
To preserve all file metadata from the original, use
@@ -302,7 +302,7 @@
*src* and *dst*, and will be used to copy *src* to *dest* if
:func:`os.rename` cannot be used. If the source is a directory,
:func:`copytree` is called, passing it the :func:`copy_function`. The
- default *copy_function* is :func:`copy2`. Using :func:`copy` as the
+ default *copy_function* is :func:`copy2`. Using :func:`~shutil.copy` as the
*copy_function* allows the move to succeed when it is not possible to also
copy the metadata, at the expense of not copying any of the metadata.
diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst
index d8f8097..337c061 100644
--- a/Doc/library/tarfile.rst
+++ b/Doc/library/tarfile.rst
@@ -146,6 +146,10 @@
.. versionchanged:: 3.5
The ``'x'`` (exclusive creation) mode was added.
+ .. versionchanged:: 3.6
+ The *name* parameter accepts a :term:`path-like object`.
+
+
.. class:: TarFile
Class for reading and writing tar archives. Do not use this class directly:
@@ -266,7 +270,8 @@
All following arguments are optional and can be accessed as instance attributes
as well.
- *name* is the pathname of the archive. It can be omitted if *fileobj* is given.
+ *name* is the pathname of the archive. *name* may be a :term:`path-like object`.
+ It can be omitted if *fileobj* is given.
In this case, the file object's :attr:`name` attribute is used if it exists.
*mode* is either ``'r'`` to read from an existing archive, ``'a'`` to append
@@ -319,6 +324,10 @@
.. versionchanged:: 3.5
The ``'x'`` (exclusive creation) mode was added.
+ .. versionchanged:: 3.6
+ The *name* parameter accepts a :term:`path-like object`.
+
+
.. classmethod:: TarFile.open(...)
Alternative constructor. The :func:`tarfile.open` function is actually a
@@ -390,14 +399,17 @@
.. versionchanged:: 3.5
Added the *numeric_owner* parameter.
+ .. versionchanged:: 3.6
+ The *path* parameter accepts a :term:`path-like object`.
+
.. method:: TarFile.extract(member, path="", set_attrs=True, *, numeric_owner=False)
Extract a member from the archive to the current working directory, using its
full name. Its file information is extracted as accurately as possible. *member*
may be a filename or a :class:`TarInfo` object. You can specify a different
- directory using *path*. File attributes (owner, mtime, mode) are set unless
- *set_attrs* is false.
+ directory using *path*. *path* may be a :term:`path-like object`.
+ File attributes (owner, mtime, mode) are set unless *set_attrs* is false.
If *numeric_owner* is :const:`True`, the uid and gid numbers from the tarfile
are used to set the owner/group for the extracted files. Otherwise, the named
@@ -418,6 +430,10 @@
.. versionchanged:: 3.5
Added the *numeric_owner* parameter.
+ .. versionchanged:: 3.6
+ The *path* parameter accepts a :term:`path-like object`.
+
+
.. method:: TarFile.extractfile(member)
Extract a member from the archive as a file object. *member* may be a filename
@@ -464,7 +480,8 @@
Create a :class:`TarInfo` object from the result of :func:`os.stat` or
equivalent on an existing file. The file is either named by *name*, or
- specified as a :term:`file object` *fileobj* with a file descriptor. If
+ specified as a :term:`file object` *fileobj* with a file descriptor.
+ *name* may be a :term:`path-like object`. If
given, *arcname* specifies an alternative name for the file in the
archive, otherwise, the name is taken from *fileobj*’s
:attr:`~io.FileIO.name` attribute, or the *name* argument. The name
@@ -478,6 +495,9 @@
The :attr:`~TarInfo.name` may also be modified, in which case *arcname*
could be a dummy string.
+ .. versionchanged:: 3.6
+ The *name* parameter accepts a :term:`path-like object`.
+
.. method:: TarFile.close()
diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst
index 665261f..c59aca1 100644
--- a/Doc/library/tempfile.rst
+++ b/Doc/library/tempfile.rst
@@ -245,12 +245,12 @@
used for temporary files returned by :func:`gettempdir`. It can be
set directly to override the selection process, but this is discouraged.
All functions in this module take a *dir* argument which can be used
-to specify the directory and this is the recommend approach.
+to specify the directory and this is the recommended approach.
.. data:: tempdir
When set to a value other than ``None``, this variable defines the
- default value for the *dir* argument to all the functions defined in this
+ default value for the *dir* argument to the functions defined in this
module.
If ``tempdir`` is unset or ``None`` at any call to any of the above
diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst
index 5eb6f10..a5d4211 100644
--- a/Doc/library/zipfile.rst
+++ b/Doc/library/zipfile.rst
@@ -132,8 +132,9 @@
.. class:: ZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=True)
- Open a ZIP file, where *file* can be either a path to a file (a string) or a
- file-like object. The *mode* parameter should be ``'r'`` to read an existing
+ Open a ZIP file, where *file* can be a path to a file (a string), a
+ file-like object or a :term:`path-like object`.
+ The *mode* parameter should be ``'r'`` to read an existing
file, ``'w'`` to truncate and write a new file, ``'a'`` to append to an
existing file, or ``'x'`` to exclusively create and write a new file.
If *mode* is ``'x'`` and *file* refers to an existing file,
@@ -183,6 +184,9 @@
Previously, a plain :exc:`RuntimeError` was raised for unrecognized
compression values.
+ .. versionchanged:: 3.6.2
+ The *file* parameter accepts a :term:`path-like object`.
+
.. method:: ZipFile.close()
@@ -284,6 +288,9 @@
Calling :meth:`extract` on a closed ZipFile will raise a
:exc:`ValueError`. Previously, a :exc:`RuntimeError` was raised.
+ .. versionchanged:: 3.6.2
+ The *path* parameter accepts a :term:`path-like object`.
+
.. method:: ZipFile.extractall(path=None, members=None, pwd=None)
@@ -304,6 +311,9 @@
Calling :meth:`extractall` on a closed ZipFile will raise a
:exc:`ValueError`. Previously, a :exc:`RuntimeError` was raised.
+ .. versionchanged:: 3.6.2
+ The *path* parameter accepts a :term:`path-like object`.
+
.. method:: ZipFile.printdir()
@@ -403,6 +413,9 @@
The following data attributes are also available:
+.. attribute:: ZipFile.filename
+
+ Name of the ZIP file.
.. attribute:: ZipFile.debug
@@ -451,12 +464,12 @@
added to the archive, compiling if necessary.
If *pathname* is a file, the filename must end with :file:`.py`, and
- just the (corresponding :file:`\*.py[co]`) file is added at the top level
+ just the (corresponding :file:`\*.pyc`) file is added at the top level
(no path information). If *pathname* is a file that does not end with
:file:`.py`, a :exc:`RuntimeError` will be raised. If it is a directory,
and the directory is not a package directory, then all the files
- :file:`\*.py[co]` are added at the top level. If the directory is a
- package directory, then all :file:`\*.py[co]` are added under the package
+ :file:`\*.pyc` are added at the top level. If the directory is a
+ package directory, then all :file:`\*.pyc` are added under the package
name as a file path, and if any subdirectories are package directories,
all of these are added recursively.
@@ -488,6 +501,9 @@
.. versionadded:: 3.4
The *filterfunc* parameter.
+ .. versionchanged:: 3.6.2
+ The *pathname* parameter accepts a :term:`path-like object`.
+
.. _zipinfo-objects:
@@ -514,6 +530,10 @@
.. versionadded:: 3.6
+ .. versionchanged:: 3.6.2
+ The *filename* parameter accepts a :term:`path-like object`.
+
+
Instances have the following methods and attributes:
.. method:: ZipInfo.is_dir()
diff --git a/Doc/library/zipimport.rst b/Doc/library/zipimport.rst
index 46b8c24..eaae2bb 100644
--- a/Doc/library/zipimport.rst
+++ b/Doc/library/zipimport.rst
@@ -9,7 +9,7 @@
--------------
This module adds the ability to import Python modules (:file:`\*.py`,
-:file:`\*.py[co]`) and packages from ZIP-format archives. It is usually not
+:file:`\*.pyc`) and packages from ZIP-format archives. It is usually not
needed to use the :mod:`zipimport` module explicitly; it is automatically used
by the built-in :keyword:`import` mechanism for :data:`sys.path` items that are paths
to ZIP archives.
diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst
index da7017a..7f9c664 100644
--- a/Doc/reference/lexical_analysis.rst
+++ b/Doc/reference/lexical_analysis.rst
@@ -696,6 +696,17 @@
>>> f"newline: {newline}"
'newline: 10'
+Formatted string literals cannot be used as docstrings, even if they do not
+include expressions.
+
+::
+
+ >>> def foo():
+ ... f"Not a docstring"
+ ...
+ >>> foo.__doc__ is None
+ True
+
See also :pep:`498` for the proposal that added formatted string literals,
and :meth:`str.format`, which uses a related format string mechanism.
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
index 195f63f..08dc311 100644
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -532,8 +532,8 @@
.. envvar:: PYTHONDONTWRITEBYTECODE
- If this is set to a non-empty string, Python won't try to write ``.pyc`` or
- ``.pyo`` files on the import of source modules. This is equivalent to
+ If this is set to a non-empty string, Python won't try to write ``.pyc``
+ files on the import of source modules. This is equivalent to
specifying the :option:`-B` option.
diff --git a/Include/fileutils.h b/Include/fileutils.h
index b933e98..900c70f 100644
--- a/Include/fileutils.h
+++ b/Include/fileutils.h
@@ -22,7 +22,7 @@
#ifdef MS_WINDOWS
struct _Py_stat_struct {
unsigned long st_dev;
- __int64 st_ino;
+ uint64_t st_ino;
unsigned short st_mode;
int st_nlink;
int st_uid;
diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h
index 587cf03..2d0d77e 100644
--- a/Include/unicodeobject.h
+++ b/Include/unicodeobject.h
@@ -1609,50 +1609,41 @@
This codec uses mappings to encode and decode characters.
- Decoding mappings must map single string characters to single
- Unicode characters, integers (which are then interpreted as Unicode
- ordinals) or None (meaning "undefined mapping" and causing an
- error).
+ Decoding mappings must map byte ordinals (integers in the range from 0 to
+ 255) to Unicode strings, integers (which are then interpreted as Unicode
+ ordinals) or None. Unmapped data bytes (ones which cause a LookupError)
+ as well as mapped to None, 0xFFFE or '\ufffe' are treated as "undefined
+ mapping" and cause an error.
- Encoding mappings must map single Unicode characters to single
- string characters, integers (which are then interpreted as Latin-1
- ordinals) or None (meaning "undefined mapping" and causing an
- error).
-
- If a character lookup fails with a LookupError, the character is
- copied as-is meaning that its ordinal value will be interpreted as
- Unicode or Latin-1 ordinal resp. Because of this mappings only need
- to contain those mappings which map characters to different code
- points.
+ Encoding mappings must map Unicode ordinal integers to bytes objects,
+ integers in the range from 0 to 255 or None. Unmapped character
+ ordinals (ones which cause a LookupError) as well as mapped to
+ None are treated as "undefined mapping" and cause an error.
*/
PyAPI_FUNC(PyObject*) PyUnicode_DecodeCharmap(
const char *string, /* Encoded string */
Py_ssize_t length, /* size of string */
- PyObject *mapping, /* character mapping
- (char ordinal -> unicode ordinal) */
+ PyObject *mapping, /* decoding mapping */
const char *errors /* error handling */
);
PyAPI_FUNC(PyObject*) PyUnicode_AsCharmapString(
PyObject *unicode, /* Unicode object */
- PyObject *mapping /* character mapping
- (unicode ordinal -> char ordinal) */
+ PyObject *mapping /* encoding mapping */
);
#ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject*) PyUnicode_EncodeCharmap(
const Py_UNICODE *data, /* Unicode char buffer */
Py_ssize_t length, /* Number of Py_UNICODE chars to encode */
- PyObject *mapping, /* character mapping
- (unicode ordinal -> char ordinal) */
+ PyObject *mapping, /* encoding mapping */
const char *errors /* error handling */
);
PyAPI_FUNC(PyObject*) _PyUnicode_EncodeCharmap(
PyObject *unicode, /* Unicode object */
- PyObject *mapping, /* character mapping
- (unicode ordinal -> char ordinal) */
+ PyObject *mapping, /* encoding mapping */
const char *errors /* error handling */
);
#endif
@@ -1661,8 +1652,8 @@
character mapping table to it and return the resulting Unicode
object.
- The mapping table must map Unicode ordinal integers to Unicode
- ordinal integers or None (causing deletion of the character).
+ The mapping table must map Unicode ordinal integers to Unicode strings,
+ Unicode ordinal integers or None (causing deletion of the character).
Mapping tables may be dictionaries or sequences. Unmapped character
ordinals (ones which cause a LookupError) are left untouched and
@@ -1960,8 +1951,8 @@
/* Translate a string by applying a character mapping table to it and
return the resulting Unicode object.
- The mapping table must map Unicode ordinal integers to Unicode
- ordinal integers or None (causing deletion of the character).
+ The mapping table must map Unicode ordinal integers to Unicode strings,
+ Unicode ordinal integers or None (causing deletion of the character).
Mapping tables may be dictionaries or sequences. Unmapped character
ordinals (ones which cause a LookupError) are left untouched and
diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py
index b172f3f..005d884 100644
--- a/Lib/_collections_abc.py
+++ b/Lib/_collections_abc.py
@@ -908,7 +908,8 @@
i = start
while stop is None or i < stop:
try:
- if self[i] == value:
+ v = self[i]
+ if v is value or v == value:
return i
except IndexError:
break
@@ -917,7 +918,7 @@
def count(self, value):
'S.count(value) -> integer -- return number of occurrences of value'
- return sum(1 for v in self if v == value)
+ return sum(1 for v in self if v is value or v == value)
Sequence.register(tuple)
Sequence.register(str)
diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py
index 7ad28d6..ab7ff0b 100644
--- a/Lib/asyncio/sslproto.py
+++ b/Lib/asyncio/sslproto.py
@@ -543,8 +543,10 @@
def _get_extra_info(self, name, default=None):
if name in self._extra:
return self._extra[name]
- else:
+ elif self._transport is not None:
return self._transport.get_extra_info(name, default)
+ else:
+ return default
def _start_shutdown(self):
if self._in_shutdown:
diff --git a/Lib/ctypes/test/test_structures.py b/Lib/ctypes/test/test_structures.py
index 3eded77..2e778fb 100644
--- a/Lib/ctypes/test/test_structures.py
+++ b/Lib/ctypes/test/test_structures.py
@@ -2,8 +2,8 @@
from ctypes import *
from ctypes.test import need_symbol
from struct import calcsize
-import _testcapi
import _ctypes_test
+import test.support
class SubclassesTest(unittest.TestCase):
def test_subclass(self):
@@ -202,7 +202,10 @@
"_pack_": -1}
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
+ @test.support.cpython_only
+ def test_packed_c_limits(self):
# Issue 15989
+ import _testcapi
d = {"_fields_": [("a", c_byte)],
"_pack_": _testcapi.INT_MAX + 1}
self.assertRaises(ValueError, type(Structure), "X", (Structure,), d)
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index 7d77973..2356f8d 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -815,7 +815,14 @@
if isinstance(address, str):
self.unixsocket = True
- self._connect_unixsocket(address)
+ # Syslog server may be unavailable during handler initialisation.
+ # C's openlog() function also ignores connection errors.
+ # Moreover, we ignore these errors while logging, so it not worse
+ # to ignore it also here.
+ try:
+ self._connect_unixsocket(address)
+ except OSError:
+ pass
else:
self.unixsocket = False
if socktype is None:
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index 822ddb4..0db6571 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -986,7 +986,7 @@
int(not close_fds),
creationflags,
env,
- cwd,
+ os.fspath(cwd) if cwd is not None else None,
startupinfo)
finally:
# Child is launched. Close the parent's copy of those pipe
diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py
index 3b3d245..e2e58bd 100644
--- a/Lib/test/libregrtest/refleak.py
+++ b/Lib/test/libregrtest/refleak.py
@@ -143,9 +143,14 @@
sys._clear_type_cache()
# Clear ABC registries, restoring previously saved ABC registries.
- for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]:
- if not isabstract(abc):
- continue
+ abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__]
+ abs_classes = filter(isabstract, abs_classes)
+ if 'typing' in sys.modules:
+ t = sys.modules['typing']
+ # These classes require special treatment because they do not appear
+ # in direct subclasses of collections.abc classes
+ abs_classes = list(abs_classes) + [t.ChainMap, t.Counter, t.DefaultDict]
+ for abc in abs_classes:
for obj in abc.__subclasses__() + [abc]:
obj._abc_registry = abcs.get(obj, WeakSet()).copy()
obj._abc_cache.clear()
diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
index 1f8967c..d67f919 100644
--- a/Lib/test/test_array.py
+++ b/Lib/test/test_array.py
@@ -14,14 +14,6 @@
import array
from array import _array_reconstructor as array_reconstructor
-try:
- # Try to determine availability of long long independently
- # of the array module under test
- struct.calcsize('@q')
- have_long_long = True
-except struct.error:
- have_long_long = False
-
sizeof_wchar = array.array('u').itemsize
@@ -32,9 +24,7 @@
def __init__(self, typecode, newarg=None):
array.array.__init__(self)
-typecodes = "ubBhHiIlLfd"
-if have_long_long:
- typecodes += 'qQ'
+typecodes = 'ubBhHiIlLfdqQ'
class MiscTest(unittest.TestCase):
@@ -1240,7 +1230,26 @@
b = array.array(self.typecode, a)
self.assertEqual(a, b)
-class SignedNumberTest(NumberTest):
+class IntegerNumberTest(NumberTest):
+ def test_type_error(self):
+ a = array.array(self.typecode)
+ a.append(42)
+ with self.assertRaises(TypeError):
+ a.append(42.0)
+ with self.assertRaises(TypeError):
+ a[0] = 42.0
+
+class Intable:
+ def __init__(self, num):
+ self._num = num
+ def __int__(self):
+ return self._num
+ def __sub__(self, other):
+ return Intable(int(self) - int(other))
+ def __add__(self, other):
+ return Intable(int(self) + int(other))
+
+class SignedNumberTest(IntegerNumberTest):
example = [-1, 0, 1, 42, 0x7f]
smallerexample = [-1, 0, 1, 42, 0x7e]
biggerexample = [-1, 0, 1, 43, 0x7f]
@@ -1251,8 +1260,9 @@
lower = -1 * int(pow(2, a.itemsize * 8 - 1))
upper = int(pow(2, a.itemsize * 8 - 1)) - 1
self.check_overflow(lower, upper)
+ self.check_overflow(Intable(lower), Intable(upper))
-class UnsignedNumberTest(NumberTest):
+class UnsignedNumberTest(IntegerNumberTest):
example = [0, 1, 17, 23, 42, 0xff]
smallerexample = [0, 1, 17, 23, 42, 0xfe]
biggerexample = [0, 1, 17, 23, 43, 0xff]
@@ -1263,6 +1273,7 @@
lower = 0
upper = int(pow(2, a.itemsize * 8)) - 1
self.check_overflow(lower, upper)
+ self.check_overflow(Intable(lower), Intable(upper))
def test_bytes_extend(self):
s = bytes(self.example)
@@ -1314,12 +1325,10 @@
typecode = 'L'
minitemsize = 4
-@unittest.skipIf(not have_long_long, 'need long long support')
class LongLongTest(SignedNumberTest, unittest.TestCase):
typecode = 'q'
minitemsize = 8
-@unittest.skipIf(not have_long_long, 'need long long support')
class UnsignedLongLongTest(UnsignedNumberTest, unittest.TestCase):
typecode = 'Q'
minitemsize = 8
diff --git a/Lib/test/test_asyncio/test_sslproto.py b/Lib/test/test_asyncio/test_sslproto.py
index 59ff0f6..f1771c5 100644
--- a/Lib/test/test_asyncio/test_sslproto.py
+++ b/Lib/test/test_asyncio/test_sslproto.py
@@ -95,5 +95,17 @@
test_utils.run_briefly(self.loop)
self.assertIsInstance(waiter.exception(), ConnectionAbortedError)
+ def test_get_extra_info_on_closed_connection(self):
+ waiter = asyncio.Future(loop=self.loop)
+ ssl_proto = self.ssl_protocol(waiter)
+ self.assertIsNone(ssl_proto._get_extra_info('socket'))
+ default = object()
+ self.assertIs(ssl_proto._get_extra_info('socket', default), default)
+ self.connection_made(ssl_proto)
+ self.assertIsNotNone(ssl_proto._get_extra_info('socket'))
+ ssl_proto.connection_lost(None)
+ self.assertIsNone(ssl_proto._get_extra_info('socket'))
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_atexit.py b/Lib/test/test_atexit.py
index 172bd25..c761076 100644
--- a/Lib/test/test_atexit.py
+++ b/Lib/test/test_atexit.py
@@ -143,6 +143,7 @@
self.assertEqual(l, [5])
+@support.cpython_only
class SubinterpreterTest(unittest.TestCase):
def test_callbacks_leak(self):
diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py
index a103a7d..cd82fa6 100644
--- a/Lib/test/test_bytes.py
+++ b/Lib/test/test_bytes.py
@@ -507,6 +507,11 @@
a = b % (b'seventy-nine', 79)
self.assertEqual(a, b'seventy-nine / 100 = 79%')
self.assertIs(type(a), self.type2test)
+ # issue 29714
+ b = self.type2test(b'hello,\x00%b!')
+ b = b % b'world'
+ self.assertEqual(b, b'hello,\x00world!')
+ self.assertIs(type(b), self.type2test)
def test_imod(self):
b = self.type2test(b'hello, %b!')
@@ -519,6 +524,11 @@
b %= (b'seventy-nine', 79)
self.assertEqual(b, b'seventy-nine / 100 = 79%')
self.assertIs(type(b), self.type2test)
+ # issue 29714
+ b = self.type2test(b'hello,\x00%b!')
+ b %= b'world'
+ self.assertEqual(b, b'hello,\x00world!')
+ self.assertIs(type(b), self.type2test)
def test_rmod(self):
with self.assertRaises(TypeError):
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index 87454cc..47f7562 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -1310,20 +1310,29 @@
class CustomEqualObject:
def __eq__(self, other):
return False
- class CustomSequence(list):
- def __contains__(self, value):
- return Sequence.__contains__(self, value)
+ class CustomSequence(Sequence):
+ def __init__(self, seq):
+ self._seq = seq
+ def __getitem__(self, index):
+ return self._seq[index]
+ def __len__(self):
+ return len(self._seq)
nan = float('nan')
obj = CustomEqualObject()
+ seq = CustomSequence([nan, obj, nan])
containers = [
- CustomSequence([nan, obj]),
+ seq,
ItemsView({1: nan, 2: obj}),
ValuesView({1: nan, 2: obj})
]
for container in containers:
for elem in container:
self.assertIn(elem, container)
+ self.assertEqual(seq.index(nan), 0)
+ self.assertEqual(seq.index(obj), 1)
+ self.assertEqual(seq.count(nan), 2)
+ self.assertEqual(seq.count(obj), 1)
def assertSameSet(self, s1, s2):
# coerce both to a real set then check equality
diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py
index b4c7b5b..2b79a17 100644
--- a/Lib/test/test_coroutines.py
+++ b/Lib/test/test_coroutines.py
@@ -1103,6 +1103,21 @@
"coroutine is being awaited already"):
waiter(coro).send(None)
+ def test_await_16(self):
+ # See https://bugs.python.org/issue29600 for details.
+
+ async def f():
+ return ValueError()
+
+ async def g():
+ try:
+ raise KeyError
+ except:
+ return await f()
+
+ _, result = run_async(g())
+ self.assertIsNone(result.__context__)
+
def test_with_1(self):
class Manager:
def __init__(self, name):
@@ -2102,6 +2117,7 @@
sys.set_coroutine_wrapper(None)
+@support.cpython_only
class CAPITest(unittest.TestCase):
def test_tp_await_1(self):
diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py
index 3da210a..57a0265 100644
--- a/Lib/test/test_fileio.py
+++ b/Lib/test/test_fileio.py
@@ -10,7 +10,7 @@
from functools import wraps
from test.support import (TESTFN, TESTFN_UNICODE, check_warnings, run_unittest,
- make_bad_fd, cpython_only)
+ make_bad_fd, cpython_only, swap_attr)
from collections import UserList
import _io # C implementation of io
@@ -176,6 +176,12 @@
finally:
os.close(fd)
+ def testRecursiveRepr(self):
+ # Issue #25455
+ with swap_attr(self.f, 'name', self.f):
+ with self.assertRaises(RuntimeError):
+ repr(self.f) # Should not crash
+
def testErrors(self):
f = self.f
self.assertFalse(f.isatty())
diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py
index ac8473d..6491f45 100644
--- a/Lib/test/test_float.py
+++ b/Lib/test/test_float.py
@@ -119,15 +119,27 @@
self.assertEqual(float(memoryview(b'12.34')[1:4]), 2.3)
def test_error_message(self):
- testlist = ('\xbd', '123\xbd', ' 123 456 ')
- for s in testlist:
- try:
+ def check(s):
+ with self.assertRaises(ValueError, msg='float(%r)' % (s,)) as cm:
float(s)
- except ValueError as e:
- self.assertIn(s.strip(), e.args[0])
- else:
- self.fail("Expected int(%r) to raise a ValueError", s)
+ self.assertEqual(str(cm.exception),
+ 'could not convert string to float: %r' % (s,))
+ check('\xbd')
+ check('123\xbd')
+ check(' 123 456 ')
+ check(b' 123 456 ')
+
+ # non-ascii digits (error came from non-digit '!')
+ check('\u0663\u0661\u0664!')
+ # embedded NUL
+ check('123\x00')
+ check('123\x00 245')
+ check('123\x00245')
+ # byte string with embedded NUL
+ check(b'123\x00')
+ # non-UTF-8 byte string
+ check(b'123\xa0')
@support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE')
def test_float_with_comma(self):
diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py
index 83eb29f..b6ba2e5 100644
--- a/Lib/test/test_format.py
+++ b/Lib/test/test_format.py
@@ -315,10 +315,12 @@
testcommon(b"%b", b"abc", b"abc")
testcommon(b"%b", bytearray(b"def"), b"def")
testcommon(b"%b", fb, b"123")
+ testcommon(b"%b", memoryview(b"abc"), b"abc")
# # %s is an alias for %b -- should only be used for Py2/3 code
testcommon(b"%s", b"abc", b"abc")
testcommon(b"%s", bytearray(b"def"), b"def")
testcommon(b"%s", fb, b"123")
+ testcommon(b"%s", memoryview(b"abc"), b"abc")
# %a will give the equivalent of
# repr(some_obj).encode('ascii', 'backslashreplace')
testcommon(b"%a", 3.14, b"3.14")
@@ -377,9 +379,11 @@
test_exc(b"%c", 3.14, TypeError,
"%c requires an integer in range(256) or a single byte")
test_exc(b"%b", "Xc", TypeError,
- "%b requires bytes, or an object that implements __bytes__, not 'str'")
+ "%b requires a bytes-like object, "
+ "or an object that implements __bytes__, not 'str'")
test_exc(b"%s", "Wd", TypeError,
- "%b requires bytes, or an object that implements __bytes__, not 'str'")
+ "%b requires a bytes-like object, "
+ "or an object that implements __bytes__, not 'str'")
if maxsize == 2**31-1:
# crashes 2.2.1 and earlier:
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py
index b7d648d..cd4664c 100644
--- a/Lib/test/test_functools.py
+++ b/Lib/test/test_functools.py
@@ -402,6 +402,32 @@
else:
self.fail('partial object allowed __dict__ to be deleted')
+ def test_manually_adding_non_string_keyword(self):
+ p = self.partial(capture)
+ # Adding a non-string/unicode keyword to partial kwargs
+ p.keywords[1234] = 'value'
+ r = repr(p)
+ self.assertIn('1234', r)
+ self.assertIn("'value'", r)
+ with self.assertRaises(TypeError):
+ p()
+
+ def test_keystr_replaces_value(self):
+ p = self.partial(capture)
+
+ class MutatesYourDict(object):
+ def __str__(self):
+ p.keywords[self] = ['sth2']
+ return 'astr'
+
+ # Raplacing the value during key formatting should keep the original
+ # value alive (at least long enough).
+ p.keywords[MutatesYourDict()] = ['sth']
+ r = repr(p)
+ self.assertIn('astr', r)
+ self.assertIn("['sth']", r)
+
+
class TestPartialPy(TestPartial, unittest.TestCase):
partial = py_functools.partial
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 88eaabe..cfea281 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -387,6 +387,11 @@
def test_getcomments(self):
self.assertEqual(inspect.getcomments(mod), '# line 1\n')
self.assertEqual(inspect.getcomments(mod.StupidGit), '# line 20\n')
+ # If the object source file is not available, return None.
+ co = compile('x=1', '_non_existing_filename.py', 'exec')
+ self.assertIsNone(inspect.getcomments(co))
+ # If the object has been defined in C, return None.
+ self.assertIsNone(inspect.getcomments(list))
def test_getmodule(self):
# Check actual module
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index aaa64ea..8f895fe 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -1014,6 +1014,16 @@
raw.name = b"dummy"
self.assertEqual(repr(b), "<%s name=b'dummy'>" % clsname)
+ def test_recursive_repr(self):
+ # Issue #25455
+ raw = self.MockRawIO()
+ b = self.tp(raw)
+ with support.swap_attr(raw, 'name', b):
+ try:
+ repr(b) # Should not crash
+ except RuntimeError:
+ pass
+
def test_flush_error_on_close(self):
# Test that buffered file is closed despite failed flush
# and that flush() is called before file closed.
@@ -2424,6 +2434,16 @@
t.buffer.detach()
repr(t) # Should not raise an exception
+ def test_recursive_repr(self):
+ # Issue #25455
+ raw = self.BytesIO()
+ t = self.TextIOWrapper(raw)
+ with support.swap_attr(raw, 'name', t):
+ try:
+ repr(t) # Should not crash
+ except RuntimeError:
+ pass
+
def test_line_buffering(self):
r = self.BytesIO()
b = self.BufferedWriter(r, 1000)
diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py
index 15f3736..9d93f93 100644
--- a/Lib/test/test_json/test_tool.py
+++ b/Lib/test/test_json/test_tool.py
@@ -2,7 +2,7 @@
import sys
import textwrap
import unittest
-import subprocess
+from subprocess import Popen, PIPE
from test import support
from test.support.script_helper import assert_python_ok
@@ -61,12 +61,11 @@
""")
def test_stdin_stdout(self):
- with subprocess.Popen(
- (sys.executable, '-m', 'json.tool'),
- stdin=subprocess.PIPE, stdout=subprocess.PIPE) as proc:
+ args = sys.executable, '-m', 'json.tool'
+ with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as proc:
out, err = proc.communicate(self.data.encode())
self.assertEqual(out.splitlines(), self.expect.encode().splitlines())
- self.assertEqual(err, None)
+ self.assertEqual(err, b'')
def _create_infile(self):
infile = support.TESTFN
diff --git a/Lib/test/test_range.py b/Lib/test/test_range.py
index 9e11e51..679759e 100644
--- a/Lib/test/test_range.py
+++ b/Lib/test/test_range.py
@@ -99,20 +99,24 @@
x = range(10**20+10, 10**20, 3)
self.assertEqual(len(x), 0)
self.assertEqual(len(list(x)), 0)
+ self.assertFalse(x)
x = range(10**20, 10**20+10, -3)
self.assertEqual(len(x), 0)
self.assertEqual(len(list(x)), 0)
+ self.assertFalse(x)
x = range(10**20+10, 10**20, -3)
self.assertEqual(len(x), 4)
self.assertEqual(len(list(x)), 4)
+ self.assertTrue(x)
# Now test range() with longs
- self.assertEqual(list(range(-2**100)), [])
- self.assertEqual(list(range(0, -2**100)), [])
- self.assertEqual(list(range(0, 2**100, -1)), [])
- self.assertEqual(list(range(0, 2**100, -1)), [])
+ for x in [range(-2**100),
+ range(0, -2**100),
+ range(0, 2**100, -1)]:
+ self.assertEqual(list(x), [])
+ self.assertFalse(x)
a = int(10 * sys.maxsize)
b = int(100 * sys.maxsize)
@@ -153,6 +157,7 @@
step = x[1] - x[0]
length = 1 + ((x[-1] - x[0]) // step)
return length
+
a = -sys.maxsize
b = sys.maxsize
expected_len = b - a
@@ -160,6 +165,7 @@
self.assertIn(a, x)
self.assertNotIn(b, x)
self.assertRaises(OverflowError, len, x)
+ self.assertTrue(x)
self.assertEqual(_range_len(x), expected_len)
self.assertEqual(x[0], a)
idx = sys.maxsize+1
@@ -177,6 +183,7 @@
self.assertIn(a, x)
self.assertNotIn(b, x)
self.assertRaises(OverflowError, len, x)
+ self.assertTrue(x)
self.assertEqual(_range_len(x), expected_len)
self.assertEqual(x[0], a)
idx = sys.maxsize+1
@@ -195,6 +202,7 @@
self.assertIn(a, x)
self.assertNotIn(b, x)
self.assertRaises(OverflowError, len, x)
+ self.assertTrue(x)
self.assertEqual(_range_len(x), expected_len)
self.assertEqual(x[0], a)
idx = sys.maxsize+1
@@ -213,6 +221,7 @@
self.assertIn(a, x)
self.assertNotIn(b, x)
self.assertRaises(OverflowError, len, x)
+ self.assertTrue(x)
self.assertEqual(_range_len(x), expected_len)
self.assertEqual(x[0], a)
idx = sys.maxsize+1
diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py
index a506b98..b945cf0 100644
--- a/Lib/test/test_re.py
+++ b/Lib/test/test_re.py
@@ -1402,7 +1402,7 @@
def test_locale_flag(self):
import locale
- enc = locale.getpreferredencoding(False)
+ _, enc = locale.getlocale(locale.LC_CTYPE)
# Search non-ASCII letter
for i in range(128, 256):
try:
diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py
index 0620b24..342ec9e 100644
--- a/Lib/test/test_site.py
+++ b/Lib/test/test_site.py
@@ -501,15 +501,15 @@
print(line, file=f)
return exe_file
except:
- os.unlink(_pth_file)
- os.unlink(exe_file)
+ test.support.unlink(_pth_file)
+ test.support.unlink(exe_file)
raise
@classmethod
def _cleanup_underpth_exe(self, exe_file):
_pth_file = os.path.splitext(exe_file)[0] + '._pth'
- os.unlink(_pth_file)
- os.unlink(exe_file)
+ test.support.unlink(_pth_file)
+ test.support.unlink(exe_file)
@classmethod
def _calc_sys_path_for_underpth_nosite(self, sys_prefix, lines):
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 97dc3cd..2497e47 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -803,11 +803,6 @@
self.fail("Error testing host resolution mechanisms. (fqdn: %s, all: %s)" % (fqhn, repr(all_host_names)))
def test_host_resolution(self):
- for addr in ['0.1.1.~1', '1+.1.1.1', '::1q', '::1::2',
- '1:1:1:1:1:1:1:1:1']:
- self.assertRaises(OSError, socket.gethostbyname, addr)
- self.assertRaises(OSError, socket.gethostbyaddr, addr)
-
for addr in [support.HOST, '10.0.0.1', '255.255.255.255']:
self.assertEqual(socket.gethostbyname(addr), addr)
@@ -816,6 +811,21 @@
for host in [support.HOST]:
self.assertIn(host, socket.gethostbyaddr(host)[2])
+ def test_host_resolution_bad_address(self):
+ # These are all malformed IP addresses and expected not to resolve to
+ # any result. But some ISPs, e.g. AWS, may successfully resolve these
+ # IPs.
+ explanation = (
+ "resolving an invalid IP address did not raise OSError; "
+ "can be caused by a broken DNS server"
+ )
+ for addr in ['0.1.1.~1', '1+.1.1.1', '::1q', '::1::2',
+ '1:1:1:1:1:1:1:1:1']:
+ with self.assertRaises(OSError):
+ socket.gethostbyname(addr)
+ with self.assertRaises(OSError, msg=explanation):
+ socket.gethostbyaddr(addr)
+
@unittest.skipUnless(hasattr(socket, 'sethostname'), "test needs socket.sethostname()")
@unittest.skipUnless(hasattr(socket, 'gethostname'), "test needs socket.gethostname()")
def test_sethostname(self):
@@ -896,6 +906,7 @@
self.assertEqual(swapped & mask, mask)
self.assertRaises(OverflowError, func, 1<<34)
+ @support.cpython_only
def testNtoHErrors(self):
good_values = [ 1, 2, 3, 1, 2, 3 ]
bad_values = [ -1, -2, -3, -1, -2, -3 ]
@@ -5469,7 +5480,7 @@
self.assertEqual(len(dec), msglen * multiplier)
self.assertEqual(dec, msg * multiplier)
- @support.requires_linux_version(4, 3) # see test_aes_cbc
+ @support.requires_linux_version(4, 9) # see issue29324
def test_aead_aes_gcm(self):
key = bytes.fromhex('c939cc13397c1d37de6ae0e1cb7c423c')
iv = bytes.fromhex('b3d8cc017cbb89b39e0f67e2')
@@ -5492,8 +5503,7 @@
op.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, iv=iv,
assoclen=assoclen, flags=socket.MSG_MORE)
op.sendall(assoc, socket.MSG_MORE)
- op.sendall(plain, socket.MSG_MORE)
- op.sendall(b'\x00' * taglen)
+ op.sendall(plain)
res = op.recv(assoclen + len(plain) + taglen)
self.assertEqual(expected_ct, res[assoclen:-taglen])
self.assertEqual(expected_tag, res[-taglen:])
@@ -5501,7 +5511,7 @@
# now with msg
op, _ = algo.accept()
with op:
- msg = assoc + plain + b'\x00' * taglen
+ msg = assoc + plain
op.sendmsg_afalg([msg], op=socket.ALG_OP_ENCRYPT, iv=iv,
assoclen=assoclen)
res = op.recv(assoclen + len(plain) + taglen)
@@ -5512,7 +5522,7 @@
pack_uint32 = struct.Struct('I').pack
op, _ = algo.accept()
with op:
- msg = assoc + plain + b'\x00' * taglen
+ msg = assoc + plain
op.sendmsg(
[msg],
([socket.SOL_ALG, socket.ALG_SET_OP, pack_uint32(socket.ALG_OP_ENCRYPT)],
@@ -5520,7 +5530,7 @@
[socket.SOL_ALG, socket.ALG_SET_AEAD_ASSOCLEN, pack_uint32(assoclen)],
)
)
- res = op.recv(len(msg))
+ res = op.recv(len(msg) + taglen)
self.assertEqual(expected_ct, res[assoclen:-taglen])
self.assertEqual(expected_tag, res[-taglen:])
@@ -5530,8 +5540,8 @@
msg = assoc + expected_ct + expected_tag
op.sendmsg_afalg([msg], op=socket.ALG_OP_DECRYPT, iv=iv,
assoclen=assoclen)
- res = op.recv(len(msg))
- self.assertEqual(plain, res[assoclen:-taglen])
+ res = op.recv(len(msg) - taglen)
+ self.assertEqual(plain, res[assoclen:])
@support.requires_linux_version(4, 3) # see test_aes_cbc
def test_drbg_pr_sha256(self):
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index 619cbc0..fc79055 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -4,6 +4,7 @@
from hashlib import md5
from contextlib import contextmanager
from random import Random
+import pathlib
import unittest
import unittest.mock
@@ -440,6 +441,22 @@
self.assertIsInstance(tar.name, bytes)
self.assertEqual(tar.name, os.path.abspath(fobj.name))
+ def test_pathlike_name(self):
+ tarname = pathlib.Path(self.tarname)
+ with tarfile.open(tarname, mode=self.mode) as tar:
+ self.assertIsInstance(tar.name, str)
+ self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
+ with self.taropen(tarname) as tar:
+ self.assertIsInstance(tar.name, str)
+ self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
+ with tarfile.TarFile.open(tarname, mode=self.mode) as tar:
+ self.assertIsInstance(tar.name, str)
+ self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
+ if self.suffix == '':
+ with tarfile.TarFile(tarname, mode='r') as tar:
+ self.assertIsInstance(tar.name, str)
+ self.assertEqual(tar.name, os.path.abspath(os.fspath(tarname)))
+
def test_illegal_mode_arg(self):
with open(tmpname, 'wb'):
pass
@@ -582,6 +599,26 @@
finally:
support.rmtree(DIR)
+ def test_extractall_pathlike_name(self):
+ DIR = pathlib.Path(TEMPDIR) / "extractall"
+ with support.temp_dir(DIR), \
+ tarfile.open(tarname, encoding="iso8859-1") as tar:
+ directories = [t for t in tar if t.isdir()]
+ tar.extractall(DIR, directories)
+ for tarinfo in directories:
+ path = DIR / tarinfo.name
+ self.assertEqual(os.path.getmtime(path), tarinfo.mtime)
+
+ def test_extract_pathlike_name(self):
+ dirtype = "ustar/dirtype"
+ DIR = pathlib.Path(TEMPDIR) / "extractall"
+ with support.temp_dir(DIR), \
+ tarfile.open(tarname, encoding="iso8859-1") as tar:
+ tarinfo = tar.getmember(dirtype)
+ tar.extract(tarinfo, path=DIR)
+ extracted = DIR / dirtype
+ self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime)
+
def test_init_close_fobj(self):
# Issue #7341: Close the internal file object in the TarFile
# constructor in case of an error. For the test we rely on
@@ -1092,6 +1129,17 @@
finally:
support.rmdir(path)
+ def test_gettarinfo_pathlike_name(self):
+ with tarfile.open(tmpname, self.mode) as tar:
+ path = pathlib.Path(TEMPDIR) / "file"
+ with open(path, "wb") as fobj:
+ fobj.write(b"aaa")
+ tarinfo = tar.gettarinfo(path)
+ tarinfo2 = tar.gettarinfo(os.fspath(path))
+ self.assertIsInstance(tarinfo.name, str)
+ self.assertEqual(tarinfo.name, tarinfo2.name)
+ self.assertEqual(tarinfo.size, 3)
+
@unittest.skipUnless(hasattr(os, "link"),
"Missing hardlink implementation")
def test_link_size(self):
@@ -1528,6 +1576,34 @@
self.assertEqual(len(names), 1)
self.assertIn("spameggs42", names[0])
+ def test_create_pathlike_name(self):
+ with tarfile.open(pathlib.Path(tmpname), self.mode) as tobj:
+ self.assertIsInstance(tobj.name, str)
+ self.assertEqual(tobj.name, os.path.abspath(tmpname))
+ tobj.add(pathlib.Path(self.file_path))
+ names = tobj.getnames()
+ self.assertEqual(len(names), 1)
+ self.assertIn('spameggs42', names[0])
+
+ with self.taropen(tmpname) as tobj:
+ names = tobj.getnames()
+ self.assertEqual(len(names), 1)
+ self.assertIn('spameggs42', names[0])
+
+ def test_create_taropen_pathlike_name(self):
+ with self.taropen(pathlib.Path(tmpname), "x") as tobj:
+ self.assertIsInstance(tobj.name, str)
+ self.assertEqual(tobj.name, os.path.abspath(tmpname))
+ tobj.add(pathlib.Path(self.file_path))
+ names = tobj.getnames()
+ self.assertEqual(len(names), 1)
+ self.assertIn('spameggs42', names[0])
+
+ with self.taropen(tmpname) as tobj:
+ names = tobj.getnames()
+ self.assertEqual(len(names), 1)
+ self.assertIn('spameggs42', names[0])
+
class GzipCreateTest(GzipTest, CreateTest):
pass
diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py
index 790ab7e..742259b 100644
--- a/Lib/test/test_tracemalloc.py
+++ b/Lib/test/test_tracemalloc.py
@@ -865,6 +865,7 @@
b'number of frames',
stderr)
+ @unittest.skipIf(_testcapi is None, 'need _testcapi')
def test_pymem_alloc0(self):
# Issue #21639: Check that PyMem_Malloc(0) with tracemalloc enabled
# does not crash.
diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py
index df9c79e..30025e3 100644
--- a/Lib/test/test_xmlrpc.py
+++ b/Lib/test/test_xmlrpc.py
@@ -343,6 +343,94 @@
self.assertEqual(p.method(), 5)
self.assertEqual(p.method(), 5)
+
+class SimpleXMLRPCDispatcherTestCase(unittest.TestCase):
+ class DispatchExc(Exception):
+ """Raised inside the dispatched functions when checking for
+ chained exceptions"""
+
+ def test_call_registered_func(self):
+ """Calls explicitly registered function"""
+ # Makes sure any exception raised inside the function has no other
+ # exception chained to it
+
+ exp_params = 1, 2, 3
+
+ def dispatched_func(*params):
+ raise self.DispatchExc(params)
+
+ dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
+ dispatcher.register_function(dispatched_func)
+ with self.assertRaises(self.DispatchExc) as exc_ctx:
+ dispatcher._dispatch('dispatched_func', exp_params)
+ self.assertEqual(exc_ctx.exception.args, (exp_params,))
+ self.assertIsNone(exc_ctx.exception.__cause__)
+ self.assertIsNone(exc_ctx.exception.__context__)
+
+ def test_call_instance_func(self):
+ """Calls a registered instance attribute as a function"""
+ # Makes sure any exception raised inside the function has no other
+ # exception chained to it
+
+ exp_params = 1, 2, 3
+
+ class DispatchedClass:
+ def dispatched_func(self, *params):
+ raise SimpleXMLRPCDispatcherTestCase.DispatchExc(params)
+
+ dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
+ dispatcher.register_instance(DispatchedClass())
+ with self.assertRaises(self.DispatchExc) as exc_ctx:
+ dispatcher._dispatch('dispatched_func', exp_params)
+ self.assertEqual(exc_ctx.exception.args, (exp_params,))
+ self.assertIsNone(exc_ctx.exception.__cause__)
+ self.assertIsNone(exc_ctx.exception.__context__)
+
+ def test_call_dispatch_func(self):
+ """Calls the registered instance's `_dispatch` function"""
+ # Makes sure any exception raised inside the function has no other
+ # exception chained to it
+
+ exp_method = 'method'
+ exp_params = 1, 2, 3
+
+ class TestInstance:
+ def _dispatch(self, method, params):
+ raise SimpleXMLRPCDispatcherTestCase.DispatchExc(
+ method, params)
+
+ dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
+ dispatcher.register_instance(TestInstance())
+ with self.assertRaises(self.DispatchExc) as exc_ctx:
+ dispatcher._dispatch(exp_method, exp_params)
+ self.assertEqual(exc_ctx.exception.args, (exp_method, exp_params))
+ self.assertIsNone(exc_ctx.exception.__cause__)
+ self.assertIsNone(exc_ctx.exception.__context__)
+
+ def test_registered_func_is_none(self):
+ """Calls explicitly registered function which is None"""
+
+ dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
+ dispatcher.register_function(None, name='method')
+ with self.assertRaisesRegex(Exception, 'method'):
+ dispatcher._dispatch('method', ('param',))
+
+ def test_instance_has_no_func(self):
+ """Attempts to call nonexistent function on a registered instance"""
+
+ dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
+ dispatcher.register_instance(object())
+ with self.assertRaisesRegex(Exception, 'method'):
+ dispatcher._dispatch('method', ('param',))
+
+ def test_cannot_locate_func(self):
+ """Calls a function that the dispatcher cannot locate"""
+
+ dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
+ with self.assertRaisesRegex(Exception, 'method'):
+ dispatcher._dispatch('method', ('param',))
+
+
class HelperTestCase(unittest.TestCase):
def test_escape(self):
self.assertEqual(xmlrpclib.escape("a&b"), "a&b")
@@ -1312,7 +1400,7 @@
KeepaliveServerTestCase1, KeepaliveServerTestCase2,
GzipServerTestCase, GzipUtilTestCase,
MultiPathServerTestCase, ServerProxyTestCase, FailingServerTestCase,
- CGIHandlerTestCase)
+ CGIHandlerTestCase, SimpleXMLRPCDispatcherTestCase)
if __name__ == "__main__":
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py
index 0a43b20..d39f05f 100644
--- a/Lib/test/test_zipfile.py
+++ b/Lib/test/test_zipfile.py
@@ -2,6 +2,7 @@
import io
import os
import importlib.util
+import pathlib
import posixpath
import time
import struct
@@ -13,7 +14,7 @@
from random import randint, random, getrandbits
from test.support import script_helper
-from test.support import (TESTFN, findfile, unlink, rmtree, temp_dir,
+from test.support import (TESTFN, findfile, unlink, rmtree, temp_dir, temp_cwd,
requires_zlib, requires_bz2, requires_lzma,
captured_stdout, check_warnings)
@@ -148,6 +149,12 @@
for f in get_files(self):
self.zip_open_test(f, self.compression)
+ def test_open_with_pathlike(self):
+ path = pathlib.Path(TESTFN2)
+ self.zip_open_test(path, self.compression)
+ with zipfile.ZipFile(path, "r", self.compression) as zipfp:
+ self.assertIsInstance(zipfp.filename, str)
+
def zip_random_open_test(self, f, compression):
self.make_test_archive(f, compression)
@@ -906,22 +913,56 @@
finally:
rmtree(TESTFN2)
+ def test_write_pathlike(self):
+ os.mkdir(TESTFN2)
+ try:
+ with open(os.path.join(TESTFN2, "mod1.py"), "w") as fp:
+ fp.write("print(42)\n")
+
+ with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
+ zipfp.writepy(pathlib.Path(TESTFN2) / "mod1.py")
+ names = zipfp.namelist()
+ self.assertCompiledIn('mod1.py', names)
+ finally:
+ rmtree(TESTFN2)
+
class ExtractTests(unittest.TestCase):
- def test_extract(self):
+
+ def make_test_file(self):
with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
for fpath, fdata in SMALL_TEST_DATA:
zipfp.writestr(fpath, fdata)
+ def test_extract(self):
+ with temp_cwd():
+ self.make_test_file()
+ with zipfile.ZipFile(TESTFN2, "r") as zipfp:
+ for fpath, fdata in SMALL_TEST_DATA:
+ writtenfile = zipfp.extract(fpath)
+
+ # make sure it was written to the right place
+ correctfile = os.path.join(os.getcwd(), fpath)
+ correctfile = os.path.normpath(correctfile)
+
+ self.assertEqual(writtenfile, correctfile)
+
+ # make sure correct data is in correct file
+ with open(writtenfile, "rb") as f:
+ self.assertEqual(fdata.encode(), f.read())
+
+ unlink(writtenfile)
+
+ def _test_extract_with_target(self, target):
+ self.make_test_file()
with zipfile.ZipFile(TESTFN2, "r") as zipfp:
for fpath, fdata in SMALL_TEST_DATA:
- writtenfile = zipfp.extract(fpath)
+ writtenfile = zipfp.extract(fpath, target)
# make sure it was written to the right place
- correctfile = os.path.join(os.getcwd(), fpath)
+ correctfile = os.path.join(target, fpath)
correctfile = os.path.normpath(correctfile)
-
- self.assertEqual(writtenfile, correctfile)
+ self.assertTrue(os.path.samefile(writtenfile, correctfile), (writtenfile, target))
# make sure correct data is in correct file
with open(writtenfile, "rb") as f:
@@ -929,26 +970,50 @@
unlink(writtenfile)
- # remove the test file subdirectories
- rmtree(os.path.join(os.getcwd(), 'ziptest2dir'))
+ unlink(TESTFN2)
+
+ def test_extract_with_target(self):
+ with temp_dir() as extdir:
+ self._test_extract_with_target(extdir)
+
+ def test_extract_with_target_pathlike(self):
+ with temp_dir() as extdir:
+ self._test_extract_with_target(pathlib.Path(extdir))
def test_extract_all(self):
- with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp:
- for fpath, fdata in SMALL_TEST_DATA:
- zipfp.writestr(fpath, fdata)
+ with temp_cwd():
+ self.make_test_file()
+ with zipfile.ZipFile(TESTFN2, "r") as zipfp:
+ zipfp.extractall()
+ for fpath, fdata in SMALL_TEST_DATA:
+ outfile = os.path.join(os.getcwd(), fpath)
+ with open(outfile, "rb") as f:
+ self.assertEqual(fdata.encode(), f.read())
+
+ unlink(outfile)
+
+ def _test_extract_all_with_target(self, target):
+ self.make_test_file()
with zipfile.ZipFile(TESTFN2, "r") as zipfp:
- zipfp.extractall()
+ zipfp.extractall(target)
for fpath, fdata in SMALL_TEST_DATA:
- outfile = os.path.join(os.getcwd(), fpath)
+ outfile = os.path.join(target, fpath)
with open(outfile, "rb") as f:
self.assertEqual(fdata.encode(), f.read())
unlink(outfile)
- # remove the test file subdirectories
- rmtree(os.path.join(os.getcwd(), 'ziptest2dir'))
+ unlink(TESTFN2)
+
+ def test_extract_all_with_target(self):
+ with temp_dir() as extdir:
+ self._test_extract_all_with_target(extdir)
+
+ def test_extract_all_with_target_pathlike(self):
+ with temp_dir() as extdir:
+ self._test_extract_all_with_target(pathlib.Path(extdir))
def check_file(self, filename, content):
self.assertTrue(os.path.isfile(filename))
@@ -1188,6 +1253,8 @@
with open(TESTFN, "w") as fp:
fp.write("this is not a legal zip file\n")
self.assertFalse(zipfile.is_zipfile(TESTFN))
+ # - passing a path-like object
+ self.assertFalse(zipfile.is_zipfile(pathlib.Path(TESTFN)))
# - passing a file object
with open(TESTFN, "rb") as fp:
self.assertFalse(zipfile.is_zipfile(fp))
@@ -2033,6 +2100,26 @@
zi = zipfile.ZipInfo.from_file(__file__)
self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
self.assertFalse(zi.is_dir())
+ self.assertEqual(zi.file_size, os.path.getsize(__file__))
+
+ def test_from_file_pathlike(self):
+ zi = zipfile.ZipInfo.from_file(pathlib.Path(__file__))
+ self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
+ self.assertFalse(zi.is_dir())
+ self.assertEqual(zi.file_size, os.path.getsize(__file__))
+
+ def test_from_file_bytes(self):
+ zi = zipfile.ZipInfo.from_file(os.fsencode(__file__), 'test')
+ self.assertEqual(posixpath.basename(zi.filename), 'test')
+ self.assertFalse(zi.is_dir())
+ self.assertEqual(zi.file_size, os.path.getsize(__file__))
+
+ def test_from_file_fileno(self):
+ with open(__file__, 'rb') as f:
+ zi = zipfile.ZipInfo.from_file(f.fileno(), 'test')
+ self.assertEqual(posixpath.basename(zi.filename), 'test')
+ self.assertFalse(zi.is_dir())
+ self.assertEqual(zi.file_size, os.path.getsize(__file__))
def test_from_dir(self):
dirpath = os.path.dirname(os.path.abspath(__file__))
diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py
index 849bfdd..6faa2d6 100644
--- a/Lib/xmlrpc/server.py
+++ b/Lib/xmlrpc/server.py
@@ -386,31 +386,36 @@
not be called.
"""
- func = None
try:
- # check to see if a matching function has been registered
+ # call the matching registered function
func = self.funcs[method]
except KeyError:
- if self.instance is not None:
- # check for a _dispatch method
- if hasattr(self.instance, '_dispatch'):
- return self.instance._dispatch(method, params)
- else:
- # call instance method directly
- try:
- func = resolve_dotted_attribute(
- self.instance,
- method,
- self.allow_dotted_names
- )
- except AttributeError:
- pass
-
- if func is not None:
- return func(*params)
+ pass
else:
+ if func is not None:
+ return func(*params)
raise Exception('method "%s" is not supported' % method)
+ if self.instance is not None:
+ if hasattr(self.instance, '_dispatch'):
+ # call the `_dispatch` method on the instance
+ return self.instance._dispatch(method, params)
+
+ # call the instance's method directly
+ try:
+ func = resolve_dotted_attribute(
+ self.instance,
+ method,
+ self.allow_dotted_names
+ )
+ except AttributeError:
+ pass
+ else:
+ if func is not None:
+ return func(*params)
+
+ raise Exception('method "%s" is not supported' % method)
+
class SimpleXMLRPCRequestHandler(BaseHTTPRequestHandler):
"""Simple XML-RPC request handler class.
diff --git a/Lib/zipfile.py b/Lib/zipfile.py
index 7f2b43c..d7f5beb 100644
--- a/Lib/zipfile.py
+++ b/Lib/zipfile.py
@@ -479,6 +479,8 @@
this will be the same as filename, but without a drive letter and with
leading path separators removed).
"""
+ if isinstance(filename, os.PathLike):
+ filename = os.fspath(filename)
st = os.stat(filename)
isdir = stat.S_ISDIR(st.st_mode)
mtime = time.localtime(st.st_mtime)
@@ -1070,6 +1072,8 @@
self._comment = b''
# Check if we were passed a file-like object
+ if isinstance(file, os.PathLike):
+ file = os.fspath(file)
if isinstance(file, str):
# No, it's a filename
self._filePassed = 0
@@ -1470,11 +1474,10 @@
as possible. `member' may be a filename or a ZipInfo object. You can
specify a different directory using `path'.
"""
- if not isinstance(member, ZipInfo):
- member = self.getinfo(member)
-
if path is None:
path = os.getcwd()
+ else:
+ path = os.fspath(path)
return self._extract_member(member, path, pwd)
@@ -1487,8 +1490,13 @@
if members is None:
members = self.namelist()
+ if path is None:
+ path = os.getcwd()
+ else:
+ path = os.fspath(path)
+
for zipinfo in members:
- self.extract(zipinfo, path, pwd)
+ self._extract_member(zipinfo, path, pwd)
@classmethod
def _sanitize_windows_name(cls, arcname, pathsep):
@@ -1509,6 +1517,9 @@
"""Extract the ZipInfo object 'member' to a physical
file on the path targetpath.
"""
+ if not isinstance(member, ZipInfo):
+ member = self.getinfo(member)
+
# build the destination pathname, replacing
# forward slashes to platform specific separators.
arcname = member.filename.replace('/', os.path.sep)
@@ -1801,6 +1812,7 @@
If filterfunc(pathname) is given, it is called with every argument.
When it is False, the file or directory is skipped.
"""
+ pathname = os.fspath(pathname)
if filterfunc and not filterfunc(pathname):
if self.debug:
label = 'path' if os.path.isdir(pathname) else 'file'
diff --git a/Misc/ACKS b/Misc/ACKS
index c3b29a4..03afeb8 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1371,6 +1371,7 @@
Barry Scott
Steven Scott
Nick Seidenman
+Michael Seifert
Žiga Seilnacht
Yury Selivanov
Fred Sells
diff --git a/Misc/NEWS b/Misc/NEWS
index bb37f04..1835d1e 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -97,8 +97,6 @@
- Issue #28598: Support __rmod__ for subclasses of str being called before
str.__mod__. Patch by Martijn Pieters.
-- bpo-29572: Update Windows build and OS X installers to use OpenSSL 1.0.2k.
-
- bpo-29607: Fix stack_effect computation for CALL_FUNCTION_EX.
Patch by Matthieu Dartiailh.
diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c
index 3bf2ca7..d88d06e 100644
--- a/Modules/_cursesmodule.c
+++ b/Modules/_cursesmodule.c
@@ -2082,7 +2082,7 @@
PyTypeObject PyCursesWindow_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "_curses.curses window", /*tp_name*/
+ "_curses.window", /*tp_name*/
sizeof(PyCursesWindowObject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index 7abc9f4..1bcf16a 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -250,8 +250,11 @@
/* Pack keyword arguments */
assert (PyDict_Check(pto->kw));
for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
- Py_SETREF(arglist, PyUnicode_FromFormat("%U, %U=%R", arglist,
+ /* Prevent key.__str__ from deleting the value. */
+ Py_INCREF(value);
+ Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
key, value));
+ Py_DECREF(value);
if (arglist == NULL)
goto done;
}
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index cbe7425..efc7d05 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -1416,8 +1416,18 @@
res = PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name);
}
else {
- res = PyUnicode_FromFormat("<%s name=%R>",
- Py_TYPE(self)->tp_name, nameobj);
+ int status = Py_ReprEnter((PyObject *)self);
+ res = NULL;
+ if (status == 0) {
+ res = PyUnicode_FromFormat("<%s name=%R>",
+ Py_TYPE(self)->tp_name, nameobj);
+ Py_ReprLeave((PyObject *)self);
+ }
+ else if (status > 0) {
+ PyErr_Format(PyExc_RuntimeError,
+ "reentrant call inside %s.__repr__",
+ Py_TYPE(self)->tp_name);
+ }
Py_DECREF(nameobj);
}
return res;
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
index 7f3bcab..833ea8e 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -1082,9 +1082,19 @@
self->fd, mode_string(self), self->closefd ? "True" : "False");
}
else {
- res = PyUnicode_FromFormat(
- "<_io.FileIO name=%R mode='%s' closefd=%s>",
- nameobj, mode_string(self), self->closefd ? "True" : "False");
+ int status = Py_ReprEnter((PyObject *)self);
+ res = NULL;
+ if (status == 0) {
+ res = PyUnicode_FromFormat(
+ "<_io.FileIO name=%R mode='%s' closefd=%s>",
+ nameobj, mode_string(self), self->closefd ? "True" : "False");
+ Py_ReprLeave((PyObject *)self);
+ }
+ else if (status > 0) {
+ PyErr_Format(PyExc_RuntimeError,
+ "reentrant call inside %s.__repr__",
+ Py_TYPE(self)->tp_name);
+ }
Py_DECREF(nameobj);
}
return res;
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index 4df5562..bc8d11e 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -2483,6 +2483,7 @@
textiowrapper_repr(textio *self)
{
PyObject *nameobj, *modeobj, *res, *s;
+ int status;
CHECK_INITIALIZED(self);
@@ -2490,6 +2491,15 @@
if (res == NULL)
return NULL;
+ status = Py_ReprEnter((PyObject *)self);
+ if (status != 0) {
+ if (status > 0) {
+ PyErr_Format(PyExc_RuntimeError,
+ "reentrant call inside %s.__repr__",
+ Py_TYPE(self)->tp_name);
+ }
+ goto error;
+ }
nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name);
if (nameobj == NULL) {
if (PyErr_ExceptionMatches(PyExc_Exception))
@@ -2504,7 +2514,7 @@
goto error;
PyUnicode_AppendAndDel(&res, s);
if (res == NULL)
- return NULL;
+ goto error;
}
modeobj = _PyObject_GetAttrId((PyObject *) self, &PyId_mode);
if (modeobj == NULL) {
@@ -2520,14 +2530,21 @@
goto error;
PyUnicode_AppendAndDel(&res, s);
if (res == NULL)
- return NULL;
+ goto error;
}
s = PyUnicode_FromFormat("%U encoding=%R>",
res, self->encoding);
Py_DECREF(res);
+ if (status == 0) {
+ Py_ReprLeave((PyObject *)self);
+ }
return s;
-error:
+
+ error:
Py_XDECREF(res);
+ if (status == 0) {
+ Py_ReprLeave((PyObject *)self);
+ }
return NULL;
}
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 2caa8ee..d4221fe 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -331,35 +331,51 @@
(unsigned long) ((unsigned int *)ap->ob_item)[i]);
}
+static PyObject *
+get_int_unless_float(PyObject *v)
+{
+ if (PyFloat_Check(v)) {
+ PyErr_SetString(PyExc_TypeError,
+ "array item must be integer");
+ return NULL;
+ }
+ return (PyObject *)_PyLong_FromNbInt(v);
+}
+
static int
II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
{
unsigned long x;
- if (PyLong_Check(v)) {
- x = PyLong_AsUnsignedLong(v);
- if (x == (unsigned long) -1 && PyErr_Occurred())
- return -1;
- }
- else {
- long y;
- if (!PyArg_Parse(v, "l;array item must be integer", &y))
- return -1;
- if (y < 0) {
- PyErr_SetString(PyExc_OverflowError,
- "unsigned int is less than minimum");
+ int do_decref = 0; /* if nb_int was called */
+
+ if (!PyLong_Check(v)) {
+ v = get_int_unless_float(v);
+ if (NULL == v) {
return -1;
}
- x = (unsigned long)y;
-
+ do_decref = 1;
+ }
+ x = PyLong_AsUnsignedLong(v);
+ if (x == (unsigned long)-1 && PyErr_Occurred()) {
+ if (do_decref) {
+ Py_DECREF(v);
+ }
+ return -1;
}
if (x > UINT_MAX) {
PyErr_SetString(PyExc_OverflowError,
- "unsigned int is greater than maximum");
+ "unsigned int is greater than maximum");
+ if (do_decref) {
+ Py_DECREF(v);
+ }
return -1;
}
-
if (i >= 0)
((unsigned int *)ap->ob_item)[i] = (unsigned int)x;
+
+ if (do_decref) {
+ Py_DECREF(v);
+ }
return 0;
}
@@ -390,31 +406,28 @@
LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
{
unsigned long x;
- if (PyLong_Check(v)) {
- x = PyLong_AsUnsignedLong(v);
- if (x == (unsigned long) -1 && PyErr_Occurred())
- return -1;
- }
- else {
- long y;
- if (!PyArg_Parse(v, "l;array item must be integer", &y))
- return -1;
- if (y < 0) {
- PyErr_SetString(PyExc_OverflowError,
- "unsigned long is less than minimum");
+ int do_decref = 0; /* if nb_int was called */
+
+ if (!PyLong_Check(v)) {
+ v = get_int_unless_float(v);
+ if (NULL == v) {
return -1;
}
- x = (unsigned long)y;
-
+ do_decref = 1;
}
- if (x > ULONG_MAX) {
- PyErr_SetString(PyExc_OverflowError,
- "unsigned long is greater than maximum");
+ x = PyLong_AsUnsignedLong(v);
+ if (x == (unsigned long)-1 && PyErr_Occurred()) {
+ if (do_decref) {
+ Py_DECREF(v);
+ }
return -1;
}
-
if (i >= 0)
((unsigned long *)ap->ob_item)[i] = x;
+
+ if (do_decref) {
+ Py_DECREF(v);
+ }
return 0;
}
@@ -446,25 +459,28 @@
QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
{
unsigned long long x;
- if (PyLong_Check(v)) {
- x = PyLong_AsUnsignedLongLong(v);
- if (x == (unsigned long long) -1 && PyErr_Occurred())
- return -1;
- }
- else {
- long long y;
- if (!PyArg_Parse(v, "L;array item must be integer", &y))
- return -1;
- if (y < 0) {
- PyErr_SetString(PyExc_OverflowError,
- "unsigned long long is less than minimum");
+ int do_decref = 0; /* if nb_int was called */
+
+ if (!PyLong_Check(v)) {
+ v = get_int_unless_float(v);
+ if (NULL == v) {
return -1;
}
- x = (unsigned long long)y;
+ do_decref = 1;
}
-
+ x = PyLong_AsUnsignedLongLong(v);
+ if (x == (unsigned long long)-1 && PyErr_Occurred()) {
+ if (do_decref) {
+ Py_DECREF(v);
+ }
+ return -1;
+ }
if (i >= 0)
((unsigned long long *)ap->ob_item)[i] = x;
+
+ if (do_decref) {
+ Py_DECREF(v);
+ }
return 0;
}
diff --git a/Modules/main.c b/Modules/main.c
index dd50211..475a2fd 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -53,7 +53,7 @@
Options and arguments (and corresponding environment variables):\n\
-b : issue warnings about str(bytes_instance), str(bytearray_instance)\n\
and comparing bytes/bytearray with str. (-bb: issue errors)\n\
--B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x\n\
+-B : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x\n\
-c cmd : program passed in as string (terminates option list)\n\
-d : debug output from parser; also PYTHONDEBUG=x\n\
-E : ignore PYTHON* environment variables (such as PYTHONPATH)\n\
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 8f8ba25..2ea5e2d 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -1932,11 +1932,13 @@
return NULL;
PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode));
-#ifdef HAVE_LARGEFILE_SUPPORT
+#if defined(HAVE_LARGEFILE_SUPPORT) || defined(MS_WINDOWS)
+ Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(st->st_ino));
PyStructSequence_SET_ITEM(v, 1,
- PyLong_FromLongLong((long long)st->st_ino));
+ PyLong_FromUnsignedLongLong(st->st_ino));
#else
- PyStructSequence_SET_ITEM(v, 1, PyLong_FromLong((long)st->st_ino));
+ Py_BUILD_ASSERT(sizeof(unsigned long) >= sizeof(st->st_ino));
+ PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLong(st->st_ino));
#endif
#ifdef MS_WINDOWS
PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLong(st->st_dev));
@@ -11156,7 +11158,7 @@
PyObject *lstat;
#ifdef MS_WINDOWS
struct _Py_stat_struct win32_lstat;
- __int64 win32_file_index;
+ uint64_t win32_file_index;
int got_file_index;
#else /* POSIX */
#ifdef HAVE_DIRENT_D_TYPE
@@ -11419,7 +11421,8 @@
self->win32_file_index = stat.st_ino;
self->got_file_index = 1;
}
- return PyLong_FromLongLong((long long)self->win32_file_index);
+ Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(self->win32_file_index));
+ return PyLong_FromUnsignedLongLong(self->win32_file_index);
#else /* POSIX */
#ifdef HAVE_LARGEFILE_SUPPORT
return PyLong_FromLongLong((long long)self->d_ino);
diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c
index b3259d5..47f70a2 100644
--- a/Modules/pyexpat.c
+++ b/Modules/pyexpat.c
@@ -1191,7 +1191,7 @@
Py_DECREF(self);
return NULL;
}
-#if ((XML_MAJOR_VERSION >= 2) && (XML_MINOR_VERSION >= 1)) || defined(XML_HAS_SET_HASH_SALT)
+#if XML_COMBINED_VERSION >= 20100 || defined(XML_HAS_SET_HASH_SALT)
/* This feature was added upstream in libexpat 2.1.0. Our expat copy
* has a backport of this feature where we also define XML_HAS_SET_HASH_SALT
* to indicate that we can still use it. */
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index f4edc06..f3654c9 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -288,36 +288,6 @@
#include <net/if.h>
#endif
-#ifdef HAVE_SOCKADDR_ALG
-#include <linux/if_alg.h>
-#ifndef AF_ALG
-#define AF_ALG 38
-#endif
-#ifndef SOL_ALG
-#define SOL_ALG 279
-#endif
-
-/* Linux 3.19 */
-#ifndef ALG_SET_AEAD_ASSOCLEN
-#define ALG_SET_AEAD_ASSOCLEN 4
-#endif
-#ifndef ALG_SET_AEAD_AUTHSIZE
-#define ALG_SET_AEAD_AUTHSIZE 5
-#endif
-/* Linux 4.8 */
-#ifndef ALG_SET_PUBKEY
-#define ALG_SET_PUBKEY 6
-#endif
-
-#ifndef ALG_OP_SIGN
-#define ALG_OP_SIGN 2
-#endif
-#ifndef ALG_OP_VERIFY
-#define ALG_OP_VERIFY 3
-#endif
-
-#endif /* HAVE_SOCKADDR_ALG */
-
/* Generic socket object definitions and includes */
#define PySocket_BUILDING_SOCKET
#include "socketmodule.h"
diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h
index 3cce927..03f982b 100644
--- a/Modules/socketmodule.h
+++ b/Modules/socketmodule.h
@@ -98,6 +98,37 @@
#include <sys/kern_control.h>
#endif
+#ifdef HAVE_SOCKADDR_ALG
+#include <linux/if_alg.h>
+#ifndef AF_ALG
+#define AF_ALG 38
+#endif
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif
+
+/* Linux 3.19 */
+#ifndef ALG_SET_AEAD_ASSOCLEN
+#define ALG_SET_AEAD_ASSOCLEN 4
+#endif
+#ifndef ALG_SET_AEAD_AUTHSIZE
+#define ALG_SET_AEAD_AUTHSIZE 5
+#endif
+/* Linux 4.8 */
+#ifndef ALG_SET_PUBKEY
+#define ALG_SET_PUBKEY 6
+#endif
+
+#ifndef ALG_OP_SIGN
+#define ALG_OP_SIGN 2
+#endif
+#ifndef ALG_OP_VERIFY
+#define ALG_OP_VERIFY 3
+#endif
+
+#endif /* HAVE_SOCKADDR_ALG */
+
+
#ifndef Py__SOCKET_H
#define Py__SOCKET_H
#ifdef __cplusplus
@@ -159,6 +190,9 @@
#ifdef HAVE_SYS_KERN_CONTROL_H
struct sockaddr_ctl ctl;
#endif
+#ifdef HAVE_SOCKADDR_ALG
+ struct sockaddr_alg alg;
+#endif
} sock_addr_t;
/* The object holding a socket. It holds some extra information,
diff --git a/Modules/zipimport.c b/Modules/zipimport.c
index 59046aa..cccc033 100644
--- a/Modules/zipimport.c
+++ b/Modules/zipimport.c
@@ -1102,7 +1102,7 @@
_Py_IDENTIFIER(decompress);
if (importing_zlib != 0)
- /* Someone has a zlib.py[co] in their Zip file;
+ /* Someone has a zlib.pyc in their Zip file;
let's avoid a stack overflow. */
return NULL;
importing_zlib = 1;
@@ -1261,7 +1261,7 @@
return d <= 1;
}
-/* Given the contents of a .py[co] file in a buffer, unmarshal the data
+/* Given the contents of a .pyc file in a buffer, unmarshal the data
and return the code object. Return None if it the magic word doesn't
match (we do this instead of raising an exception as we fall back
to .py if available and we don't want to mask other errors).
@@ -1403,7 +1403,7 @@
PyObject *toc_entry, *stripped;
time_t mtime;
- /* strip 'c' or 'o' from *.py[co] */
+ /* strip 'c' from *.pyc */
if (PyUnicode_READY(path) == -1)
return (time_t)-1;
stripped = PyUnicode_FromKindAndData(PyUnicode_KIND(path),
diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c
index a8d6980..d456678 100644
--- a/Objects/bytearrayobject.c
+++ b/Objects/bytearrayobject.c
@@ -254,7 +254,7 @@
if (PyObject_GetBuffer(a, &va, PyBUF_SIMPLE) != 0 ||
PyObject_GetBuffer(b, &vb, PyBUF_SIMPLE) != 0) {
PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s",
- Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name);
+ Py_TYPE(b)->tp_name, Py_TYPE(a)->tp_name);
goto done;
}
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index 5d48440..c95a46d 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -528,6 +528,8 @@
return 0;
}
+static PyObject *_PyBytes_FromBuffer(PyObject *x);
+
static PyObject *
format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen)
{
@@ -564,8 +566,19 @@
*plen = PyBytes_GET_SIZE(result);
return result;
}
+ /* does it support buffer protocol? */
+ if (PyObject_CheckBuffer(v)) {
+ /* maybe we can avoid making a copy of the buffer object here? */
+ result = _PyBytes_FromBuffer(v);
+ if (result == NULL)
+ return NULL;
+ *pbuf = PyBytes_AS_STRING(result);
+ *plen = PyBytes_GET_SIZE(result);
+ return result;
+ }
PyErr_Format(PyExc_TypeError,
- "%%b requires bytes, or an object that implements __bytes__, not '%.100s'",
+ "%%b requires a bytes-like object, "
+ "or an object that implements __bytes__, not '%.100s'",
Py_TYPE(v)->tp_name);
return NULL;
}
@@ -619,11 +632,11 @@
Py_ssize_t len;
char *pos;
- pos = strchr(fmt + 1, '%');
+ pos = (char *)memchr(fmt + 1, '%', fmtcnt);
if (pos != NULL)
len = pos - fmt;
else
- len = format_len - (fmt - format);
+ len = fmtcnt + 1;
assert(len != 0);
memcpy(res, fmt, len);
@@ -1425,7 +1438,7 @@
if (PyObject_GetBuffer(a, &va, PyBUF_SIMPLE) != 0 ||
PyObject_GetBuffer(b, &vb, PyBUF_SIMPLE) != 0) {
PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s",
- Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name);
+ Py_TYPE(b)->tp_name, Py_TYPE(a)->tp_name);
goto done;
}
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 2680ab0..1c29e29 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -575,8 +575,7 @@
PyObject *e;
if (value == NULL ||
- (!PyTuple_Check(value) &&
- !PyObject_TypeCheck(value, (PyTypeObject *) PyExc_StopIteration)))
+ (!PyTuple_Check(value) && !PyExceptionInstance_Check(value)))
{
/* Delay exception instantiation if we can */
PyErr_SetObject(PyExc_StopIteration, value);
diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c
index 8449fc7..8f5fc43 100644
--- a/Objects/rangeobject.c
+++ b/Objects/rangeobject.c
@@ -668,6 +668,16 @@
(objobjargproc)0, /* mp_ass_subscript */
};
+static int
+range_bool(rangeobject* self)
+{
+ return PyObject_IsTrue(self->length);
+}
+
+static PyNumberMethods range_as_number = {
+ .nb_bool = (inquiry)range_bool,
+};
+
static PyObject * range_iter(PyObject *seq);
static PyObject * range_reverse(PyObject *seq);
@@ -707,7 +717,7 @@
0, /* tp_setattr */
0, /* tp_reserved */
(reprfunc)range_repr, /* tp_repr */
- 0, /* tp_as_number */
+ &range_as_number, /* tp_as_number */
&range_as_sequence, /* tp_as_sequence */
&range_as_mapping, /* tp_as_mapping */
(hashfunc)range_hash, /* tp_hash */
diff --git a/PC/getpathp.c b/PC/getpathp.c
index 1eeebfe..e7be704 100644
--- a/PC/getpathp.c
+++ b/PC/getpathp.c
@@ -185,7 +185,7 @@
may extend 'filename' by one character.
*/
static int
-ismodule(wchar_t *filename, int update_filename) /* Is module -- check for .pyc/.pyo too */
+ismodule(wchar_t *filename, int update_filename) /* Is module -- check for .pyc too */
{
size_t n;
@@ -196,7 +196,7 @@
n = wcsnlen_s(filename, MAXPATHLEN+1);
if (n < MAXPATHLEN) {
int exist = 0;
- filename[n] = Py_OptimizeFlag ? L'o' : L'c';
+ filename[n] = L'c';
filename[n + 1] = L'\0';
exist = exists(filename);
if (!update_filename)
diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat
index 98a755d8..3a2656e 100644
--- a/PCbuild/get_externals.bat
+++ b/PCbuild/get_externals.bat
@@ -66,7 +66,7 @@
echo.%%e already exists, skipping.
) else (
echo.Fetching %%e...
- svn export %SVNROOT%%%e
+ svn export -q %SVNROOT%%%e
)
)
diff --git a/PCbuild/rmpyc.py b/PCbuild/rmpyc.py
index a1e75bb..0b58f68 100644
--- a/PCbuild/rmpyc.py
+++ b/PCbuild/rmpyc.py
@@ -1,25 +1,19 @@
-# Remove all the .pyc and .pyo files under ../Lib.
+# Remove all the .pyc files under ../Lib.
def deltree(root):
import os
from os.path import join
- npyc = npyo = 0
+ npyc = 0
for root, dirs, files in os.walk(root):
for name in files:
- delete = False
- if name.endswith('.pyc'):
- delete = True
+ # to be thorough
+ if name.endswith(('.pyc', '.pyo')):
npyc += 1
- elif name.endswith('.pyo'):
- delete = True
- npyo += 1
-
- if delete:
os.remove(join(root, name))
- return npyc, npyo
+ return npyc
-npyc, npyo = deltree("../Lib")
-print(npyc, ".pyc deleted,", npyo, ".pyo deleted")
+npyc = deltree("../Lib")
+print(npyc, ".pyc deleted")
diff --git a/PCbuild/rt.bat b/PCbuild/rt.bat
index 3582672..e73ac04 100644
--- a/PCbuild/rt.bat
+++ b/PCbuild/rt.bat
@@ -4,8 +4,8 @@
rem -d Run Debug build (python_d.exe). Else release build.
rem -O Run python.exe or python_d.exe (see -d) with -O.
rem -q "quick" -- normally the tests are run twice, the first time
-rem after deleting all the .py[co] files reachable from Lib/.
-rem -q runs the tests just once, and without deleting .py[co] files.
+rem after deleting all the .pyc files reachable from Lib/.
+rem -q runs the tests just once, and without deleting .pyc files.
rem -x64 Run the 64-bit build of python (or python_d if -d was specified)
rem from the 'amd64' dir instead of the 32-bit build in this dir.
rem All leading instances of these switches are shifted off, and
@@ -45,7 +45,7 @@
set cmd="%exe%" %dashO% -Wd -E -bb -m test %regrtestargs%
if defined qmode goto Qmode
-echo Deleting .pyc/.pyo files ...
+echo Deleting .pyc files ...
"%exe%" "%pcbuild%rmpyc.py"
echo Cleaning _pth files ...
@@ -55,7 +55,7 @@
%cmd%
@echo off
-echo About to run again without deleting .pyc/.pyo first:
+echo About to run again without deleting .pyc first:
pause
:Qmode
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index ef5a34c..597e26e 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -1927,12 +1927,15 @@
PyObject *result;
size_t len;
+ /* stdin is a text stream, so it must have an encoding. */
stdin_encoding = _PyObject_GetAttrId(fin, &PyId_encoding);
stdin_errors = _PyObject_GetAttrId(fin, &PyId_errors);
- if (!stdin_encoding || !stdin_errors)
- /* stdin is a text stream, so it must have an
- encoding. */
+ if (!stdin_encoding || !stdin_errors ||
+ !PyUnicode_Check(stdin_encoding) ||
+ !PyUnicode_Check(stdin_errors)) {
+ tty = 0;
goto _readline_errors;
+ }
stdin_encoding_str = PyUnicode_AsUTF8(stdin_encoding);
stdin_errors_str = PyUnicode_AsUTF8(stdin_errors);
if (!stdin_encoding_str || !stdin_errors_str)
@@ -1948,8 +1951,12 @@
PyObject *stringpo;
stdout_encoding = _PyObject_GetAttrId(fout, &PyId_encoding);
stdout_errors = _PyObject_GetAttrId(fout, &PyId_errors);
- if (!stdout_encoding || !stdout_errors)
+ if (!stdout_encoding || !stdout_errors ||
+ !PyUnicode_Check(stdout_encoding) ||
+ !PyUnicode_Check(stdout_errors)) {
+ tty = 0;
goto _readline_errors;
+ }
stdout_encoding_str = PyUnicode_AsUTF8(stdout_encoding);
stdout_errors_str = PyUnicode_AsUTF8(stdout_errors);
if (!stdout_encoding_str || !stdout_errors_str)
@@ -2003,13 +2010,17 @@
Py_XDECREF(po);
PyMem_FREE(s);
return result;
+
_readline_errors:
Py_XDECREF(stdin_encoding);
Py_XDECREF(stdout_encoding);
Py_XDECREF(stdin_errors);
Py_XDECREF(stdout_errors);
Py_XDECREF(po);
- return NULL;
+ if (tty)
+ return NULL;
+
+ PyErr_Clear();
}
/* Fallback if we're not interactive */
diff --git a/Python/fileutils.c b/Python/fileutils.c
index e84d66e..f3764e4 100644
--- a/Python/fileutils.c
+++ b/Python/fileutils.c
@@ -583,7 +583,7 @@
FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec);
FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec);
result->st_nlink = info->nNumberOfLinks;
- result->st_ino = (((__int64)info->nFileIndexHigh)<<32) + info->nFileIndexLow;
+ result->st_ino = (((uint64_t)info->nFileIndexHigh) << 32) + info->nFileIndexLow;
if (reparse_tag == IO_REPARSE_TAG_SYMLINK) {
/* first clear the S_IFMT bits */
result->st_mode ^= (result->st_mode & S_IFMT);
@@ -653,7 +653,7 @@
_Py_attribute_data_to_stat(&info, 0, status);
/* specific to fstat() */
- status->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow;
+ status->st_ino = (((uint64_t)info.nFileIndexHigh) << 32) + info.nFileIndexLow;
return 0;
#else
return fstat(fd, status);
diff --git a/Python/marshal.c b/Python/marshal.c
index 87a4b24..7b12ab7 100644
--- a/Python/marshal.c
+++ b/Python/marshal.c
@@ -549,7 +549,7 @@
w_object(co->co_lnotab, p);
}
else if (PyObject_CheckBuffer(v)) {
- /* Write unknown bytes-like objects as a byte string */
+ /* Write unknown bytes-like objects as a bytes object */
Py_buffer view;
if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) != 0) {
w_byte(TYPE_UNKNOWN, p);
@@ -1086,7 +1086,7 @@
if (PyErr_Occurred())
break;
if (n < 0 || n > SIZE32_MAX) {
- PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)");
+ PyErr_SetString(PyExc_ValueError, "bad marshal data (bytes object size out of range)");
break;
}
v = PyBytes_FromStringAndSize((char *)NULL, n);
@@ -1110,7 +1110,7 @@
if (PyErr_Occurred())
break;
if (n < 0 || n > SIZE32_MAX) {
- PyErr_SetString(PyExc_ValueError, "bad marshal data (unicode size out of range)");
+ PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)");
break;
}
goto _read_ascii;
@@ -1150,7 +1150,7 @@
if (PyErr_Occurred())
break;
if (n < 0 || n > SIZE32_MAX) {
- PyErr_SetString(PyExc_ValueError, "bad marshal data (unicode size out of range)");
+ PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)");
break;
}
if (n != 0) {
@@ -1612,7 +1612,7 @@
if (wf.ptr - base > PY_SSIZE_T_MAX) {
Py_DECREF(wf.str);
PyErr_SetString(PyExc_OverflowError,
- "too much marshal data for a string");
+ "too much marshal data for a bytes object");
return NULL;
}
if (_PyBytes_Resize(&wf.str, (Py_ssize_t)(wf.ptr - base)) < 0)
@@ -1658,8 +1658,7 @@
"dump(value, file[, version])\n\
\n\
Write the value on the open file. The value must be a supported type.\n\
-The file must be an open file object such as sys.stdout or returned by\n\
-open() or os.popen(). It must be opened in binary mode ('wb' or 'w+b').\n\
+The file must be a writeable binary file.\n\
\n\
If the value has (or contains an object that has) an unsupported type, a\n\
ValueError exception is raised - but garbage data will also be written\n\
@@ -1715,8 +1714,7 @@
Read one value from the open file and return it. If no valid value is\n\
read (e.g. because the data has a different Python version's\n\
incompatible marshal format), raise EOFError, ValueError or TypeError.\n\
-The file must be an open file object opened in binary mode ('rb' or\n\
-'r+b').\n\
+The file must be a readable binary file.\n\
\n\
Note: If an object containing an unsupported type was marshalled with\n\
dump(), load() will substitute None for the unmarshallable type.");
@@ -1735,7 +1733,7 @@
PyDoc_STRVAR(dumps_doc,
"dumps(value[, version])\n\
\n\
-Return the string that would be written to a file by dump(value, file).\n\
+Return the bytes object that would be written to a file by dump(value, file).\n\
The value must be a supported type. Raise a ValueError exception if\n\
value has (or contains an object that has) an unsupported type.\n\
\n\
@@ -1771,8 +1769,8 @@
PyDoc_STRVAR(loads_doc,
"loads(bytes)\n\
\n\
-Convert the bytes object to a value. If no valid value is found, raise\n\
-EOFError, ValueError or TypeError. Extra characters in the input are\n\
+Convert the bytes-like object to a value. If no valid value is found,\n\
+raise EOFError, ValueError or TypeError. Extra bytes in the input are\n\
ignored.");
static PyMethodDef marshal_methods[] = {
@@ -1810,8 +1808,8 @@
\n\
dump() -- write value to a file\n\
load() -- read value from a file\n\
-dumps() -- write value to a string\n\
-loads() -- read value from a string");
+dumps() -- marshal value as a bytes object\n\
+loads() -- read value from a bytes-like object");
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index a4f7f82..af96d6d 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -88,7 +88,7 @@
int Py_UseClassExceptionsFlag = 1; /* Needed by bltinmodule.c: deprecated */
int Py_FrozenFlag; /* Needed by getpath.c */
int Py_IgnoreEnvironmentFlag; /* e.g. PYTHONPATH, PYTHONHOME */
-int Py_DontWriteBytecodeFlag; /* Suppress writing bytecode files (*.py[co]) */
+int Py_DontWriteBytecodeFlag; /* Suppress writing bytecode files (*.pyc) */
int Py_NoUserSiteDirectory = 0; /* for -s and site.py */
int Py_UnbufferedStdioFlag = 0; /* Unbuffered binary std{in,out,err} */
int Py_HashRandomizationFlag = 0; /* for -R and PYTHONHASHSEED */
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h
index 27e0dc8..ba7393f 100644
--- a/Python/thread_pthread.h
+++ b/Python/thread_pthread.h
@@ -143,6 +143,8 @@
} pthread_lock;
#define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1; }
+#define CHECK_STATUS_PTHREAD(name) if (status != 0) { fprintf(stderr, \
+ "%s: %s\n", name, strerror(status)); error = 1; }
/*
* Initialization.
@@ -417,7 +419,7 @@
status = pthread_mutex_init(&lock->mut,
pthread_mutexattr_default);
- CHECK_STATUS("pthread_mutex_init");
+ CHECK_STATUS_PTHREAD("pthread_mutex_init");
/* Mark the pthread mutex underlying a Python mutex as
pure happens-before. We can't simply mark the
Python-level mutex as a mutex because it can be
@@ -427,7 +429,7 @@
status = pthread_cond_init(&lock->lock_released,
pthread_condattr_default);
- CHECK_STATUS("pthread_cond_init");
+ CHECK_STATUS_PTHREAD("pthread_cond_init");
if (error) {
PyMem_RawFree((void *)lock);
@@ -452,10 +454,10 @@
* and must have the cond destroyed first.
*/
status = pthread_cond_destroy( &thelock->lock_released );
- CHECK_STATUS("pthread_cond_destroy");
+ CHECK_STATUS_PTHREAD("pthread_cond_destroy");
status = pthread_mutex_destroy( &thelock->mut );
- CHECK_STATUS("pthread_mutex_destroy");
+ CHECK_STATUS_PTHREAD("pthread_mutex_destroy");
PyMem_RawFree((void *)thelock);
}
@@ -472,7 +474,7 @@
lock, microseconds, intr_flag));
status = pthread_mutex_lock( &thelock->mut );
- CHECK_STATUS("pthread_mutex_lock[1]");
+ CHECK_STATUS_PTHREAD("pthread_mutex_lock[1]");
if (thelock->locked == 0) {
success = PY_LOCK_ACQUIRED;
@@ -494,13 +496,13 @@
&thelock->mut, &ts);
if (status == ETIMEDOUT)
break;
- CHECK_STATUS("pthread_cond_timed_wait");
+ CHECK_STATUS_PTHREAD("pthread_cond_timed_wait");
}
else {
status = pthread_cond_wait(
&thelock->lock_released,
&thelock->mut);
- CHECK_STATUS("pthread_cond_wait");
+ CHECK_STATUS_PTHREAD("pthread_cond_wait");
}
if (intr_flag && status == 0 && thelock->locked) {
@@ -518,7 +520,7 @@
}
if (success == PY_LOCK_ACQUIRED) thelock->locked = 1;
status = pthread_mutex_unlock( &thelock->mut );
- CHECK_STATUS("pthread_mutex_unlock[1]");
+ CHECK_STATUS_PTHREAD("pthread_mutex_unlock[1]");
if (error) success = PY_LOCK_FAILURE;
dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n",
@@ -536,16 +538,16 @@
dprintf(("PyThread_release_lock(%p) called\n", lock));
status = pthread_mutex_lock( &thelock->mut );
- CHECK_STATUS("pthread_mutex_lock[3]");
+ CHECK_STATUS_PTHREAD("pthread_mutex_lock[3]");
thelock->locked = 0;
/* wake up someone (anyone, if any) waiting on the lock */
status = pthread_cond_signal( &thelock->lock_released );
- CHECK_STATUS("pthread_cond_signal");
+ CHECK_STATUS_PTHREAD("pthread_cond_signal");
status = pthread_mutex_unlock( &thelock->mut );
- CHECK_STATUS("pthread_mutex_unlock[3]");
+ CHECK_STATUS_PTHREAD("pthread_mutex_unlock[3]");
}
#endif /* USE_SEMAPHORES */
diff --git a/README.rst b/README.rst
index 9ea0360..b0ce135 100644
--- a/README.rst
+++ b/README.rst
@@ -1,10 +1,14 @@
-This is Python version 3.6.1
-============================
+This is Python version 3.6.1+
+=============================
.. image:: https://travis-ci.org/python/cpython.svg?branch=3.6
:alt: CPython build status on Travis CI
:target: https://travis-ci.org/python/cpython
+.. image:: https://ci.appveyor.com/api/projects/status/4mew1a93xdkbf5ua/branch/3.6?svg=true
+ :alt: CPython build status on Appveyor
+ :target: https://ci.appveyor.com/project/python/cpython/branch/3.6
+
.. image:: https://codecov.io/gh/python/cpython/branch/3.6/graph/badge.svg
:alt: CPython code coverage on Codecov
:target: https://codecov.io/gh/python/cpython
diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py
index cc1afbe..d28851f 100755
--- a/Tools/gdb/libpython.py
+++ b/Tools/gdb/libpython.py
@@ -714,7 +714,7 @@
try:
# <= Python 3.5
return keys['dk_entries'], dk_size
- except gdb.error:
+ except RuntimeError:
# >= Python 3.6
pass
diff --git a/Tools/scripts/patchcheck.py b/Tools/scripts/patchcheck.py
index 58b081a..f4ec7d8 100755
--- a/Tools/scripts/patchcheck.py
+++ b/Tools/scripts/patchcheck.py
@@ -12,7 +12,6 @@
SRCDIR = sysconfig.get_config_var('srcdir')
-
def n_files_str(count):
"""Return 'N file(s)' with the proper plurality on 'file'."""
return "{} file{}".format(count, "s" if count != 1 else "")
@@ -46,27 +45,76 @@
return st.returncode == 0 and bstdout
+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)
+ except subprocess.CalledProcessError:
+ return None
+
+
+def get_git_upstream_remote():
+ """Get the remote name to use for upstream branches
+
+ Uses "upstream" if it exists, "origin" otherwise
+ """
+ cmd = "git remote get-url upstream".split()
+ try:
+ subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
+ except subprocess.CalledProcessError:
+ return "origin"
+ return "upstream"
+
+
+@status("Getting base branch for PR",
+ info=lambda x: x if x is not None else "not a PR branch")
+def get_base_branch():
+ if not os.path.isdir(os.path.join(SRCDIR, '.git')):
+ # Not a git checkout, so there's no base branch
+ return None
+ version = sys.version_info
+ if version.releaselevel == 'alpha':
+ base_branch = "master"
+ else:
+ base_branch = "{0.major}.{0.minor}".format(version)
+ this_branch = get_git_branch()
+ if this_branch is None or this_branch == base_branch:
+ # Not on a git PR branch, so there's no base branch
+ return None
+ upstream_remote = get_git_upstream_remote()
+ return upstream_remote + "/" + base_branch
+
+
@status("Getting the list of files that have been added/changed",
info=lambda x: n_files_str(len(x)))
-def changed_files():
+def changed_files(base_branch=None):
"""Get the list of changed or added files from Mercurial or git."""
if os.path.isdir(os.path.join(SRCDIR, '.hg')):
+ if base_branch is not None:
+ sys.exit('need a git checkout to check PR status')
cmd = 'hg status --added --modified --no-status'
if mq_patches_applied():
cmd += ' --rev qparent'
with subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) as st:
return [x.decode().rstrip() for x in st.stdout]
- elif os.path.isdir(os.path.join(SRCDIR, '.git')):
- cmd = 'git status --porcelain'
+ elif os.path.exists(os.path.join(SRCDIR, '.git')):
+ # We just use an existence check here as:
+ # directory = normal git checkout/clone
+ # file = git worktree directory
+ if base_branch:
+ cmd = 'git diff --name-status ' + base_branch
+ else:
+ cmd = 'git status --porcelain'
filenames = []
with subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) as st:
for line in st.stdout:
line = line.decode().rstrip()
- status = set(line[:2])
+ status_text, filename = line.split(maxsplit=1)
+ status = set(status_text)
# modified, added or unmerged files
if not status.intersection('MAU'):
continue
- filename = line[3:]
if ' -> ' in filename:
# file is renamed
filename = filename.split(' -> ', 2)[1].strip()
@@ -165,7 +213,8 @@
return "not needed"
def main():
- file_paths = changed_files()
+ base_branch = get_base_branch()
+ file_paths = changed_files(base_branch)
python_files = [fn for fn in file_paths if fn.endswith('.py')]
c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))]
doc_files = [fn for fn in file_paths if fn.startswith('Doc') and