inputs:
versionSpec: '>=3.6'
-- script: python -m pip install sphinx~=1.6.1 blurb python-docs-theme
+- script: python -m pip install sphinx==1.8.2 blurb python-docs-theme
displayName: 'Install build dependencies'
- ${{ if ne(parameters.latex, 'true') }}:
--- /dev/null
+jobs:
+- job: Prebuild
+ displayName: Pre-build checks
+
+ pool:
+ vmImage: ubuntu-16.04
+
+ steps:
+ - template: ./prebuild-checks.yml
+
+
+- job: Windows_Appx_Tests
+ displayName: Windows Appx Tests
+ dependsOn: Prebuild
+ condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true'))
+
+ pool:
+ vmImage: vs2017-win2016
+
+ strategy:
+ matrix:
+ win64:
+ arch: amd64
+ buildOpt: '-p x64'
+ testRunTitle: '$(Build.SourceBranchName)-win64-appx'
+ testRunPlatform: win64
+ maxParallel: 2
+
+ steps:
+ - checkout: self
+ clean: true
+ fetchDepth: 5
+
+ - powershell: |
+ # Relocate build outputs outside of source directory to make cleaning faster
+ Write-Host '##vso[task.setvariable variable=Py_IntDir]$(Build.BinariesDirectory)\obj'
+ # UNDONE: Do not build to a different directory because of broken tests
+ Write-Host '##vso[task.setvariable variable=Py_OutDir]$(Build.SourcesDirectory)\PCbuild'
+ Write-Host '##vso[task.setvariable variable=EXTERNAL_DIR]$(Build.BinariesDirectory)\externals'
+ displayName: Update build locations
+
+ - script: PCbuild\build.bat -e $(buildOpt)
+ displayName: 'Build CPython'
+ env:
+ IncludeUwp: true
+
+ - script: python.bat PC\layout -vv -s "$(Build.SourcesDirectory)" -b "$(Py_OutDir)\$(arch)" -t "$(Py_IntDir)\layout-tmp-$(arch)" --copy "$(Py_IntDir)\layout-$(arch)" --precompile --preset-appx --include-tests
+ displayName: 'Create APPX layout'
+
+ - script: .\python.exe -m test.pythoninfo
+ workingDirectory: $(Py_IntDir)\layout-$(arch)
+ displayName: 'Display build info'
+
+ - script: .\python.exe -m test -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 --junit-xml="$(Build.BinariesDirectory)\test-results.xml" --tempdir "$(Py_IntDir)\tmp-$(arch)"
+ workingDirectory: $(Py_IntDir)\layout-$(arch)
+ displayName: 'Tests'
+ env:
+ PREFIX: $(Py_IntDir)\layout-$(arch)
+
+ - task: PublishTestResults@2
+ displayName: 'Publish Test Results'
+ inputs:
+ testResultsFiles: '$(Build.BinariesDirectory)\test-results.xml'
+ mergeTestResults: true
+ testRunTitle: $(testRunTitle)
+ platform: $(testRunPlatform)
+ condition: succeededOrFailed()
- script: PCbuild\build.bat -e $(buildOpt)
displayName: 'Build CPython'
+ env:
+ IncludeUwp: true
- script: python.bat -m test.pythoninfo
displayName: 'Display build info'
-- script: PCbuild\rt.bat -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 --junit-xml="$(Build.BinariesDirectory)\test-results.xml"
+- script: PCbuild\rt.bat -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 --junit-xml="$(Build.BinariesDirectory)\test-results.xml" --tempdir="$(Build.BinariesDirectory)\test"
displayName: 'Tests'
env:
PREFIX: $(Py_OutDir)\$(arch)
indicates that no de-referencing should occur (striding in a contiguous
memory block).
- If all suboffsets are negative (i.e. no de-referencing is needed, then
+ If all suboffsets are negative (i.e. no de-referencing is needed), then
this field must be NULL (the default value).
This type of array representation is used by the Python Imaging Library
The conversion is independent of the current locale.
If ``endptr`` is ``NULL``, convert the whole string. Raise
- ValueError and return ``-1.0`` if the string is not a valid
+ :exc:`ValueError` and return ``-1.0`` if the string is not a valid
representation of a floating-point number.
If endptr is not ``NULL``, convert as much of the string as
then it constructs a tuple object whose first item is the *ierr* value and whose
second item is the corresponding error message (gotten from
:c:func:`FormatMessage`), and then calls ``PyErr_SetObject(PyExc_WindowsError,
- object)``. This function always returns *NULL*. Availability: Windows.
+ object)``. This function always returns *NULL*.
+
+ .. availability:: Windows.
.. c:function:: PyObject* PyErr_SetExcFromWindowsErr(PyObject *type, int ierr)
Similar to :c:func:`PyErr_SetFromWindowsErr`, with an additional parameter
- specifying the exception type to be raised. Availability: Windows.
+ specifying the exception type to be raised.
+
+ .. availability:: Windows.
.. c:function:: PyObject* PyErr_SetFromWindowsErrWithFilename(int ierr, const char *filename)
Similar to :c:func:`PyErr_SetFromWindowsErrWithFilenameObject`, but the
filename is given as a C string. *filename* is decoded from the filesystem
- encoding (:func:`os.fsdecode`). Availability: Windows.
+ encoding (:func:`os.fsdecode`).
+
+ .. availability:: Windows.
.. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilenameObject(PyObject *type, int ierr, PyObject *filename)
Similar to :c:func:`PyErr_SetFromWindowsErrWithFilenameObject`, with an
additional parameter specifying the exception type to be raised.
- Availability: Windows.
+
+ .. availability:: Windows.
.. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilenameObjects(PyObject *type, int ierr, PyObject *filename, PyObject *filename2)
Similar to :c:func:`PyErr_SetExcFromWindowsErrWithFilenameObject`,
but accepts a second filename object.
- Availability: Windows.
+
+ .. availability:: Windows.
.. versionadded:: 3.4
.. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilename(PyObject *type, int ierr, const char *filename)
Similar to :c:func:`PyErr_SetFromWindowsErrWithFilename`, with an additional
- parameter specifying the exception type to be raised. Availability: Windows.
+ parameter specifying the exception type to be raised.
+
+ .. availability:: Windows.
.. c:function:: PyObject* PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path)
A macro version of :c:func:`PyObject_GC_Track`. It should not be used for
extension modules.
+ .. deprecated:: 3.6
+ This macro is removed from Python 3.8.
+
Similarly, the deallocator for the object must conform to a similar pair of
rules:
A macro version of :c:func:`PyObject_GC_UnTrack`. It should not be used for
extension modules.
+ .. deprecated:: 3.6
+ This macro is removed from Python 3.8.
+
The :c:member:`~PyTypeObject.tp_traverse` handler accepts a function parameter of this type:
See :pep:`529` for more details.
- Availability: Windows.
+ .. availability:: Windows.
.. c:var:: Py_LegacyWindowsStdioFlag
See :pep:`528` for more details.
- Availability: Windows.
+ .. availability:: Windows.
.. c:var:: Py_NoSiteFlag
Release build ``"pymalloc"`` ``malloc`` ``pymalloc`` ``pymalloc``
Debug build ``"pymalloc_debug"`` ``malloc`` + debug ``pymalloc`` + debug ``pymalloc`` + debug
Release build, without pymalloc ``"malloc"`` ``malloc`` ``malloc`` ``malloc``
-Release build, without pymalloc ``"malloc_debug"`` ``malloc`` + debug ``malloc`` + debug ``malloc`` + debug
+Debug build, without pymalloc ``"malloc_debug"`` ``malloc`` + debug ``malloc`` + debug ``malloc`` + debug
=============================== ==================== ================== ===================== ====================
Legend:
:attr:`flags` can be ``0`` for write and read access or :c:macro:`READONLY` for
read-only access. Using :c:macro:`T_STRING` for :attr:`type` implies
- :c:macro:`READONLY`. Only :c:macro:`T_OBJECT` and :c:macro:`T_OBJECT_EX`
+ :c:macro:`READONLY`. :c:macro:`T_STRING` data is interpreted as UTF-8.
+ Only :c:macro:`T_OBJECT` and :c:macro:`T_OBJECT_EX`
members can be deleted. (They are set to *NULL*).
Clear the internal lookup cache. Return the current version tag.
-.. c:function:: long PyType_GetFlags(PyTypeObject* type)
+.. c:function:: unsigned long PyType_GetFlags(PyTypeObject* type)
Return the :c:member:`~PyTypeObject.tp_flags` member of *type*. This function is primarily
meant for use with `Py_LIMITED_API`; the individual flag bits are
.. versionadded:: 3.2
+ .. versionchanged:: 3.4
+ The return type is now ``unsigned long`` rather than ``long``.
+
.. c:function:: void PyType_Modified(PyTypeObject *type)
Evaluate a precompiled code object, given a particular environment for its
evaluation. This environment consists of a dictionary of global variables,
a mapping object of local variables, arrays of arguments, keywords and
- defaults, a dictionary of default values for :ref:`keyword-only\
+ defaults, a dictionary of default values for :ref:`keyword-only
<keyword-only_parameter>` arguments and a closure tuple of cells.
# By default, highlight as Python 3.
highlight_language = 'python3'
-# Require Sphinx 1.2 for build.
-needs_sphinx = '1.2'
+# Require Sphinx 1.6.6 for build.
+needs_sphinx = "1.6.6"
# Ignore any .rst files in the venv/ directory.
venvdir = os.getenv('VENVDIR', 'venv')
exclude_patterns = [venvdir+'/*', 'README.rst']
+# Disable Docutils smartquotes for several translations
+smartquotes_excludes = {
+ 'languages': ['ja', 'fr', 'zh_TW', 'zh_CN'], 'builders': ['man', 'text'],
+}
+
# Options for HTML output
# -----------------------
| *sources* | list of source filenames, | a list of strings |
| | relative to the distribution | |
| | root (where the setup script | |
- | | lives), in Unix form (slash- | |
- | | separated) for portability. | |
+ | | lives), in Unix form | |
+ | | (slash-separated) for | |
+ | | portability. | |
| | Source files may be C, C++, | |
| | SWIG (.i), platform-specific | |
| | resource files, or whatever | |
.. function:: newer_group(sources, target[, missing='error'])
Return true if *target* is out-of-date with respect to any file listed in
- *sources* In other words, if *target* exists and is newer than every file in
+ *sources*. In other words, if *target* exists and is newer than every file in
*sources*, return false; otherwise return true. *missing* controls what we do
when a source file is missing; the default (``'error'``) is to blow up with an
:exc:`OSError` from inside :func:`os.stat`; if it is ``'ignore'``, we silently
+------------------+--------------------------------+---------+
| option name | description | default |
+==================+================================+=========+
- | *strip_comments* | strip from ``'#'`` to end-of- | true |
- | | line, as well as any | |
+ | *strip_comments* | strip from ``'#'`` to | true |
+ | | end-of-line, as well as any | |
| | whitespace leading up to the | |
| | ``'#'``\ ---unless it is | |
| | escaped by a backslash | |
python setup.py bdist --format=zip
-would, when run on a Unix system, create :file:`Distutils-1.0.{plat}.zip`\
----again, this archive would be unpacked from the root directory to install the
-Distutils.
+would, when run on a Unix system, create
+:file:`Distutils-1.0.{plat}.zip`\ ---again, this archive would be unpacked
+from the root directory to install the Distutils.
The available formats for built distributions are:
provide default values for any command option, which the installer can then
override either on the command-line or by editing the config file.
-The setup configuration file is a useful middle-ground between the setup script
----which, ideally, would be opaque to installers [#]_---and the command-line to
+The setup configuration file is a useful middle-ground between the setup
+script---which, ideally, would be opaque to installers [#]_---and the command-line to
the setup script, which is outside of your control and entirely up to the
installer. In fact, :file:`setup.cfg` (and any other Distutils configuration
files present on the target system) are processed after the contents of the
)
.. versionchanged:: 3.7
- :class:`~distutils.core.setup` now raises a :exc:`TypeError` if
- ``classifiers``, ``keywords`` and ``platforms`` fields are not specified
- as a list.
+ :class:`~distutils.core.setup` now warns when ``classifiers``, ``keywords``
+ or ``platforms`` fields are not specified as a list or a string.
.. _debug-setup-script:
+++ /dev/null
-[restructuredtext parser]
-smartquotes-locales: ja: ""''
:c:func:`PyObject_CallObject` returns a Python object pointer: this is the return
value of the Python function. :c:func:`PyObject_CallObject` is
"reference-count-neutral" with respect to its arguments. In the example a new
-tuple was created to serve as the argument list, which is :c:func:`Py_DECREF`\
--ed immediately after the :c:func:`PyObject_CallObject` call.
+tuple was created to serve as the argument list, which is
+:c:func:`Py_DECREF`\ -ed immediately after the :c:func:`PyObject_CallObject`
+call.
The return value of :c:func:`PyObject_CallObject` is "new": either it is a brand
new object, or it is an existing object whose reference count has been
mydict = {[1, 2]: '12'}
print(mydict[[1, 2]])
- would raise a KeyError exception because the id of the ``[1, 2]`` used in the
+ would raise a :exc:`KeyError` exception because the id of the ``[1, 2]`` used in the
second line differs from that in the first line. In other words, dictionary
keys should be compared using ``==``, not using :keyword:`is`.
The highest-level function to do this is :c:func:`PyRun_SimpleString` which takes
a single string argument to be executed in the context of the module
``__main__`` and returns ``0`` for success and ``-1`` when an exception occurred
-(including ``SyntaxError``). If you want more control, use
+(including :exc:`SyntaxError`). If you want more control, use
:c:func:`PyRun_String`; see the source for :c:func:`PyRun_SimpleString` in
``Python/pythonrun.c``.
thread as your rest application and you can't allow the
:c:func:`PyRun_InteractiveLoop` to stop while waiting for user input. The one
solution then is to call :c:func:`PyParser_ParseString` and test for ``e.error``
-equal to ``E_EOF``, which means the input is incomplete). Here's a sample code
+equal to ``E_EOF``, which means the input is incomplete. Here's a sample code
fragment, untested, inspired by code from Alex Farber::
#include <Python.h>
with running programs from the Windows command line then everything will seem
obvious; otherwise, you might need a little more guidance.
-.. sidebar:: |Python Development on XP|_
- :subtitle: `Python Development on XP`_
-
- This series of screencasts aims to get you up and running with Python on
- Windows XP. The knowledge is distilled into 1.5 hours and will get you up
- and running with the right Python distribution, coding in your choice of IDE,
- and debugging and writing solid code with unit-tests.
-
-.. |Python Development on XP| image:: python-video-icon.png
-.. _`Python Development on XP`:
- http://showmedo.com/videotutorials/series?name=pythonOzsvaldPyNewbieSeries
-
Unless you use some sort of integrated development environment, you will end up
*typing* Windows commands into what is variously referred to as a "DOS window"
or "Command prompt window". Usually you can create such a window from your
-Start menu; under Windows 7 the menu selection is :menuselection:`Start -->
-Programs --> Accessories --> Command Prompt`. You should be able to recognize
+search bar by searching for ``cmd``. You should be able to recognize
when you have started such a window because you will see a Windows "command
prompt", which usually looks like this:
program. So, how do you arrange for the interpreter to handle your Python?
First, you need to make sure that your command window recognises the word
-"python" as an instruction to start the interpreter. If you have opened a
-command window, you should try entering the command ``python`` and hitting
+"py" as an instruction to start the interpreter. If you have opened a
+command window, you should try entering the command ``py`` and hitting
return:
.. code-block:: doscon
- C:\Users\YourName> python
+ C:\Users\YourName> py
You should then see something like:
.. code-block:: pycon
- Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit (Intel)] on win32
+ Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
'HelloHelloHello'
Many people use the interactive mode as a convenient yet highly programmable
-calculator. When you want to end your interactive Python session, hold the :kbd:`Ctrl`
-key down while you enter a :kbd:`Z`, then hit the ":kbd:`Enter`" key to get back to your
-Windows command prompt.
+calculator. When you want to end your interactive Python session,
+call the :func:`exit` function or hold the :kbd:`Ctrl` key down
+while you enter a :kbd:`Z`, then hit the ":kbd:`Enter`" key to get
+back to your Windows command prompt.
You may also find that you have a Start-menu entry such as :menuselection:`Start
---> Programs --> Python 3.3 --> Python (command line)` that results in you
+--> Programs --> Python 3.x --> Python (command line)` that results in you
seeing the ``>>>`` prompt in a new window. If so, the window will disappear
-after you enter the :kbd:`Ctrl-Z` character; Windows is running a single "python"
+after you call the :func:`exit` function or enter the :kbd:`Ctrl-Z`
+character; Windows is running a single "python"
command in the window, and closes it when you terminate the interpreter.
-If the ``python`` command, instead of displaying the interpreter prompt ``>>>``,
-gives you a message like::
-
- 'python' is not recognized as an internal or external command, operable program or batch file.
-
-.. sidebar:: |Adding Python to DOS Path|_
- :subtitle: `Adding Python to DOS Path`_
-
- Python is not added to the DOS path by default. This screencast will walk
- you through the steps to add the correct entry to the `System Path`, allowing
- Python to be executed from the command-line by all users.
-
-.. |Adding Python to DOS Path| image:: python-video-icon.png
-.. _`Adding Python to DOS Path`:
- http://showmedo.com/videotutorials/video?name=960000&fromSeriesID=96
-
-
-or::
-
- Bad command or filename
-
-then you need to make sure that your computer knows where to find the Python
-interpreter. To do this you will have to modify a setting called PATH, which is
-a list of directories where Windows will look for programs.
-
-You should arrange for Python's installation directory to be added to the PATH
-of every command window as it starts. If you installed Python fairly recently
-then the command ::
-
- dir C:\py*
+Now that we know the ``py`` command is recognized, you can give your
+Python script to it. You'll have to give either an absolute or a
+relative path to the Python script. Let's say your Python script is
+located in your desktop and is named ``hello.py``, and your command
+prompt is nicely opened in your home directory so you're seeing something
+similar to::
-will probably tell you where it is installed; the usual location is something
-like ``C:\Python33``. Otherwise you will be reduced to a search of your whole
-disk ... use :menuselection:`Tools --> Find` or hit the :guilabel:`Search`
-button and look for "python.exe". Supposing you discover that Python is
-installed in the ``C:\Python33`` directory (the default at the time of writing),
-you should make sure that entering the command ::
+ C:\Users\YourName>
- c:\Python33\python
+So now you'll ask the ``py`` command to give your script to Python by
+typing ``py`` followed by your script path::
-starts up the interpreter as above (and don't forget you'll need a ":kbd:`Ctrl-Z`" and
-an ":kbd:`Enter`" to get out of it). Once you have verified the directory, you can
-add it to the system path to make it easier to start Python by just running
-the ``python`` command. This is currently an option in the installer as of
-CPython 3.3.
-More information about environment variables can be found on the
-:ref:`Using Python on Windows <setting-envvars>` page.
+ C:\Users\YourName> py Desktop\hello.py
+ hello
How do I make Python scripts executable?
----------------------------------------
Use the msvcrt module. This is a standard Windows-specific extension module.
It defines a function ``kbhit()`` which checks whether a keyboard hit is
present, and ``getch()`` which gets one character without echoing it.
-
-
-How do I emulate os.kill() in Windows?
---------------------------------------
-
-Prior to Python 2.7 and 3.2, to terminate a process, you can use :mod:`ctypes`:
-
-.. code-block:: python
-
- import ctypes
-
- def kill(pid):
- """kill function for Win32"""
- kernel32 = ctypes.windll.kernel32
- handle = kernel32.OpenProcess(1, 0, pid)
- return (0 != kernel32.TerminateProcess(handle, 0))
-
-In 2.7 and 3.2, :func:`os.kill` is implemented similar to the above function,
-with the additional feature of being able to send :kbd:`Ctrl+C` and :kbd:`Ctrl+Break`
-to console subprocesses which are designed to handle those signals. See
-:func:`os.kill` for further details.
-
-How do I extract the downloaded documentation on Windows?
----------------------------------------------------------
-
-Sometimes, when you download the documentation package to a Windows machine
-using a web browser, the file extension of the saved file ends up being .EXE.
-This is a mistake; the extension should be .TGZ.
-
-Simply rename the downloaded file to have the .TGZ extension, and WinZip will be
-able to handle it. (If your copy of WinZip doesn't, get a newer one from
-https://www.winzip.com.)
-
that it contains :keyword:`yield` expressions for producing a series of
values usable in an :keyword:`async for` loop.
- Usually refers to a asynchronous generator function, but may refer to an
+ Usually refers to an asynchronous generator function, but may refer to an
*asynchronous generator iterator* in some contexts. In cases where the
intended meaning isn't clear, using the full terms avoids ambiguity.
This is an :term:`asynchronous iterator` which when called using the
:meth:`__anext__` method returns an awaitable object which will execute
- that the body of the asynchronous generator function until the
- next :keyword:`yield` expression.
+ the body of the asynchronous generator function until the next
+ :keyword:`yield` expression.
Each :keyword:`yield` temporarily suspends processing, remembering the
location execution state (including local variables and pending
``int(3.15)`` converts the floating point number to the integer ``3``, but
in ``3+4.5``, each argument is of a different type (one int, one float),
and both must be converted to the same type before they can be added or it
- will raise a ``TypeError``. Without coercion, all arguments of even
+ will raise a :exc:`TypeError`. Without coercion, all arguments of even
compatible types would have to be normalized to the same value by the
programmer, e.g., ``float(3)+4.5`` rather than just ``3+4.5``.
An :term:`annotation` of a function parameter or return value.
Function annotations are usually used for
- :term:`type hints <type hint>`: for example this function is expected to take two
+ :term:`type hints <type hint>`: for example, this function is expected to take two
:class:`int` arguments and is also expected to have an :class:`int`
return value::
The :class:`NullHandler`, :class:`StreamHandler` and :class:`FileHandler`
classes are defined in the core logging package. The other handlers are
-defined in a sub- module, :mod:`logging.handlers`. (There is also another
+defined in a sub-module, :mod:`logging.handlers`. (There is also another
sub-module, :mod:`logging.config`, for configuration functionality.)
Logged messages are formatted for presentation through instances of the
These override options can be relative, absolute,
or explicitly defined in terms of one of the installation base directories.
-(There are two installation base directories, and they are normally the same---
-they only differ when you use the Unix "prefix scheme" and supply different
-``--prefix`` and ``--exec-prefix`` options; using ``--install-lib`` will
-override values computed or given for ``--install-purelib`` and
+(There are two installation base directories, and they are normally the
+same---they only differ when you use the Unix "prefix scheme" and supply
+different ``--prefix`` and ``--exec-prefix`` options; using ``--install-lib``
+will override values computed or given for ``--install-purelib`` and
``--install-platlib``, and is recommended for schemes that don't make a
difference between Python and extension modules.)
If you maintain Python on Windows, you might want third-party modules to live in
a subdirectory of :file:`{prefix}`, rather than right in :file:`{prefix}`
-itself. This is almost as easy as customizing the script installation directory
----you just have to remember that there are two types of modules to worry about,
-Python and extension modules, which can conveniently be both controlled by one
-option::
+itself. This is almost as easy as customizing the script installation
+directory---you just have to remember that there are two types of modules
+to worry about, Python and extension modules, which can conveniently be both
+controlled by one option::
python setup.py install --install-lib=Site
repository of open source licensed packages made available for use by
other Python users.
* the `Python Packaging Authority
- <https://www.pypa.io/>`__ are the group of
+ <https://www.pypa.io/>`__ is the group of
developers and documentation authors responsible for the maintenance and
evolution of the standard packaging tools and the associated metadata and
file format standards. They maintain a variety of tools, documentation,
memory page size - platform documentation should be referred to for more
information (4 KiB pages are common; using multiples of 4096 for the stack size is
the suggested approach in the absence of more specific information).
- Availability: Windows, systems with POSIX threads.
+
+ .. availability:: Windows, systems with POSIX threads.
.. data:: TIMEOUT_MAX
:mod:`numbers` module regarding a type hierarchy for numbers based on ABCs.)
The :mod:`collections` module has some concrete classes that derive from
-ABCs; these can, of course, be further derived. In addition the
+ABCs; these can, of course, be further derived. In addition, the
:mod:`collections.abc` submodule has some ABCs that can be used to test whether
-a class or instance provides a particular interface, for example, is it
-hashable or a mapping.
+a class or instance provides a particular interface, for example, if it is
+hashable or if it is a mapping.
This module provides the metaclass :class:`ABCMeta` for defining ABCs and
the descriptor must identify itself as abstract using
:attr:`__isabstractmethod__`. In general, this attribute should be ``True``
if any of the methods used to compose the descriptor are abstract. For
- example, Python's built-in property does the equivalent of::
+ example, Python's built-in :class:`property` does the equivalent of::
class Descriptor:
...
Note that ``nargs=1`` produces a list of one item. This is different from
the default, in which the item is produced by itself.
+.. index:: single: ? (question mark); in argparse module
+
* ``'?'``. One argument will be consumed from the command line if possible, and
produced as a single item. If no command-line argument is present, the value from
default_ will be produced. Note that for optional arguments, there is an
Namespace(infile=<_io.TextIOWrapper name='<stdin>' encoding='UTF-8'>,
outfile=<_io.TextIOWrapper name='<stdout>' encoding='UTF-8'>)
+.. index:: single: * (asterisk); in argparse module
+
* ``'*'``. All command-line arguments present are gathered into a list. Note that
it generally doesn't make much sense to have more than one positional argument
with ``nargs='*'``, but multiple optional arguments with ``nargs='*'`` is
>>> parser.parse_args('a b --foo x y --bar 1 2'.split())
Namespace(bar=['1', '2'], baz=['a', 'b'], foo=['x', 'y'])
+.. index:: single: + (plus); in argparse module
+
* ``'+'``. Just like ``'*'``, all command-line args present are gathered into a
list. Additionally, an error message will be generated if there wasn't at
least one command-line argument present. For example::
with alternatives (aka "sums"), the left-hand side class is abstract: only
instances of specific constructor nodes are ever created.
+ .. index:: single: ? (question mark); in AST grammar
+ .. index:: single: * (asterisk); in AST grammar
+
.. attribute:: _fields
Each concrete class has an attribute :attr:`_fields` which gives the names
<asyncio-coroutine-not-scheduled>` and logs them; this mitigates
the "forgotten await" pitfall.
-* Many non-treadsafe asyncio APIs (such as :meth:`loop.call_soon` and
+* Many non-threadsafe asyncio APIs (such as :meth:`loop.call_soon` and
:meth:`loop.call_at` methods) raise an exception if they are called
from a wrong thread.
Close the event loop.
- The loop must be running when this function is called.
+ The loop must not be running when this function is called.
Any pending callbacks will be discarded.
This method clears all queues and shuts down the executor, but does
See the documentation of the :meth:`loop.create_connection` method
for information about arguments to this method.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.7
See the documentation of the :meth:`loop.create_server` method
for information about arguments to this method.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.7
writing.
Use :func:`functools.partial` :ref:`to pass keyword arguments
- <asyncio-pass-keywords>` to *func*.
+ <asyncio-pass-keywords>` to *callback*.
.. method:: loop.remove_writer(fd)
Raise :exc:`RuntimeError` if there is a problem setting up the handler.
Use :func:`functools.partial` :ref:`to pass keyword arguments
- <asyncio-pass-keywords>` to *func*.
+ <asyncio-pass-keywords>` to *callback*.
.. method:: loop.remove_signal_handler(sig)
Return ``True`` if the signal handler was removed, or ``False`` if
no handler was set for the given signal.
-Availability: Unix.
+ .. availability:: Unix.
.. seealso::
asyncio.set_event_loop(loop)
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. class:: ProactorEventLoop
An event loop for Windows that uses "I/O Completion Ports" (IOCP).
- Availability: Windows.
+ .. availability:: Windows.
An example how to use :class:`ProactorEventLoop` on Windows::
An alternative event loop policy that uses the
:class:`ProactorEventLoop` event loop implementation.
- Availability: Windows.
+ .. availability:: Windows.
Process Watchers
import asyncio
- class EchoServerClientProtocol(asyncio.Protocol):
+ class EchoServerProtocol(asyncio.Protocol):
def connection_made(self, transport):
peername = transport.get_extra_info('peername')
print('Connection from {}'.format(peername))
loop = asyncio.get_running_loop()
server = await loop.create_server(
- lambda: EchoServerClientProtocol(),
+ lambda: EchoServerProtocol(),
'127.0.0.1', 8888)
async with server:
See also the documentation of :meth:`loop.create_unix_connection`.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.7
See also the documentation of :meth:`loop.create_unix_server`.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.7
print(what)
async def main():
- print('started at', time.strftime('%X'))
+ print(f"started at {time.strftime('%X')}")
await say_after(1, 'hello')
await say_after(2, 'world')
- print('finished at', time.strftime('%X'))
+ print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
task2 = asyncio.create_task(
say_after(2, 'world'))
- print('started at', time.strftime('%X'))
+ print(f"started at {time.strftime('%X')}")
# Wait until both tasks are completed (should take
# around 2 seconds.)
await task1
await task2
- print('finished at', time.strftime('%X'))
+ print(f"finished at {time.strftime('%X')}")
Note that expected output now shows that the snippet runs
1 second faster than before::
print('The coroutine took too long, cancelling the task...')
future.cancel()
except Exception as exc:
- print('The coroutine raised an exception: {!r}'.format(exc))
+ print(f'The coroutine raised an exception: {exc!r}')
else:
- print('The coroutine returned: {!r}'.format(result))
+ print(f'The coroutine returned: {result!r}')
See the :ref:`concurrency and multithreading <asyncio-multithreading>`
section of the documentation.
with an optional map argument and wraps it for use with the :c:func:`poll`
or :c:func:`loop` functions. If provided a file object or anything with a
:c:func:`fileno` method, that method will be called and passed to the
- :class:`file_wrapper` constructor. Availability: UNIX.
+ :class:`file_wrapper` constructor.
+
+ .. availability:: Unix.
.. class:: file_wrapper()
A file_wrapper takes an integer file descriptor and calls :func:`os.dup` to
duplicate the handle so that the original handle may be closed independently
of the file_wrapper. This class implements sufficient methods to emulate a
- socket for use by the :class:`file_dispatcher` class. Availability: UNIX.
+ socket for use by the :class:`file_dispatcher` class.
+
+ .. availability:: Unix.
.. _asyncore-example-1:
An end-of-file on input is passed back as the string ``'EOF'``.
+ .. index::
+ single: ? (question mark); in a command interpreter
+ single: ! (exclamation); in a command interpreter
+
An interpreter instance will recognize a command name ``foo`` if and only if it
has a method :meth:`do_foo`. As a special case, a line beginning with the
character ``'?'`` is dispatched to the method :meth:`do_help`. As another
The following error handlers are only applicable to
:term:`text encodings <text encoding>`:
+.. index::
+ single: ? (question mark); replacement character
+ single: \ (backslash); escape sequence
+ single: \x; escape sequence
+ single: \u; escape sequence
+ single: \U; escape sequence
+ single: \N; escape sequence
+
+-------------------------+-----------------------------------------------+
| Value | Meaning |
+=========================+===============================================+
| | ks_c-5601, ks_c-5601-1987, | |
| | ksx1001, ks_x-1001 | |
+-----------------+--------------------------------+--------------------------------+
-| gb2312 | chinese, csiso58gb231280, euc- | Simplified Chinese |
-| | cn, euccn, eucgb2312-cn, | |
-| | gb2312-1980, gb2312-80, iso- | |
-| | ir-58 | |
+| gb2312 | chinese, csiso58gb231280, | Simplified Chinese |
+| | euc-cn, euccn, eucgb2312-cn, | |
+| | gb2312-1980, gb2312-80, | |
+| | iso-ir-58 | |
+-----------------+--------------------------------+--------------------------------+
| gbk | 936, cp936, ms936 | Unified Chinese |
+-----------------+--------------------------------+--------------------------------+
Encode operand according to the ANSI codepage (CP_ACP).
-Availability: Windows only.
+.. availability:: Windows only.
.. versionchanged:: 3.3
Support any error handler.
.. class:: Counter([iterable-or-mapping])
A :class:`Counter` is a :class:`dict` subclass for counting hashable objects.
- It is an unordered collection where elements are stored as dictionary keys
+ It is a collection where elements are stored as dictionary keys
and their counts are stored as dictionary values. Counts are allowed to be
any integer value including zero or negative counts. The :class:`Counter`
class is similar to bags or multisets in other languages.
.. cmdoption:: --invalidation-mode [timestamp|checked-hash|unchecked-hash]
- Control how the generated pycs will be invalidated at runtime. The default
- setting, ``timestamp``, means that ``.pyc`` files with the source timestamp
+ Control how the generated byte-code files are invalidated at runtime.
+ The ``timestamp`` value, means that ``.pyc`` files with the source timestamp
and size embedded will be generated. The ``checked-hash`` and
``unchecked-hash`` values cause hash-based pycs to be generated. Hash-based
pycs embed a hash of the source file contents rather than a timestamp. See
- :ref:`pyc-invalidation` for more information on how Python validates bytecode
- cache files at runtime.
+ :ref:`pyc-invalidation` for more information on how Python validates
+ bytecode cache files at runtime.
+ The default is ``timestamp`` if the :envvar:`SOURCE_DATE_EPOCH` environment
+ variable is not set, and ``checked-hash`` if the ``SOURCE_DATE_EPOCH``
+ environment variable is set.
.. versionchanged:: 3.2
Added the ``-i``, ``-b`` and ``-h`` options.
each worker thread; *initargs* is a tuple of arguments passed to the
initializer. Should *initializer* raise an exception, all currently
pending jobs will raise a :exc:`~concurrent.futures.thread.BrokenThreadPool`,
- as well any attempt to submit more jobs to the pool.
+ as well as any attempt to submit more jobs to the pool.
.. versionchanged:: 3.5
If *max_workers* is ``None`` or
.. versionadded:: 3.6
The *thread_name_prefix* argument was added to allow users to
- control the threading.Thread names for worker threads created by
+ control the :class:`threading.Thread` names for worker threads created by
the pool for easier debugging.
.. versionchanged:: 3.7
interpolation. This means values can be preprocessed before returning them
from ``get()`` calls.
+.. index:: single: % (percent); interpolation in configuration files
+
.. class:: BasicInterpolation()
The default implementation used by :class:`ConfigParser`. It enables
``%(my_dir)s/Pictures`` as the value of ``my_pictures`` and
``%(home_dir)s/lumberjack`` as the value of ``my_dir``.
+.. index:: single: $ (dollar); interpolation in configuration files
+
.. class:: ExtendedInterpolation()
An alternative handler for interpolation which implements a more advanced
because default values cannot be deleted from the section (because technically
they are not there). If they are overridden in the section, deleting causes
the default value to be visible again. Trying to delete a default value
- causes a ``KeyError``.
+ causes a :exc:`KeyError`.
* ``DEFAULTSECT`` cannot be removed from the parser:
- * trying to delete it raises ``ValueError``,
+ * trying to delete it raises :exc:`ValueError`,
* ``parser.clear()`` leaves it intact,
these parser attributes. The defaults are defined on the classes, so they may
be overridden by subclasses or by attribute assignment.
-.. attribute:: BOOLEAN_STATES
+.. attribute:: ConfigParser.BOOLEAN_STATES
By default when using :meth:`~ConfigParser.getboolean`, config parsers
consider the following values ``True``: ``'1'``, ``'yes'``, ``'true'``,
Other typical Boolean pairs include ``accept``/``reject`` or
``enabled``/``disabled``.
-.. method:: optionxform(option)
+.. method:: ConfigParser.optionxform(option)
This method transforms option names on every read, get, or set
operation. The default converts the name to lowercase. This also
>>> list(custom['Section2'].keys())
['AnotherKey']
-.. attribute:: SECTCRE
+.. attribute:: ConfigParser.SECTCRE
A compiled regular expression used to parse section headers. The default
matches ``[section]`` to the name ``"section"``. Whitespace is considered
See :exc:`NotImplementedError` for details on when to use it.
+.. index:: single: ...; ellipsis literal
.. data:: Ellipsis
- The same as ``...``. Special value used mostly in conjunction with extended
- slicing syntax for user-defined container data types.
+ The same as the ellipsis literal "``...``". Special value used mostly in conjunction
+ with extended slicing syntax for user-defined container data types.
.. data:: __debug__
Return a shallow copy of *x*.
-.. function:: deepcopy(x)
+.. function:: deepcopy(x[, memo])
Return a deep copy of *x*.
The :func:`deepcopy` function avoids these problems by:
-* keeping a "memo" dictionary of objects already copied during the current
+* keeping a ``memo`` dictionary of objects already copied during the current
copying pass; and
* letting user-defined classes override the copying operation or the set of
special methods :meth:`__copy__` and :meth:`__deepcopy__`. The former is called
to implement the shallow copy operation; no additional arguments are passed.
The latter is called to implement the deep copy operation; it is passed one
-argument, the memo dictionary. If the :meth:`__deepcopy__` implementation needs
+argument, the ``memo`` dictionary. If the :meth:`__deepcopy__` implementation needs
to make a deep copy of a component, it should call the :func:`deepcopy` function
with the component as first argument and the memo dictionary as second argument.
may be available on all platforms), or a full encrypted password
including salt, as returned by this function. If *salt* is not
provided, the strongest method will be used (as returned by
- :func:`methods`.
+ :func:`methods`).
Checking a password is usually done by passing the plain-text password
as *word* and the full results of a previous :func:`crypt` call,
it returns a string.
+.. index::
+ single: ^ (caret); in curses module
+ single: ! (exclamation); in curses module
+
.. function:: unctrl(c)
Return a string representation of the ASCII character *c*. If *c* is printable,
| ``+t1`` | Returns a :class:`timedelta` object with the |
| | same value. (2) |
+--------------------------------+-----------------------------------------------+
-| ``-t1`` | equivalent to :class:`timedelta`\ |
-| | (-*t1.days*, -*t1.seconds*, |
-| | -*t1.microseconds*), and to *t1*\* -1. (1)(4) |
+| ``-t1`` | equivalent to |
+| | :class:`timedelta`\ (-*t1.days*, |
+| | -*t1.seconds*, -*t1.microseconds*), |
+| | and to *t1*\* -1. (1)(4) |
+--------------------------------+-----------------------------------------------+
| ``abs(t)`` | equivalent to +\ *t* when ``t.days >= 0``, and|
| | to -*t* when ``t.days < 0``. (2) |
The UTC timezone, ``timezone(timedelta(0))``.
+.. index::
+ single: % (percent); datetime format
+
.. _strftime-strptime-behavior:
:meth:`strftime` and :meth:`strptime` Behavior
Conversely, the :meth:`datetime.strptime` class method creates a
:class:`.datetime` object from a string representing a date and time and a
corresponding format string. ``datetime.strptime(date_string, format)`` is
-equivalent to ``datetime(*(time.strptime(date_string, format)[0:6]))``.
+equivalent to ``datetime(*(time.strptime(date_string, format)[0:6]))``, except
+when the format includes sub-second components or timezone offset information,
+which are supported in ``datetime.strptime`` but are discarded by ``time.strptime``.
For :class:`.time` objects, the format codes for year, month, and day should not
be used, as time objects have no such values. If they're used anyway, ``1900``
.. method:: get_matching_blocks()
- Return list of triples describing matching subsequences. Each triple is of
- the form ``(i, j, n)``, and means that ``a[i:i+n] == b[j:j+n]``. The
+ Return list of triples describing non-overlapping matching subsequences.
+ Each triple is of the form ``(i, j, n)``,
+ and means that ``a[i:i+n] == b[j:j+n]``. The
triples are monotonically increasing in *i* and *j*.
The last triple is a dummy, and has the value ``(len(a), len(b), 0)``. It
is the only triple with ``n == 0``. If ``(i, j, n)`` and ``(i', j', n')``
are adjacent triples in the list, and the second is not the last triple in
- the list, then ``i+n != i'`` or ``j+n != j'``; in other words, adjacent
+ the list, then ``i+n < i'`` or ``j+n < j'``; in other words, adjacent
triples always describe non-adjacent equal blocks.
.. XXX Explain why a dummy is used!
NO!!!
>>>
+.. index::
+ single: >>>; interpreter prompt
+ single: ...; interpreter prompt
+
Any expected output must immediately follow the final ``'>>> '`` or ``'... '``
line containing the code, and the expected output (if any) extends to the next
``'>>> '`` or all-whitespace line.
to test a :exc:`SyntaxError` that omits the traceback header, you will need to
manually add the traceback header line to your test example.
+.. index:: single: ^ (caret); marker
+
* For some :exc:`SyntaxError`\ s, Python displays the character position of the
syntax error, using a ``^`` marker::
option will probably go away, but not for several years.
+.. index:: single: <BLANKLINE>
.. data:: DONT_ACCEPT_BLANKLINE
By default, if an expected output block contains a line containing only the
your source.
+.. index:: single: ...; in doctests
.. data:: ELLIPSIS
When specified, an ellipsis marker (``...``) in the expected output can match
MY_FLAG = register_optionflag('MY_FLAG')
+.. index::
+ single: # (hash); in doctests
+ single: + (plus); in doctests
+ single: - (minus); in doctests
.. _doctest-directives:
Directives
.. method:: is_multipart()
- Return ``True`` if the message's payload is a list of sub-\
- :class:`Message` objects, otherwise return ``False``. When
+ Return ``True`` if the message's payload is a list of
+ sub-\ :class:`Message` objects, otherwise return ``False``. When
:meth:`is_multipart` returns ``False``, the payload should be a string
- object (which might be a CTE encoded binary payload. (Note that
+ object (which might be a CTE encoded binary payload). (Note that
:meth:`is_multipart` returning ``True`` does not necessarily mean that
"msg.get_content_maintype() == 'multipart'" will return the ``True``.
For example, ``is_multipart`` will return ``True`` when the
.. method:: __str__()
- Equivalent to `as_string(policy=self.policy.clone(utf8=True)`. Allows
+ Equivalent to ``as_string(policy=self.policy.clone(utf8=True))``. Allows
``str(msg)`` to produce a string containing the serialized message in a
readable format.
.. method:: is_multipart()
- Return ``True`` if the message's payload is a list of sub-\
- :class:`EmailMessage` objects, otherwise return ``False``. When
+ Return ``True`` if the message's payload is a list of
+ sub-\ :class:`EmailMessage` objects, otherwise return ``False``. When
:meth:`is_multipart` returns ``False``, the payload should be a string
object (which might be a CTE encoded binary payload). Note that
:meth:`is_multipart` returning ``True`` does not necessarily mean that
Note that existing parameter values of headers may be accessed through
the :attr:`~email.headerregistry.BaseHeader.params` attribute of the
- header value (for example, ``msg['Content-Type'].params['charset']``.
+ header value (for example, ``msg['Content-Type'].params['charset']``).
.. versionchanged:: 3.4 ``replace`` keyword was added.
specified by the current :mod:`~email.policy`. If the added part
has no :mailheader:`Content-Disposition` header, add one with the value
``attachment``. This method can be used both for explicit attachments
- (:mailheader:`Content-Disposition: attachment` and ``inline`` attachments
+ (:mailheader:`Content-Disposition: attachment`) and ``inline`` attachments
(:mailheader:`Content-Disposition: inline`), by passing appropriate
options to the ``content_manager``.
envelope header. The header block is terminated either by the end of the
data or by a blank line. Following the header block is the body of the
message (which may contain MIME-encoded subparts, including subparts
- with a :mailheader:`Content-Transfer-Encoding` of ``8bit``.
+ with a :mailheader:`Content-Transfer-Encoding` of ``8bit``).
Optional *headersonly* is a flag specifying whether to stop parsing after
reading the headers or not. The default is ``False``, meaning it parses
Return a message object structure from a :term:`bytes-like object`. This is
equivalent to ``BytesParser().parsebytes(s)``. Optional *_class* and
- *strict* are interpreted as with the :class:`~email.parser.BytesParser` class
+ *policy* are interpreted as with the :class:`~email.parser.BytesParser` class
constructor.
.. versionadded:: 3.2
Following those is a set of examples of using the fundamental parts of the APIs
covered in the preceding sections.
-The forgoing represent the modern (unicode friendly) API of the email package.
+The foregoing represent the modern (unicode friendly) API of the email package.
The remaining sections, starting with the :class:`~email.message.Message`
class, cover the legacy :data:`~email.policy.compat32` API that deals much more
directly with the details of how email messages are represented. The
email.header.rst
email.charset.rst
email.encoders.rst
- email.util.rst
+ email.utils.rst
email.iterators.rst
:attr:`__cause__` also implicitly sets the :attr:`__suppress_context__`
attribute to ``True``, so that using ``raise new_exc from None``
effectively replaces the old exception with the new one for display
-purposes (e.g. converting :exc:`KeyError` to :exc:`AttributeError`, while
+purposes (e.g. converting :exc:`KeyError` to :exc:`AttributeError`), while
leaving the old exception available in :attr:`__context__` for introspection
when debugging.
same as regular expressions (which are documented in the :mod:`re` module). The
special characters used in shell-style wildcards are:
+.. index::
+ single: * (asterisk); in glob-style wildcards
+ single: ? (question mark); in glob-style wildcards
+ single: [] (square brackets); in glob-style wildcards
+ single: ! (exclamation); in glob-style wildcards
+ single: - (minus); in glob-style wildcards
+
+------------+------------------------------------+
| Pattern | Meaning |
+============+====================================+
Note that the filename separator (``'/'`` on Unix) is *not* special to this
module. See module :mod:`glob` for pathname expansion (:mod:`glob` uses
-:func:`fnmatch` to match pathname segments). Similarly, filenames starting with
+:func:`.filter` to match pathname segments). Similarly, filenames starting with
a period are not special for this module, and are matched by the ``*`` and ``?``
patterns.
Has two optional arguments which must be specified as keyword arguments.
*key* specifies a function of one argument that is used to extract a comparison
- key from each list element: ``key=str.lower``. The default value is ``None``
- (compare the elements directly).
+ key from each element in *iterable* (for example, ``key=str.lower``). The
+ default value is ``None`` (compare the elements directly).
*reverse* is a boolean value. If set to ``True``, then the list elements are
sorted as if each comparison were reversed.
The cache's size limit assures that the cache does not grow without bound on
long-running processes such as web servers.
+ In general, the LRU cache should only be used when you want to reuse
+ previously computed values. Accordingly, it doesn't make sense to cache
+ functions with side-effects, functions that need to create distinct mutable
+ objects on each call, or impure functions such as time() or random().
+
Example of an LRU cache for static web content::
@lru_cache(maxsize=32)
.. function:: partial(func, *args, **keywords)
- Return a new :class:`partial` object which when called will behave like *func*
- called with the positional arguments *args* and keyword arguments *keywords*. If
- more arguments are supplied to the call, they are appended to *args*. If
- additional keyword arguments are supplied, they extend and override *keywords*.
+ Return a new :ref:`partial object<partial-objects>` which when called
+ will behave like *func* called with the positional arguments *args*
+ and keyword arguments *keywords*. If more arguments are supplied to the
+ call, they are appended to *args*. If additional keyword arguments are
+ supplied, they extend and override *keywords*.
Roughly equivalent to::
def partial(func, *args, **keywords):
:func:`classmethod`, :func:`staticmethod`, :func:`abstractmethod` or
another instance of :class:`partialmethod`), calls to ``__get__`` are
delegated to the underlying descriptor, and an appropriate
- :class:`partial` object returned as the result.
+ :ref:`partial object<partial-objects>` returned as the result.
When *func* is a non-descriptor callable, an appropriate bound method is
created dynamically. This behaves like a normal Python function when
*domain*, which is returned.
+.. index:: single: _ (underscore); gettext
.. function:: gettext(message)
Return the localized translation of *message*, based on the current global
--------------
+.. index::
+ single: * (asterisk); in glob-style wildcards
+ single: ? (question mark); in glob-style wildcards
+ single: [] (square brackets); in glob-style wildcards
+ single: ! (exclamation); in glob-style wildcards
+ single: - (minus); in glob-style wildcards
+ single: . (dot); in glob-style wildcards
+
The :mod:`glob` module finds all the pathnames matching a specified pattern
according to the rules used by the Unix shell, although results are returned in
arbitrary order. No tilde expansion is done, but ``*``, ``?``, and character
:file:`../../Tools/\*/\*.gif`), and can contain shell-style wildcards. Broken
symlinks are included in the results (as in the shell).
+ .. index::
+ single: **; in glob-style wildcards
+
If *recursive* is true, the pattern "``**``" will match any files and zero or
more directories and subdirectories. If the pattern is followed by an
``os.sep``, only directories and subdirectories match.
factor and *maxmem* limits memory (OpenSSL 1.1.0 defaults to 32 MiB).
*dklen* is the length of the derived key.
- Availability: OpenSSL 1.1+
+ .. availability:: OpenSSL 1.1+.
.. versionadded:: 3.6
Return a list with the *n* largest elements from the dataset defined by
*iterable*. *key*, if provided, specifies a function of one argument that is
- used to extract a comparison key from each element in the iterable:
- ``key=str.lower`` Equivalent to: ``sorted(iterable, key=key,
- reverse=True)[:n]``
+ used to extract a comparison key from each element in *iterable* (for example,
+ ``key=str.lower``). Equivalent to: ``sorted(iterable, key=key,
+ reverse=True)[:n]``.
.. function:: nsmallest(n, iterable, key=None)
Return a list with the *n* smallest elements from the dataset defined by
*iterable*. *key*, if provided, specifies a function of one argument that is
- used to extract a comparison key from each element in the iterable:
- ``key=str.lower`` Equivalent to: ``sorted(iterable, key=key)[:n]``
+ used to extract a comparison key from each element in *iterable* (for example,
+ ``key=str.lower``). Equivalent to: ``sorted(iterable, key=key)[:n]``.
The latter two functions perform best for smaller values of *n*. For larger
This module defines classes for implementing HTTP servers (Web servers).
+.. warning::
+
+ :mod:`http.server` is not recommended for production. It only implements
+ basic security checks.
+
One class, :class:`HTTPServer`, is a :class:`socketserver.TCPServer` subclass.
It creates and listens at the HTTP socket, dispatching the requests to a
handler. Code to create and run the server looks like this::
* coded in 100% pure Python, using the :mod:`tkinter` GUI toolkit
-* cross-platform: works mostly the same on Windows, Unix, and Mac OS X
+* cross-platform: works mostly the same on Windows, Unix, and macOS
* Python shell window (interactive interpreter) with colorizing
of code input, output, and error messages
-----
IDLE has two main window types, the Shell window and the Editor window. It is
-possible to have multiple editor windows simultaneously. Output windows, such
-as used for Edit / Find in Files, are a subtype of edit window. They currently
-have the same top menu as Editor windows but a different default title and
-context menu.
+possible to have multiple editor windows simultaneously. On Windows and
+Linux, each has its own top menu. Each menu documented below indicates
+which window type it is associated with.
-IDLE's menus dynamically change based on which window is currently selected.
-Each menu documented below indicates which window type it is associated with.
+Output windows, such as used for Edit => Find in Files, are a subtype of editor
+window. They currently have the same top menu but a different
+default title and context menu.
+
+On macOS, there is one application menu. It dynamically changes according
+to the window currently selected. It has an IDLE menu, and some entries
+described below are moved around to conform to Apple guidlines.
File menu (Shell and Editor)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Configure IDLE
Open a configuration dialog and change preferences for the following:
fonts, indentation, keybindings, text color themes, startup windows and
- size, additional help sources, and extensions (see below). On OS X,
+ size, additional help sources, and extensions (see below). On macOS,
open the configuration dialog by selecting Preferences in the application
menu. To use a new built-in color theme (IDLE Dark) with older IDLEs,
save it as a new custom theme.
Display version, copyright, license, credits, and more.
IDLE Help
- Display a help file for IDLE detailing the menu options, basic editing and
+ Display this IDLE document, detailing the menu options, basic editing and
navigation, and other tips.
Python Docs
Run the turtledemo module with example Python code and turtle drawings.
Additional help sources may be added here with the Configure IDLE dialog under
-the General tab.
+the General tab. See the "Help sources" subsection below for more
+on Help menu choices.
.. index::
single: Cut
Context Menus
^^^^^^^^^^^^^^^^^^^^^^^^^^
-Open a context menu by right-clicking in a window (Control-click on OS X).
+Open a context menu by right-clicking in a window (Control-click on macOS).
Context menus have the standard clipboard functions also on the Edit menu.
Cut
Clear Breakpoint
Clear the breakpoint on that line.
-Shell and Output windows have the following.
+Shell and Output windows also have the following.
Go to file/line
Same as in Debug menu.
+The Shell window also has an output squeezing facility explained in the
+the *Python Shell window* subsection below.
+
+Squeeze
+ If the cursor is over an output line, squeeze all the output between
+ the code above and the prompt below down to a 'Squeezed text' label.
+
Editing and navigation
----------------------
+Editor windows
+^^^^^^^^^^^^^^
+
+IDLE may open editor windows when it starts, depending on settings
+and how you start IDLE. Thereafter, use the File menu. There can be only
+one open editor window for a given file.
+
+The title bar contains the name of the file, the full path, and the version
+of Python and IDLE running the window. The status bar contains the line
+number ('Ln') and column number ('Col'). Line numbers start with 1;
+column numbers with 0.
+
+IDLE assumes that files with a known .py* extension contain Python code
+and that other files do not. Run Python code with the Run menu.
+
+Key bindings
+^^^^^^^^^^^^
+
In this section, 'C' refers to the :kbd:`Control` key on Windows and Unix and
-the :kbd:`Command` key on Mac OSX.
+the :kbd:`Command` key on macOS.
* :kbd:`Backspace` deletes to the left; :kbd:`Del` deletes to the right
Standard keybindings (like :kbd:`C-c` to copy and :kbd:`C-v` to paste)
may work. Keybindings are selected in the Configure IDLE dialog.
-
Automatic indentation
^^^^^^^^^^^^^^^^^^^^^
Python Shell window
^^^^^^^^^^^^^^^^^^^
+With IDLE's Shell, one enters, edits, and recalls complete statements.
+Most consoles and terminals only work with a single physical line at a time.
+
+When one pastes code into Shell, it is not compiled and possibly executed
+until one hits :kbd:`Return`. One may edit pasted code first.
+If one pastes more that one statement into Shell, the result will be a
+:exc:`SyntaxError` when multiple statements are compiled as if they were one.
+
+The editing features described in previous subsections work when entering
+code interactively. IDLE's Shell window also responds to the following keys.
+
* :kbd:`C-c` interrupts executing command
* :kbd:`C-d` sends end-of-file; closes window if typed at a ``>>>`` prompt
Command history
* :kbd:`Alt-p` retrieves previous command matching what you have typed. On
- OS X use :kbd:`C-p`.
+ macOS use :kbd:`C-p`.
- * :kbd:`Alt-n` retrieves next. On OS X use :kbd:`C-n`.
+ * :kbd:`Alt-n` retrieves next. On macOS use :kbd:`C-n`.
* :kbd:`Return` while on any previous command retrieves that command
-
Text colors
^^^^^^^^^^^
executed in the Tk namespace, so this file is not useful for importing
functions to be used from IDLE's Python shell.
-
Command line usage
^^^^^^^^^^^^^^^^^^
* Otherwise, arguments are files opened for editing and
``sys.argv`` reflects the arguments passed to IDLE itself.
-
Startup failure
^^^^^^^^^^^^^^^
If IDLE quits with no message, and it was not started from a console, try
starting from a console (``python -m idlelib)`` and see if a message appears.
-
-IDLE-console differences
-^^^^^^^^^^^^^^^^^^^^^^^^
+Running user code
+^^^^^^^^^^^^^^^^^
With rare exceptions, the result of executing Python code with IDLE is
-intended to be the same as executing the same code in a console window.
+intended to be the same as executing the same code by the default method,
+directly with Python in a text-mode system console or terminal window.
However, the different interface and operation occasionally affect
-visible results. For instance, ``sys.modules`` starts with more entries.
+visible results. For instance, ``sys.modules`` starts with more entries,
+and ``threading.activeCount()`` returns 2 instead of 1.
+
+By default, IDLE runs user code in a separate OS process rather than in
+the user interface process that runs the shell and editor. In the execution
+process, it replaces ``sys.stdin``, ``sys.stdout``, and ``sys.stderr``
+with objects that get input from and send output to the Shell window.
+The original values stored in ``sys.__stdin__``, ``sys.__stdout__``, and
+``sys.__stderr__`` are not touched, but may be ``None``.
-IDLE also replaces ``sys.stdin``, ``sys.stdout``, and ``sys.stderr`` with
-objects that get input from and send output to the Shell window.
When Shell has the focus, it controls the keyboard and screen. This is
normally transparent, but functions that directly access the keyboard
-and screen will not work. If ``sys`` is reset with ``importlib.reload(sys)``,
-IDLE's changes are lost and things like ``input``, ``raw_input``, and
-``print`` will not work correctly.
-
-With IDLE's Shell, one enters, edits, and recalls complete statements.
-Some consoles only work with a single physical line at a time. IDLE uses
-``exec`` to run each statement. As a result, ``'__builtins__'`` is always
-defined for each statement.
+and screen will not work. These include system-specific functions that
+determine whether a key has been pressed and if so, which.
+
+IDLE's standard stream replacements are not inherited by subprocesses
+created in the execution process, whether directly by user code or by modules
+such as multiprocessing. If such subprocess use ``input`` from sys.stdin
+or ``print`` or ``write`` to sys.stdout or sys.stderr,
+IDLE should be started in a command line window. The secondary subprocess
+will then be attached to that window for input and output.
+
+If ``sys`` is reset by user code, such as with ``importlib.reload(sys)``,
+IDLE's changes are lost and input from the keyboard and output to the screen
+will not work correctly.
+
+User output in Shell
+^^^^^^^^^^^^^^^^^^^^
+
+When a program outputs text, the result is determined by the
+corresponding output device. When IDLE executes user code, ``sys.stdout``
+and ``sys.stderr`` are connected to the display area of IDLE's Shell. Some of
+its features are inherited from the underlying Tk Text widget. Others
+are programmed additions. Where it matters, Shell is designed for development
+rather than production runs.
+
+For instance, Shell never throws away output. A program that sends unlimited
+output to Shell will eventually fill memory, resulting in a memory error.
+In contrast, some system text windows only keep the last n lines of output.
+A Windows console, for instance, keeps a user-settable 1 to 9999 lines,
+with 300 the default.
+
+Text widgets display a subset of Unicode, the Basic Multilingual Plane (BMP).
+Which characters get a proper glyph instead of a replacement box depends on
+the operating system and installed fonts. Newline characters cause following
+text to appear on a new line, but other control characters are either
+replaced with a box or deleted. However, ``repr()``, which is used for
+interactive echo of expression values, replaces control characters,
+some BMP codepoints, and all non-BMP characters with escape codes
+before they are output.
+
+Normal and error output are generally kept separate (on separate lines)
+from code input and each other. They each get different highlight colors.
+
+For SyntaxError tracebacks, the normal '^' marking where the error was
+detected is replaced by coloring the text with an error highlight.
+When code run from a file causes other exceptions, one may right click
+on a traceback line to jump to the corresponding line in an IDLE editor.
+The file will be opened if necessary.
+
+Shell has a special facility for squeezing output lines down to a
+'Squeezed text' label. This is done automatically
+for output over N lines (N = 50 by default).
+N can be changed in the PyShell section of the General
+page of the Settings dialog. Output with fewer lines can be squeezed by
+right clicking on the output. This can be useful lines long enough to slow
+down scrolling.
+
+Squeezed output is expanded in place by double-clicking the label.
+It can also be sent to the clipboard or a separate view window by
+right-clicking the label.
Developing tkinter applications
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Help and preferences
--------------------
-Additional help sources
-^^^^^^^^^^^^^^^^^^^^^^^
+Help sources
+^^^^^^^^^^^^
-IDLE includes a help menu entry called "Python Docs" that will open the
-extensive sources of help, including tutorials, available at docs.python.org.
-Selected URLs can be added or removed from the help menu at any time using the
-Configure IDLE dialog. See the IDLE help option in the help menu of IDLE for
-more information.
+Help menu entry "IDLE Help" displays a formatted html version of the
+IDLE chapter of the Library Reference. The result, in a read-only
+tkinter text window, is close to what one sees in a web browser.
+Navigate through the text with a mousewheel,
+the scrollbar, or up and down arrow keys held down.
+Or click the TOC (Table of Contents) button and select a section
+header in the opened box.
+Help menu entry "Python Docs" opens the extensive sources of help,
+including tutorials, available at docs.python.org/x.y, where 'x.y'
+is the currently running Python version. If your system
+has an off-line copy of the docs (this may be an installation option),
+that will be opened instead.
+
+Selected URLs can be added or removed from the help menu at any time using the
+General tab of the Configure IDLE dialog .
Setting preferences
^^^^^^^^^^^^^^^^^^^
IDLE ships with four built-in key sets. In addition, a user can create a
custom key set in the Configure IDLE dialog under the keys tab.
+IDLE on macOS
+^^^^^^^^^^^^^
+
+Under System Preferences: Dock, one can set "Prefer tabs when opening
+documents" to "Always". This setting is not compatible with the tk/tkinter
+GUI framework used by IDLE, and it breaks a few IDLE features.
Extensions
^^^^^^^^^^
file path. For example, if *path* is
``/foo/bar/__pycache__/baz.cpython-32.pyc`` the returned path would be
``/foo/bar/baz.py``. *path* need not exist, however if it does not conform
- to :pep:`3147` format, a ``ValueError`` is raised. If
+ to :pep:`3147` format, a :exc:`ValueError` is raised. If
:attr:`sys.implementation.cache_tag` is not defined,
:exc:`NotImplementedError` is raised.
file path. For example, if *path* is
``/foo/bar/__pycache__/baz.cpython-32.pyc`` the returned path would be
``/foo/bar/baz.py``. *path* need not exist, however if it does not conform
- to :pep:`3147` or :pep:`488` format, a ``ValueError`` is raised. If
+ to :pep:`3147` or :pep:`488` format, a :exc:`ValueError` is raised. If
:attr:`sys.implementation.cache_tag` is not defined,
:exc:`NotImplementedError` is raised.
''''''''''''''''''''''''''''''''
To import a Python source file directly, use the following recipe
-(Python 3.4 and newer only)::
+(Python 3.5 and newer only)::
import importlib.util
import sys
if '.' in absolute_name:
parent_name, _, child_name = absolute_name.rpartition('.')
parent_module = import_module(parent_name)
- path = parent_module.spec.submodule_search_locations
+ path = parent_module.__spec__.submodule_search_locations
for finder in sys.meta_path:
spec = finder.find_spec(absolute_name, path)
if spec is not None:
| | f_locals | local namespace seen by |
| | | this frame |
+-----------+-------------------+---------------------------+
-| | f_restricted | 0 or 1 if frame is in |
-| | | restricted execution mode |
-+-----------+-------------------+---------------------------+
| | f_trace | tracing function for this |
| | | frame, or ``None`` |
+-----------+-------------------+---------------------------+
Let the show begin!
+
+.. _availability:
+
+Notes on availability
+=====================
+
+* An "Availability: Unix" note means that this function is commonly found on
+ Unix systems. It does not make any claims about its existence on a specific
+ operating system.
+
+* If not separately noted, all functions that claim "Availability: Unix" are
+ supported on Mac OS X, which builds on a Unix core.
+
categories is called a :term:`file object`. Other common terms are *stream*
and *file-like object*.
-Independently of its category, each concrete stream object will also have
+Independent of its category, each concrete stream object will also have
various capabilities: it can be read-only, write-only, or read-write. It can
also allow arbitrary random access (seeking forwards or backwards to any
location), or only sequential access (for example in the case of a socket or
All streams are careful about the type of data you give to them. For example
giving a :class:`str` object to the ``write()`` method of a binary stream
-will raise a ``TypeError``. So will giving a :class:`bytes` object to the
+will raise a :exc:`TypeError`. So will giving a :class:`bytes` object to the
``write()`` method of a text stream.
.. versionchanged:: 3.3
when serializing instances of "exotic" numerical types such as
:class:`decimal.Decimal`.
+
.. _json-commandline:
+.. program:: json.tool
Command Line Interface
----------------------
:option:`--sort-keys` option to sort the output of dictionaries
alphabetically by key.
+
Command line options
^^^^^^^^^^^^^^^^^^^^
+--------------+-----------------------------------------+
The function sets temporarily the ``LC_CTYPE`` locale to the ``LC_NUMERIC``
- locale to decode ``decimal_point`` and ``thousands_sep`` byte strings if
- they are non-ASCII or longer than 1 byte, and the ``LC_NUMERIC`` locale is
- different than the ``LC_CTYPE`` locale. This temporary change affects other
- threads.
+ locale or the ``LC_MONETARY`` locale if locales are different and numeric or
+ monetary strings are non-ASCII. This temporary change affects other threads.
.. versionchanged:: 3.7
The function now sets temporarily the ``LC_CTYPE`` locale to the
Module-Level Functions
----------------------
-In addition to the classes described above, there are a number of module- level
+In addition to the classes described above, there are a number of module-level
functions.
There are three keyword arguments in *kwargs* which are inspected: *exc_info*
which, if it does not evaluate as false, causes exception information to be
added to the logging message. If an exception tuple (in the format returned by
- :func:`sys.exc_info`) is provided, it is used; otherwise, :func:`sys.exc_info`
- is called to get the exception information.
+ :func:`sys.exc_info`) or an exception instance is provided, it is used;
+ otherwise, :func:`sys.exc_info` is called to get the exception information.
The second optional keyword argument is *stack_info*, which defaults to
``False``. If true, stack information is added to the logging
.. method:: MimeTypes.read_windows_registry(strict=True)
- Load MIME type information from the Windows registry. Availability: Windows.
+ Load MIME type information from the Windows registry.
+
+ .. availability:: Windows.
If *strict* is ``True``, information will be added to the list of standard
types, else to the list of non-standard types.
*offset* may be specified as a non-negative integer offset. mmap references
will be relative to the offset from the beginning of the file. *offset*
- defaults to 0. *offset* must be a multiple of the ALLOCATIONGRANULARITY.
+ defaults to 0. *offset* must be a multiple of the :const:`ALLOCATIONGRANULARITY`.
.. class:: mmap(fileno, length, flags=MAP_SHARED, prot=PROT_WRITE|PROT_READ, access=ACCESS_DEFAULT[, offset])
*offset* may be specified as a non-negative integer offset. mmap references
will be relative to the offset from the beginning of the file. *offset*
- defaults to 0. *offset* must be a multiple of the PAGESIZE or
- ALLOCATIONGRANULARITY.
+ defaults to 0. *offset* must be a multiple of :const:`ALLOCATIONGRANULARITY`
+ which is equal to :const:`PAGESIZE` on Unix systems.
To ensure validity of the created memory mapping the file specified
by the descriptor *fileno* is internally automatically synchronized
use of this call there is no guarantee that changes are written back before
the object is destroyed. If *offset* and *size* are specified, only
changes to the given range of bytes will be flushed to disk; otherwise, the
- whole extent of the mapping is flushed.
+ whole extent of the mapping is flushed. *offset* must be a multiple of the
+ :const:`PAGESIZE` or :const:`ALLOCATIONGRANULARITY`.
**(Windows version)** A nonzero value returned indicates success; zero
indicates failure.
Handling boolean (flag) options
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Flag options---set a variable to true or false when a particular option is seen
----are quite common. :mod:`optparse` supports them with two separate actions,
+Flag options---set a variable to true or false when a particular option is
+seen---are quite common. :mod:`optparse` supports them with two separate actions,
``store_true`` and ``store_false``. For example, you might have a ``verbose``
flag that is turned on with ``-v`` and off with ``-q``::
parser.add_option("-q", action="store_false", dest="verbose")
Here we have two different options with the same destination, which is perfectly
-OK. (It just means you have to be a bit careful when setting default values---
-see below.)
+OK. (It just means you have to be a bit careful when setting default
+values---see below.)
When :mod:`optparse` encounters ``-v`` on the command line, it sets
``options.verbose`` to ``True``; when it encounters ``-q``,
default: ``"Usage: %prog [options]"``, which is fine if your script doesn't
take any positional arguments.
-* every option defines a help string, and doesn't worry about line-wrapping---
- :mod:`optparse` takes care of wrapping lines and making the help output look
- good.
+* every option defines a help string, and doesn't worry about
+ line-wrapping---\ :mod:`optparse` takes care of wrapping lines and making
+ the help output look good.
* options that take a value indicate this fact in their automatically-generated
help message, e.g. for the "mode" option::
pathnames, or if *paths* is empty. Unlike :func:`commonprefix`, this
returns a valid path.
- Availability: Unix, Windows
+ .. availability:: Unix, Windows.
.. versionadded:: 3.5
Accepts a :term:`path-like object`.
+.. index:: single: ~ (tilde); home directory expansion
+
.. function:: expanduser(path)
On Unix and Windows, return the argument with an initial component of ``~`` or
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
+.. index::
+ single: $ (dollar); environment variables expansion
+ single: % (percent); environment variables expansion (Windows)
.. function:: expandvars(path)
Normalize the case of a pathname. On Unix and Mac OS X, this returns the
path unchanged; on case-insensitive filesystems, it converts the path to
lowercase. On Windows, it also converts forward slashes to backward slashes.
- Raise a TypeError if the type of *path* is not ``str`` or ``bytes`` (directly
+ Raise a :exc:`TypeError` if the type of *path* is not ``str`` or ``bytes`` (directly
or indirectly through the :class:`os.PathLike` interface).
.. versionchanged:: 3.6
*start* defaults to :attr:`os.curdir`.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
This is determined by the device number and i-node number and raises an
exception if an :func:`os.stat` call on either pathname fails.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. versionchanged:: 3.2
Added Windows support.
Return ``True`` if the file descriptors *fp1* and *fp2* refer to the same file.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. versionchanged:: 3.2
Added Windows support.
:func:`os.lstat`, or :func:`os.stat`. This function implements the
underlying comparison used by :func:`samefile` and :func:`sameopenfile`.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. versionchanged:: 3.4
Added Windows support.
objects, and result in an object of the same type, if a path or file name is
returned.
-* An "Availability: Unix" note means that this function is commonly found on
- Unix systems. It does not make any claims about its existence on a specific
- operating system.
-
-* If not separately noted, all functions that claim "Availability: Unix" are
- supported on Mac OS X, which builds on a Unix core.
-
-.. Availability notes get their own line and occur at the end of the function
-.. documentation.
.. note::
Return the filename corresponding to the controlling terminal of the process.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: environ
and ``'surrogateescape'`` error handler. Use :func:`os.getenvb` if you
would like to use a different encoding.
- Availability: most flavors of Unix, Windows.
+ .. availability:: most flavors of Unix, Windows.
.. function:: getenvb(key, default=None)
:func:`getenvb` is only available if :data:`supports_bytes_environ`
is True.
- Availability: most flavors of Unix.
+ .. availability:: most flavors of Unix.
.. versionadded:: 3.2
Return the effective group id of the current process. This corresponds to the
"set id" bit on the file being executed in the current process.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: geteuid()
Return the current process's effective user id.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: getgid()
Return the real group id of the current process.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: getgrouplist(user, group)
list, it is included; typically, *group* is specified as the group ID
field from the password record for *user*.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Return list of supplemental group ids associated with the current process.
- Availability: Unix.
+ .. availability:: Unix.
.. note::
falls back to ``pwd.getpwuid(os.getuid())[0]`` to get the login name of the
current real user id.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. function:: getpgid(pid)
Return the process group id of the process with process id *pid*. If *pid* is 0,
the process group id of the current process is returned.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: getpgrp()
Return the id of the current process group.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: getpid()
the id returned is the one of the init process (1), on Windows it is still
the same id, which may be already reused by another process.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. versionchanged:: 3.2
Added support for Windows.
(respectively) the calling process, the process group of the calling process,
or the real user ID of the calling process.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Parameters for the :func:`getpriority` and :func:`setpriority` functions.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Return a tuple (ruid, euid, suid) denoting the current process's
real, effective, and saved user ids.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.2
Return a tuple (rgid, egid, sgid) denoting the current process's
real, effective, and saved group ids.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.2
Return the current process's real user id.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: initgroups(username, gid)
the groups of which the specified username is a member, plus the specified
group id.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.2
changes to the environment affect subprocesses started with :func:`os.system`,
:func:`popen` or :func:`fork` and :func:`execv`.
- Availability: most flavors of Unix, Windows.
+ .. availability:: most flavors of Unix, Windows.
.. note::
Set the current process's effective group id.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: seteuid(euid)
Set the current process's effective user id.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: setgid(gid)
Set the current process' group id.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: setgroups(groups)
*groups*. *groups* must be a sequence, and each element must be an integer
identifying a group. This operation is typically available only to the superuser.
- Availability: Unix.
+ .. availability:: Unix.
.. note:: On Mac OS X, the length of *groups* may not exceed the
system-defined maximum number of effective group ids, typically 16.
Call the system call :c:func:`setpgrp` or ``setpgrp(0, 0)`` depending on
which version is implemented (if any). See the Unix manual for the semantics.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: setpgid(pid, pgrp)
process with id *pid* to the process group with id *pgrp*. See the Unix manual
for the semantics.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: setpriority(which, who, priority)
*priority* is a value in the range -20 to 19. The default priority is 0;
lower priorities cause more favorable scheduling.
- Availability: Unix
+ .. availability:: Unix.
.. versionadded:: 3.3
Set the current process's real and effective group ids.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: setresgid(rgid, egid, sgid)
Set the current process's real, effective, and saved group ids.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.2
Set the current process's real, effective, and saved user ids.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.2
Set the current process's real and effective user ids.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: getsid(pid)
Call the system call :c:func:`getsid`. See the Unix manual for the semantics.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: setsid()
Call the system call :c:func:`setsid`. See the Unix manual for the semantics.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: setuid(uid)
Set the current process's user id.
- Availability: Unix.
+ .. availability:: Unix.
.. placed in this section since it relates to errno.... a little weak
:func:`socket.gethostname` or even
``socket.gethostbyaddr(socket.gethostname())``.
- Availability: recent flavors of Unix.
+ .. availability:: recent flavors of Unix.
.. versionchanged:: 3.3
Return type changed from a tuple to a tuple-like object
calls to :func:`unsetenv` don't update ``os.environ``, so it is actually
preferable to delete items of ``os.environ``.
- Availability: most flavors of Unix, Windows.
+ .. availability:: most flavors of Unix, Windows.
.. _os-newstreams:
docs for :func:`chmod` for possible values of *mode*. As of Python 3.3, this
is equivalent to ``os.chmod(fd, mode)``.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: fchown(fd, uid, gid)
:func:`chown`. As of Python 3.3, this is equivalent to ``os.chown(fd, uid,
gid)``.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: fdatasync(fd)
Force write of file with filedescriptor *fd* to disk. Does not force update of
metadata.
- Availability: Unix.
+ .. availability:: Unix.
.. note::
This function is not available on MacOS.
As of Python 3.3, this is equivalent to ``os.pathconf(fd, name)``.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: fstat(fd)
file descriptor *fd*, like :func:`statvfs`. As of Python 3.3, this is
equivalent to ``os.statvfs(fd)``.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: fsync(fd)
``f.flush()``, and then do ``os.fsync(f.fileno())``, to ensure that all internal
buffers associated with *f* are written to disk.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. function:: ftruncate(fd, length)
most *length* bytes in size. As of Python 3.3, this is equivalent to
``os.truncate(fd, length)``.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. versionchanged:: 3.5
Added support for Windows
See also :func:`set_blocking` and :meth:`socket.socket.setblocking`.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.5
:data:`F_ULOCK` or :data:`F_TEST`.
*len* specifies the section of the file to lock.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Flags that specify what action :func:`lockf` will take.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
descriptors are :ref:`non-inheritable <fd_inheritance>`. For a (slightly) more
portable approach, use the :mod:`pty` module.
- Availability: some flavors of Unix.
+ .. availability:: some flavors of Unix.
.. versionchanged:: 3.4
The new file descriptors are now non-inheritable.
reading and writing, respectively. The new file descriptor is
:ref:`non-inheritable <fd_inheritance>`.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. versionchanged:: 3.4
The new file descriptors are now non-inheritable.
Return a pair of file descriptors ``(r, w)`` usable for reading and writing,
respectively.
- Availability: some flavors of Unix.
+ .. availability:: some flavors of Unix.
.. versionadded:: 3.3
Ensures that enough disk space is allocated for the file specified by *fd*
starting from *offset* and continuing for *len* bytes.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
:data:`POSIX_FADV_RANDOM`, :data:`POSIX_FADV_NOREUSE`,
:data:`POSIX_FADV_WILLNEED` or :data:`POSIX_FADV_DONTNEED`.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Flags that can be used in *advice* in :func:`posix_fadvise` that specify
the access pattern that is likely to be used.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Return a bytestring containing the bytes read. If the end of the file
referred to by *fd* has been reached, an empty bytes object is returned.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Combine the functionality of :func:`os.readv` and :func:`os.pread`.
- Availability: Linux 2.6.30 and newer, FreeBSD 6.0 and newer,
- OpenBSD 2.7 and newer. Using flags requires Linux 4.6 or newer.
+ .. availability:: Linux 2.6.30 and newer, FreeBSD 6.0 and newer,
+ OpenBSD 2.7 and newer. Using flags requires Linux 4.6 or newer.
.. versionadded:: 3.7
If no bytes were read, it will return ``-1`` and set errno to
:data:`errno.EAGAIN`.
- Availability: Linux 4.14 and newer.
+ .. availability:: Linux 4.14 and newer.
.. versionadded:: 3.7
Currently, on Linux, this feature is usable only on a file descriptor opened
using the :data:`O_DIRECT` flag.
- Availability: Linux 4.6 and newer.
+ .. availability:: Linux 4.6 and newer.
.. versionadded:: 3.7
Return the number of bytes actually written.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Combine the functionality of :func:`os.writev` and :func:`os.pwrite`.
- Availability: Linux 2.6.30 and newer, FreeBSD 6.0 and newer,
- OpenBSD 2.7 and newer. Using flags requires Linux 4.7 or newer.
+ .. availability:: Linux 2.6.30 and newer, FreeBSD 6.0 and newer,
+ OpenBSD 2.7 and newer. Using flags requires Linux 4.7 or newer.
.. versionadded:: 3.7
Provide a per-write equivalent of the :data:`O_DSYNC` ``open(2)`` flag. This
flag effect applies only to the data range written by the system call.
- Availability: Linux 4.7 and newer.
+ .. availability:: Linux 4.7 and newer.
.. versionadded:: 3.7
Provide a per-write equivalent of the :data:`O_SYNC` ``open(2)`` flag. This
flag effect applies only to the data range written by the system call.
- Availability: Linux 4.7 and newer.
+ .. availability:: Linux 4.7 and newer.
.. versionadded:: 3.7
Cross-platform applications should not use *headers*, *trailers* and *flags*
arguments.
- Availability: Unix.
+ .. availability:: Unix.
.. note::
See also :func:`get_blocking` and :meth:`socket.socket.setblocking`.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.5
Parameters to the :func:`sendfile` function, if the implementation supports
them.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
The operating system may set a limit (:func:`sysconf` value
``'SC_IOV_MAX'``) on the number of buffers that can be used.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Return the process group associated with the terminal given by *fd* (an open
file descriptor as returned by :func:`os.open`).
- Availability: Unix.
+ .. availability:: Unix.
.. function:: tcsetpgrp(fd, pg)
Set the process group associated with the terminal given by *fd* (an open file
descriptor as returned by :func:`os.open`) to *pg*.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: ttyname(fd)
file descriptor *fd*. If *fd* is not associated with a terminal device, an
exception is raised.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: write(fd, str)
The operating system may set a limit (:func:`sysconf` value
``'SC_IOV_MAX'``) on the number of buffers that can be used.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
should normally be used, ``os.get_terminal_size`` is the low-level
implementation.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. class:: terminal_size
Get the "inheritable" flag of the specified handle (a boolean).
- Availability: Windows.
+ .. availability:: Windows.
.. function:: set_handle_inheritable(handle, inheritable)
Set the "inheritable" flag of the specified handle.
- Availability: Windows.
+ .. availability:: Windows.
.. _os-file-dir:
This function can support :ref:`not following symlinks <follow_symlinks>`.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
The *follow_symlinks* argument.
See :func:`shutil.chown` for a higher-level function that accepts names in
addition to numeric ids.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Added support for specifying an open file descriptor for *path*,
Change the root directory of the current process to *path*.
- Availability: Unix.
+ .. availability:: Unix.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
descriptor *fd*. The descriptor must refer to an opened directory, not an
open file. As of Python 3.3, this is equivalent to ``os.chdir(fd)``.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: getcwd()
not follow symbolic links. As of Python 3.3, this is equivalent to
``os.chflags(path, flags, follow_symlinks=False)``.
- Availability: Unix.
+ .. availability:: Unix.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
for possible values of *mode*. As of Python 3.3, this is equivalent to
``os.chmod(path, mode, follow_symlinks=False)``.
- Availability: Unix.
+ .. availability:: Unix.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
function will not follow symbolic links. As of Python 3.3, this is equivalent
to ``os.chown(path, uid, gid, follow_symlinks=False)``.
- Availability: Unix.
+ .. availability:: Unix.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
supply :ref:`paths relative to directory descriptors <dir_fd>`, and :ref:`not
following symlinks <follow_symlinks>`.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. versionchanged:: 3.2
Added Windows support.
FIFO for reading, and the client opens it for writing. Note that :func:`mkfifo`
doesn't open the FIFO --- it just creates the rendezvous point.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
The *dir_fd* argument.
This function can also support :ref:`paths relative to directory descriptors
<dir_fd>`.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
The *dir_fd* argument.
This function can support :ref:`specifying a file descriptor
<path_fd>`.
- Availability: Unix.
+ .. availability:: Unix.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
the integer values defined for those names by the host operating system. This
can be used to determine the set of names known to the system.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: readlink(path, *, dir_fd=None)
This function can also support :ref:`paths relative to directory descriptors
<dir_fd>`.
- Availability: Unix, Windows
+ .. availability:: Unix, Windows.
.. versionchanged:: 3.2
Added support for Windows 6.0 (Vista) symbolic links.
This function can support :ref:`specifying a file descriptor <path_fd>`.
- Availability: Unix.
+ .. availability:: Unix.
.. versionchanged:: 3.2
The :const:`ST_RDONLY` and :const:`ST_NOSUID` constants were added.
morph to the target dynamically. If the target is present, the type of the
symlink will be created to match. Otherwise, the symlink will be created
as a directory if *target_is_directory* is ``True`` or a file symlink (the
- default) otherwise. On non-Window platforms, *target_is_directory* is ignored.
+ default) otherwise. On non-Windows platforms, *target_is_directory* is ignored.
Symbolic link support was introduced in Windows 6.0 (Vista). :func:`symlink`
will raise a :exc:`NotImplementedError` on Windows versions earlier than 6.0.
:exc:`OSError` is raised when the function is called by an unprivileged
user.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. versionchanged:: 3.2
Added support for Windows 6.0 (Vista) symbolic links.
Force write of everything to disk.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
This function can support :ref:`specifying a file descriptor <path_fd>`.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. versionadded:: 3.3
for name in dirs:
os.rmdir(name, dir_fd=rootfd)
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
you can check whether or not it is available using :data:`os.supports_fd`.
If it is unavailable, using it will raise a :exc:`NotImplementedError`.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. versionadded:: 3.3
Added support for specifying an open file descriptor for *path*
Exit code that means no error occurred.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_USAGE
Exit code that means the command was used incorrectly, such as when the wrong
number of arguments are given.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_DATAERR
Exit code that means the input data was incorrect.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_NOINPUT
Exit code that means an input file did not exist or was not readable.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_NOUSER
Exit code that means a specified user did not exist.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_NOHOST
Exit code that means a specified host did not exist.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_UNAVAILABLE
Exit code that means that a required service is unavailable.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_SOFTWARE
Exit code that means an internal software error was detected.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_OSERR
Exit code that means an operating system error was detected, such as the
inability to fork or create a pipe.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_OSFILE
Exit code that means some system file did not exist, could not be opened, or had
some other kind of error.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_CANTCREAT
Exit code that means a user specified output file could not be created.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_IOERR
Exit code that means that an error occurred while doing I/O on some file.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_TEMPFAIL
that may not really be an error, such as a network connection that couldn't be
made during a retryable operation.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_PROTOCOL
Exit code that means that a protocol exchange was illegal, invalid, or not
understood.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_NOPERM
Exit code that means that there were insufficient permissions to perform the
operation (but not intended for file system problems).
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_CONFIG
Exit code that means that some kind of configuration error occurred.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: EX_NOTFOUND
Exit code that means something like "an entry was not found".
- Availability: Unix.
+ .. availability:: Unix.
.. function:: fork()
See :mod:`ssl` for applications that use the SSL module with fork().
- Availability: Unix.
+ .. availability:: Unix.
.. function:: forkpty()
master end of the pseudo-terminal. For a more portable approach, use the
:mod:`pty` module. If an error occurs :exc:`OSError` is raised.
- Availability: some flavors of Unix.
+ .. availability:: some flavors of Unix.
.. function:: kill(pid, sig)
Send the signal *sig* to the process group *pgid*.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: nice(increment)
Add *increment* to the process's "niceness". Return the new niceness.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: plock(op)
Lock program segments into memory. The value of *op* (defined in
``<sys/lock.h>``) determines which segments are locked.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: popen(cmd, mode='r', buffering=-1)
There is no way to unregister a function.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.7
L = ['cp', 'index.html', '/dev/null']
os.spawnvpe(os.P_WAIT, 'cp', L, os.environ)
- Availability: Unix, Windows. :func:`spawnlp`, :func:`spawnlpe`, :func:`spawnvp`
- and :func:`spawnvpe` are not available on Windows. :func:`spawnle` and
- :func:`spawnve` are not thread-safe on Windows; we advise you to use the
- :mod:`subprocess` module instead.
+ .. availability:: Unix, Windows. :func:`spawnlp`, :func:`spawnlpe`, :func:`spawnvp`
+ and :func:`spawnvpe` are not available on Windows. :func:`spawnle` and
+ :func:`spawnve` are not thread-safe on Windows; we advise you to use the
+ :mod:`subprocess` module instead.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
will return as soon as the new process has been created, with the process id as
the return value.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. data:: P_WAIT
of the process the run is successful, or ``-signal`` if a signal kills the
process.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. data:: P_DETACH
console of the calling process. If :const:`P_OVERLAY` is used, the current
process will be replaced; the :func:`spawn\* <spawnl>` function will not return.
- Availability: Windows.
+ .. availability:: Windows.
.. function:: startfile(path[, operation])
function is not resolved until this function is first called. If the function
cannot be resolved, :exc:`NotImplementedError` will be raised.
- Availability: Windows.
+ .. availability:: Windows.
.. function:: system(command)
to using this function. See the :ref:`subprocess-replacements` section in
the :mod:`subprocess` documentation for some helpful recipes.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. function:: times()
On Windows, only :attr:`user` and :attr:`system` are known; the other
attributes are zero.
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. versionchanged:: 3.3
Return type changed from a tuple to a tuple-like object
number is zero); the high bit of the low byte is set if a core file was
produced.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: waitid(idtype, id, options)
:attr:`si_code` or ``None`` if :data:`WNOHANG` is specified and there are no
children in a waitable state.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
These are the possible values for *idtype* in :func:`waitid`. They affect
how *id* is interpreted.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Flags that can be used in *options* in :func:`waitid` that specify what
child signal to wait for.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
These are the possible values for :attr:`si_code` in the result returned by
:func:`waitid`.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
.. function:: wait3(options)
Similar to :func:`waitpid`, except no process id argument is given and a
- 3-element tuple containing the child's process id, exit status indication, and
- resource usage information is returned. Refer to :mod:`resource`.\
- :func:`~resource.getrusage` for details on resource usage information. The
- option argument is the same as that provided to :func:`waitpid` and
- :func:`wait4`.
+ 3-element tuple containing the child's process id, exit status indication,
+ and resource usage information is returned. Refer to
+ :mod:`resource`.\ :func:`~resource.getrusage` for details on resource usage
+ information. The option argument is the same as that provided to
+ :func:`waitpid` and :func:`wait4`.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: wait4(pid, options)
resource usage information. The arguments to :func:`wait4` are the same
as those provided to :func:`waitpid`.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: WNOHANG
The option for :func:`waitpid` to return immediately if no child process status
is available immediately. The function returns ``(0, 0)`` in this case.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: WCONTINUED
This option causes child processes to be reported if they have been continued
from a job control stop since their status was last reported.
- Availability: some Unix systems.
+ .. availability:: some Unix systems.
.. data:: WUNTRACED
This option causes child processes to be reported if they have been stopped but
their current state has not been reported since they were stopped.
- Availability: Unix.
+ .. availability:: Unix.
The following functions take a process status code as returned by
Return ``True`` if a core dump was generated for the process, otherwise
return ``False``.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: WIFCONTINUED(status)
Return ``True`` if the process has been continued from a job control stop,
otherwise return ``False``.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: WIFSTOPPED(status)
Return ``True`` if the process has been stopped, otherwise return
``False``.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: WIFSIGNALED(status)
Return ``True`` if the process exited due to a signal, otherwise return
``False``.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: WIFEXITED(status)
Return ``True`` if the process exited using the :manpage:`exit(2)` system call,
otherwise return ``False``.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: WEXITSTATUS(status)
If ``WIFEXITED(status)`` is true, return the integer parameter to the
:manpage:`exit(2)` system call. Otherwise, the return value is meaningless.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: WSTOPSIG(status)
Return the signal which caused the process to stop.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: WTERMSIG(status)
Return the signal which caused the process to exit.
- Availability: Unix.
+ .. availability:: Unix.
Interface to the scheduler
included in ``confstr_names``, an :exc:`OSError` is raised with
:const:`errno.EINVAL` for the error number.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: confstr_names
defined for those names by the host operating system. This can be used to
determine the set of names known to the system.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: cpu_count()
1, 5, and 15 minutes or raises :exc:`OSError` if the load average was
unobtainable.
- Availability: Unix.
+ .. availability:: Unix.
.. function:: sysconf(name)
the *name* parameter for :func:`confstr` apply here as well; the dictionary that
provides information on the known names is given by ``sysconf_names``.
- Availability: Unix.
+ .. availability:: Unix.
.. data:: sysconf_names
defined for those names by the host operating system. This can be used to
determine the set of names known to the system.
- Availability: Unix.
+ .. availability:: Unix.
The following data values are used to support path manipulation operations. These
are defined for all platforms.
Higher-level operations on pathnames are defined in the :mod:`os.path` module.
+.. index:: single: . (dot); in pathnames
.. data:: curdir
The constant string used by the operating system to refer to the current
:mod:`os.path`.
+.. index:: single: ..; in pathnames
.. data:: pardir
The constant string used by the operating system to refer to the parent
:mod:`os.path`.
+.. index:: single: / (slash); in pathnames
+.. index:: single: \ (backslash); in pathnames (Windows)
.. data:: sep
The character used by the operating system to separate pathname components.
useful. Also available via :mod:`os.path`.
+.. index:: single: / (slash); in pathnames
.. data:: altsep
An alternative character used by the operating system to separate pathname
:mod:`os.path`.
+.. index:: single: . (dot); in pathnames
.. data:: extsep
The character which separates the base filename from the extension; for example,
the ``'.'`` in :file:`os.py`. Also available via :mod:`os.path`.
+.. index:: single: : (colon); path separator (POSIX)
+ single: ; (semicolon)
.. data:: pathsep
The character conventionally used by the operating system to separate search
See also the `Linux getrandom() manual page
<http://man7.org/linux/man-pages/man2/getrandom.2.html>`_.
- Availability: Linux 3.17 and newer.
+ .. availability:: Linux 3.17 and newer.
.. versionadded:: 3.6
number of bytes written. If the audio device is in blocking mode (the
default), the entire data is always written (again, this is different from
usual Unix device semantics). If the device is in non-blocking mode, some
- data may not be written
- ---see :meth:`writeall`.
+ data may not be written---see :meth:`writeall`.
.. versionchanged:: 3.5
Writable :term:`bytes-like object` is now accepted.
:file:`.pyc` files, the Python implementers reserve the right to change the
serialization format in non-backwards compatible ways should the need arise.
The :mod:`pickle` serialization format is guaranteed to be backwards compatible
- across Python releases.
+ across Python releases provided a compatible pickle protocol is chosen and
+ pickling and unpickling code deals with Python 2 to Python 3 type differences
+ if your data is crossing that unique breaking change language boundary.
Comparison with ``json``
^^^^^^^^^^^^^^^^^^^^^^^^
*errors* tell pickle how to decode 8-bit string instances pickled by Python
2; these default to 'ASCII' and 'strict', respectively. The *encoding* can
be 'bytes' to read these 8-bit string instances as bytes objects.
+ Using ``encoding='latin1'`` is required for unpickling NumPy arrays and
+ instances of :class:`~datetime.datetime`, :class:`~datetime.date` and
+ :class:`~datetime.time` pickled by Python 2.
.. function:: loads(bytes_object, \*, fix_imports=True, encoding="ASCII", errors="strict")
*errors* tell pickle how to decode 8-bit string instances pickled by Python
2; these default to 'ASCII' and 'strict', respectively. The *encoding* can
be 'bytes' to read these 8-bit string instances as bytes objects.
+ Using ``encoding='latin1'`` is required for unpickling NumPy arrays and
+ instances of :class:`~datetime.datetime`, :class:`~datetime.date` and
+ :class:`~datetime.time` pickled by Python 2.
The :mod:`pickle` module defines three exceptions:
.. First the implementation class:
+.. index:: single: ...; placeholder
+
.. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, \
compact=False)
>>> import json
>>> import pprint
>>> from urllib.request import urlopen
- >>> with urlopen('http://pypi.org/project/Twisted/json') as url:
- ... http_info = url.info()
- ... raw_data = url.read().decode(http_info.get_content_charset())
- >>> project_info = json.loads(raw_data)
+ >>> with urlopen('https://pypi.org/pypi/sampleproject/json') as resp:
+ ... project_info = json.load(resp)['info']
In its basic form, :func:`pprint` shows the whole object::
>>> pprint.pprint(project_info)
- {'info': {'_pypi_hidden': False,
- '_pypi_ordering': 125,
- 'author': 'Glyph Lefkowitz',
- 'author_email': 'glyph@twistedmatrix.com',
- 'bugtrack_url': '',
- 'cheesecake_code_kwalitee_id': None,
- 'cheesecake_documentation_id': None,
- 'cheesecake_installability_id': None,
- 'classifiers': ['Programming Language :: Python :: 2.6',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 2 :: Only'],
- 'description': 'An extensible framework for Python programming, with '
- 'special focus\r\n'
- 'on event-based network programming and multiprotocol '
- 'integration.',
- 'docs_url': '',
- 'download_url': 'UNKNOWN',
- 'home_page': 'http://twistedmatrix.com/',
- 'keywords': '',
- 'license': 'MIT',
- 'maintainer': '',
- 'maintainer_email': '',
- 'name': 'Twisted',
- 'package_url': 'http://pypi.org/project/Twisted',
- 'platform': 'UNKNOWN',
- 'release_url': 'http://pypi.org/project/Twisted/12.3.0',
- 'requires_python': None,
- 'stable_version': None,
- 'summary': 'An asynchronous networking framework written in Python',
- 'version': '12.3.0'},
- 'urls': [{'comment_text': '',
- 'downloads': 71844,
- 'filename': 'Twisted-12.3.0.tar.bz2',
- 'has_sig': False,
- 'md5_digest': '6e289825f3bf5591cfd670874cc0862d',
- 'packagetype': 'sdist',
- 'python_version': 'source',
- 'size': 2615733,
- 'upload_time': '2012-12-26T12:47:03',
- 'url': 'https://pypi.org/packages/source/T/Twisted/Twisted-12.3.0.tar.bz2'},
- {'comment_text': '',
- 'downloads': 5224,
- 'filename': 'Twisted-12.3.0.win32-py2.7.msi',
- 'has_sig': False,
- 'md5_digest': '6b778f5201b622a5519a2aca1a2fe512',
- 'packagetype': 'bdist_msi',
- 'python_version': '2.7',
- 'size': 2916352,
- 'upload_time': '2012-12-26T12:48:15',
- 'url': 'https://pypi.org/packages/2.7/T/Twisted/Twisted-12.3.0.win32-py2.7.msi'}]}
+ {'author': 'The Python Packaging Authority',
+ 'author_email': 'pypa-dev@googlegroups.com',
+ 'bugtrack_url': None,
+ 'classifiers': ['Development Status :: 3 - Alpha',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: MIT License',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.2',
+ 'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: 3.4',
+ 'Topic :: Software Development :: Build Tools'],
+ 'description': 'A sample Python project\n'
+ '=======================\n'
+ '\n'
+ 'This is the description file for the project.\n'
+ '\n'
+ 'The file should use UTF-8 encoding and be written using '
+ 'ReStructured Text. It\n'
+ 'will be used to generate the project webpage on PyPI, and '
+ 'should be written for\n'
+ 'that purpose.\n'
+ '\n'
+ 'Typical contents for this file would include an overview of '
+ 'the project, basic\n'
+ 'usage examples, etc. Generally, including the project '
+ 'changelog in here is not\n'
+ 'a good idea, although a simple "What\'s New" section for the '
+ 'most recent version\n'
+ 'may be appropriate.',
+ 'description_content_type': None,
+ 'docs_url': None,
+ 'download_url': 'UNKNOWN',
+ 'downloads': {'last_day': -1, 'last_month': -1, 'last_week': -1},
+ 'home_page': 'https://github.com/pypa/sampleproject',
+ 'keywords': 'sample setuptools development',
+ 'license': 'MIT',
+ 'maintainer': None,
+ 'maintainer_email': None,
+ 'name': 'sampleproject',
+ 'package_url': 'https://pypi.org/project/sampleproject/',
+ 'platform': 'UNKNOWN',
+ 'project_url': 'https://pypi.org/project/sampleproject/',
+ 'project_urls': {'Download': 'UNKNOWN',
+ 'Homepage': 'https://github.com/pypa/sampleproject'},
+ 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
+ 'requires_dist': None,
+ 'requires_python': None,
+ 'summary': 'A sample Python project',
+ 'version': '1.2.0'}
The result can be limited to a certain *depth* (ellipsis is used for deeper
contents)::
- >>> pprint.pprint(project_info, depth=2)
- {'info': {'_pypi_hidden': False,
- '_pypi_ordering': 125,
- 'author': 'Glyph Lefkowitz',
- 'author_email': 'glyph@twistedmatrix.com',
- 'bugtrack_url': '',
- 'cheesecake_code_kwalitee_id': None,
- 'cheesecake_documentation_id': None,
- 'cheesecake_installability_id': None,
- 'classifiers': [...],
- 'description': 'An extensible framework for Python programming, with '
- 'special focus\r\n'
- 'on event-based network programming and multiprotocol '
- 'integration.',
- 'docs_url': '',
- 'download_url': 'UNKNOWN',
- 'home_page': 'http://twistedmatrix.com/',
- 'keywords': '',
- 'license': 'MIT',
- 'maintainer': '',
- 'maintainer_email': '',
- 'name': 'Twisted',
- 'package_url': 'http://pypi.org/project/Twisted',
- 'platform': 'UNKNOWN',
- 'release_url': 'http://pypi.org/project/Twisted/12.3.0',
- 'requires_python': None,
- 'stable_version': None,
- 'summary': 'An asynchronous networking framework written in Python',
- 'version': '12.3.0'},
- 'urls': [{...}, {...}]}
+ >>> pprint.pprint(project_info, depth=1)
+ {'author': 'The Python Packaging Authority',
+ 'author_email': 'pypa-dev@googlegroups.com',
+ 'bugtrack_url': None,
+ 'classifiers': [...],
+ 'description': 'A sample Python project\n'
+ '=======================\n'
+ '\n'
+ 'This is the description file for the project.\n'
+ '\n'
+ 'The file should use UTF-8 encoding and be written using '
+ 'ReStructured Text. It\n'
+ 'will be used to generate the project webpage on PyPI, and '
+ 'should be written for\n'
+ 'that purpose.\n'
+ '\n'
+ 'Typical contents for this file would include an overview of '
+ 'the project, basic\n'
+ 'usage examples, etc. Generally, including the project '
+ 'changelog in here is not\n'
+ 'a good idea, although a simple "What\'s New" section for the '
+ 'most recent version\n'
+ 'may be appropriate.',
+ 'description_content_type': None,
+ 'docs_url': None,
+ 'download_url': 'UNKNOWN',
+ 'downloads': {...},
+ 'home_page': 'https://github.com/pypa/sampleproject',
+ 'keywords': 'sample setuptools development',
+ 'license': 'MIT',
+ 'maintainer': None,
+ 'maintainer_email': None,
+ 'name': 'sampleproject',
+ 'package_url': 'https://pypi.org/project/sampleproject/',
+ 'platform': 'UNKNOWN',
+ 'project_url': 'https://pypi.org/project/sampleproject/',
+ 'project_urls': {...},
+ 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
+ 'requires_dist': None,
+ 'requires_python': None,
+ 'summary': 'A sample Python project',
+ 'version': '1.2.0'}
Additionally, maximum character *width* can be suggested. If a long object
cannot be split, the specified width will be exceeded::
- >>> pprint.pprint(project_info, depth=2, width=50)
- {'info': {'_pypi_hidden': False,
- '_pypi_ordering': 125,
- 'author': 'Glyph Lefkowitz',
- 'author_email': 'glyph@twistedmatrix.com',
- 'bugtrack_url': '',
- 'cheesecake_code_kwalitee_id': None,
- 'cheesecake_documentation_id': None,
- 'cheesecake_installability_id': None,
- 'classifiers': [...],
- 'description': 'An extensible '
- 'framework for Python '
- 'programming, with '
- 'special focus\r\n'
- 'on event-based network '
- 'programming and '
- 'multiprotocol '
- 'integration.',
- 'docs_url': '',
- 'download_url': 'UNKNOWN',
- 'home_page': 'http://twistedmatrix.com/',
- 'keywords': '',
- 'license': 'MIT',
- 'maintainer': '',
- 'maintainer_email': '',
- 'name': 'Twisted',
- 'package_url': 'http://pypi.org/project/Twisted',
- 'platform': 'UNKNOWN',
- 'release_url': 'http://pypi.org/project/Twisted/12.3.0',
- 'requires_python': None,
- 'stable_version': None,
- 'summary': 'An asynchronous networking '
- 'framework written in '
- 'Python',
- 'version': '12.3.0'},
- 'urls': [{...}, {...}]}
+ >>> pprint.pprint(project_info, depth=1, width=60)
+ {'author': 'The Python Packaging Authority',
+ 'author_email': 'pypa-dev@googlegroups.com',
+ 'bugtrack_url': None,
+ 'classifiers': [...],
+ 'description': 'A sample Python project\n'
+ '=======================\n'
+ '\n'
+ 'This is the description file for the '
+ 'project.\n'
+ '\n'
+ 'The file should use UTF-8 encoding and be '
+ 'written using ReStructured Text. It\n'
+ 'will be used to generate the project '
+ 'webpage on PyPI, and should be written '
+ 'for\n'
+ 'that purpose.\n'
+ '\n'
+ 'Typical contents for this file would '
+ 'include an overview of the project, '
+ 'basic\n'
+ 'usage examples, etc. Generally, including '
+ 'the project changelog in here is not\n'
+ 'a good idea, although a simple "What\'s '
+ 'New" section for the most recent version\n'
+ 'may be appropriate.',
+ 'description_content_type': None,
+ 'docs_url': None,
+ 'download_url': 'UNKNOWN',
+ 'downloads': {...},
+ 'home_page': 'https://github.com/pypa/sampleproject',
+ 'keywords': 'sample setuptools development',
+ 'license': 'MIT',
+ 'maintainer': None,
+ 'maintainer_email': None,
+ 'name': 'sampleproject',
+ 'package_url': 'https://pypi.org/project/sampleproject/',
+ 'platform': 'UNKNOWN',
+ 'project_url': 'https://pypi.org/project/sampleproject/',
+ 'project_urls': {...},
+ 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
+ 'requires_dist': None,
+ 'requires_python': None,
+ 'summary': 'A sample Python project',
+ 'version': '1.2.0'}
level of the current interpreter.
*invalidation_mode* should be a member of the :class:`PycInvalidationMode`
- enum and controls how the generated ``.pyc`` files are invalidated at
- runtime. If the :envvar:`SOURCE_DATE_EPOCH` environment variable is set,
- *invalidation_mode* will be forced to
- :attr:`PycInvalidationMode.CHECKED_HASH`.
+ enum and controls how the generated bytecode cache is invalidated at
+ runtime. The default is :attr:`PycInvalidationMode.CHECKED_HASH` if
+ the :envvar:`SOURCE_DATE_EPOCH` environment variable is set, otherwise
+ the default is :attr:`PycInvalidationMode.TIMESTAMP`.
.. versionchanged:: 3.2
Changed default value of *cfile* to be :PEP:`3147`-compliant. Previous
*invalidation_mode* will be forced to
:attr:`PycInvalidationMode.CHECKED_HASH`.
+ .. versionchanged:: 3.7.2
+ The :envvar:`SOURCE_DATE_EPOCH` environment variable no longer
+ overrides the value of the *invalidation_mode* argument, and determines
+ its default value instead.
+
.. class:: PycInvalidationMode
within a thread.
In addition, the module implements a "simple"
-:abbr:`FIFO (first-in, first-out)` queue type where
-specific implementations can provide additional guarantees
+:abbr:`FIFO (first-in, first-out)` queue type, :class:`SimpleQueue`, whose
+specific implementation provides additional guarantees
in exchange for the smaller functionality.
The :mod:`queue` module defines the following classes and exceptions:
The special characters are:
+.. index:: single: . (dot); in regular expressions
+
``.``
(Dot.) In the default mode, this matches any character except a newline. If
the :const:`DOTALL` flag has been specified, this matches any character
including a newline.
+.. index:: single: ^ (caret); in regular expressions
+
``^``
(Caret.) Matches the start of the string, and in :const:`MULTILINE` mode also
matches immediately after each newline.
+.. index:: single: $ (dollar); in regular expressions
+
``$``
Matches the end of the string or just before the newline at the end of the
string, and in :const:`MULTILINE` mode also matches before a newline. ``foo``
a single ``$`` in ``'foo\n'`` will find two (empty) matches: one just before
the newline, and one at the end of the string.
+.. index:: single: * (asterisk); in regular expressions
+
``*``
Causes the resulting RE to match 0 or more repetitions of the preceding RE, as
many repetitions as are possible. ``ab*`` will match 'a', 'ab', or 'a' followed
by any number of 'b's.
+.. index:: single: + (plus); in regular expressions
+
``+``
Causes the resulting RE to match 1 or more repetitions of the preceding RE.
``ab+`` will match 'a' followed by any non-zero number of 'b's; it will not
match just 'a'.
+.. index:: single: ? (question mark); in regular expressions
+
``?``
Causes the resulting RE to match 0 or 1 repetitions of the preceding RE.
``ab?`` will match either 'a' or 'ab'.
+.. index::
+ single: *?; in regular expressions
+ single: +?; in regular expressions
+ single: ??; in regular expressions
+
``*?``, ``+?``, ``??``
The ``'*'``, ``'+'``, and ``'?'`` qualifiers are all :dfn:`greedy`; they match
as much text as possible. Sometimes this behaviour isn't desired; if the RE
characters as possible will be matched. Using the RE ``<.*?>`` will match
only ``'<a>'``.
+.. index::
+ single: {} (curly brackets); in regular expressions
+
``{m}``
Specifies that exactly *m* copies of the previous RE should be matched; fewer
matches cause the entire RE not to match. For example, ``a{6}`` will match
6-character string ``'aaaaaa'``, ``a{3,5}`` will match 5 ``'a'`` characters,
while ``a{3,5}?`` will only match 3 characters.
+.. index:: single: \ (backslash); in regular expressions
+
``\``
Either escapes special characters (permitting you to match characters like
``'*'``, ``'?'``, and so forth), or signals a special sequence; special
is complicated and hard to understand, so it's highly recommended that you use
raw strings for all but the simplest expressions.
+.. index::
+ single: [] (square brackets); in regular expressions
+
``[]``
Used to indicate a set of characters. In a set:
* Characters can be listed individually, e.g. ``[amk]`` will match ``'a'``,
``'m'``, or ``'k'``.
+ .. index:: single: - (minus); in regular expressions
+
* Ranges of characters can be indicated by giving two characters and separating
them by a ``'-'``, for example ``[a-z]`` will match any lowercase ASCII letter,
``[0-5][0-9]`` will match all the two-digits numbers from ``00`` to ``59``, and
``[(+*)]`` will match any of the literal characters ``'('``, ``'+'``,
``'*'``, or ``')'``.
+ .. index:: single: \ (backslash); in regular expressions
+
* Character classes such as ``\w`` or ``\S`` (defined below) are also accepted
inside a set, although the characters they match depends on whether
:const:`ASCII` or :const:`LOCALE` mode is in force.
+ .. index:: single: ^ (caret); in regular expressions
+
* Characters that are not within a range can be matched by :dfn:`complementing`
the set. If the first character of the set is ``'^'``, all the characters
that are *not* in the set will be matched. For example, ``[^5]`` will match
place it at the beginning of the set. For example, both ``[()[\]{}]`` and
``[]()[{}]`` will both match a parenthesis.
+ .. .. index:: single: --; in regular expressions
+ .. .. index:: single: &&; in regular expressions
+ .. .. index:: single: ~~; in regular expressions
+ .. .. index:: single: ||; in regular expressions
+
* Support of nested sets and set operations as in `Unicode Technical
Standard #18`_ might be added in the future. This would change the
syntax, so to facilitate this change a :exc:`FutureWarning` will be raised
:exc:`FutureWarning` is raised if a character set contains constructs
that will change semantically in the future.
+.. index:: single: | (vertical bar); in regular expressions
+
``|``
``A|B``, where *A* and *B* can be arbitrary REs, creates a regular expression that
will match either *A* or *B*. An arbitrary number of REs can be separated by the
greedy. To match a literal ``'|'``, use ``\|``, or enclose it inside a
character class, as in ``[|]``.
+.. index::
+ single: () (parentheses); in regular expressions
+
``(...)``
Matches whatever regular expression is inside the parentheses, and indicates the
start and end of a group; the contents of a group can be retrieved after a match
special sequence, described below. To match the literals ``'('`` or ``')'``,
use ``\(`` or ``\)``, or enclose them inside a character class: ``[(]``, ``[)]``.
+.. index:: single: (?; in regular expressions
+
``(?...)``
This is an extension notation (a ``'?'`` following a ``'('`` is not meaningful
otherwise). The first character after the ``'?'`` determines what the meaning
:func:`re.compile` function. Flags should be used first in the
expression string.
+.. index:: single: (?:; in regular expressions
+
``(?:...)``
A non-capturing version of regular parentheses. Matches whatever regular
expression is inside the parentheses, but the substring matched by the group
.. versionchanged:: 3.7
The letters ``'a'``, ``'L'`` and ``'u'`` also can be used in a group.
+.. index:: single: (?P<; in regular expressions
+
``(?P<name>...)``
Similar to regular parentheses, but the substring matched by the group is
accessible via the symbolic group name *name*. Group names must be valid
| | * ``\1`` |
+---------------------------------------+----------------------------------+
+.. index:: single: (?P=; in regular expressions
+
``(?P=name)``
A backreference to a named group; it matches whatever text was matched by the
earlier group named *name*.
+.. index:: single: (?#; in regular expressions
+
``(?#...)``
A comment; the contents of the parentheses are simply ignored.
called a :dfn:`lookahead assertion`. For example, ``Isaac (?=Asimov)`` will match
``'Isaac '`` only if it's followed by ``'Asimov'``.
+.. index:: single: (?!; in regular expressions
+
``(?!...)``
Matches if ``...`` doesn't match next. This is a :dfn:`negative lookahead assertion`.
For example, ``Isaac (?!Asimov)`` will match ``'Isaac '`` only if it's *not*
followed by ``'Asimov'``.
+.. index:: single: (?<=; in regular expressions
+
``(?<=...)``
Matches if the current position in the string is preceded by a match for ``...``
that ends at the current position. This is called a :dfn:`positive lookbehind
.. versionchanged:: 3.5
Added support for group references of fixed length.
+.. index:: single: (?<!; in regular expressions
+
``(?<!...)``
Matches if the current position in the string is not preceded by a match for
``...``. This is called a :dfn:`negative lookbehind assertion`. Similar to
resulting RE will match the second character. For example, ``\$`` matches the
character ``'$'``.
+.. index:: single: \ (backslash); in regular expressions
+
``\number``
Matches the contents of the group of the same number. Groups are numbered
starting from 1. For example, ``(.+) \1`` matches ``'the the'`` or ``'55 55'``,
``'['`` and ``']'`` of a character class, all numeric escapes are treated as
characters.
+.. index:: single: \A; in regular expressions
+
``\A``
Matches only at the start of the string.
+.. index:: single: \b; in regular expressions
+
``\b``
Matches the empty string, but only at the beginning or end of a word.
A word is defined as a sequence of word characters. Note that formally,
Inside a character range, ``\b`` represents the backspace character, for
compatibility with Python's string literals.
+.. index:: single: \B; in regular expressions
+
``\B``
Matches the empty string, but only when it is *not* at the beginning or end
of a word. This means that ``r'py\B'`` matches ``'python'``, ``'py3'``,
be changed by using the :const:`ASCII` flag. Word boundaries are
determined by the current locale if the :const:`LOCALE` flag is used.
+.. index:: single: \d; in regular expressions
+
``\d``
For Unicode (str) patterns:
Matches any Unicode decimal digit (that is, any character in
For 8-bit (bytes) patterns:
Matches any decimal digit; this is equivalent to ``[0-9]``.
+.. index:: single: \D; in regular expressions
+
``\D``
Matches any character which is not a decimal digit. This is
the opposite of ``\d``. If the :const:`ASCII` flag is used this
becomes the equivalent of ``[^0-9]``.
+.. index:: single: \s; in regular expressions
+
``\s``
For Unicode (str) patterns:
Matches Unicode whitespace characters (which includes
Matches characters considered whitespace in the ASCII character set;
this is equivalent to ``[ \t\n\r\f\v]``.
+.. index:: single: \S; in regular expressions
+
``\S``
Matches any character which is not a whitespace character. This is
the opposite of ``\s``. If the :const:`ASCII` flag is used this
becomes the equivalent of ``[^ \t\n\r\f\v]``.
+.. index:: single: \w; in regular expressions
+
``\w``
For Unicode (str) patterns:
Matches Unicode word characters; this includes most characters
used, matches characters considered alphanumeric in the current locale
and the underscore.
+.. index:: single: \W; in regular expressions
+
``\W``
Matches any character which is not a word character. This is
the opposite of ``\w``. If the :const:`ASCII` flag is used this
used, matches characters considered alphanumeric in the current locale
and the underscore.
+.. index:: single: \Z; in regular expressions
+
``\Z``
Matches only at the end of the string.
+.. index::
+ single: \a; in regular expressions
+ single: \b; in regular expressions
+ single: \f; in regular expressions
+ single: \n; in regular expressions
+ single: \N; in regular expressions
+ single: \r; in regular expressions
+ single: \t; in regular expressions
+ single: \u; in regular expressions
+ single: \U; in regular expressions
+ single: \v; in regular expressions
+ single: \x; in regular expressions
+ single: \\; in regular expressions
+
Most of the standard escapes supported by Python string literals are also
accepted by the regular expression parser::
.. data:: X
VERBOSE
+ .. index:: single: # (hash); in regular expressions
+
This flag allows you to write regular expressions that look nicer and are
more readable by allowing you to visually separate logical sections of the
pattern and add comments. Whitespace within the pattern is ignored, except
when not adjacent to a previous empty match, so ``sub('x*', '-', 'abxd')`` returns
``'-a-b--d-'``.
+ .. index:: single: \g; in regular expressions
+
In string-type *repl* arguments, in addition to the character escapes and
backreferences described above,
``\g<name>`` will use the substring matched by the group named ``name``, as
import collections
import re
- Token = collections.namedtuple('Token', ['typ', 'value', 'line', 'column'])
+ Token = collections.namedtuple('Token', ['type', 'value', 'line', 'column'])
def tokenize(code):
keywords = {'IF', 'THEN', 'ENDIF', 'FOR', 'NEXT', 'GOSUB', 'RETURN'}
token_specification = [
- ('NUMBER', r'\d+(\.\d*)?'), # Integer or decimal number
- ('ASSIGN', r':='), # Assignment operator
- ('END', r';'), # Statement terminator
- ('ID', r'[A-Za-z]+'), # Identifiers
- ('OP', r'[+\-*/]'), # Arithmetic operators
- ('NEWLINE', r'\n'), # Line endings
- ('SKIP', r'[ \t]+'), # Skip over spaces and tabs
- ('MISMATCH',r'.'), # Any other character
+ ('NUMBER', r'\d+(\.\d*)?'), # Integer or decimal number
+ ('ASSIGN', r':='), # Assignment operator
+ ('END', r';'), # Statement terminator
+ ('ID', r'[A-Za-z]+'), # Identifiers
+ ('OP', r'[+\-*/]'), # Arithmetic operators
+ ('NEWLINE', r'\n'), # Line endings
+ ('SKIP', r'[ \t]+'), # Skip over spaces and tabs
+ ('MISMATCH', r'.'), # Any other character
]
tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification)
line_num = 1
line_start = 0
for mo in re.finditer(tok_regex, code):
kind = mo.lastgroup
- value = mo.group(kind)
- if kind == 'NEWLINE':
+ value = mo.group()
+ column = mo.start() - line_start
+ if kind == 'NUMBER':
+ value = float(value) if '.' in value else int(value)
+ elif kind == 'ID' and value in keywords:
+ kind = value
+ elif kind == 'NEWLINE':
line_start = mo.end()
line_num += 1
+ continue
elif kind == 'SKIP':
- pass
+ continue
elif kind == 'MISMATCH':
raise RuntimeError(f'{value!r} unexpected on line {line_num}')
- else:
- if kind == 'ID' and value in keywords:
- kind = value
- column = mo.start() - line_start
- yield Token(kind, value, line_num, column)
+ yield Token(kind, value, line_num, column)
statements = '''
IF quantity THEN
The tokenizer produces the following output::
- Token(typ='IF', value='IF', line=2, column=4)
- Token(typ='ID', value='quantity', line=2, column=7)
- Token(typ='THEN', value='THEN', line=2, column=16)
- Token(typ='ID', value='total', line=3, column=8)
- Token(typ='ASSIGN', value=':=', line=3, column=14)
- Token(typ='ID', value='total', line=3, column=17)
- Token(typ='OP', value='+', line=3, column=23)
- Token(typ='ID', value='price', line=3, column=25)
- Token(typ='OP', value='*', line=3, column=31)
- Token(typ='ID', value='quantity', line=3, column=33)
- Token(typ='END', value=';', line=3, column=41)
- Token(typ='ID', value='tax', line=4, column=8)
- Token(typ='ASSIGN', value=':=', line=4, column=12)
- Token(typ='ID', value='price', line=4, column=15)
- Token(typ='OP', value='*', line=4, column=21)
- Token(typ='NUMBER', value='0.05', line=4, column=23)
- Token(typ='END', value=';', line=4, column=27)
- Token(typ='ENDIF', value='ENDIF', line=5, column=4)
- Token(typ='END', value=';', line=5, column=9)
+ Token(type='IF', value='IF', line=2, column=4)
+ Token(type='ID', value='quantity', line=2, column=7)
+ Token(type='THEN', value='THEN', line=2, column=16)
+ Token(type='ID', value='total', line=3, column=8)
+ Token(type='ASSIGN', value=':=', line=3, column=14)
+ Token(type='ID', value='total', line=3, column=17)
+ Token(type='OP', value='+', line=3, column=23)
+ Token(type='ID', value='price', line=3, column=25)
+ Token(type='OP', value='*', line=3, column=31)
+ Token(type='ID', value='quantity', line=3, column=33)
+ Token(type='END', value=';', line=3, column=41)
+ Token(type='ID', value='tax', line=4, column=8)
+ Token(type='ASSIGN', value=':=', line=4, column=12)
+ Token(type='ID', value='price', line=4, column=15)
+ Token(type='OP', value='*', line=4, column=21)
+ Token(type='NUMBER', value=0.05, line=4, column=23)
+ Token(type='END', value=';', line=4, column=27)
+ Token(type='ENDIF', value='ENDIF', line=5, column=4)
+ Token(type='END', value=';', line=5, column=9)
.. [Frie09] Friedl, Jeffrey. Mastering Regular Expressions. 3rd ed., O'Reilly
detecting recursive calls to :meth:`__repr__` and substituting a placeholder
string instead.
+
+.. index:: single: ...; placeholder
+
.. decorator:: recursive_repr(fillvalue="...")
Decorator for :meth:`__repr__` methods to detect recursive calls within the
:exc:`PermissionError` when the user doesn't have ``CAP_SYS_RESOURCE`` for
the process.
- Availability: Linux 2.6.36 or later with glibc 2.13 or later
+ .. availability:: Linux 2.6.36 or later with glibc 2.13 or later.
.. versionadded:: 3.4
The number of bytes that can be allocated for POSIX message queues.
- Availability: Linux 2.6.8 or later.
+ .. availability:: Linux 2.6.8 or later.
.. versionadded:: 3.4
The ceiling for the process's nice level (calculated as 20 - rlim_cur).
- Availability: Linux 2.6.12 or later.
+ .. availability:: Linux 2.6.12 or later.
.. versionadded:: 3.4
The ceiling of the real-time priority.
- Availability: Linux 2.6.12 or later.
+ .. availability:: Linux 2.6.12 or later.
.. versionadded:: 3.4
The time limit (in microseconds) on CPU time that a process can spend
under real-time scheduling without making a blocking syscall.
- Availability: Linux 2.6.25 or later.
+ .. availability:: Linux 2.6.25 or later.
.. versionadded:: 3.4
The number of signals which the process may queue.
- Availability: Linux 2.6.8 or later.
+ .. availability:: Linux 2.6.8 or later.
.. versionadded:: 3.4
This limits the amount of network memory, and hence the amount of mbufs,
that this user may hold at any time.
- Availability: FreeBSD 9 or later.
+ .. availability:: FreeBSD 9 or later.
.. versionadded:: 3.4
This limit is enforced only if bit 1 of the vm.overcommit sysctl is set.
Please see :manpage:`tuning(7)` for a complete description of this sysctl.
- Availability: FreeBSD 9 or later.
+ .. availability:: FreeBSD 9 or later.
.. versionadded:: 3.4
The maximum number of pseudo-terminals created by this user id.
- Availability: FreeBSD 9 or later.
+ .. availability:: FreeBSD 9 or later.
.. versionadded:: 3.4
:func:`poll` or another interface in this module. This doesn't apply
to other kind of file-like objects such as sockets.
- This value is guaranteed by POSIX to be at least 512. Availability: Unix.
+ This value is guaranteed by POSIX to be at least 512.
+
+ .. availability:: Unix
.. versionadded:: 3.2
.. function:: copy2(src, dst, *, follow_symlinks=True)
Identical to :func:`~shutil.copy` except that :func:`copy2`
- also attempts to preserve all file metadata.
+ also attempts to preserve file metadata.
When *follow_symlinks* is false, and *src* is a symbolic
link, :func:`copy2` attempts to copy all metadata from the
.. versionadded:: 3.3
- Availability: Unix, Windows.
+ .. availability:: Unix, Windows.
.. function:: chown(path, user=None, group=None)
See also :func:`os.chown`, the underlying function.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
The signal corresponding to the :kbd:`Ctrl+C` keystroke event. This signal can
only be used with :func:`os.kill`.
- Availability: Windows.
+ .. availability:: Windows.
.. versionadded:: 3.2
The signal corresponding to the :kbd:`Ctrl+Break` keystroke event. This signal can
only be used with :func:`os.kill`.
- Availability: Windows.
+ .. availability:: Windows.
.. versionadded:: 3.2
then the number of seconds before any previously set alarm was to have been
delivered. If *time* is zero, no alarm is scheduled, and any scheduled alarm is
canceled. If the return value is zero, no alarm is currently scheduled. (See
- the Unix man page :manpage:`alarm(2)`.) Availability: Unix.
+ the Unix man page :manpage:`alarm(2)`.)
+
+ .. availability:: Unix.
.. function:: getsignal(signalnum)
If *signalnum* is 0, then no signal is sent, but error checking is still
performed; this can be used to check if the target thread is still running.
- Availability: Unix (see the man page :manpage:`pthread_kill(3)` for further
- information).
+ .. availability:: Unix (see the man page :manpage:`pthread_kill(3)` for further
+ information).
See also :func:`os.kill`.
For example, ``signal.pthread_sigmask(signal.SIG_BLOCK, [])`` reads the
signal mask of the calling thread.
- Availability: Unix. See the man page :manpage:`sigprocmask(3)` and
- :manpage:`pthread_sigmask(3)` for further information.
+ .. availability:: Unix. See the man page :manpage:`sigprocmask(3)` and
+ :manpage:`pthread_sigmask(3)` for further information.
See also :func:`pause`, :func:`sigpending` and :func:`sigwait`.
The old values are returned as a tuple: (delay, interval).
Attempting to pass an invalid interval timer will cause an
- :exc:`ItimerError`. Availability: Unix.
+ :exc:`ItimerError`.
+
+ .. availability:: Unix.
.. function:: getitimer(which)
Returns current value of a given interval timer specified by *which*.
- Availability: Unix.
+
+ .. availability:: Unix.
.. function:: set_wakeup_fd(fd, *, warn_on_full_buffer=True)
Change system call restart behaviour: if *flag* is :const:`False`, system
calls will be restarted when interrupted by signal *signalnum*, otherwise
- system calls will be interrupted. Returns nothing. Availability: Unix (see
- the man page :manpage:`siginterrupt(3)` for further information).
+ system calls will be interrupted. Returns nothing.
+
+ .. availability:: Unix (see the man page :manpage:`siginterrupt(3)`
+ for further information).
Note that installing a signal handler with :func:`signal` will reset the
restart behaviour to interruptible by implicitly calling
thread (i.e., the signals which have been raised while blocked). Return the
set of the pending signals.
- Availability: Unix (see the man page :manpage:`sigpending(2)` for further
- information).
+ .. availability:: Unix (see the man page :manpage:`sigpending(2)` for further
+ information).
See also :func:`pause`, :func:`pthread_sigmask` and :func:`sigwait`.
signals specified in the signal set *sigset*. The function accepts the signal
(removes it from the pending list of signals), and returns the signal number.
- Availability: Unix (see the man page :manpage:`sigwait(3)` for further
- information).
+ .. availability:: Unix (see the man page :manpage:`sigwait(3)` for further
+ information).
See also :func:`pause`, :func:`pthread_sigmask`, :func:`sigpending`,
:func:`sigwaitinfo` and :func:`sigtimedwait`.
:attr:`si_errno`, :attr:`si_pid`, :attr:`si_uid`, :attr:`si_status`,
:attr:`si_band`.
- Availability: Unix (see the man page :manpage:`sigwaitinfo(2)` for further
- information).
+ .. availability:: Unix (see the man page :manpage:`sigwaitinfo(2)` for further
+ information).
See also :func:`pause`, :func:`sigwait` and :func:`sigtimedwait`.
specifying a timeout. If *timeout* is specified as :const:`0`, a poll is
performed. Returns :const:`None` if a timeout occurs.
- Availability: Unix (see the man page :manpage:`sigtimedwait(2)` for further
- information).
+ .. availability:: Unix (see the man page :manpage:`sigtimedwait(2)` for further
+ information).
See also :func:`pause`, :func:`sigwait` and :func:`sigwaitinfo`.
(case-insensitive), the system-level prefixes will still also be
searched for site-packages; otherwise they won't.
+.. index::
+ single: # (hash); comment
+ statement: import
+
A path configuration file is a file whose name has the form :file:`{name}.pth`
and exists in one of the four directories mentioned above; its contents are
additional items (one per line) to be added to ``sys.path``. Non-existing items
the OS default behavior will be used.
For normal use, you should only require the initialization/connect,
- :meth:`sendmail`, and :meth:`~smtplib.quit` methods.
+ :meth:`sendmail`, and :meth:`SMTP.quit` methods.
An example is included below.
The :class:`SMTP` class supports the :keyword:`with` statement. When used
- *feat* and *mask* are unsigned 32bit integers.
- Availability Linux 2.6.38, some algorithm types require more recent Kernels.
+ .. availability:: Linux 2.6.38, some algorithm types require more recent Kernels.
.. versionadded:: 3.6
their hosts. The sockets are represented as a ``(CID, port)`` tuple
where the context ID or CID and port are integers.
- Availability: Linux >= 4.8 QEMU >= 2.8 ESX >= 4.0 ESX Workstation >= 6.5
+ .. availability:: Linux >= 4.8 QEMU >= 2.8 ESX >= 4.0 ESX Workstation >= 6.5.
.. versionadded:: 3.7
`Secure File Descriptor Handling <http://udrepper.livejournal.com/20407.html>`_
for a more thorough explanation.
- Availability: Linux >= 2.6.27.
+ .. availability:: Linux >= 2.6.27.
.. versionadded:: 3.2
Many constants of these forms, documented in the Linux documentation, are
also defined in the socket module.
- Availability: Linux >= 2.6.25.
+ .. availability:: Linux >= 2.6.25.
.. versionadded:: 3.3
Broadcast manager constants, documented in the Linux documentation, are also
defined in the socket module.
- Availability: Linux >= 2.6.25.
+ .. availability:: Linux >= 2.6.25.
.. versionadded:: 3.4
This constant is documented in the Linux documentation.
- Availability: Linux >= 3.6.
+ .. availability:: Linux >= 3.6.
.. versionadded:: 3.5
CAN_ISOTP, in the CAN protocol family, is the ISO-TP (ISO 15765-2) protocol.
ISO-TP constants, documented in the Linux documentation.
- Availability: Linux >= 2.6.25
+ .. availability:: Linux >= 2.6.25.
.. versionadded:: 3.7
Many constants of these forms, documented in the Linux documentation, are
also defined in the socket module.
- Availability: Linux >= 2.2.
+ .. availability:: Linux >= 2.2.
.. data:: AF_RDS
Many constants of these forms, documented in the Linux documentation, are
also defined in the socket module.
- Availability: Linux >= 2.6.30.
+ .. availability:: Linux >= 2.6.30.
.. versionadded:: 3.3
Constants for Linux Kernel cryptography.
- Availability: Linux >= 2.6.38.
+ .. availability:: Linux >= 2.6.38.
.. versionadded:: 3.6
Constants for Linux host/guest communication.
- Availability: Linux >= 4.8.
+ .. availability:: Linux >= 4.8.
.. versionadded:: 3.7
.. data:: AF_LINK
- Availability: BSD, OSX.
+ .. availability:: BSD, OSX.
.. versionadded:: 3.4
Instantiate a socket from data obtained from the :meth:`socket.share`
method. The socket is assumed to be in blocking mode.
- Availability: Windows.
+ .. availability:: Windows.
.. versionadded:: 3.3
both the value of *address_family* and the underlying implementation of
:c:func:`inet_pton`.
- Availability: Unix (maybe not all platforms), Windows.
+ .. availability:: Unix (maybe not all platforms), Windows.
.. versionchanged:: 3.4
Windows support added
length for the specified address family, :exc:`ValueError` will be raised.
:exc:`OSError` is raised for errors from the call to :func:`inet_ntop`.
- Availability: Unix (maybe not all platforms), Windows.
+ .. availability:: Unix (maybe not all platforms), Windows.
.. versionchanged:: 3.4
Windows support added
buffer. Raises :exc:`OverflowError` if *length* is outside the
permissible range of values.
- Availability: most Unix platforms, possibly others.
+ .. availability:: most Unix platforms, possibly others.
.. versionadded:: 3.3
amount of ancillary data that can be received, since additional
data may be able to fit into the padding area.
- Availability: most Unix platforms, possibly others.
+ .. availability:: most Unix platforms, possibly others.
.. versionadded:: 3.3
Set the machine's hostname to *name*. This will raise an
:exc:`OSError` if you don't have enough rights.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
(index int, name string) tuples.
:exc:`OSError` if the system call fails.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
interface name.
:exc:`OSError` if no interface with the given name exists.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
interface index number.
:exc:`OSError` if no interface with the given index exists.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
return msg, list(fds)
- Availability: most Unix platforms, possibly others.
+ .. availability:: most Unix platforms, possibly others.
.. versionadded:: 3.3
>>> [b1, b2, b3]
[bytearray(b'Mary'), bytearray(b'01 had a 9'), bytearray(b'little lamb---')]
- Availability: most Unix platforms, possibly others.
+ .. availability:: most Unix platforms, possibly others.
.. versionadded:: 3.3
def send_fds(sock, msg, fds):
return sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array("i", fds))])
- Availability: most Unix platforms, possibly others.
+ .. availability:: most Unix platforms, possibly others.
.. versionadded:: 3.3
Specialized version of :meth:`~socket.sendmsg` for :const:`AF_ALG` socket.
Set mode, IV, AEAD associated data length and flags for :const:`AF_ALG` socket.
- Availability: Linux >= 2.6.38
+ .. availability:: Linux >= 2.6.38.
.. versionadded:: 3.6
Once this method has been called, it is safe to close the socket since
the operating system has already duplicated it for the target process.
- Availability: Windows.
+ .. availability:: Windows.
.. versionadded:: 3.3
A :class:`Cursor` instance has the following attributes and methods.
+ .. index:: single: ? (question mark); in SQL statements
+ .. index:: single: : (colon); in SQL statements
+
.. method:: execute(sql[, parameters])
Executes an SQL statement. The SQL statement may be parameterized (i. e.
See http://egd.sourceforge.net/ or http://prngd.sourceforge.net/ for sources
of entropy-gathering daemons.
- Availability: not available with LibreSSL and OpenSSL > 1.1.0
+ .. availability:: not available with LibreSSL and OpenSSL > 1.1.0.
.. function:: RAND_add(bytes, entropy)
* :attr:`openssl_capath_env` - OpenSSL's environment key that points to a capath,
* :attr:`openssl_capath` - hard coded path to a capath directory
- Availability: LibreSSL ignores the environment vars
- :attr:`openssl_cafile_env` and :attr:`openssl_capath_env`
+ .. availability:: LibreSSL ignores the environment vars
+ :attr:`openssl_cafile_env` and :attr:`openssl_capath_env`.
.. versionadded:: 3.4
[(b'data...', 'x509_asn', {'1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2'}),
(b'data...', 'x509_asn', True)]
- Availability: Windows.
+ .. availability:: Windows.
.. versionadded:: 3.4
:const:`x509_asn` for X.509 ASN.1 data or :const:`pkcs_7_asn` for
PKCS#7 ASN.1 data.
- Availability: Windows.
+ .. availability:: Windows.
.. versionadded:: 3.4
'strength_bits': 128,
'symmetric': 'aes-128-gcm'}]
- Availability: OpenSSL 1.0.2+
+ .. availability:: OpenSSL 1.0.2+.
.. versionadded:: 3.6
.. note::
With versions of OpenSSL older than 0.9.8m, it is only possible
to set options, not to clear them. Attempting to clear an option
- (by resetting the corresponding bits) will raise a ``ValueError``.
+ (by resetting the corresponding bits) will raise a :exc:`ValueError`.
.. versionchanged:: 3.6
:attr:`SSLContext.options` returns :class:`Options` flags:
.. function:: S_IMODE(mode)
- Return the portion of the file's mode that can be set by :func:`os.chmod`\
- ---that is, the file's permission bits, plus the sticky bit, set-group-id, and
- set-user-id bits (on systems that support them).
+ Return the portion of the file's mode that can be set by
+ :func:`os.chmod`\ ---that is, the file's permission bits, plus the sticky
+ bit, set-group-id, and set-user-id bits (on systems that support them).
.. function:: S_IFMT(mode)
pair: chaining; comparisons
pair: operator; comparison
operator: ==
- operator: <
+ operator: < (less)
operator: <=
- operator: >
+ operator: > (greater)
operator: >=
operator: !=
operator: is
builtin: int
builtin: float
builtin: complex
- operator: +
- operator: -
- operator: *
- operator: /
+ single: operator; + (plus)
+ single: + (plus); unary operator
+ single: + (plus); binary operator
+ single: operator; - (minus)
+ single: - (minus); unary operator
+ single: - (minus); binary operator
+ operator: * (asterisk)
+ operator: / (slash)
operator: //
- operator: %
+ operator: % (percent)
operator: **
Python fully supports mixed arithmetic: when a binary arithmetic operator has
pair: bitwise; operations
pair: shifting; operations
pair: masking; operations
- operator: |
- operator: ^
- operator: &
+ operator: | (vertical bar)
+ operator: ^ (caret)
+ operator: & (ampersand)
operator: <<
operator: >>
- operator: ~
+ operator: ~ (tilde)
Bitwise operations only make sense for integers. The result of bitwise
operations is calculated as though carried out in two's complement with an
(4)
Performing these calculations with at least one extra sign extension bit in
a finite two's complement representation (a working bit-width of
- ``1 + max(x.bit_length(), y.bit_length()`` or more) is sufficient to get the
+ ``1 + max(x.bit_length(), y.bit_length())`` or more) is sufficient to get the
same result as if there were an infinite number of sign bits.
single: string; interpolation, printf
single: printf-style formatting
single: sprintf-style formatting
- single: % formatting
- single: % interpolation
+ single: % (percent); printf-style formatting
.. note::
items specified by the format string, or a single mapping object (for example, a
dictionary).
+.. index::
+ single: () (parentheses); in printf-style formatting
+ single: * (asterisk); in printf-style formatting
+ single: . (dot); in printf-style formatting
+
A conversion specifier contains two or more characters and has the following
components, which must occur in this order:
The conversion flag characters are:
+.. index::
+ single: # (hash); in printf-style formatting
+ single: - (minus); in printf-style formatting
+ single: + (plus); in printf-style formatting
+ single: space; in printf-style formatting
+
+---------+---------------------------------------------------------------------+
| Flag | Meaning |
+=========+=====================================================================+
Return a copy of the sequence left filled with ASCII ``b'0'`` digits to
make a sequence of length *width*. A leading sign prefix (``b'+'``/
- ``b'-'`` is handled by inserting the padding *after* the sign character
+ ``b'-'``) is handled by inserting the padding *after* the sign character
rather than before. For :class:`bytes` objects, the original sequence is
returned if *width* is less than or equal to ``len(seq)``.
----------------------------------
.. index::
- single: formatting, bytes (%)
- single: formatting, bytearray (%)
- single: interpolation, bytes (%)
- single: interpolation, bytearray (%)
+ single: formatting; bytes (%)
+ single: formatting; bytearray (%)
+ single: interpolation; bytes (%)
+ single: interpolation; bytearray (%)
single: bytes; formatting
single: bytearray; formatting
single: bytes; interpolation
single: bytearray; interpolation
single: printf-style formatting
single: sprintf-style formatting
- single: % formatting
- single: % interpolation
+ single: % (percent); printf-style formatting
.. note::
items specified by the format bytes object, or a single mapping object (for
example, a dictionary).
+.. index::
+ single: () (parentheses); in printf-style formatting
+ single: * (asterisk); in printf-style formatting
+ single: . (dot); in printf-style formatting
+
A conversion specifier contains two or more characters and has the following
components, which must occur in this order:
The conversion flag characters are:
+.. index::
+ single: # (hash); in printf-style formatting
+ single: - (minus); in printf-style formatting
+ single: + (plus); in printf-style formatting
+ single: space; in printf-style formatting
+
+---------+---------------------------------------------------------------------+
| Flag | Meaning |
+=========+=====================================================================+
``nbytes == product(shape) * itemsize == len(m.tobytes())``. This is
the amount of space in bytes that the array would use in a contiguous
- representation. It is not necessarily equal to len(m)::
+ representation. It is not necessarily equal to ``len(m)``::
>>> import array
>>> a = array.array('i', [1,2,3,4,5])
.. versionchanged:: 3.7
Dictionary order is guaranteed to be insertion order. This behavior was
- implementation detail of CPython from 3.6.
+ an implementation detail of CPython from 3.6.
.. seealso::
:class:`types.MappingProxyType` can be used to create a read-only view
It is written as ``None``.
+.. index:: single: ...; ellipsis literal
.. _bltin-ellipsis-object:
The Ellipsis Object
related to that of :ref:`formatted string literals <f-strings>`, but
there are differences.
+.. index::
+ single: {} (curly brackets); in string formatting
+ single: . (dot); in string formatting
+ single: [] (square brackets); in string formatting
+ single: ! (exclamation); in string formatting
+ single: : (colon); in string formatting
+
Format strings contain "replacement fields" surrounded by curly braces ``{}``.
Anything that is not contained in braces is considered literal text, which is
copied unchanged to the output. If you need to include a brace character in the
The meaning of the various alignment options is as follows:
+ .. index::
+ single: < (less); in string formatting
+ single: > (greater); in string formatting
+ single: = (equals); in string formatting
+ single: ^ (caret); in string formatting
+
+---------+----------------------------------------------------------+
| Option | Meaning |
+=========+==========================================================+
The *sign* option is only valid for number types, and can be one of the
following:
+ .. index::
+ single: + (plus); in string formatting
+ single: - (minus); in string formatting
+ single: space; in string formatting
+
+---------+----------------------------------------------------------+
| Option | Meaning |
+=========+==========================================================+
+---------+----------------------------------------------------------+
+.. index:: single: # (hash); in string formatting
+
The ``'#'`` option causes the "alternate form" to be used for the
conversion. The alternate form is defined differently for different
types. This option is only valid for integer, float, complex and
only if a digit follows it. In addition, for ``'g'`` and ``'G'``
conversions, trailing zeros are not removed from the result.
+.. index:: single: , (comma); in string formatting
+
The ``','`` option signals the use of a comma for a thousands separator.
For a locale aware separator, use the ``'n'`` integer presentation type
instead.
.. versionchanged:: 3.1
Added the ``','`` option (see also :pep:`378`).
+.. index:: single: _ (underscore); in string formatting
+
The ``'_'`` option signals the use of an underscore for a thousands
separator for floating point presentation types and for integer
presentation type ``'d'``. For integer presentation types ``'b'``,
+---------+----------------------------------------------------------+
| ``'o'`` | Octal format. Outputs the number in base 8. |
+---------+----------------------------------------------------------+
- | ``'x'`` | Hex format. Outputs the number in base 16, using lower- |
- | | case letters for the digits above 9. |
+ | ``'x'`` | Hex format. Outputs the number in base 16, using |
+ | | lower-case letters for the digits above 9. |
+---------+----------------------------------------------------------+
- | ``'X'`` | Hex format. Outputs the number in base 16, using upper- |
- | | case letters for the digits above 9. |
+ | ``'X'`` | Hex format. Outputs the number in base 16, using |
+ | | upper-case letters for the digits above 9. |
+---------+----------------------------------------------------------+
| ``'n'`` | Number. This is the same as ``'d'``, except that it uses |
| | the current locale setting to insert the appropriate |
For example, ``'%03.2f'`` can be translated to ``'{:03.2f}'``.
The new format syntax also supports new and different options, shown in the
-follow examples.
+following examples.
Accessing arguments by position::
strings for i18n, see the
`flufl.i18n <http://flufli18n.readthedocs.io/en/latest/>`_ package.
+.. index:: single: $ (dollar); in template strings
+
Template strings support ``$``-based substitutions, using the following rules:
* ``$$`` is an escape; it is replaced with a single ``$``.
simply return ``$`` instead of raising :exc:`ValueError`.
While other exceptions may still occur, this method is called "safe"
- because substitutions always tries to return a usable string instead of
+ because it always tries to return a usable string instead of
raising an exception. In another sense, :meth:`safe_substitute` may be
anything other than safe, since it will silently ignore malformed
templates containing dangling delimiters, unmatched braces, or
order, and properly aligned by skipping pad bytes if necessary (according to the
rules used by the C compiler).
+.. index::
+ single: @ (at); in struct format strings
+ single: = (equals); in struct format strings
+ single: < (less); in struct format strings
+ single: > (greater); in struct format strings
+ single: ! (exclamation); in struct format strings
+
Alternatively, the first character of the format string can be used to indicate
the byte order, size and alignment of the packed data, according to the
following table:
Notes:
(1)
+ .. index:: single: ? (question mark); in struct format strings
+
The ``'?'`` conversion code corresponds to the :c:type:`_Bool` type defined by
C99. If this type is not available, it is simulated using a :c:type:`char`. In
standard mode, it is always represented by one byte.
``count`` bytes, but that the string returned can never contain more than 255
bytes.
+.. index:: single: ? (question mark); in struct format strings
+
For the ``'?'`` format character, the return value is either :const:`True` or
:const:`False`. When packing, the truth value of the argument object is used.
Either 0 or 1 in the native or standard bool representation will be packed, and
.. function:: run(args, *, stdin=None, input=None, stdout=None, stderr=None,\
capture_output=False, shell=False, cwd=None, timeout=None, \
- check=False, encoding=None, errors=None, text=None, env=None)
+ check=False, encoding=None, errors=None, text=None, env=None, \
+ universal_newlines=None)
Run the command described by *args*. Wait for command to complete, then
return a :class:`CompletedProcess` instance.
.. class:: Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, \
stderr=None, preexec_fn=None, close_fds=True, shell=False, \
- cwd=None, env=None, universal_newlines=False, \
+ cwd=None, env=None, universal_newlines=None, \
startupinfo=None, creationflags=0, restore_signals=True, \
start_new_session=False, pass_fds=(), *, \
encoding=None, errors=None, text=None)
.. function:: check_output(args, *, stdin=None, stderr=None, shell=False, \
cwd=None, encoding=None, errors=None, \
- universal_newlines=False, timeout=None)
+ universal_newlines=None, timeout=None, text=None)
Run command with arguments and return its output.
.. versionchanged:: 3.6
*encoding* and *errors* were added. See :func:`run` for details.
+ .. versionadded:: 3.7
+ *text* was added as a more readable alias for *universal_newlines*.
+
+
.. _subprocess-replacements:
Replacing Older Functions with the :mod:`subprocess` Module
>>> subprocess.getstatusoutput('/bin/kill $$')
(-15, '')
- Availability: POSIX & Windows
+ .. availability:: POSIX & Windows.
.. versionchanged:: 3.3.4
Windows support was added.
>>> subprocess.getoutput('ls /bin/ls')
'/bin/ls'
- Availability: POSIX & Windows
+ .. availability:: POSIX & Windows.
.. versionchanged:: 3.3.4
Windows support added
.. data:: dllhandle
- Integer specifying the handle of the Python DLL. Availability: Windows.
+ Integer specifying the handle of the Python DLL.
+
+ .. availability:: Windows.
.. function:: displayhook(value)
Return the build time API version of Android as an integer.
- Availability: Android.
+ .. availability:: Android.
.. versionadded:: 3.7
Return the current value of the flags that are used for
:c:func:`dlopen` calls. Symbolic names for the flag values can be
found in the :mod:`os` module (``RTLD_xxx`` constants, e.g.
- :data:`os.RTLD_LAZY`). Availability: Unix.
+ :data:`os.RTLD_LAZY`).
+
+ .. availability:: Unix.
.. function:: getfilesystemencoding()
is being emulated for the process. It is intended for use in logging rather
than for feature detection.
- Availability: Windows.
+ .. availability:: Windows.
.. versionchanged:: 3.2
Changed to a named tuple and added *service_pack_minor*,
.. function:: get_coroutine_origin_tracking_depth()
Get the current coroutine origin tracking depth, as set by
- func:`set_coroutine_origin_tracking_depth`.
+ :func:`set_coroutine_origin_tracking_depth`.
.. versionadded:: 3.7
.. index::
single: interpreter prompts
single: prompts, interpreter
+ single: >>>; interpreter prompt
+ single: ...; interpreter prompt
Strings specifying the primary and secondary prompt of the interpreter. These
are only defined if the interpreter is in interactive mode. Their initial
can be found in the :mod:`os` module (``RTLD_xxx`` constants, e.g.
:data:`os.RTLD_LAZY`).
- Availability: Unix.
+ .. availability:: Unix.
.. function:: setprofile(profilefunc)
This is equivalent to defining the :envvar:`PYTHONLEGACYWINDOWSFSENCODING`
environment variable before launching Python.
- Availability: Windows
+ .. availability:: Windows.
.. versionadded:: 3.6
See :pep:`529` for more details.
stored as string resource 1000 in the Python DLL. The value is normally the
first three characters of :const:`version`. It is provided in the :mod:`sys`
module for informational purposes; modifying this value has no effect on the
- registry keys used by Python. Availability: Windows.
+ registry keys used by Python.
+
+ .. availability:: Windows.
.. data:: _xoptions
Windows will return one of:
- - win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
+ - win-amd64 (64bit Windows on AMD64, aka x86_64, Intel64, and EM64T)
- win32 (all others - specifically, sys.platform is returned)
Mac OS X can return:
.. function:: tcsendbreak(fd, duration)
- Send a break on file descriptor *fd*. A zero *duration* sends a break for 0.25
- --0.5 seconds; a nonzero *duration* has a system dependent meaning.
+ Send a break on file descriptor *fd*. A zero *duration* sends a break for
+ 0.25--0.5 seconds; a nonzero *duration* has a system dependent meaning.
.. function:: tcdrain(fd)
.. versionadded:: 3.4
+ .. index:: single: ...; placeholder
+
.. attribute:: placeholder
(default: ``' [...]'``) String that will appear at the end of the output
memory page size - platform documentation should be referred to for more
information (4 KiB pages are common; using multiples of 4096 for the stack size is
the suggested approach in the absence of more specific information).
- Availability: Windows, systems with POSIX threads.
+
+ .. availability:: Windows, systems with POSIX threads.
This module also defines the following constant:
Passing an invalid or expired *thread_id* may result in
undefined behavior, such as segmentation fault.
- Availability: Unix (see the man page for :manpage:`pthread_getcpuclockid(3)` for
- further information)
+ .. availability:: Unix (see the man page for :manpage:`pthread_getcpuclockid(3)` for
+ further information).
.. versionadded:: 3.7
Return the resolution (precision) of the specified clock *clk_id*. Refer to
:ref:`time-clock-id-constants` for a list of accepted values for *clk_id*.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Return the time of the specified clock *clk_id*. Refer to
:ref:`time-clock-id-constants` for a list of accepted values for *clk_id*.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Similar to :func:`clock_gettime` but return time as nanoseconds.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.7
Set the time of the specified clock *clk_id*. Currently,
:data:`CLOCK_REALTIME` is the only accepted value for *clk_id*.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
Similar to :func:`clock_settime` but set time with nanoseconds.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.7
:pep:`475` for the rationale).
+.. index::
+ single: % (percent); datetime format
+
.. function:: strftime(format[, t])
Convert a tuple or :class:`struct_time` representing a time as returned by
it is 3.
+.. index::
+ single: % (percent); datetime format
+
.. function:: strptime(string[, format])
Parse a string representing a time according to a format. The return value
returned value is undefined, so that only the difference between the results
of consecutive calls in the same thread is valid.
- Availability: Windows, Linux, Unix systems supporting
- ``CLOCK_THREAD_CPUTIME_ID``.
+ .. availability:: Windows, Linux, Unix systems supporting
+ ``CLOCK_THREAD_CPUTIME_ID``.
.. versionadded:: 3.7
nonzero if there is a time, past, present or future when daylight saving time
applies).
- Availability: Unix.
+ .. availability:: Unix.
.. note::
have discontinuities if the time is changed using ``settimeofday()`` or
similar.
- Availability: Linux 2.6.39 or later.
+ .. availability:: Linux 2.6.39 or later.
.. versionadded:: 3.7
hardware source, and may give close to nanosecond resolution.
``CLOCK_HIGHRES`` is the nonadjustable, high-resolution clock.
- Availability: Solaris.
+ .. availability:: Solaris.
.. versionadded:: 3.3
Clock that cannot be set and represents monotonic time since some unspecified
starting point.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
High-resolution per-process timer from the CPU.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
High-resolution per-process timer from the CPU.
- Availability: FreeBSD, NetBSD 7 or later, OpenBSD.
+ .. availability:: FreeBSD, NetBSD 7 or later, OpenBSD.
.. versionadded:: 3.7
suspended, providing accurate uptime measurement, both absolute and
interval.
- Availability: FreeBSD, OpenBSD 5.5 or later.
+ .. availability:: FreeBSD, OpenBSD 5.5 or later.
.. versionadded:: 3.7
System-wide real-time clock. Setting this clock requires appropriate
privileges.
- Availability: Unix.
+ .. availability:: Unix.
.. versionadded:: 3.3
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
+ self.master = master
self.pack()
self.create_widgets()
self.hi_there.pack(side="top")
self.quit = tk.Button(self, text="QUIT", fg="red",
- command=root.destroy)
+ command=self.master.destroy)
self.quit.pack(side="bottom")
def say_hi(self):
*classCommand*
denotes which kind of widget to make (a button, a label, a menu...)
+.. index:: single: . (dot); in Tkinter
+
*newPathname*
is the new name for this widget. All names in Tk must be unique. To help
enforce this, widgets in Tk are named with *pathnames*, just like files in a
* if *tb* is not ``None``, it prints a header ``Traceback (most recent
call last):``
+
* it prints the exception *etype* and *value* after the stack trace
+
+ .. index:: single: ^ (caret); marker
+
* if *type(value)* is :exc:`SyntaxError` and *value* has the appropriate
format, it prints the line where the syntax error occurred with a caret
indicating the approximate position of the error.
:param fun: a function with two arguments which will be called with the
coordinates of the clicked point on the canvas
- :param num: number of the mouse-button, defaults to 1 (left mouse button)
+ :param btn: number of the mouse-button, defaults to 1 (left mouse button)
:param add: ``True`` or ``False`` -- if ``True``, a new binding will be
added, otherwise it will replace a former binding
:param fun: a function with two arguments which will be called with the
coordinates of the clicked point on the canvas
- :param num: number of the mouse-button, defaults to 1 (left mouse button)
+ :param btn: number of the mouse-button, defaults to 1 (left mouse button)
:param add: ``True`` or ``False`` -- if ``True``, a new binding will be
added, otherwise it will replace a former binding
:param fun: a function with two arguments which will be called with the
coordinates of the clicked point on the canvas
- :param num: number of the mouse-button, defaults to 1 (left mouse button)
+ :param btn: number of the mouse-button, defaults to 1 (left mouse button)
:param add: ``True`` or ``False`` -- if ``True``, a new binding will be
added, otherwise it will replace a former binding
:param fun: a function with two arguments which will be called with the
coordinates of the clicked point on the canvas
- :param num: number of the mouse-button, defaults to 1 (left mouse button)
+ :param btn: number of the mouse-button, defaults to 1 (left mouse button)
:param add: ``True`` or ``False`` -- if ``True``, a new binding will be
added, otherwise it will replace a former binding
.. versionadded:: 3.5.2
+.. class:: OrderedDict(collections.OrderedDict, MutableMapping[KT, VT])
+
+ A generic version of :class:`collections.OrderedDict`.
+
+ .. versionadded:: 3.7.2
+
.. class:: Counter(collections.Counter, Dict[T, int])
A generic version of :class:`collections.Counter`.
.. versionadded:: 3.5.2
-.. class:: io
-
- Wrapper namespace for I/O stream types.
+.. class:: IO
+ TextIO
+ BinaryIO
- This defines the generic type ``IO[AnyStr]`` and subclasses ``TextIO``
- and ``BinaryIO``, deriving from ``IO[str]`` and ``IO[bytes]``,
- respectively. These represent the types of I/O streams such as returned by
+ Generic type ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])``
+ and ``BinaryIO(IO[bytes])``
+ represent the types of I/O streams such as returned by
:func:`open`.
- These types are also accessible directly as ``typing.IO``,
- ``typing.TextIO``, and ``typing.BinaryIO``.
+.. class:: Pattern
+ Match
-.. class:: re
-
- Wrapper namespace for regular expression matching types.
-
- This defines the type aliases ``Pattern`` and ``Match`` which
+ These type aliases
correspond to the return types from :func:`re.compile` and
:func:`re.match`. These types (and the corresponding functions)
are generic in ``AnyStr`` and can be made specific by writing
``Pattern[str]``, ``Pattern[bytes]``, ``Match[str]``, or
``Match[bytes]``.
- These types are also accessible directly as ``typing.Pattern``
- and ``typing.Match``.
-
.. class:: NamedTuple
Typed version of namedtuple.
non-``@overload``-decorated definition, while the latter is used at
runtime but should be ignored by a type checker. At runtime, calling
a ``@overload``-decorated function directly will raise
- ``NotImplementedError``. An example of overload that gives a more
+ :exc:`NotImplementedError`. An example of overload that gives a more
precise type than can be expressed using a union or a type variable::
@overload
>>> mock.mock_calls == expected
True
+However, parameters to calls that return mocks are not recorded, which means it is not
+possible to track nested calls where the parameters used to create ancestors are important:
+
+ >>> m = Mock()
+ >>> m.factory(important=True).deliver()
+ <Mock name='mock.factory().deliver()' id='...'>
+ >>> m.mock_calls[-1] == call.factory(important=False).deliver()
+ True
+
Setting Return Values and Attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
unpacked as tuples to get at the individual arguments. See
:ref:`calls as tuples <calls-as-tuples>`.
+ .. note::
+
+ The way :attr:`mock_calls` are recorded means that where nested
+ calls are made, the parameters of ancestor calls are not recorded
+ and so will always compare equal:
+
+ >>> mock = MagicMock()
+ >>> mock.top(a=3).bottom()
+ <MagicMock name='mock.top().bottom()' id='...'>
+ >>> mock.mock_calls
+ [call.top(a=3), call.top().bottom()]
+ >>> mock.mock_calls[-1] == call.top(a=-1).bottom()
+ True
.. attribute:: __class__
.. function:: seal(mock)
- Seal will disable the creation of mock children by preventing getting or setting
- of any new attribute on the sealed mock. The sealing process is performed recursively.
+ Seal will disable the automatic creation of mocks when accessing an attribute of
+ the mock being sealed or any of its attributes that are already mocks recursively.
- If a mock instance is assigned to an attribute instead of being dynamically created
+ If a mock instance with a name or a spec is assigned to an attribute
it won't be considered in the sealing chain. This allows one to prevent seal from
fixing part of the mock object.
>>> mock = Mock()
>>> mock.submock.attribute1 = 2
- >>> mock.not_submock = mock.Mock()
+ >>> mock.not_submock = mock.Mock(name="sample_name")
>>> seal(mock)
+ >>> mock.new_attribute # This will raise AttributeError.
>>> mock.submock.attribute2 # This will raise AttributeError.
>>> mock.not_submock.attribute2 # This won't raise.
Kent Beck's original paper on testing frameworks using the pattern shared
by :mod:`unittest`.
- `Nose <https://nose.readthedocs.io/>`_ and `py.test <https://docs.pytest.org/>`_
+ `Nose <https://nose.readthedocs.io/>`_ and `pytest <https://docs.pytest.org/>`_
Third-party unittest frameworks with a lighter-weight syntax for writing
tests. For example, ``assert func(10) == 42``.
.. decorator:: expectedFailure
- Mark the test as an expected failure. If the test fails when run, the test
- is not counted as a failure.
+ Mark the test as an expected failure. If the test fails it will be
+ considered a success. If the test passes, it will be considered a failure.
.. exception:: SkipTest(reason)
.. versionadded:: 3.4
-When some of your tests differ only by a some very small differences, for
+When there are very small differences among your tests, for
instance some parameters, unittest allows you to distinguish them inside
the body of a test method using the :meth:`~TestCase.subTest` context manager.
If *delta* is supplied instead of *places* then the difference
between *first* and *second* must be less or equal to (or greater than) *delta*.
- Supplying both *delta* and *places* raises a ``TypeError``.
+ Supplying both *delta* and *places* raises a :exc:`TypeError`.
.. versionchanged:: 3.2
:meth:`assertAlmostEqual` automatically considers almost equal objects
returning :const:`None`.
-.. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace')
+.. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None)
Parse a query string given as a string argument (data of type
:mimetype:`application/x-www-form-urlencoded`). Data are returned as a
percent-encoded sequences into Unicode characters, as accepted by the
:meth:`bytes.decode` method.
+ The optional argument *max_num_fields* is the maximum number of fields to
+ read. If set, then throws a :exc:`ValueError` if there are more than
+ *max_num_fields* fields read.
+
Use the :func:`urllib.parse.urlencode` function (with the ``doseq``
parameter set to ``True``) to convert such dictionaries into query
strings.
-
.. versionchanged:: 3.2
Add *encoding* and *errors* parameters.
+ .. versionchanged:: 3.7.2
+ Added *max_num_fields* parameter.
-.. function:: parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace')
+
+.. function:: parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None)
Parse a query string given as a string argument (data of type
:mimetype:`application/x-www-form-urlencoded`). Data are returned as a list of
percent-encoded sequences into Unicode characters, as accepted by the
:meth:`bytes.decode` method.
+ The optional argument *max_num_fields* is the maximum number of fields to
+ read. If set, then throws a :exc:`ValueError` if there are more than
+ *max_num_fields* fields read.
+
Use the :func:`urllib.parse.urlencode` function to convert such lists of pairs into
query strings.
.. versionchanged:: 3.2
Add *encoding* and *errors* parameters.
+ .. versionchanged:: 3.7.2
+ Added *max_num_fields* parameter.
.. function:: urlunparse(parts)
Cause requests to go through a proxy. If *proxies* is given, it must be a
dictionary mapping protocol names to URLs of proxies. The default is to read
the list of proxies from the environment variables
- :envvar:`<protocol>_proxy`. If no proxy environment variables are set, then
+ ``<protocol>_proxy``. If no proxy environment variables are set, then
in a Windows environment proxy settings are obtained from the registry's
Internet Settings section, and in a Mac OS X environment proxy information
is retrieved from the OS X System Configuration Framework.
.. versionadded:: 3.6
Added the ``prompt`` parameter
-
Creators of third-party virtual environment tools will be free to use the
provided ``EnvBuilder`` class as a base class.
.. method:: setup_python(context)
- Creates a copy of the Python executable (and, under Windows, DLLs) in
- the environment. On a POSIX system, if a specific executable
- ``python3.x`` was used, symlinks to ``python`` and ``python3`` will be
- created pointing to that executable, unless files with those names
- already exist.
+ Creates a copy of the Python executable in the environment on POSIX
+ systems. If a specific executable ``python3.x`` was used, symlinks to
+ ``python`` and ``python3`` will be created pointing to that executable,
+ unless files with those names already exist.
.. method:: setup_scripts(context)
Installs activation scripts appropriate to the platform into the virtual
- environment.
+ environment. On Windows, also installs the ``python[w].exe`` scripts.
.. method:: post_setup(context)
implementations to pre-install packages in the virtual environment or
perform other post-creation steps.
+ .. versionchanged:: 3.7.2
+ Windows now uses redirector scripts for ``python[w].exe`` instead of
+ copying the actual binaries, and so :meth:`setup_python` does nothing
+ unless running from a build in the source tree.
+
In addition, :class:`EnvBuilder` provides this utility method that can be
called from :meth:`setup_scripts` or :meth:`post_setup` in subclasses to
assist in installing custom scripts into the virtual environment.
See :ref:`above <exception-changed>`.
+.. index::
+ single: % (percent); environment variables expansion (Windows)
+
.. function:: ExpandEnvironmentStrings(str)
Expands environment variable placeholders ``%NAME%`` in strings like
encoding. Encoding this string in an encoding other than UTF-8 is
likely incorrect, since UTF-8 is the default encoding of XML.
-.. method:: Node.toprettyxml(indent="", newl="", encoding="")
+.. method:: Node.toprettyxml(indent="\\t", newl="\\n", encoding=None)
Return a pretty-printed version of the document. *indent* specifies the
indentation string and defaults to a tabulator; *newl* specifies the string
2. :mod:`xml.dom.minidom` doesn't expand external entities and simply returns
the unexpanded entity verbatim.
3. :mod:`xmlrpclib` doesn't expand external entities and omits them.
-4. Since Python 3.8.0, external general entities are no longer processed by
- default since Python.
+4. Since Python 3.7.1, external general entities are no longer processed by
+ default.
billion laughs / exponential entity expansion
Create and return a SAX :class:`~xml.sax.xmlreader.XMLReader` object. The
first parser found will
- be used. If *parser_list* is provided, it must be a sequence of strings which
+ be used. If *parser_list* is provided, it must be a list of strings which
name modules that have a function named :func:`create_parser`. Modules listed
in *parser_list* will be used before modules in the default list of parsers.
Return the name of the first bad file, or else return ``None``.
.. versionchanged:: 3.6
- Calling :meth:`testfile` on a closed ZipFile will raise a
+ Calling :meth:`testzip` on a closed ZipFile will raise a
:exc:`ValueError`. Previously, a :exc:`RuntimeError` was raised.
.. note::
- There is no official file name encoding for ZIP files. If you have unicode file
- names, you must convert them to byte strings in your desired encoding before
- passing them to :meth:`write`. WinZip interprets all file names as encoded in
- CP437, also known as DOS Latin.
-
- .. note::
-
Archive names should be relative to the archive root, that is, they should not
start with a path separator.
.. method:: ZipFile.writestr(zinfo_or_arcname, data, compress_type=None, \
compresslevel=None)
- Write the string *data* to the archive; *zinfo_or_arcname* is either the file
+ Write a file into the archive. The contents is *data*, which may be either
+ a :class:`str` or a :class:`bytes` instance; if it is a :class:`str`,
+ it is encoded as UTF-8 first. *zinfo_or_arcname* is either the file
name it will be given in the archive, or a :class:`ZipInfo` instance. If it's
an instance, at least the filename, date, and time must be given. If it's a
name, the date and time is set to the current date and time.
.. attribute:: ZipFile.comment
- The comment text associated with the ZIP file. If assigning a comment to a
+ The comment associated with the ZIP file as a :class:`bytes` object.
+ If assigning a comment to a
:class:`ZipFile` instance created with mode ``'w'``, ``'x'`` or ``'a'``,
- this should be a
- string no longer than 65535 bytes. Comments longer than this will be
- truncated in the written archive when :meth:`close` is called.
+ it should be no longer than 65535 bytes. Comments longer than this will be
+ truncated.
.. _pyzipfile-objects:
.. attribute:: ZipInfo.comment
- Comment for the individual archive member.
+ Comment for the individual archive member as a :class:`bytes` object.
.. attribute:: ZipInfo.extra
Expansion field data. The `PKZIP Application Note`_ contains
- some comments on the internal structure of the data contained in this string.
+ some comments on the internal structure of the data contained in this
+ :class:`bytes` object.
.. attribute:: ZipInfo.create_system
%PYTHON% -m pip install sphinx\r
if errorlevel 1 exit /B\r
)\r
- set SPHINXBUILD=%PYTHON% -c "import sphinx, sys; sys.argv[0] = 'sphinx-build'; sys.exit(sphinx.main())"\r
+ set SPHINXBUILD=%PYTHON% -c "import sphinx.cmd.build, sys; sys.exit(sphinx.cmd.build.main())"\r
)\r
\r
%PYTHON% -c "import python_docs_theme" > nul 2> nul\r
:build\r
if not exist "%BUILDDIR%" mkdir "%BUILDDIR%"\r
\r
+rem PY_MISC_NEWS_DIR is also used by our Sphinx extension in tools/extensions/pyspecific.py\r
+if not defined PY_MISC_NEWS_DIR set PY_MISC_NEWS_DIR=%BUILDDIR%\%1\r
if exist ..\Misc\NEWS (\r
- echo.Copying Misc\NEWS to build\NEWS\r
- copy ..\Misc\NEWS build\NEWS > nul\r
+ echo.Copying Misc\NEWS to %PY_MISC_NEWS_DIR%\NEWS\r
+ copy ..\Misc\NEWS "%PY_MISC_NEWS_DIR%\NEWS" > nul\r
) else if exist ..\Misc\NEWS.D (\r
if defined BLURB (\r
echo.Merging Misc/NEWS with %BLURB%\r
- %BLURB% merge -f build\NEWS\r
+ if not exist build mkdir build\r
+ %BLURB% merge -f "%PY_MISC_NEWS_DIR%\NEWS"\r
) else (\r
echo.No Misc/NEWS file and Blurb is not available.\r
exit /B 1\r
.. index::
single: clause
single: suite
+ single: ; (semicolon)
A compound statement consists of one or more 'clauses.' A clause consists of a
header and a 'suite.' The clause headers of a particular compound statement are
statement: if
keyword: elif
keyword: else
- keyword: elif
- keyword: else
+ single: : (colon); compound statement
The :keyword:`if` statement is used for conditional execution:
keyword: else
pair: loop; statement
keyword: else
+ single: : (colon); compound statement
The :keyword:`while` statement is used for repeated execution as long as an
expression is true:
keyword: else
pair: target; list
object: sequence
+ single: : (colon); compound statement
The :keyword:`for` statement is used to iterate over the elements of a sequence
(such as a string, tuple or list) or other iterable object:
statement: try
keyword: except
keyword: finally
-.. index:: keyword: except
+ keyword: else
+ keyword: as
+ single: : (colon); compound statement
The :keyword:`try` statement specifies exception handlers and/or cleanup code
for a group of statements:
the new exception in the surrounding code and on the call stack (it is treated
as if the entire :keyword:`try` statement raised the exception).
+.. index:: single: as; except clause
+
When a matching except clause is found, the exception is assigned to the target
specified after the :keyword:`as` keyword in that except clause, if present, and
the except clause's suite is executed. All except clauses must have an
statement: break
statement: continue
-The optional :keyword:`else` clause is executed if and when control flows off
-the end of the :keyword:`try` clause. [#]_ Exceptions in the :keyword:`else`
-clause are not handled by the preceding :keyword:`except` clauses.
+The optional :keyword:`else` clause is executed if the control flow leaves the
+:keyword:`try` suite, no exception was raised, and no :keyword:`return`,
+:keyword:`continue`, or :keyword:`break` statement was executed. Exceptions in
+the :keyword:`else` clause are not handled by the preceding :keyword:`except`
+clauses.
.. index:: keyword: finally
=============================
.. index::
- statement: with
- single: as; with statement
+ statement: with
+ keyword: as
+ single: as; with statement
+ single: , (comma); with statement
+ single: : (colon); compound statement
The :keyword:`with` statement is used to wrap the execution of a block with
methods defined by a context manager (see section :ref:`context-managers`).
object: function
pair: function; name
pair: name; binding
+ single: () (parentheses); function definition
+ single: , (comma); parameter list
+ single: : (colon); compound statement
A function definition defines a user-defined function object (see section
:ref:`types`):
only when the function is called. [#]_
.. index::
- statement: @
+ single: @ (at); function definition
A function definition may be wrapped by one or more :term:`decorator` expressions.
Decorator expressions are evaluated when the function is defined, in the scope
.. index::
triple: default; parameter; value
single: argument; function definition
+ single: = (equals); function definition
When one or more :term:`parameters <parameter>` have the form *parameter* ``=``
*expression*, the function is said to have "default parameter values." For a
return penguin
.. index::
- statement: *
- statement: **
+ single: * (asterisk); function definition
+ single: **; function definition
Function call semantics are described in more detail in section :ref:`calls`. A
function call always assigns values to all parameters mentioned in the parameter
"``*identifier``" are keyword-only parameters and may only be passed
used keyword arguments.
-.. index:: pair: function; annotations
+.. index::
+ pair: function; annotations
+ single: ->; function annotations
+ single: : (colon); function annotations
Parameters may have annotations of the form "``: expression``" following the
parameter name. Any parameter may have an annotation even those of the form
pair: execution; frame
single: inheritance
single: docstring
+ single: () (parentheses); class definition
+ single: , (comma); expression list
+ single: : (colon); compound statement
A class definition defines a class object (see section :ref:`types`):
Class creation can be customized heavily using :ref:`metaclasses <metaclasses>`.
+.. index::
+ single: @ (at); class definition
+
Classes can also be decorated: just like when decorating functions, ::
@f1(arg)
.. seealso::
- :pep:`3115` - Metaclasses in Python 3
+ :pep:`3115` - Metaclasses in Python 3000
+ The proposal that changed the declaration of metaclasses to the current
+ syntax, and the semantics for how classes with metaclasses are
+ constructed.
+
:pep:`3129` - Class Decorators
+ The proposal that added class decorators. Function and method decorators
+ were introduced in :pep:`318`.
.. _async:
keyword: await
Execution of Python coroutines can be suspended and resumed at many points
-(see :term:`coroutine`). In the body of a coroutine, any ``await`` and
+(see :term:`coroutine`). Inside the body of a coroutine function, ``await`` and
``async`` identifiers become reserved keywords; :keyword:`await` expressions,
:keyword:`async for` and :keyword:`async with` can only be used in
-coroutine bodies.
+coroutine function bodies.
Functions defined with ``async def`` syntax are always coroutine functions,
even if they do not contain ``await`` or ``async`` keywords.
-It is a :exc:`SyntaxError` to use ``yield from`` expressions in
-``async def`` coroutines.
+It is a :exc:`SyntaxError` to use a ``yield from`` expression inside the body
+of a coroutine function.
An example of a coroutine function::
See also :meth:`__aiter__` and :meth:`__anext__` for details.
-It is a :exc:`SyntaxError` to use ``async for`` statement outside of an
-:keyword:`async def` function.
+It is a :exc:`SyntaxError` to use an ``async for`` statement outside the
+body of a coroutine function.
.. index:: statement: async with
See also :meth:`__aenter__` and :meth:`__aexit__` for details.
-It is a :exc:`SyntaxError` to use ``async with`` statement outside of an
-:keyword:`async def` function.
+It is a :exc:`SyntaxError` to use an ``async with`` statement outside the
+body of a coroutine function.
.. seealso::
:pep:`492` - Coroutines with async and await syntax
+ The proposal that made coroutines a proper standalone concept in Python,
+ and added supporting syntax.
.. rubric:: Footnotes
there is a :keyword:`finally` clause which happens to raise another
exception. That new exception causes the old one to be lost.
-.. [#] Currently, control "flows off the end" except in the case of an exception
- or the execution of a :keyword:`return`, :keyword:`continue`, or
- :keyword:`break` statement.
-
.. [#] A string literal appearing as the first statement in the function body is
transformed into the function's ``__doc__`` attribute and therefore the
function's :term:`docstring`.
Ellipsis
- .. index:: object: Ellipsis
+ .. index::
+ object: Ellipsis
+ single: ...; ellipsis literal
This type has a single value. There is a single object with this value. This
object is accessed through the literal ``...`` or the built-in name
dict insertion, O(n^2) complexity. See
http://www.ocert.org/advisories/ocert-2011-003.html for details.
- Changing hash values affects the iteration order of dicts, sets and
- other mappings. Python has never made guarantees about this ordering
+ Changing hash values affects the iteration order of sets.
+ Python has never made guarantees about this ordering
(and it typically varies between 32-bit and 64-bit builds).
See also :envvar:`PYTHONHASHSEED`.
def __setattr__(self, attr, value):
print(f'Setting {attr}...')
- setattr(self, attr, value)
+ super().__setattr__(attr, value)
sys.modules[__name__].__class__ = VerboseModule
^^^^^^^^^^^
.. index::
- single: metaclass
- builtin: type
+ single: metaclass
+ builtin: type
+ single: = (equals); class definition
By default, classes are constructed using :func:`type`. The class body is
executed in a new namespace and the class name is bound locally to the
Describes the implicit ``__class__`` closure reference
-Metaclass example
-^^^^^^^^^^^^^^^^^
+Uses for metaclasses
+^^^^^^^^^^^^^^^^^^^^
The potential uses for metaclasses are boundless. Some ideas that have been
explored include enum, logging, interface checking, automatic delegation,
automatic property creation, proxies, frameworks, and automatic resource
locking/synchronization.
-Here is an example of a metaclass that uses an :class:`collections.OrderedDict`
-to remember the order that class variables are defined::
-
- class OrderedClass(type):
-
- @classmethod
- def __prepare__(metacls, name, bases, **kwds):
- return collections.OrderedDict()
-
- def __new__(cls, name, bases, namespace, **kwds):
- result = type.__new__(cls, name, bases, dict(namespace))
- result.members = tuple(namespace)
- return result
-
- class A(metaclass=OrderedClass):
- def one(self): pass
- def two(self): pass
- def three(self): pass
- def four(self): pass
-
- >>> A.members
- ('__module__', 'one', 'two', 'three', 'four')
-
-When the class definition for *A* gets executed, the process begins with
-calling the metaclass's :meth:`__prepare__` method which returns an empty
-:class:`collections.OrderedDict`. That mapping records the methods and
-attributes of *A* as they are defined within the body of the class statement.
-Once those definitions are executed, the ordered dictionary is fully populated
-and the metaclass's :meth:`__new__` method gets invoked. That method builds
-the new type and it saves the ordered dictionary keys in an attribute
-called ``members``.
-
Customizing instance and subclass checks
----------------------------------------
.. versionadded:: 3.4
+.. index:: object: slice
+
.. note::
Slicing is done exclusively with the following three methods. A call like ::
.. method:: object.__getitem__(self, key)
- .. index:: object: slice
-
Called to implement evaluation of ``self[key]``. For sequence types, the
accepted keys should be integers and slice objects. Note that the special
interpretation of negative indexes (if the class wishes to emulate a sequence
indexes to allow proper detection of the end of the sequence.
-.. method:: object.__missing__(self, key)
-
- Called by :class:`dict`\ .\ :meth:`__getitem__` to implement ``self[key]`` for dict subclasses
- when key is not in the dictionary.
-
-
.. method:: object.__setitem__(self, key, value)
Called to implement assignment to ``self[key]``. Same note as for
values as for the :meth:`__getitem__` method.
+.. method:: object.__missing__(self, key)
+
+ Called by :class:`dict`\ .\ :meth:`__getitem__` to implement ``self[key]`` for dict subclasses
+ when key is not in the dictionary.
+
+
.. method:: object.__iter__(self)
This method is called when an iterator is required for a container. This method
Each command typed interactively is a block. A script file (a file given as
standard input to the interpreter or specified as a command line argument to the
interpreter) is a code block. A script command (a command specified on the
-interpreter command line with the '**-c**' option) is a code block. The string
+interpreter command line with the :option:`-c` option) is a code block. The string
argument passed to the built-in functions :func:`eval` and :func:`exec` is a
code block.
:dfn:`Names` refer to objects. Names are introduced by name binding operations.
-.. index:: statement: from
+.. index:: single: from; import statement
The following constructs bind names: formal parameters to functions,
:keyword:`import` statements, class and function definitions (these bind the
Parenthesized forms
-------------------
-.. index:: single: parenthesized form
+.. index::
+ single: parenthesized form
+ single: () (parentheses); tuple display
A parenthesized form is an optional expression list enclosed in parentheses:
tuple may or may not yield the same object).
.. index::
- single: comma
+ single: comma; tuple display
pair: tuple; display
+ single: , (comma); tuple display
Note that tuples are not formed by the parentheses, but rather by use of the
comma operator. The exception is the empty tuple, for which parentheses *are*
* they are computed via a set of looping and filtering instructions, called a
:dfn:`comprehension`.
+.. index::
+ single: for; in comprehensions
+ single: if; in comprehensions
+ single: async for; in comprehensions
+
Common syntax elements for comprehensions are:
.. productionlist::
nested scope (in Python 3.7, such expressions emit :exc:`DeprecationWarning`
when compiled, in Python 3.8+ they will emit :exc:`SyntaxError`).
+.. index::
+ single: await; in comprehensions
+
Since Python 3.6, in an :keyword:`async def` function, an :keyword:`async for`
clause may be used to iterate over a :term:`asynchronous iterator`.
A comprehension in an :keyword:`async def` function may consist of either a
pair: list; comprehensions
pair: empty; list
object: list
+ single: [] (square brackets); list expression
+ single: , (comma); expression list
A list display is a possibly empty series of expressions enclosed in square
brackets:
Set displays
------------
-.. index:: pair: set; display
- object: set
+.. index::
+ pair: set; display
+ object: set
+ single: {} (curly brackets); set expression
+ single: , (comma); expression list
A set display is denoted by curly braces and distinguishable from dictionary
displays by the lack of colons separating keys and values:
Dictionary displays
-------------------
-.. index:: pair: dictionary; display
- key, datum, key/datum pair
- object: dictionary
+.. index::
+ pair: dictionary; display
+ key, datum, key/datum pair
+ object: dictionary
+ single: {} (curly brackets); dictionary expression
+ single: : (colon); in dictionary expressions
+ single: , (comma); in dictionary displays
A dictionary display is a possibly empty series of key/datum pairs enclosed in
curly braces:
that you can specify the same key multiple times in the key/datum list, and the
final dictionary's value for that key will be the last one given.
-.. index:: unpacking; dictionary, **; in dictionary displays
+.. index::
+ unpacking; dictionary
+ single: **; in dictionary displays
A double asterisk ``**`` denotes :dfn:`dictionary unpacking`.
Its operand must be a :term:`mapping`. Each mapping item is added
Generator expressions
---------------------
-.. index:: pair: generator; expression
- object: generator
+.. index::
+ pair: generator; expression
+ object: generator
+ single: () (parentheses); generator expression
A generator expression is a compact generator notation in parentheses:
.. index::
keyword: yield
+ keyword: from
pair: yield; expression
pair: generator; function
def gen(): # defines a generator function
yield 123
- async def agen(): # defines an asynchronous generator function (PEP 525)
+ async def agen(): # defines an asynchronous generator function
yield 123
Due to their side effects on the containing scope, ``yield`` expressions
the generator-iterator's :meth:`~generator.close` method will be called,
allowing any pending :keyword:`finally` clauses to execute.
+.. index::
+ single: from; yield from expression
+
When ``yield from <expr>`` is used, it treats the supplied expression as
a subiterator. All values produced by that subiterator are passed directly
to the caller of the current generator's methods. Any values passed in with
The proposal to introduce the :token:`yield_from` syntax, making delegation
to sub-generators easy.
+ :pep:`525` - Asynchronous Generators
+ The proposal that expanded on :pep:`492` by adding generator capabilities to
+ coroutine functions.
+
.. index:: object: generator
.. _generator-methods:
Attribute references
--------------------
-.. index:: pair: attribute; reference
+.. index::
+ pair: attribute; reference
+ single: . (dot); attribute reference
An attribute reference is a primary followed by a period and a name:
Subscriptions
-------------
-.. index:: single: subscription
+.. index::
+ single: subscription
+ single: [] (square brackets); subscription
.. index::
object: sequence
.. index::
single: slicing
single: slice
+ single: : (colon); slicing
+ single: , (comma); slicing
.. index::
object: sequence
object: callable
single: call
single: argument; call semantics
+ single: () (parentheses); call
+ single: , (comma); argument list
+ single: = (equals); in function calls
.. _calls:
there were no excess keyword arguments.
.. index::
- single: *; in function calls
+ single: * (asterisk); in function calls
single: unpacking; in function calls
If the syntax ``*expression`` appears in the function call, ``expression`` must
if that method was called.
+.. index:: keyword: await
.. _await:
Await expression
The power operator
==================
+.. index::
+ pair: power; operation
+ operator: **
+
The power operator binds more tightly than unary operators on its left; it binds
less tightly than unary operators on its right. The syntax is:
.. index::
single: negation
single: minus
+ single: operator; - (minus)
+ single: - (minus); unary operator
The unary ``-`` (minus) operator yields the negation of its numeric argument.
-.. index:: single: plus
+.. index::
+ single: plus
+ single: operator; + (plus)
+ single: + (plus); unary operator
The unary ``+`` (plus) operator yields its numeric argument unchanged.
-.. index:: single: inversion
-
+.. index::
+ single: inversion
+ operator: ~ (tilde)
The unary ``~`` (invert) operator yields the bitwise inversion of its integer
argument. The bitwise inversion of ``x`` is defined as ``-(x+1)``. It only
: `m_expr` "%" `u_expr`
a_expr: `m_expr` | `a_expr` "+" `m_expr` | `a_expr` "-" `m_expr`
-.. index:: single: multiplication
+.. index::
+ single: multiplication
+ operator: * (asterisk)
The ``*`` (multiplication) operator yields the product of its arguments. The
arguments must either both be numbers, or one argument must be an integer and
.. index::
single: matrix multiplication
- operator: @
+ operator: @ (at)
The ``@`` (at) operator is intended to be used for matrix multiplication. No
builtin Python types implement this operator.
.. index::
exception: ZeroDivisionError
single: division
+ operator: / (slash)
+ operator: //
The ``/`` (division) and ``//`` (floor division) operators yield the quotient of
their arguments. The numeric arguments are first converted to a common type.
applied to the result. Division by zero raises the :exc:`ZeroDivisionError`
exception.
-.. index:: single: modulo
+.. index::
+ single: modulo
+ operator: % (percent)
The ``%`` (modulo) operator yields the remainder from the division of the first
argument by the second. The numeric arguments are first converted to a common
function are not defined for complex numbers. Instead, convert to a floating
point number using the :func:`abs` function if appropriate.
-.. index:: single: addition
+.. index::
+ single: addition
+ single: operator; + (plus)
+ single: + (plus); binary operator
The ``+`` (addition) operator yields the sum of its arguments. The arguments
must either both be numbers or both be sequences of the same type. In the
former case, the numbers are converted to a common type and then added together.
In the latter case, the sequences are concatenated.
-.. index:: single: subtraction
+.. index::
+ single: subtraction
+ single: operator; - (minus)
+ single: - (minus); binary operator
The ``-`` (subtraction) operator yields the difference of its arguments. The
numeric arguments are first converted to a common type.
Shifting operations
===================
-.. index:: pair: shifting; operation
+.. index::
+ pair: shifting; operation
+ operator: <<
+ operator: >>
The shifting operations have lower priority than the arithmetic operations:
xor_expr: `and_expr` | `xor_expr` "^" `and_expr`
or_expr: `xor_expr` | `or_expr` "|" `xor_expr`
-.. index:: pair: bitwise; and
+.. index::
+ pair: bitwise; and
+ operator: & (ampersand)
The ``&`` operator yields the bitwise AND of its arguments, which must be
integers.
.. index::
pair: bitwise; xor
pair: exclusive; or
+ operator: ^ (caret)
The ``^`` operator yields the bitwise XOR (exclusive OR) of its arguments, which
must be integers.
.. index::
pair: bitwise; or
pair: inclusive; or
+ operator: | (vertical bar)
The ``|`` operator yields the bitwise (inclusive) OR of its arguments, which
must be integers.
Comparisons
===========
-.. index:: single: comparison
-
-.. index:: pair: C; language
+.. index::
+ single: comparison
+ pair: C; language
+ operator: < (less)
+ operator: > (greater)
+ operator: <=
+ operator: >=
+ operator: ==
+ operator: !=
Unlike C, all comparison operations in Python have the same priority, which is
lower than that of any arithmetic, shifting or bitwise operation. Also unlike
The expression ``x or y`` first evaluates *x*; if *x* is true, its value is
returned; otherwise, *y* is evaluated and the resulting value is returned.
-(Note that neither :keyword:`and` nor :keyword:`or` restrict the value and type
+Note that neither :keyword:`and` nor :keyword:`or` restrict the value and type
they return to ``False`` and ``True``, but rather return the last evaluated
argument. This is sometimes useful, e.g., if ``s`` is a string that should be
replaced by a default value if it is empty, the expression ``s or 'foo'`` yields
.. index::
pair: conditional; expression
pair: ternary; operator
+ single: if; conditional expression
+ single: else; conditional expression
.. productionlist::
conditional_expression: `or_test` ["if" `or_test` "else" `expression`]
pair: lambda; expression
pair: lambda; form
pair: anonymous; function
+ single: : (colon); lambda expression
.. productionlist::
- lambda_expr: "lambda" [`parameter_list`]: `expression`
- lambda_expr_nocond: "lambda" [`parameter_list`]: `expression_nocond`
+ lambda_expr: "lambda" [`parameter_list`] ":" `expression`
+ lambda_expr_nocond: "lambda" [`parameter_list`] ":" `expression_nocond`
Lambda expressions (sometimes called lambda forms) are used to create anonymous
functions. The expression ``lambda parameters: expression`` yields a function
Expression lists
================
-.. index:: pair: expression; list
+.. index::
+ pair: expression; list
+ single: , (comma); expression list
.. productionlist::
expression_list: `expression` ("," `expression`)* [","]
.. index::
pair: iterable; unpacking
- single: *; in expression lists
+ single: * (asterisk); in expression lists
An asterisk ``*`` denotes :dfn:`iterable unpacking`. Its operand must be
an :term:`iterable`. The iterable is expanded into a sequence of items,
Operator precedence
===================
-.. index:: pair: operator; precedence
+.. index::
+ pair: operator; precedence
The following table summarizes the operator precedence in Python, from lowest
precedence (least binding) to highest precedence (most binding). Operators in
+-----------------------------------------------+-------------------------------------+
| ``**`` | Exponentiation [#]_ |
+-----------------------------------------------+-------------------------------------+
-| ``await`` ``x`` | Await expression |
+| :keyword:`await` ``x`` | Await expression |
+-----------------------------------------------+-------------------------------------+
| ``x[index]``, ``x[index:index]``, | Subscription, slicing, |
| ``x(arguments...)``, ``x.attribute`` | call, attribute reference |
------------------
.. index::
- pair:: package; namespace
- pair:: package; portion
+ pair: package; namespace
+ pair: package; portion
A namespace package is a composite of various :term:`portions <portion>`,
where each portion contributes a subpackage to the parent package. Portions
:mod:`__main__` does not correspond directly with an importable module:
- interactive prompt
-- -c switch
+- :option:`-c` option
- running from stdin
- running directly from a source or bytecode file
--------
.. index:: comment, hash character
+ single: # (hash); comment
A comment starts with a hash character (``#``) that is not part of a string
literal, and ends at the end of the physical line. A comment signifies the end
---------------------
.. index:: source character set, encoding declarations (source file)
+ single: # (hash); source encoding declaration
If a comment in the first or second line of the Python script matches the
regular expression ``coding[=:]\s*([-\w.]+)``, this comment is processed as an
assert del global not with
async elif if or yield
+.. index::
+ single: _, identifiers
+ single: __, identifiers
.. _id-classes:
Reserved classes of identifiers
Literals are notations for constant values of some built-in types.
+.. index:: string literal, bytes literal, ASCII
+ single: ' (single quote); string literal
+ single: " (double quote); string literal
+ single: u'; string literal
+ single: u"; string literal
.. _strings:
String and Bytes literals
-------------------------
-.. index:: string literal, bytes literal, ASCII
-
String literals are described by the following lexical definitions:
.. productionlist::
see section :ref:`encodings`.
.. index:: triple-quoted string, Unicode Consortium, raw string
+ single: """; string literal
+ single: '''; string literal
In plain English: Both types of literals can be enclosed in matching single quotes
(``'``) or double quotes (``"``). They can also be enclosed in matching groups
characters that otherwise have a special meaning, such as newline, backslash
itself, or the quote character.
+.. index::
+ single: b'; bytes literal
+ single: b"; bytes literal
+
Bytes literals are always prefixed with ``'b'`` or ``'B'``; they produce an
instance of the :class:`bytes` type instead of the :class:`str` type. They
may only contain ASCII characters; bytes with a numeric value of 128 or greater
must be expressed with escapes.
+.. index::
+ single: r'; raw string literal
+ single: r"; raw string literal
+
Both string and bytes literals may optionally be prefixed with a letter ``'r'``
or ``'R'``; such strings are called :dfn:`raw strings` and treat backslashes as
literal characters. As a result, in string literals, ``'\U'`` and ``'\u'``
to simplify the maintenance of dual Python 2.x and 3.x codebases.
See :pep:`414` for more information.
+.. index::
+ single: f'; formatted string literal
+ single: f"; formatted string literal
+
A string literal with ``'f'`` or ``'F'`` in its prefix is a
:dfn:`formatted string literal`; see :ref:`f-strings`. The ``'f'`` may be
combined with ``'r'``, but not with ``'b'`` or ``'u'``, therefore raw
"quote" is the character used to open the literal, i.e. either ``'`` or ``"``.)
.. index:: physical line, escape sequence, Standard C, C
+ single: \ (backslash); escape sequence
+ single: \\; escape sequence
+ single: \a; escape sequence
+ single: \b; escape sequence
+ single: \f; escape sequence
+ single: \n; escape sequence
+ single: \r; escape sequence
+ single: \t; escape sequence
+ single: \v; escape sequence
+ single: \x; escape sequence
+ single: \N; escape sequence
+ single: \u; escape sequence
+ single: \U; escape sequence
Unless an ``'r'`` or ``'R'`` prefix is present, escape sequences in string and
bytes literals are interpreted according to rules similar to those used by
single: string; formatted literal
single: string; interpolated literal
single: f-string
+ single: {} (curly brackets); in formatted string literal
+ single: ! (exclamation); in formatted string literal
+ single: : (colon); in formatted string literal
.. _f-strings:
Formatted string literals
``1``.
+.. index::
+ single: 0b; integer literal
+ single: 0o; integer literal
+ single: 0x; integer literal
+ single: _ (underscore); in numeric literal
+
.. _integers:
Integer literals
Underscores are now allowed for grouping purposes in literals.
+.. index::
+ single: . (dot); in numeric literal
+ single: e; in numeric literal
+ single: _ (underscore); in numeric literal
.. _floating:
Floating point literals
Underscores are now allowed for grouping purposes in literals.
+.. index::
+ single: j; in numeric literal
.. _imaginary:
Imaginary literals
: | `break_stmt`
: | `continue_stmt`
: | `import_stmt`
+ : | `future_stmt`
: | `global_stmt`
: | `nonlocal_stmt`
=====================
.. index::
- single: =; assignment statement
+ single: = (equals); assignment statement
pair: assignment; statement
pair: binding; name
pair: rebinding; name
given with the definition of the object types (see section :ref:`types`).
.. index:: triple: target; list; assignment
+ single: , (comma); in target list
+ single: * (asterisk); in assignment target list
+ single: [] (square brackets); in assignment target list
+ single: () (parentheses); in assignment target list
Assignment of an object to a target list, optionally enclosed in parentheses or
square brackets, is recursively defined as follows.
-* If the target list is empty: The object must also be an empty iterable.
+* If the target list is a single target with no trailing comma,
+ optionally in parentheses, the object is assigned to that target.
-* If the target list is a single target in parentheses: The object is assigned
- to that target.
-
-* If the target list is a comma-separated list of targets, or a single target
- in square brackets: The object must be an iterable with the same number of
+* Else: The object must be an iterable with the same number of
items as there are targets in the target list, and the items are assigned,
from left to right, to the corresponding targets.
.. index::
pair: annotated; assignment
single: statement; assignment, annotated
+ single: : (colon); annotated variable
Annotation assignment is the combination, in a single statement,
of a variable or attribute annotation and an optional assignment statement:
.. seealso::
- :pep:`526` - Variable and attribute annotation syntax
+ :pep:`526` - Syntax for Variable Annotations
+ The proposal that added syntax for annotating the types of variables
+ (including class variables and instance variables), instead of expressing
+ them through comments.
+
:pep:`484` - Type hints
+ The proposal that added the :mod:`typing` module to provide a standard
+ syntax for type annotations that can be used in static analysis tools and
+ IDEs.
.. _assert:
.. index::
statement: assert
pair: debugging; assertions
+ single: , (comma); expression list
Assert statements are a convenient way to insert debugging assertions into a
program:
These equivalences assume that :const:`__debug__` and :exc:`AssertionError` refer to
the built-in variables with those names. In the current implementation, the
built-in variable :const:`__debug__` is ``True`` under normal circumstances,
-``False`` when optimization is requested (command line option -O). The current
+``False`` when optimization is requested (command line option :option:`-O`). The current
code generator emits no code for an assert statement when optimization is
requested at compile time. Note that it is unnecessary to include the source
code for the expression that failed in the error message; it will be displayed
single: module; importing
pair: name; binding
keyword: from
+ keyword: as
+ exception: ImportError
+ single: , (comma); import statement
.. productionlist::
import_stmt: "import" `module` ["as" `identifier`] ("," `module` ["as" `identifier`])*
.. index::
pair: name; binding
- keyword: from
- exception: ImportError
+ single: from; import statement
The :keyword:`from` form uses a slightly more complex process:
from foo.bar import baz # foo.bar.baz imported and bound as baz
from foo import attr # foo imported and foo.attr bound as attr
+.. index:: single: * (asterisk); import statement
+
If the list of identifiers is replaced by a star (``'*'``), all public
names defined in the module are bound in the local namespace for the scope
where the :keyword:`import` statement occurs.
Future statements
-----------------
-.. index:: pair: future; statement
+.. index::
+ pair: future; statement
+ single: __future__; future statement
A :dfn:`future statement` is a directive to the compiler that a particular
module should be compiled using syntax or semantics that will be available in a
.. index::
statement: global
triple: global; name; binding
+ single: , (comma); identifier list
.. productionlist::
global_stmt: "global" `identifier` ("," `identifier`)*
=================================
.. index:: statement: nonlocal
+ single: , (comma); identifier list
.. productionlist::
nonlocal_stmt: "nonlocal" `identifier` ("," `identifier`)*
import re
from html.entities import codepoint2name
+from sphinx.util.logging import getLogger
+
# escape the characters which codepoint > 0x7F
def _process(string):
def escape(matchobj):
def escape_for_chm(app, pagename, templatename, context, doctree):
# only works for .chm output
- if not hasattr(app.builder, 'name') or app.builder.name != 'htmlhelp':
+ if getattr(app.builder, 'name', '') != 'htmlhelp':
return
# escape the `body` part to 7-bit ASCII
if body is not None:
context['body'] = _process(body)
+def fixup_keywords(app, exception):
+ # only works for .chm output
+ if getattr(app.builder, 'name', '') != 'htmlhelp' or exception:
+ return
+
+ getLogger(__name__).info('fixing HTML escapes in keywords file...')
+ outdir = app.builder.outdir
+ outname = app.builder.config.htmlhelp_basename
+ with app.builder.open_file(outdir, outname + '.hhk', 'r') as f:
+ index = f.read()
+ with app.builder.open_file(outdir, outname + '.hhk', 'w') as f:
+ f.write(index.replace(''', '''))
+
def setup(app):
# `html-page-context` event emitted when the HTML builder has
# created a context dictionary to render a template with.
app.connect('html-page-context', escape_for_chm)
+ # `build-finished` event emitted when all the files have been
+ # output.
+ app.connect('build-finished', fixup_keywords)
return {'version': '1.0', 'parallel_read_safe': True}
import re
import io
-from os import path
+from os import getenv, path
from time import asctime
from pprint import pformat
from docutils.io import StringOutput
return [pnode]
+# Support for documenting platform availability
+
+class Availability(Directive):
+
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = True
+
+ def run(self):
+ availability_ref = ':ref:`Availability <availability>`: '
+ pnode = nodes.paragraph(availability_ref + self.arguments[0],
+ classes=["availability"],)
+ n, m = self.state.inline_text(availability_ref, self.lineno)
+ pnode.extend(n + m)
+ n, m = self.state.inline_text(self.arguments[0], self.lineno)
+ pnode.extend(n + m)
+ return [pnode]
+
+
# Support for documenting decorators
class PyDecoratorMixin(object):
fname = self.arguments[0]
source = self.state_machine.input_lines.source(
self.lineno - self.state_machine.input_offset - 1)
- source_dir = path.dirname(path.abspath(source))
+ source_dir = getenv('PY_MISC_NEWS_DIR')
+ if not source_dir:
+ source_dir = path.dirname(path.abspath(source))
fpath = path.join(source_dir, fname)
self.state.document.settings.record_dependencies.add(fpath)
try:
app.add_role('issue', issue_role)
app.add_role('source', source_role)
app.add_directive('impl-detail', ImplementationDetail)
+ app.add_directive('availability', Availability)
app.add_directive('deprecated-removed', DeprecatedRemoved)
app.add_builder(PydocTopicsBuilder)
app.add_builder(suspicious.CheckSuspiciousMarkupBuilder)
- app.add_description_unit('opcode', 'opcode', '%s (opcode)',
- parse_opcode_signature)
- app.add_description_unit('pdbcommand', 'pdbcmd', '%s (pdb command)',
- parse_pdb_command)
- app.add_description_unit('2to3fixer', '2to3fixer', '%s (2to3 fixer)')
+ app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature)
+ app.add_object_type('pdbcommand', 'pdbcmd', '%s (pdb command)', parse_pdb_command)
+ app.add_object_type('2to3fixer', '2to3fixer', '%s (2to3 fixer)')
app.add_directive_to_domain('py', 'decorator', PyDecoratorFunction)
app.add_directive_to_domain('py', 'decoratormethod', PyDecoratorMethod)
app.add_directive_to_domain('py', 'coroutinefunction', PyCoroutineFunction)
'table', 'target-notes', 'tip', 'title', 'topic', 'unicode', 'warning',
# Sphinx and Python docs custom ones
'acks', 'attribute', 'autoattribute', 'autoclass', 'autodata',
- 'autoexception', 'autofunction', 'automethod', 'automodule', 'centered',
- 'cfunction', 'class', 'classmethod', 'cmacro', 'cmdoption', 'cmember',
- 'code-block', 'confval', 'cssclass', 'ctype', 'currentmodule', 'cvar',
- 'data', 'decorator', 'decoratormethod', 'deprecated-removed',
- 'deprecated(?!-removed)', 'describe', 'directive', 'doctest', 'envvar',
- 'event', 'exception', 'function', 'glossary', 'highlight', 'highlightlang',
- 'impl-detail', 'index', 'literalinclude', 'method', 'miscnews', 'module',
- 'moduleauthor', 'opcode', 'pdbcommand', 'productionlist',
- 'program', 'role', 'sectionauthor', 'seealso', 'sourcecode', 'staticmethod',
- 'tabularcolumns', 'testcode', 'testoutput', 'testsetup', 'toctree', 'todo',
- 'todolist', 'versionadded', 'versionchanged'
+ 'autoexception', 'autofunction', 'automethod', 'automodule',
+ 'availability', 'centered', 'cfunction', 'class', 'classmethod', 'cmacro',
+ 'cmdoption', 'cmember', 'code-block', 'confval', 'cssclass', 'ctype',
+ 'currentmodule', 'cvar', 'data', 'decorator', 'decoratormethod',
+ 'deprecated-removed', 'deprecated(?!-removed)', 'describe', 'directive',
+ 'doctest', 'envvar', 'event', 'exception', 'function', 'glossary',
+ 'highlight', 'highlightlang', 'impl-detail', 'index', 'literalinclude',
+ 'method', 'miscnews', 'module', 'moduleauthor', 'opcode', 'pdbcommand',
+ 'productionlist', 'program', 'role', 'sectionauthor', 'seealso',
+ 'sourcecode', 'staticmethod', 'tabularcolumns', 'testcode', 'testoutput',
+ 'testsetup', 'toctree', 'todo', 'todolist', 'versionadded',
+ 'versionchanged'
]
all_directives = '(' + '|'.join(directives) + ')'
else
buf.push('<option value="' + language + '">' + title + '</option>');
});
+ if (!(current_language in all_languages)) {
+ // In case we're browsing a language that is not yet in all_languages.
+ buf.push('<option value="' + current_language + '" selected="selected">' +
+ current_language + '</option>');
+ all_languages[current_language] = current_language;
+ }
buf.push('</select>');
return buf.join('');
}
faq/programming,,::,for x in sequence[::-1]:
faq/programming,,:reduce,"print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y,"
faq/programming,,:reduce,"Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro,"
-faq/windows,,:bd8afb90ebf2,"Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit (Intel)] on win32"
+faq/windows,,:d48eceb,"Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32"
howto/cporting,,:encode,"if (!PyArg_ParseTuple(args, ""O:encode_object"", &myobj))"
howto/cporting,,:say,"if (!PyArg_ParseTuple(args, ""U:say_hello"", &name))"
howto/curses,,:black,"colors when it activates color mode. They are: 0:black, 1:red,"
library/pdb,,:lineno,filename:lineno
library/pickle,,:memory,"conn = sqlite3.connect("":memory:"")"
library/posix,,`,"CFLAGS=""`getconf LFS_CFLAGS`"" OPT=""-g -O2 $CFLAGS"""
-library/pprint,,::,"'Programming Language :: Python :: 2 :: Only'],"
library/pprint,,::,"'Programming Language :: Python :: 2.6',"
library/pprint,,::,"'Programming Language :: Python :: 2.7',"
+library/pprint,225,::,"'classifiers': ['Development Status :: 3 - Alpha',"
+library/pprint,225,::,"'Intended Audience :: Developers',"
+library/pprint,225,::,"'License :: OSI Approved :: MIT License',"
+library/pprint,225,::,"'Programming Language :: Python :: 2',"
+library/pprint,225,::,"'Programming Language :: Python :: 3',"
+library/pprint,225,::,"'Programming Language :: Python :: 3.2',"
+library/pprint,225,::,"'Programming Language :: Python :: 3.3',"
+library/pprint,225,::,"'Programming Language :: Python :: 3.4',"
+library/pprint,225,::,"'Topic :: Software Development :: Build Tools'],"
library/profile,,:lineno,filename:lineno(function)
library/pyexpat,,:elem1,<py:elem1 />
library/pyexpat,,:py,"xmlns:py = ""http://www.python.org/ns/"">"
<h3>{% trans %}Download{% endtrans %}</h3>
<p><a href="{{ pathto('download') }}">{% trans %}Download these documents{% endtrans %}</a></p>
-<h3>{% trans %}Docs for other versions{% endtrans %}</h3>
+<h3>{% trans %}Docs by version{% endtrans %}</h3>
<ul>
<li><a href="https://docs.python.org/3.8/">{% trans %}Python 3.8 (in development){% endtrans %}</a></li>
+ <li><a href="https://docs.python.org/3.7/">{% trans %}Python 3.7 (stable){% endtrans %}</a></li>
<li><a href="https://docs.python.org/3.6/">{% trans %}Python 3.6 (stable){% endtrans %}</a></li>
<li><a href="https://docs.python.org/3.5/">{% trans %}Python 3.5 (security-fixes){% endtrans %}</a></li>
<li><a href="https://docs.python.org/2.7/">{% trans %}Python 2.7 (stable){% endtrans %}</a></li>
- <li><a href="https://www.python.org/doc/versions/">{% trans %}Old versions{% endtrans %}</a></li>
+ <li><a href="https://www.python.org/doc/versions/">{% trans %}All versions{% endtrans %}</a></li>
</ul>
<h3>{% trans %}Other resources{% endtrans %}</h3>
or a data member). It should be considered an implementation detail and subject
to change without notice.
+.. index::
+ pair: name; mangling
+
Since there is a valid use-case for class-private members (namely to avoid name
clashes of names with names defined by subclasses), there is limited support for
such a mechanism, called :dfn:`name mangling`. Any identifier of the form
for item in zip(keys, values):
self.items_list.append(item)
+The above example would work even if ``MappingSubclass`` were to introduce a
+``__update`` identifier since it is replaced with ``_Mapping__update`` in the
+``Mapping`` class and ``_MappingSubclass__update`` in the ``MappingSubclass``
+class respectively.
+
Note that the mangling rules are designed mostly to avoid accidents; it still is
possible to access or modify a variable that is considered private. This can
even be useful in special circumstances, such as in the debugger.
------------------------
.. index::
- statement: *
+ single: * (asterisk); in function calls
Finally, the least frequently used option is to specify that a function can be
called with an arbitrary number of arguments. These arguments will be wrapped
[3, 4, 5]
.. index::
- statement: **
+ single: **; in function calls
-In the same fashion, dictionaries can deliver keyword arguments with the ``**``\
--operator::
+In the same fashion, dictionaries can deliver keyword arguments with the
+``**``\ -operator::
>>> def parrot(voltage, state='a stiff', action='voom'):
... print("-- This parrot wouldn't", action, end=' ')
.. sectionauthor:: Zachary Ware <zachary.ware@gmail.com>
.. index::
pair: function; annotations
- single: -> (return annotation assignment)
+ single: ->; function annotations
+ single: : (colon); function annotations
:ref:`Function annotations <function>` are completely optional metadata
information about the types used by user-defined functions (see :pep:`3107` and
:noindex:
Remove the first item from the list whose value is equal to *x*. It raises a
- ``ValueError`` if there is no such item.
+ :exc:`ValueError` if there is no such item.
.. method:: list.pop([i])
self.next = next
self.message = message
-Most exceptions are defined with names that end in "Error," similar to the
+Most exceptions are defined with names that end in "Error", similar to the
naming of the standard exceptions.
Many standard modules define their own exceptions to report errors that may
line by itself in an example means you must type a blank line; this is used to
end a multi-line command.
+.. index:: single: # (hash); comment
+
Many of the examples in this manual, even those entered at the interactive
prompt, include comments. Comments in Python start with the hash character,
``#``, and extend to the end of the physical line. A comment may appear at the
This may also be enabled at runtime with
:func:`sys._enablelegacywindowsfsencoding()`.
- Availability: Windows
+ .. availability:: Windows.
.. versionadded:: 3.6
See :pep:`529` for more details.
This variable is ignored if the standard streams are redirected (to files
or pipes) rather than referring to console buffers.
- Availability: Windows
+ .. availability:: Windows.
.. versionadded:: 3.6
order to force the interpreter to use ``ASCII`` instead of ``UTF-8`` for
system interfaces.
- Availability: \*nix
+ .. availability:: \*nix.
.. versionadded:: 3.7
See :pep:`538` for more details.
Also available as the :option:`-X` ``utf8`` option.
- Availability: \*nix
+ .. availability:: \*nix.
.. versionadded:: 3.7
See :pep:`540` for more details.
================
There are a number of IDEs that support Python programming language.
-Many editors and IDEs provide syntax highlighting, debugging tools, and PEP-8 checks.
+Many editors and IDEs provide syntax highlighting, debugging tools, and :pep:`8` checks.
Please go to `Python Editors <https://wiki.python.org/moin/PythonEditors>`_ and
`Integrated Development Environments <https://wiki.python.org/moin/IntegratedDevelopmentEnvironments>`_
Once a virtual environment has been created, it can be "activated" using a
script in the virtual environment's binary directory. The invocation of the
-script is platform-specific:
+script is platform-specific (`<venv>` must be replaced by the path of the
+directory containing the virtual environment):
+-------------+-----------------+-----------------------------------------+
| Platform | Shell | Command to activate virtual environment |
This document aims to give an overview of Windows-specific behaviour you should
know about when using Python on Microsoft Windows.
-Installing Python
-=================
-
Unlike most Unix systems and services, Windows does not include a system
supported installation of Python. To make Python available, the CPython team
has compiled Windows installers (MSI packages) with every `release
able to install for all users of a single machine, and a separate ZIP file is
available for application-local distributions.
-Supported Versions
-------------------
-
As specified in :pep:`11`, a Python release only supports a Windows platform
while Microsoft considers the platform under extended support. This means that
Python |version| supports Windows Vista and newer. If you require Windows XP
support then please install Python 3.4.
-Installation Steps
+There are a number of different installers available for Windows, each with
+certain benefits and downsides.
+
+:ref:`windows-full` contains all components and is the best option for
+developers using Python for any kind of project.
+
+:ref:`windows-store` is a simple installation of Python that is suitable for
+running scripts and packages, and using IDLE or other development environments.
+It requires Windows 10, but can be safely installed without corrupting other
+programs. It also provides many convenient commands for launching Python and
+its tools.
+
+:ref:`windows-nuget` are lightweight installations intended for continuous
+integration systems. It can be used to build Python packages or run scripts,
+but is not updateable and has no user interface tools.
+
+:ref:`windows-embeddable` is a minimal package of Python suitable for
+embedding into a larger application.
+
+
+.. _windows-full:
+
+The full installer
+==================
+
+Installation steps
------------------
Four Python |version| installers are available for download - two each for the
"Uninstall" will remove Python entirely, with the exception of the
:ref:`launcher`, which has its own entry in Programs and Features.
-Other Platforms
----------------
-With ongoing development of Python, some platforms that used to be supported
-earlier are no longer supported (due to the lack of users or developers).
-Check :pep:`11` for details on all unsupported platforms.
+.. _windows-store:
-* `Windows CE <http://pythonce.sourceforge.net/>`_ is still supported.
-* The `Cygwin <https://cygwin.com/>`_ installer offers to install the Python
- interpreter as well (cf. `Cygwin package source
- <ftp://ftp.uni-erlangen.de/pub/pc/gnuwin32/cygwin/mirrors/cygnus/
- release/python>`_, `Maintainer releases
- <http://www.tishler.net/jason/software/python/>`_)
+The Microsoft Store package
+===========================
-See `Python for Windows <https://www.python.org/downloads/windows/>`_
-for detailed information about platforms with pre-compiled installers.
+.. versionadded:: 3.7.2
-.. seealso::
+.. note::
+ The Microsoft Store package is currently considered unstable while its
+ interactions with other tools and other copies of Python are evaluated.
+ While Python itself is stable, this installation method may change its
+ behavior and capabilities during Python 3.7 releases.
- `Python on XP <http://dooling.com/index.php/2006/03/14/python-on-xp-7-minutes-to-hello-world/>`_
- "7 Minutes to "Hello World!""
- by Richard Dooling, 2006
+The Microsoft Store package is an easily installable Python interpreter that
+is intended mainly for interactive use, for example, by students.
- `Installing on Windows <http://www.diveintopython.net/installing_python/windows.html>`_
- in "`Dive into Python: Python from novice to pro
- <http://www.diveintopython.net/>`_"
- by Mark Pilgrim, 2004,
- ISBN 1-59059-356-1
+To install the package, ensure you have the latest Windows 10 updates and
+search the Microsoft Store app for "Python |version|". Ensure that the app
+you select is published by the Python Software Foundation, and install it.
- `For Windows users <https://python.swaroopch.com/installation.html#installation-on-windows>`_
- in "Installing Python"
- in "`A Byte of Python <https://python.swaroopch.com/>`_"
- by Swaroop C H, 2003
+.. warning::
+ Python will always be available for free on the Microsoft Store. If you
+ are asked to pay for it, you have not selected the correct package.
+
+After installation, Python may be launched by finding it in Start.
+Alternatively, it will be available from any Command Prompt or PowerShell
+session by typing ``python``. Further, pip and IDLE may be used by typing
+``pip`` or ``idle``. IDLE can also be found in Start.
+
+All three commands are also available with version number suffixes, for
+example, as ``python3.exe`` and ``python3.x.exe`` as well as
+``python.exe`` (where ``3.x`` is the specific version you want to launch,
+such as |version|).
+
+Virtual environments can be created with ``python -m venv`` and activated
+and used as normal.
+
+If you have installed another version of Python and added it to your
+``PATH`` variable, it will be available as ``python.exe`` rather than the
+one from the Microsoft Store. To access the new installation, use
+``python3.exe`` or ``python3.x.exe``.
+
+To remove Python, open Settings and use Apps and Features, or else find
+Python in Start and right-click to select Uninstall. Uninstalling will
+remove all packages you installed directly into this Python installation, but
+will not remove any virtual environments
+
+Known Issues
+------------
+
+Currently, the ``py.exe`` launcher cannot be used to start Python when it
+has been installed from the Microsoft Store.
+
+Because of restrictions on Microsoft Store apps, Python scripts may not have
+full write access to shared locations such as ``TEMP`` and the registry.
+Instead, it will write to a private copy. If your scripts must modify the
+shared locations, you will need to install the full installer.
+
+
+.. _windows-nuget:
+
+The nuget.org packages
+======================
+
+.. versionadded:: 3.5.2
+
+The nuget.org package is a reduced size Python environment intended for use on
+continuous integration and build systems that do not have a system-wide
+install of Python. While nuget is "the package manager for .NET", it also works
+perfectly fine for packages containing build-time tools.
+
+Visit `nuget.org <https://www.nuget.org/>`_ for the most up-to-date information
+on using nuget. What follows is a summary that is sufficient for Python
+developers.
+
+The ``nuget.exe`` command line tool may be downloaded directly from
+``https://aka.ms/nugetclidl``, for example, using curl or PowerShell. With the
+tool, the latest version of Python for 64-bit or 32-bit machines is installed
+using::
+
+ nuget.exe install python -ExcludeVersion -OutputDirectory .
+ nuget.exe install pythonx86 -ExcludeVersion -OutputDirectory .
+
+To select a particular version, add a ``-Version 3.x.y``. The output directory
+may be changed from ``.``, and the package will be installed into a
+subdirectory. By default, the subdirectory is named the same as the package,
+and without the ``-ExcludeVersion`` option this name will include the specific
+version installed. Inside the subdirectory is a ``tools`` directory that
+contains the Python installation::
+
+ # Without -ExcludeVersion
+ > .\python.3.5.2\tools\python.exe -V
+ Python 3.5.2
+
+ # With -ExcludeVersion
+ > .\python\tools\python.exe -V
+ Python 3.5.2
+
+In general, nuget packages are not upgradeable, and newer versions should be
+installed side-by-side and referenced using the full path. Alternatively,
+delete the package directory manually and install it again. Many CI systems
+will do this automatically if they do not preserve files between builds.
+
+Alongside the ``tools`` directory is a ``build\native`` directory. This
+contains a MSBuild properties file ``python.props`` that can be used in a
+C++ project to reference the Python install. Including the settings will
+automatically use the headers and import libraries in your build.
+
+The package information pages on nuget.org are
+`www.nuget.org/packages/python <https://www.nuget.org/packages/python>`_
+for the 64-bit version and `www.nuget.org/packages/pythonx86
+<https://www.nuget.org/packages/pythonx86>`_ for the 32-bit version.
+
+
+.. _windows-embeddable:
+
+The embeddable package
+======================
+
+.. versionadded:: 3.5
+
+The embedded distribution is a ZIP file containing a minimal Python environment.
+It is intended for acting as part of another application, rather than being
+directly accessed by end-users.
+
+When extracted, the embedded distribution is (almost) fully isolated from the
+user's system, including environment variables, system registry settings, and
+installed packages. The standard library is included as pre-compiled and
+optimized ``.pyc`` files in a ZIP, and ``python3.dll``, ``python37.dll``,
+``python.exe`` and ``pythonw.exe`` are all provided. Tcl/tk (including all
+dependants, such as Idle), pip and the Python documentation are not included.
+
+.. note::
+
+ The embedded distribution does not include the `Microsoft C Runtime
+ <https://www.microsoft.com/en-us/download/details.aspx?id=48145>`_ and it is
+ the responsibility of the application installer to provide this. The
+ runtime may have already been installed on a user's system previously or
+ automatically via Windows Update, and can be detected by finding
+ ``ucrtbase.dll`` in the system directory.
+
+Third-party packages should be installed by the application installer alongside
+the embedded distribution. Using pip to manage dependencies as for a regular
+Python installation is not supported with this distribution, though with some
+care it may be possible to include and use pip for automatic updates. In
+general, third-party packages should be treated as part of the application
+("vendoring") so that the developer can ensure compatibility with newer
+versions before providing updates to users.
+
+The two recommended use cases for this distribution are described below.
+
+Python Application
+------------------
+
+An application written in Python does not necessarily require users to be aware
+of that fact. The embedded distribution may be used in this case to include a
+private version of Python in an install package. Depending on how transparent it
+should be (or conversely, how professional it should appear), there are two
+options.
+
+Using a specialized executable as a launcher requires some coding, but provides
+the most transparent experience for users. With a customized launcher, there are
+no obvious indications that the program is running on Python: icons can be
+customized, company and version information can be specified, and file
+associations behave properly. In most cases, a custom launcher should simply be
+able to call ``Py_Main`` with a hard-coded command line.
+
+The simpler approach is to provide a batch file or generated shortcut that
+directly calls the ``python.exe`` or ``pythonw.exe`` with the required
+command-line arguments. In this case, the application will appear to be Python
+and not its actual name, and users may have trouble distinguishing it from other
+running Python processes or file associations.
+
+With the latter approach, packages should be installed as directories alongside
+the Python executable to ensure they are available on the path. With the
+specialized launcher, packages can be located in other locations as there is an
+opportunity to specify the search path before launching the application.
+
+Embedding Python
+----------------
+
+Applications written in native code often require some form of scripting
+language, and the embedded Python distribution can be used for this purpose. In
+general, the majority of the application is in native code, and some part will
+either invoke ``python.exe`` or directly use ``python3.dll``. For either case,
+extracting the embedded distribution to a subdirectory of the application
+installation is sufficient to provide a loadable Python interpreter.
+
+As with the application use, packages can be installed to any location as there
+is an opportunity to specify search paths before initializing the interpreter.
+Otherwise, there is no fundamental differences between using the embedded
+distribution and a regular installation.
Alternative bundles
system-wide ones, and orders by language version rather than using the most
recently installed version.
+The launcher was originally specified in :pep:`397`.
+
Getting started
---------------
Windows function ``SHGetFolderPath`` with ``CSIDL_LOCAL_APPDATA``) and ``py.ini`` in the
same directory as the launcher. The same .ini files are used for both the
'console' version of the launcher (i.e. py.exe) and for the 'windows' version
-(i.e. pyw.exe)
+(i.e. pyw.exe).
Customization specified in the "application directory" will have precedence over
the one next to the executable, so a user, who may not have write access to the
-.ini file next to the launcher, can override commands in that global .ini file)
+.ini file next to the launcher, can override commands in that global .ini file.
Customizing default Python versions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
by Trent Apted et al, 2007
-Embedded Distribution
-=====================
-
-.. versionadded:: 3.5
-
-The embedded distribution is a ZIP file containing a minimal Python environment.
-It is intended for acting as part of another application, rather than being
-directly accessed by end-users.
-
-When extracted, the embedded distribution is (almost) fully isolated from the
-user's system, including environment variables, system registry settings, and
-installed packages. The standard library is included as pre-compiled and
-optimized ``.pyc`` files in a ZIP, and ``python3.dll``, ``python37.dll``,
-``python.exe`` and ``pythonw.exe`` are all provided. Tcl/tk (including all
-dependants, such as Idle), pip and the Python documentation are not included.
-
-.. note::
-
- The embedded distribution does not include the `Microsoft C Runtime
- <https://www.microsoft.com/en-us/download/details.aspx?id=48145>`_ and it is
- the responsibility of the application installer to provide this. The
- runtime may have already been installed on a user's system previously or
- automatically via Windows Update, and can be detected by finding
- ``ucrtbase.dll`` in the system directory.
-
-Third-party packages should be installed by the application installer alongside
-the embedded distribution. Using pip to manage dependencies as for a regular
-Python installation is not supported with this distribution, though with some
-care it may be possible to include and use pip for automatic updates. In
-general, third-party packages should be treated as part of the application
-("vendoring") so that the developer can ensure compatibility with newer
-versions before providing updates to users.
-
-The two recommended use cases for this distribution are described below.
-
-Python Application
-------------------
-
-An application written in Python does not necessarily require users to be aware
-of that fact. The embedded distribution may be used in this case to include a
-private version of Python in an install package. Depending on how transparent it
-should be (or conversely, how professional it should appear), there are two
-options.
-
-Using a specialized executable as a launcher requires some coding, but provides
-the most transparent experience for users. With a customized launcher, there are
-no obvious indications that the program is running on Python: icons can be
-customized, company and version information can be specified, and file
-associations behave properly. In most cases, a custom launcher should simply be
-able to call ``Py_Main`` with a hard-coded command line.
-
-The simpler approach is to provide a batch file or generated shortcut that
-directly calls the ``python.exe`` or ``pythonw.exe`` with the required
-command-line arguments. In this case, the application will appear to be Python
-and not its actual name, and users may have trouble distinguishing it from other
-running Python processes or file associations.
-
-With the latter approach, packages should be installed as directories alongside
-the Python executable to ensure they are available on the path. With the
-specialized launcher, packages can be located in other locations as there is an
-opportunity to specify the search path before launching the application.
-
-Embedding Python
-----------------
-
-Applications written in native code often require some form of scripting
-language, and the embedded Python distribution can be used for this purpose. In
-general, the majority of the application is in native code, and some part will
-either invoke ``python.exe`` or directly use ``python3.dll``. For either case,
-extracting the embedded distribution to a subdirectory of the application
-installation is sufficient to provide a loadable Python interpreter.
-
-As with the application use, packages can be installed to any location as there
-is an opportunity to specify search paths before initializing the interpreter.
-Otherwise, there is no fundamental differences between using the embedded
-distribution and a regular installation.
-
-Other resources
+Other Platforms
===============
-.. seealso::
-
- `Python Programming On Win32 <http://shop.oreilly.com/product/9781565926219.do>`_
- "Help for Windows Programmers"
- by Mark Hammond and Andy Robinson, O'Reilly Media, 2000,
- ISBN 1-56592-621-8
+With ongoing development of Python, some platforms that used to be supported
+earlier are no longer supported (due to the lack of users or developers).
+Check :pep:`11` for details on all unsupported platforms.
- `A Python for Windows Tutorial <http://www.imladris.com/Scripts/PythonForWindows.html>`_
- by Amanda Birmingham, 2004
+* `Windows CE <http://pythonce.sourceforge.net/>`_ is still supported.
+* The `Cygwin <https://cygwin.com/>`_ installer offers to install the Python
+ interpreter as well (cf. `Cygwin package source
+ <ftp://ftp.uni-erlangen.de/pub/pc/gnuwin32/cygwin/mirrors/cygnus/
+ release/python>`_, `Maintainer releases
+ <http://www.tishler.net/jason/software/python/>`_)
- :pep:`397` - Python launcher for Windows
- The proposal for the launcher to be included in the Python distribution.
+See `Python for Windows <https://www.python.org/downloads/windows/>`_
+for detailed information about platforms with pre-compiled installers.
variables are preserved. On the next call to the generator's ``next()`` method,
the function will resume executing immediately after the :keyword:`yield`
statement. (For complicated reasons, the :keyword:`yield` statement isn't
-allowed inside the :keyword:`try` block of a :keyword:`try`...\
-:keyword:`finally` statement; read :pep:`255` for a full explanation of the
-interaction between :keyword:`yield` and exceptions.)
+allowed inside the :keyword:`try` block of a
+:keyword:`try`...\ :keyword:`finally` statement; read :pep:`255` for a full
+explanation of the interaction between :keyword:`yield` and exceptions.)
Here's a sample usage of the :func:`generate_ints` generator::
variables are preserved. On the next call to the generator's ``.next()``
method, the function will resume executing immediately after the
:keyword:`yield` statement. (For complicated reasons, the :keyword:`yield`
-statement isn't allowed inside the :keyword:`try` block of a :keyword:`try`...\
-:keyword:`finally` statement; read :pep:`255` for a full explanation of the
-interaction between :keyword:`yield` and exceptions.)
+statement isn't allowed inside the :keyword:`try` block of a
+:keyword:`try`...\ :keyword:`finally` statement; read :pep:`255` for a full
+explanation of the interaction between :keyword:`yield` and exceptions.)
Here's a sample usage of the :func:`generate_ints` generator::
will have to change your ``import`` statements to import it as :mod:`bsddb`.
* The new :mod:`bz2` module is an interface to the bz2 data compression library.
- bz2-compressed data is usually smaller than corresponding :mod:`zlib`\
- -compressed data. (Contributed by Gustavo Niemeyer.)
+ bz2-compressed data is usually smaller than corresponding
+ :mod:`zlib`\ -compressed data. (Contributed by Gustavo Niemeyer.)
* A set of standard date/time types has been added in the new :mod:`datetime`
module. See the following section for more details.
The parentheses aren't always necessary, but it's easier to always add them
instead of having to remember when they're needed.
-(:pep:`342` explains the exact rules, which are that a :keyword:`yield`\
--expression must always be parenthesized except when it occurs at the top-level
+(:pep:`342` explains the exact rules, which are that a
+:keyword:`yield`\ -expression must always be parenthesized except when it
+occurs at the top-level
expression on the right-hand side of an assignment. This means you can write
``val = yield i`` but have to use parentheses when there's an operation, as in
``val = (yield i) + 12``.)
:class:`~ssl.SSLContext` has a new method,
:meth:`~ssl.SSLContext.cert_store_stats`, that reports the number of loaded
-``X.509`` certs, ``X.509 CA`` certs, and certificate revocation lists (``crl``\
-s), as well as a :meth:`~ssl.SSLContext.get_ca_certs` method that returns a
-list of the loaded ``CA`` certificates. (Contributed by Christian Heimes in
-:issue:`18147`.)
+``X.509`` certs, ``X.509 CA`` certs, and certificate revocation lists
+(``crl``\ s), as well as a :meth:`~ssl.SSLContext.get_ca_certs` method that
+returns a list of the loaded ``CA`` certificates. (Contributed by Christian
+Heimes in :issue:`18147`.)
If OpenSSL 0.9.8 or later is available, :class:`~ssl.SSLContext` has a new
attribute :attr:`~ssl.SSLContext.verify_flags` that can be used to control the
RuntimeError: generator raised StopIteration
Without a ``__future__`` import, a :exc:`PendingDeprecationWarning` will be
-raised whenever a ``StopIteration`` exception is raised inside a generator.
+raised whenever a :exc:`StopIteration` exception is raised inside a generator.
.. seealso::
* A ``global`` or ``nonlocal`` statement must now textually appear
before the first use of the affected name in the same scope.
- Previously this was a ``SyntaxWarning``.
+ Previously this was a :exc:`SyntaxWarning`.
* It is now possible to set a :ref:`special method <specialnames>` to
``None`` to indicate that the corresponding operation is not available.
The :func:`locale.localeconv` function now sets temporarily the ``LC_CTYPE``
locale to the ``LC_NUMERIC`` locale in some cases.
(Contributed by Victor Stinner in :issue:`31900`.)
+
+Notable changes in Python 3.6.7
+===============================
+
+In 3.6.7 the :mod:`tokenize` module now implicitly emits a ``NEWLINE`` token
+when provided with input that does not have a trailing new line. This behavior
+now matches what the C tokenizer does internally.
+(Contributed by Ammar Askar in :issue:`33899`.)
generated. While effective, this invalidation method has its drawbacks. When
filesystem timestamps are too coarse, Python can miss source updates, leading to
user confusion. Additionally, having a timestamp in the cache file is
-problematic for `build reproduciblity <https://reproducible-builds.org/>`_ and
+problematic for `build reproducibility <https://reproducible-builds.org/>`_ and
content-based build systems.
:pep:`552` extends the pyc format to allow the hash of the source file to be
lacks a spec.
(Contributed by Garvit Khatri in :issue:`29851`.)
-:func:`importlib.find_spec` now raises ``ModuleNotFoundError`` instead of
+:func:`importlib.find_spec` now raises :exc:`ModuleNotFoundError` instead of
:exc:`AttributeError` if the specified parent module is not a package (i.e.
lacks a ``__path__`` attribute).
(Contributed by Milan Oberkirch in :issue:`30436`.)
:mod:`xml.dom.minidom` and :mod:`xml.sax` modules no longer process
external entities by default. See also :issue:`17239`.
+
+In 3.7.1 the :mod:`tokenize` module now implicitly emits a ``NEWLINE`` token
+when provided with input that does not have a trailing new line. This behavior
+now matches what the C tokenizer does internally.
+(Contributed by Ammar Askar in :issue:`33899`.)
+
+Notable changes in Python 3.7.2
+===============================
+
+In 3.7.2, :mod:`venv` on Windows no longer copies the original binaries, but
+creates redirector scripts named ``python.exe`` and ``pythonw.exe`` instead.
+This resolves a long standing issue where all virtual environments would have
+to be upgraded or recreated with each Python update. However, note that this
+release will still require recreation of virtual environments in order to get
+the new scripts.
#include "pyport.h"
#include "pymacro.h"
+/* A convenient way for code to know if clang's memory sanitizer is enabled. */
+#if defined(__has_feature)
+# if __has_feature(memory_sanitizer)
+# if !defined(_Py_MEMORY_SANITIZER)
+# define _Py_MEMORY_SANITIZER
+# endif
+# endif
+#endif
+
#include "pyatomic.h"
/* Debug-mode build with pymalloc implies PYMALLOC_DEBUG.
PyAPI_FUNC(PyObject *) PyEval_GetLocals(void);
PyAPI_FUNC(struct _frame *) PyEval_GetFrame(void);
+#ifndef Py_LIMITED_API
+/* Helper to look up a builtin object */
+PyAPI_FUNC(PyObject *) _PyEval_GetBuiltinId(_Py_Identifier *);
/* Look at the current frame's (if any) code's co_flags, and turn on
the corresponding compiler flags in cf->cf_flags. Return 1 if any
flag was set, else return 0. */
-#ifndef Py_LIMITED_API
PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf);
#endif
#ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _Py_device_encoding(int);
+#if defined(MS_WINDOWS) || defined(__APPLE__)
+ /* On Windows, the count parameter of read() is an int (bpo-9015, bpo-9611).
+ On macOS 10.13, read() and write() with more than INT_MAX bytes
+ fail with EINVAL (bpo-24658). */
+# define _PY_READ_MAX INT_MAX
+# define _PY_WRITE_MAX INT_MAX
+#else
+ /* write() should truncate the input to PY_SSIZE_T_MAX bytes,
+ but it's safer to do it ourself to have a portable behaviour */
+# define _PY_READ_MAX PY_SSIZE_T_MAX
+# define _PY_WRITE_MAX PY_SSIZE_T_MAX
+#endif
+
#ifdef MS_WINDOWS
struct _Py_stat_struct {
unsigned long st_dev;
#endif /* Py_LIMITED_API */
+#ifdef Py_BUILD_CORE
+PyAPI_FUNC(int) _Py_GetForceASCII(void);
+
+/* Reset "force ASCII" mode (if it was initialized).
+
+ This function should be called when Python changes the LC_CTYPE locale,
+ so the "force ASCII" mode can be detected again on the new locale
+ encoding. */
+PyAPI_FUNC(void) _Py_ResetForceASCII(void);
+#endif
+
#ifdef __cplusplus
}
#endif
PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
PyAPI_FUNC(void) _Py_BreakPoint(void);
PyAPI_FUNC(void) _PyObject_Dump(PyObject *);
+PyAPI_FUNC(int) _PyObject_IsFreed(PyObject *);
#endif
PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *);
/*--start constants--*/
#define PY_MAJOR_VERSION 3
#define PY_MINOR_VERSION 7
-#define PY_MICRO_VERSION 1
+#define PY_MICRO_VERSION 2
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL
#define PY_RELEASE_SERIAL 0
/* Version as a string */
-#define PY_VERSION "3.7.1"
+#define PY_VERSION "3.7.2"
/*--end constants--*/
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
#endif
#if defined(__clang__) || \
- (defined(__GNUC_MAJOR__) && \
- ((__GNUC_MAJOR__ >= 3) || \
- (__GNUC_MAJOR__ == 2) && (__GNUC_MINOR__ >= 5)))
+ (defined(__GNUC__) && \
+ ((__GNUC__ >= 3) || \
+ (__GNUC__ == 2) && (__GNUC_MINOR__ >= 5)))
#define _Py_NO_RETURN __attribute__((__noreturn__))
#else
#define _Py_NO_RETURN
PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void);
#ifndef Py_LIMITED_API
+PyAPI_FUNC(void) _Py_SetProgramFullPath(const wchar_t *);
+
/* Only used by applications that embed the interpreter and need to
* override the standard encoding determination mechanism
*/
PyAPI_FUNC(void) _Py_Initialize_ReadEnvVarsNoAlloc(void);
#endif
+PyAPI_FUNC(PyObject *) _Py_GetGlobalVariablesAsDict(void);
+
PyAPI_FUNC(_PyInitError) _PyCoreConfig_Read(_PyCoreConfig *);
PyAPI_FUNC(void) _PyCoreConfig_Clear(_PyCoreConfig *);
PyAPI_FUNC(int) _PyCoreConfig_Copy(
_PyCoreConfig *config,
const _PyCoreConfig *config2);
+PyAPI_FUNC(PyObject *) _PyCoreConfig_AsDict(const _PyCoreConfig *config);
PyAPI_FUNC(void) _PyCoreConfig_SetGlobalConfig(
const _PyCoreConfig *config);
PyAPI_FUNC(int) _PyMainInterpreterConfig_Copy(
_PyMainInterpreterConfig *config,
const _PyMainInterpreterConfig *config2);
+/* Used by _testcapi.get_main_config() */
+PyAPI_FUNC(PyObject*) _PyMainInterpreterConfig_AsDict(
+ const _PyMainInterpreterConfig *config);
PyAPI_FUNC(_PyInitError) _Py_InitializeMainInterpreter(
PyInterpreterState *interp,
PyAPI_FUNC(void) _Py_FatalInitError(_PyInitError err) _Py_NO_RETURN;
#endif
PyAPI_FUNC(void) Py_Finalize(void);
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000
PyAPI_FUNC(int) Py_FinalizeEx(void);
+#endif
PyAPI_FUNC(int) Py_IsInitialized(void);
/* Subinterpreter support */
PyAPI_FUNC(PyObject*) _PyTraceMalloc_GetTraceback(
unsigned int domain,
uintptr_t ptr);
-#endif /* !Py_LIMITED_API */
+
+PyAPI_FUNC(int) _PyMem_IsFreed(void *ptr, size_t size);
+#endif /* !defined(Py_LIMITED_API) */
/* BEWARE:
see Objects/stringlib/localeutil.h */
#ifndef Py_LIMITED_API
PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGrouping(
- PyObject *unicode,
- Py_ssize_t index,
+ _PyUnicodeWriter *writer,
Py_ssize_t n_buffer,
- void *digits,
+ PyObject *digits,
+ Py_ssize_t d_pos,
Py_ssize_t n_digits,
Py_ssize_t min_width,
const char *grouping,
_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS',
'BLDSHARED', 'LDSHARED', 'CC', 'CXX',
'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
- 'PY_CORE_CFLAGS')
+ 'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS')
# configuration variables that may contain compiler calls
_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX')
if not other and not self:
return context._raise_error(InvalidOperation,
'at least one of pow() 1st argument '
- 'and 2nd argument must be nonzero ;'
+ 'and 2nd argument must be nonzero; '
'0**0 is not defined')
# compute sign of result
futures._get_loop(fut).stop()
+if hasattr(socket, 'TCP_NODELAY'):
+ def _set_nodelay(sock):
+ if (sock.family in {socket.AF_INET, socket.AF_INET6} and
+ sock.type == socket.SOCK_STREAM and
+ sock.proto == socket.IPPROTO_TCP):
+ sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+else:
+ def _set_nodelay(sock):
+ pass
+
+
class _SendfileFallbackProtocol(protocols.Protocol):
def __init__(self, transp):
if not isinstance(transp, transports._FlowControlMixin):
_sendfile_compatible = constants._SendfileMode.TRY_NATIVE
+ def __init__(self, loop, sock, protocol, waiter=None,
+ extra=None, server=None):
+ super().__init__(loop, sock, protocol, waiter, extra, server)
+ base_events._set_nodelay(sock)
+
def _set_extra(self, sock):
self._extra['socket'] = sock
return bool(key.events & event)
-if hasattr(socket, 'TCP_NODELAY'):
- def _set_nodelay(sock):
- if (sock.family in {socket.AF_INET, socket.AF_INET6} and
- sock.type == socket.SOCK_STREAM and
- sock.proto == socket.IPPROTO_TCP):
- sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-else:
- def _set_nodelay(sock):
- pass
-
-
class BaseSelectorEventLoop(base_events.BaseEventLoop):
"""Selector event loop.
# Disable the Nagle algorithm -- small writes will be
# sent without waiting for the TCP ACK. This generally
# decreases the latency (in some cases significantly.)
- _set_nodelay(self._sock)
+ base_events._set_nodelay(self._sock)
self._loop.call_soon(self._protocol.connection_made, self)
# only start reading when connection_made() has been called
import os
import sys
import runpy
+ import pstats
from optparse import OptionParser
usage = "cProfile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..."
parser = OptionParser(usage=usage)
help="Save stats to <outfile>", default=None)
parser.add_option('-s', '--sort', dest="sort",
help="Sort order when printing to stdout, based on pstats.Stats class",
- default=-1)
+ default=-1,
+ choices=sorted(pstats.Stats.sort_arg_dict_default))
parser.add_option('-m', dest="module", action="store_true",
help="Profile a library module", default=False)
"""
def __init__(self, fp=None, headers=None, outerboundary=b'',
environ=os.environ, keep_blank_values=0, strict_parsing=0,
- limit=None, encoding='utf-8', errors='replace'):
+ limit=None, encoding='utf-8', errors='replace',
+ max_num_fields=None):
"""Constructor. Read multipart/* until last part.
Arguments, all optional:
for the page sending the form (content-type : meta http-equiv or
header)
+ max_num_fields: int. If set, then __init__ throws a ValueError
+ if there are more than n fields read by parse_qsl().
+
"""
method = 'GET'
self.keep_blank_values = keep_blank_values
self.strict_parsing = strict_parsing
+ self.max_num_fields = max_num_fields
if 'REQUEST_METHOD' in environ:
method = environ['REQUEST_METHOD'].upper()
self.qs_on_post = None
qs = qs.decode(self.encoding, self.errors)
if self.qs_on_post:
qs += '&' + self.qs_on_post
- self.list = []
query = urllib.parse.parse_qsl(
qs, self.keep_blank_values, self.strict_parsing,
- encoding=self.encoding, errors=self.errors)
- for key, value in query:
- self.list.append(MiniFieldStorage(key, value))
+ encoding=self.encoding, errors=self.errors,
+ max_num_fields=self.max_num_fields)
+ self.list = [MiniFieldStorage(key, value) for key, value in query]
self.skip_lines()
FieldStorageClass = None
if self.qs_on_post:
query = urllib.parse.parse_qsl(
self.qs_on_post, self.keep_blank_values, self.strict_parsing,
- encoding=self.encoding, errors=self.errors)
- for key, value in query:
- self.list.append(MiniFieldStorage(key, value))
+ encoding=self.encoding, errors=self.errors,
+ max_num_fields=self.max_num_fields)
+ self.list.extend(MiniFieldStorage(key, value) for key, value in query)
klass = self.FieldStorageClass or self.__class__
first_line = self.fp.readline() # bytes
first_line = self.fp.readline()
self.bytes_read += len(first_line)
+ # Propagate max_num_fields into the sub class appropriately
+ max_num_fields = self.max_num_fields
+ if max_num_fields is not None:
+ max_num_fields -= len(self.list)
+
while True:
parser = FeedParser()
hdr_text = b""
part = klass(self.fp, headers, ib, environ, keep_blank_values,
strict_parsing,self.limit-self.bytes_read,
- self.encoding, self.errors)
+ self.encoding, self.errors, max_num_fields)
+
+ if max_num_fields is not None:
+ max_num_fields -= 1
+ if part.list:
+ max_num_fields -= len(part.list)
+ if max_num_fields < 0:
+ raise ValueError('Max number of fields exceeded')
+
self.bytes_read += part.bytes_read
self.list.append(part)
if part.done or self.bytes_read >= self.length > 0:
import py_compile
import struct
-try:
- from concurrent.futures import ProcessPoolExecutor
-except ImportError:
- ProcessPoolExecutor = None
from functools import partial
__all__ = ["compile_dir","compile_file","compile_path"]
def compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None,
quiet=0, legacy=False, optimize=-1, workers=1,
- invalidation_mode=py_compile.PycInvalidationMode.TIMESTAMP):
+ invalidation_mode=None):
"""Byte-compile all modules in the given directory tree.
Arguments (only dir is required):
workers: maximum number of parallel workers
invalidation_mode: how the up-to-dateness of the pyc will be checked
"""
- if workers is not None and workers < 0:
- raise ValueError('workers must be greater or equal to 0')
-
+ ProcessPoolExecutor = None
+ if workers is not None:
+ if workers < 0:
+ raise ValueError('workers must be greater or equal to 0')
+ elif workers != 1:
+ try:
+ # Only import when needed, as low resource platforms may
+ # fail to import it
+ from concurrent.futures import ProcessPoolExecutor
+ except ImportError:
+ workers = 1
files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels,
ddir=ddir)
success = True
def compile_file(fullname, ddir=None, force=False, rx=None, quiet=0,
legacy=False, optimize=-1,
- invalidation_mode=py_compile.PycInvalidationMode.TIMESTAMP):
+ invalidation_mode=None):
"""Byte-compile one file.
Arguments (only fullname is required):
def compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=0,
legacy=False, optimize=-1,
- invalidation_mode=py_compile.PycInvalidationMode.TIMESTAMP):
+ invalidation_mode=None):
"""Byte-compile all module on sys.path.
Arguments (all optional):
type=int, help='Run compileall concurrently')
invalidation_modes = [mode.name.lower().replace('_', '-')
for mode in py_compile.PycInvalidationMode]
- parser.add_argument('--invalidation-mode', default='timestamp',
+ parser.add_argument('--invalidation-mode',
choices=sorted(invalidation_modes),
- help='How the pycs will be invalidated at runtime')
+ help=('set .pyc invalidation mode; defaults to '
+ '"checked-hash" if the SOURCE_DATE_EPOCH '
+ 'environment variable is set, and '
+ '"timestamp" otherwise.'))
args = parser.parse_args()
compile_dests = args.compile_dest
if args.workers is not None:
args.workers = args.workers or None
- ivl_mode = args.invalidation_mode.replace('-', '_').upper()
- invalidation_mode = py_compile.PycInvalidationMode[ivl_mode]
+ if args.invalidation_mode:
+ ivl_mode = args.invalidation_mode.replace('-', '_').upper()
+ invalidation_mode = py_compile.PycInvalidationMode[ivl_mode]
+ else:
+ invalidation_mode = None
success = True
try:
if self._shutdown:
raise RuntimeError('cannot schedule new futures after shutdown')
if _shutdown:
- raise RuntimeError('cannot schedule new futures after'
+ raise RuntimeError('cannot schedule new futures after '
'interpreter shutdown')
f = _base.Future()
x.value = "y"
c_char.from_param(b"x")
self.assertRaises(TypeError, c_char.from_param, "x")
+ self.assertIn('xbd', repr(c_char.from_param(b"\xbd")))
(c_char * 3)(b"a", b"b", b"c")
self.assertRaises(TypeError, c_char * 3, "a", "b", "c")
import inspect
import keyword
import builtins
+import functools
+import _thread
+
__all__ = ['dataclass',
'field',
return f'({",".join([f"{obj_name}.{f.name}" for f in fields])},)'
+# This function's logic is copied from "recursive_repr" function in
+# reprlib module to avoid dependency.
+def _recursive_repr(user_function):
+ # Decorator to make a repr function return "..." for a recursive
+ # call.
+ repr_running = set()
+
+ @functools.wraps(user_function)
+ def wrapper(self):
+ key = id(self), _thread.get_ident()
+ if key in repr_running:
+ return '...'
+ repr_running.add(key)
+ try:
+ result = user_function(self)
+ finally:
+ repr_running.discard(key)
+ return result
+ return wrapper
+
+
def _create_fn(name, args, body, *, globals=None, locals=None,
return_type=MISSING):
# Note that we mutate locals when exec() is called. Caller
def _repr_fn(fields):
- return _create_fn('__repr__',
- ('self',),
- ['return self.__class__.__qualname__ + f"(' +
- ', '.join([f"{f.name}={{self.{f.name}!r}}"
- for f in fields]) +
- ')"'])
+ fn = _create_fn('__repr__',
+ ('self',),
+ ['return self.__class__.__qualname__ + f"(' +
+ ', '.join([f"{f.name}={{self.{f.name}!r}}"
+ for f in fields]) +
+ ')"'])
+ return _recursive_repr(fn)
def _frozen_get_del_attr(cls, fields):
year, month, day (required, base 1)
"""
- if month is None and isinstance(year, bytes) and len(year) == 4 and \
- 1 <= year[2] <= 12:
+ if (month is None and
+ isinstance(year, (bytes, str)) and len(year) == 4 and
+ 1 <= ord(year[2:3]) <= 12):
# Pickle support
+ if isinstance(year, str):
+ try:
+ year = year.encode('latin1')
+ except UnicodeEncodeError:
+ # More informative error message.
+ raise ValueError(
+ "Failed to encode latin1 string when unpickling "
+ "a date object. "
+ "pickle.load(data, encoding='latin1') is assumed.")
self = object.__new__(cls)
self.__setstate(year)
self._hashcode = -1
assert len(date_string) == 10
return cls(*_parse_isoformat_date(date_string))
except Exception:
- raise ValueError('Invalid isoformat string: %s' % date_string)
+ raise ValueError(f'Invalid isoformat string: {date_string!r}')
# Conversions to string
tzinfo (default to None)
fold (keyword only, default to zero)
"""
- if isinstance(hour, bytes) and len(hour) == 6 and hour[0]&0x7F < 24:
+ if (isinstance(hour, (bytes, str)) and len(hour) == 6 and
+ ord(hour[0:1])&0x7F < 24):
# Pickle support
+ if isinstance(hour, str):
+ try:
+ hour = hour.encode('latin1')
+ except UnicodeEncodeError:
+ # More informative error message.
+ raise ValueError(
+ "Failed to encode latin1 string when unpickling "
+ "a time object. "
+ "pickle.load(data, encoding='latin1') is assumed.")
self = object.__new__(cls)
self.__setstate(hour, minute or None)
self._hashcode = -1
try:
return cls(*_parse_isoformat_time(time_string))
except Exception:
- raise ValueError('Invalid isoformat string: %s' % time_string)
+ raise ValueError(f'Invalid isoformat string: {time_string!r}')
def strftime(self, fmt):
def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
microsecond=0, tzinfo=None, *, fold=0):
- if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2]&0x7F <= 12:
+ if (isinstance(year, (bytes, str)) and len(year) == 10 and
+ 1 <= ord(year[2:3])&0x7F <= 12):
# Pickle support
+ if isinstance(year, str):
+ try:
+ year = bytes(year, 'latin1')
+ except UnicodeEncodeError:
+ # More informative error message.
+ raise ValueError(
+ "Failed to encode latin1 string when unpickling "
+ "a datetime object. "
+ "pickle.load(data, encoding='latin1') is assumed.")
self = object.__new__(cls)
self.__setstate(year, month)
self._hashcode = -1
try:
date_components = _parse_isoformat_date(dstr)
except ValueError:
- raise ValueError('Invalid isoformat string: %s' % date_string)
+ raise ValueError(f'Invalid isoformat string: {date_string!r}')
if tstr:
try:
time_components = _parse_isoformat_time(tstr)
except ValueError:
- raise ValueError('Invalid isoformat string: %s' % date_string)
+ raise ValueError(f'Invalid isoformat string: {date_string!r}')
else:
time_components = [0, 0, 0, 0, None]
return best_version, best_dir
def _find_vc2017():
- import _distutils_findvs
- import threading
+ """Returns "15, path" based on the result of invoking vswhere.exe
+ If no install is found, returns "None, None"
- best_version = 0, # tuple for full version comparisons
- best_dir = None
+ The version is returned to avoid unnecessarily changing the function
+ result. It may be ignored when the path is not None.
+
+ If vswhere.exe is not available, by definition, VS 2017 is not
+ installed.
+ """
+ import json
+
+ root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles")
+ if not root:
+ return None, None
- # We need to call findall() on its own thread because it will
- # initialize COM.
- all_packages = []
- def _getall():
- all_packages.extend(_distutils_findvs.findall())
- t = threading.Thread(target=_getall)
- t.start()
- t.join()
-
- for name, version_str, path, packages in all_packages:
- if 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64' in packages:
- vc_dir = os.path.join(path, 'VC', 'Auxiliary', 'Build')
- if not os.path.isdir(vc_dir):
- continue
- try:
- version = tuple(int(i) for i in version_str.split('.'))
- except (ValueError, TypeError):
- continue
- if version > best_version:
- best_version, best_dir = version, vc_dir
try:
- best_version = best_version[0]
- except IndexError:
- best_version = None
- return best_version, best_dir
+ path = subprocess.check_output([
+ os.path.join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"),
+ "-latest",
+ "-prerelease",
+ "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
+ "-property", "installationPath",
+ ], encoding="mbcs", errors="strict").strip()
+ except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
+ return None, None
+
+ path = os.path.join(path, "VC", "Auxiliary", "Build")
+ if os.path.isdir(path):
+ return 15, path
+
+ return None, None
def _find_vcvarsall(plat_spec):
- best_version, best_dir = _find_vc2017()
+ _, best_dir = _find_vc2017()
vcruntime = None
vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
- if best_version:
+ if best_dir:
vcredist = os.path.join(best_dir, "..", "..", "redist", "MSVC", "**",
"Microsoft.VC141.CRT", "vcruntime140.dll")
try:
except (ImportError, OSError, LookupError):
vcruntime = None
- if not best_version:
+ if not best_dir:
best_version, best_dir = _find_vc2015()
if best_version:
vcruntime = os.path.join(best_dir, 'redist', vcruntime_plat,
"Microsoft.VC140.CRT", "vcruntime140.dll")
- if not best_version:
+ if not best_dir:
log.debug("No suitable Visual C++ version found")
return None, None
zip = zipfile.ZipFile(zip_filename, "w",
compression=zipfile.ZIP_STORED)
+ if base_dir != os.curdir:
+ path = os.path.normpath(os.path.join(base_dir, ''))
+ zip.write(path, path)
+ log.info("adding '%s'", path)
for dirpath, dirnames, filenames in os.walk(base_dir):
+ for name in dirnames:
+ path = os.path.normpath(os.path.join(dirpath, name, ''))
+ zip.write(path, path)
+ log.info("adding '%s'", path)
for name in filenames:
path = os.path.normpath(os.path.join(dirpath, name))
if os.path.isfile(path):
('skip-build', None,
"skip rebuilding everything (for testing/debugging)"),
('relative', None,
- "build the archive using relative paths"
+ "build the archive using relative paths "
"(default: false)"),
('owner=', 'u',
"Owner name used when creating a tar file"
('no-target-compile', 'c',
"do not compile .py to .pyc on the target system"),
('no-target-optimize', 'o',
- "do not compile .py to .pyo (optimized)"
+ "do not compile .py to .pyo (optimized) "
"on the target system"),
('dist-dir=', 'd',
"directory to put final built distributions in"),
('skip-build', None,
"skip rebuilding everything (for testing/debugging)"),
('install-script=', None,
- "basename of installation script to be run after"
+ "basename of installation script to be run after "
"installation or before deinstallation"),
('pre-install-script=', None,
"Fully qualified filename of a script to be run before "
"RPM \"vendor\" (eg. \"Joe Blow <joe@example.com>\") "
"[default: maintainer or author from setup script]"),
('packager=', None,
- "RPM packager (eg. \"Jane Doe <jane@example.net>\")"
+ "RPM packager (eg. \"Jane Doe <jane@example.net>\") "
"[default: vendor]"),
('doc-files=', None,
"list of documentation files (space or comma-separated)"),
('no-target-compile', 'c',
"do not compile .py to .pyc on the target system"),
('no-target-optimize', 'o',
- "do not compile .py to .pyo (optimized)"
+ "do not compile .py to .pyo (optimized) "
"on the target system"),
('dist-dir=', 'd',
"directory to put final built distributions in"),
('skip-build', None,
"skip rebuilding everything (for testing/debugging)"),
('install-script=', None,
- "basename of installation script to be run after"
+ "basename of installation script to be run after "
"installation or before deinstallation"),
('pre-install-script=', None,
"Fully qualified filename of a script to be run before "
ext_name, build_info = ext
log.warn("old-style (ext_name, build_info) tuple found in "
- "ext_modules for extension '%s'"
+ "ext_modules for extension '%s' "
"-- please convert to Extension instance", ext_name)
if not (isinstance(ext_name, str) and
try:
names = tar.getnames()
names.sort()
- return tuple(names)
+ return names
finally:
tar.close()
- _created_files = ('dist', 'dist/file1', 'dist/file2',
- 'dist/sub', 'dist/sub/file3', 'dist/sub2')
+ _zip_created_files = ['dist/', 'dist/file1', 'dist/file2',
+ 'dist/sub/', 'dist/sub/file3', 'dist/sub2/']
+ _created_files = [p.rstrip('/') for p in _zip_created_files]
def _create_files(self):
# creating something to tar
tarball = base_name + '.zip'
self.assertTrue(os.path.exists(tarball))
with zipfile.ZipFile(tarball) as zf:
- self.assertEqual(sorted(zf.namelist()),
- ['dist/file1', 'dist/file2', 'dist/sub/file3'])
+ self.assertEqual(sorted(zf.namelist()), self._zip_created_files)
@unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
def test_make_zipfile_no_zlib(self):
[((tarball, "w"), {'compression': zipfile.ZIP_STORED})])
self.assertTrue(os.path.exists(tarball))
with zipfile.ZipFile(tarball) as zf:
- self.assertEqual(sorted(zf.namelist()),
- ['dist/file1', 'dist/file2', 'dist/sub/file3'])
+ self.assertEqual(sorted(zf.namelist()), self._zip_created_files)
def test_check_archive_formats(self):
self.assertEqual(check_archive_formats(['gztar', 'xxx', 'zip']),
finally:
fp.close()
- contents = sorted(os.path.basename(fn) for fn in contents)
+ contents = sorted(filter(None, map(os.path.basename, contents)))
wanted = ['foo-0.1-py%s.%s.egg-info' % sys.version_info[:2], 'foo.py']
if not sys.dont_write_bytecode:
wanted.append('foo.%s.pyc' % sys.implementation.cache_tag)
zip_file.close()
# making sure everything has been pruned correctly
- self.assertEqual(len(content), 4)
+ expected = ['', 'PKG-INFO', 'README', 'setup.py',
+ 'somecode/', 'somecode/__init__.py']
+ self.assertEqual(sorted(content), ['fake-1.0/' + x for x in expected])
@unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
@unittest.skipIf(find_executable('tar') is None,
zip_file.close()
# making sure everything was added
- self.assertEqual(len(content), 12)
+ expected = ['', 'PKG-INFO', 'README', 'buildout.cfg',
+ 'data/', 'data/data.dt', 'inroot.txt',
+ 'scripts/', 'scripts/script.py', 'setup.py',
+ 'some/', 'some/file.txt', 'some/other_file.txt',
+ 'somecode/', 'somecode/__init__.py', 'somecode/doc.dat',
+ 'somecode/doc.txt']
+ self.assertEqual(sorted(content), ['fake-1.0/' + x for x in expected])
# checking the MANIFEST
f = open(join(self.tmp_dir, 'MANIFEST'))
digits += value[0]
value = value[1:]
if digits[0] == '0' and digits != '0':
- section.defects.append(errors.InvalidHeaderError("section number"
- "has an invalid leading 0"))
+ section.defects.append(errors.InvalidHeaderError(
+ "section number has an invalid leading 0"))
section.number = int(digits)
section.append(ValueTerminal(digits, 'digits'))
return section, value
__all__ = ["version", "bootstrap"]
-_SETUPTOOLS_VERSION = "39.0.1"
+_SETUPTOOLS_VERSION = "40.6.2"
-_PIP_VERSION = "10.0.1"
+_PIP_VERSION = "18.1"
_PROJECTS = [
("setuptools", _SETUPTOOLS_VERSION),
if member._value_ == value:
return member
# still not found -- try _missing_ hook
- return cls._missing_(value)
+ try:
+ exc = None
+ result = cls._missing_(value)
+ except Exception as e:
+ exc = e
+ result = None
+ if isinstance(result, cls):
+ return result
+ else:
+ ve_exc = ValueError("%r is not a valid %s" % (value, cls.__name__))
+ if result is None and exc is None:
+ raise ve_exc
+ elif exc is None:
+ exc = TypeError(
+ 'error in %s._missing_: returned %r instead of None or a valid member'
+ % (cls.__name__, result)
+ )
+ exc.__context__ = ve_exc
+ raise exc
def _generate_next_value_(name, start, count, last_values):
for last_value in reversed(last_values):
"exclusive")
if keyfile is not None or certfile is not None:
import warnings
- warnings.warn("keyfile and certfile are deprecated, use a"
+ warnings.warn("keyfile and certfile are deprecated, use a "
"custom context instead", DeprecationWarning, 2)
self.keyfile = keyfile
self.certfile = certfile
-What's New in IDLE 3.7.1
+What's New in IDLE 3.7.2
Released on 2018-07-31?
======================================
+bpo-34864: When starting IDLE on MacOS, warn if the system setting
+"Prefer tabs when opening documents" is "Always". As previous
+documented for this issue, running IDLE with this setting causes
+problems. If the setting is changed while IDLE is running,
+there will be no warning until IDLE is restarted.
+
+bpo-35213: Where appropriate, use 'macOS' in idlelib.
+
+bpo-34864: Document two IDLE on MacOS issues. The System Preferences
+Dock "prefer tabs always" setting disables some IDLE features.
+Menus are a bit different than as described for Windows and Linux.
+
+bpo-35202: Remove unused imports in idlelib.
+
+bpo-33000: Document that IDLE's shell has no line limit.
+A program that runs indefinitely can overfill memory.
+
+bpo-23220: Explain how IDLE's Shell displays output.
+Add new subsection "User output in Shell".
+
+bpo-35099: Improve the doc about IDLE running user code.
+"IDLE -- console differences" is renamed "Running user code".
+It mostly covers the implications of using custom sys.stdxxx objects.
+
+bpo-35097: Add IDLE doc subsection explaining editor windows.
+Topics include opening, title and status bars, .py* extension, and running.
+
+Issue 35093: Document the IDLE document viewer in the IDLE doc.
+Add a paragraph in "Help and preferences", "Help sources" subsection.
+
+bpo-1529353: Explain Shell text squeezing in the IDLE doc.
+
+bpo-35088: Update idlelib.help.copy_string docstring.
+We now use git and backporting instead of hg and forward merging.
+
+bpo-35087: Update idlelib help files for the current doc build.
+The main change is the elimination of chapter-section numbers.
+
+
+What's New in IDLE 3.7.1
+Released on 2018-07-31?
+======================================
+
bpo-1529353: Output over N lines (50 by default) is squeezed down to a button.
N can be changed in the PyShell section of the General page of the
Settings dialog. Fewer, but possibly extra long, lines can be squeezed by
from sys import maxsize as INFINITY
import tkinter
-from tkinter.constants import TOP, LEFT, X, W, SUNKEN
+from tkinter.constants import TOP, X, SUNKEN
from idlelib.config import idleConf
result = self.GetKeySet(self.CurrentKeys())
if sys.platform == "darwin":
- # OS X Tk variants do not support the "Alt" keyboard modifier.
- # So replace all keybingings that use "Alt" with ones that
- # use the "Option" keyboard modifier.
- # TODO (Ned?): the "Option" modifier does not work properly for
- # Cocoa Tk and XQuartz Tk so we should not use it
- # in default OS X KeySets.
+ # macOS (OS X) Tk variants do not support the "Alt"
+ # keyboard modifier. Replace it with "Option".
+ # TODO (Ned?): the "Option" modifier does not work properly
+ # for Cocoa Tk and XQuartz Tk so we should not use it
+ # in the default 'OSX' keyset.
for k, v in result.items():
v2 = [ x.replace('<Alt-', '<Option-') for x in v ]
if v != v2:
#----------called by a DictProxy----------
def dict_keys(self, did):
- raise NotImplemented("dict_keys not public or pickleable")
+ raise NotImplementedError("dict_keys not public or pickleable")
## dict = dicttable[did]
## return dict.keys()
from tkinter import Tk
from idlelib.editor import fixwordbreaks
from idlelib.run import fix_scaling
- import sys
root = Tk()
fix_scaling(root)
fixwordbreaks(root)
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>26.5. IDLE — Python 3.8.0a0 documentation</title>
+ <title>IDLE — Python 3.8.0a0 documentation</title>
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
- <script type="text/javascript" src="../_static/documentation_options.js"></script>
+
+ <script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
+ <script async="async" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
+
<script type="text/javascript" src="../_static/sidebar.js"></script>
+
<link rel="search" type="application/opensearchdescription+xml"
title="Search within Python 3.8.0a0 documentation"
href="../_static/opensearch.xml"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="copyright" title="Copyright" href="../copyright.html" />
- <link rel="next" title="26.6. Other Graphical User Interface Packages" href="othergui.html" />
- <link rel="prev" title="26.4. tkinter.scrolledtext — Scrolled Text Widget" href="tkinter.scrolledtext.html" />
+ <link rel="next" title="Other Graphical User Interface Packages" href="othergui.html" />
+ <link rel="prev" title="tkinter.scrolledtext — Scrolled Text Widget" href="tkinter.scrolledtext.html" />
<link rel="canonical" href="https://docs.python.org/3/library/idle.html" />
+
+ <style>
+ @media only screen {
+ table.full-width-table {
+ width: 100%;
+ }
+ }
+ </style>
+
<link rel="shortcut icon" type="image/png" href="../_static/py.png" />
<script type="text/javascript" src="../_static/copybutton.js"></script>
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
- <a href="othergui.html" title="26.6. Other Graphical User Interface Packages"
+ <a href="othergui.html" title="Other Graphical User Interface Packages"
accesskey="N">next</a> |</li>
<li class="right" >
- <a href="tkinter.scrolledtext.html" title="26.4. tkinter.scrolledtext — Scrolled Text Widget"
+ <a href="tkinter.scrolledtext.html" title="tkinter.scrolledtext — Scrolled Text Widget"
accesskey="P">previous</a> |</li>
<li><img src="../_static/py.png" alt=""
</li>
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
- <li class="nav-item nav-item-2"><a href="tk.html" accesskey="U">26. Graphical User Interfaces with Tk</a> »</li>
+ <li class="nav-item nav-item-2"><a href="tk.html" accesskey="U">Graphical User Interfaces with Tk</a> »</li>
<li class="right">
<div class="body" role="main">
<div class="section" id="idle">
-<span id="id1"></span><h1>26.5. IDLE<a class="headerlink" href="#idle" title="Permalink to this headline">¶</a></h1>
+<span id="id1"></span><h1>IDLE<a class="headerlink" href="#idle" title="Permalink to this headline">¶</a></h1>
<p><strong>Source code:</strong> <a class="reference external" href="https://github.com/python/cpython/tree/master/Lib/idlelib/">Lib/idlelib/</a></p>
<hr class="docutils" id="index-0" />
<p>IDLE is Python’s Integrated Development and Learning Environment.</p>
<p>IDLE has the following features:</p>
<ul class="simple">
<li>coded in 100% pure Python, using the <a class="reference internal" href="tkinter.html#module-tkinter" title="tkinter: Interface to Tcl/Tk for graphical user interfaces"><code class="xref py py-mod docutils literal notranslate"><span class="pre">tkinter</span></code></a> GUI toolkit</li>
-<li>cross-platform: works mostly the same on Windows, Unix, and Mac OS X</li>
+<li>cross-platform: works mostly the same on Windows, Unix, and macOS</li>
<li>Python shell window (interactive interpreter) with colorizing
of code input, output, and error messages</li>
<li>multi-window text editor with multiple undo, Python colorizing,
<li>configuration, browsers, and other dialogs</li>
</ul>
<div class="section" id="menus">
-<h2>26.5.1. Menus<a class="headerlink" href="#menus" title="Permalink to this headline">¶</a></h2>
+<h2>Menus<a class="headerlink" href="#menus" title="Permalink to this headline">¶</a></h2>
<p>IDLE has two main window types, the Shell window and the Editor window. It is
-possible to have multiple editor windows simultaneously. Output windows, such
-as used for Edit / Find in Files, are a subtype of edit window. They currently
-have the same top menu as Editor windows but a different default title and
-context menu.</p>
-<p>IDLE’s menus dynamically change based on which window is currently selected.
-Each menu documented below indicates which window type it is associated with.</p>
+possible to have multiple editor windows simultaneously. On Windows and
+Linux, each has its own top menu. Each menu documented below indicates
+which window type it is associated with.</p>
+<p>Output windows, such as used for Edit => Find in Files, are a subtype of editor
+window. They currently have the same top menu but a different
+default title and context menu.</p>
+<p>On macOS, there is one application menu. It dynamically changes according
+to the window currently selected. It has an IDLE menu, and some entries
+described below are moved around to conform to Apple guidlines.</p>
<div class="section" id="file-menu-shell-and-editor">
-<h3>26.5.1.1. File menu (Shell and Editor)<a class="headerlink" href="#file-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
+<h3>File menu (Shell and Editor)<a class="headerlink" href="#file-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
<dl class="docutils">
<dt>New File</dt>
<dd>Create a new file editing window.</dd>
</dl>
</div>
<div class="section" id="edit-menu-shell-and-editor">
-<h3>26.5.1.2. Edit menu (Shell and Editor)<a class="headerlink" href="#edit-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
+<h3>Edit menu (Shell and Editor)<a class="headerlink" href="#edit-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
<dl class="docutils">
<dt>Undo</dt>
<dd>Undo the last change to the current window. A maximum of 1000 changes may
</dl>
</div>
<div class="section" id="format-menu-editor-window-only">
-<h3>26.5.1.3. Format menu (Editor window only)<a class="headerlink" href="#format-menu-editor-window-only" title="Permalink to this headline">¶</a></h3>
+<h3>Format menu (Editor window only)<a class="headerlink" href="#format-menu-editor-window-only" title="Permalink to this headline">¶</a></h3>
<dl class="docutils">
<dt>Indent Region</dt>
<dd>Shift selected lines right by the indent width (default 4 spaces).</dd>
</dl>
</div>
<div class="section" id="run-menu-editor-window-only">
-<span id="index-2"></span><h3>26.5.1.4. Run menu (Editor window only)<a class="headerlink" href="#run-menu-editor-window-only" title="Permalink to this headline">¶</a></h3>
+<span id="index-2"></span><h3>Run menu (Editor window only)<a class="headerlink" href="#run-menu-editor-window-only" title="Permalink to this headline">¶</a></h3>
<dl class="docutils">
<dt>Python Shell</dt>
<dd>Open or wake up the Python Shell window.</dd>
</dl>
</div>
<div class="section" id="shell-menu-shell-window-only">
-<h3>26.5.1.5. Shell menu (Shell window only)<a class="headerlink" href="#shell-menu-shell-window-only" title="Permalink to this headline">¶</a></h3>
+<h3>Shell menu (Shell window only)<a class="headerlink" href="#shell-menu-shell-window-only" title="Permalink to this headline">¶</a></h3>
<dl class="docutils">
<dt>View Last Restart</dt>
<dd>Scroll the shell window to the last Shell restart.</dd>
</dl>
</div>
<div class="section" id="debug-menu-shell-window-only">
-<h3>26.5.1.6. Debug menu (Shell window only)<a class="headerlink" href="#debug-menu-shell-window-only" title="Permalink to this headline">¶</a></h3>
+<h3>Debug menu (Shell window only)<a class="headerlink" href="#debug-menu-shell-window-only" title="Permalink to this headline">¶</a></h3>
<dl class="docutils">
<dt>Go to File/Line</dt>
<dd>Look on the current line. with the cursor, and the line above for a filename
</dl>
</div>
<div class="section" id="options-menu-shell-and-editor">
-<h3>26.5.1.7. Options menu (Shell and Editor)<a class="headerlink" href="#options-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
+<h3>Options menu (Shell and Editor)<a class="headerlink" href="#options-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
<dl class="docutils">
<dt>Configure IDLE</dt>
<dd><p class="first">Open a configuration dialog and change preferences for the following:
fonts, indentation, keybindings, text color themes, startup windows and
-size, additional help sources, and extensions (see below). On OS X,
+size, additional help sources, and extensions (see below). On macOS,
open the configuration dialog by selecting Preferences in the application
menu. To use a new built-in color theme (IDLE Dark) with older IDLEs,
save it as a new custom theme.</p>
</dl>
</div>
<div class="section" id="window-menu-shell-and-editor">
-<h3>26.5.1.8. Window menu (Shell and Editor)<a class="headerlink" href="#window-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
+<h3>Window menu (Shell and Editor)<a class="headerlink" href="#window-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
<dl class="docutils">
<dt>Zoom Height</dt>
<dd>Toggles the window between normal size and maximum height. The initial size
it to the foreground (deiconifying it if necessary).</p>
</div>
<div class="section" id="help-menu-shell-and-editor">
-<h3>26.5.1.9. Help menu (Shell and Editor)<a class="headerlink" href="#help-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
+<h3>Help menu (Shell and Editor)<a class="headerlink" href="#help-menu-shell-and-editor" title="Permalink to this headline">¶</a></h3>
<dl class="docutils">
<dt>About IDLE</dt>
<dd>Display version, copyright, license, credits, and more.</dd>
<dt>IDLE Help</dt>
-<dd>Display a help file for IDLE detailing the menu options, basic editing and
+<dd>Display this IDLE document, detailing the menu options, basic editing and
navigation, and other tips.</dd>
<dt>Python Docs</dt>
<dd>Access local Python documentation, if installed, or start a web browser
and open docs.python.org showing the latest Python documentation.</dd>
<dt>Turtle Demo</dt>
-<dd>Run the turtledemo module with example python code and turtle drawings.</dd>
+<dd>Run the turtledemo module with example Python code and turtle drawings.</dd>
</dl>
<p>Additional help sources may be added here with the Configure IDLE dialog under
-the General tab.</p>
+the General tab. See the “Help sources” subsection below for more
+on Help menu choices.</p>
</div>
<div class="section" id="context-menus">
-<span id="index-4"></span><h3>26.5.1.10. Context Menus<a class="headerlink" href="#context-menus" title="Permalink to this headline">¶</a></h3>
-<p>Open a context menu by right-clicking in a window (Control-click on OS X).
+<span id="index-4"></span><h3>Context Menus<a class="headerlink" href="#context-menus" title="Permalink to this headline">¶</a></h3>
+<p>Open a context menu by right-clicking in a window (Control-click on macOS).
Context menus have the standard clipboard functions also on the Edit menu.</p>
<dl class="docutils">
<dt>Cut</dt>
<dt>Clear Breakpoint</dt>
<dd>Clear the breakpoint on that line.</dd>
</dl>
-<p>Shell and Output windows have the following.</p>
+<p>Shell and Output windows also have the following.</p>
<dl class="docutils">
<dt>Go to file/line</dt>
<dd>Same as in Debug menu.</dd>
</dl>
+<p>The Shell window also has an output squeezing facility explained in the
+the <em>Python Shell window</em> subsection below.</p>
+<dl class="docutils">
+<dt>Squeeze</dt>
+<dd>If the cursor is over an output line, squeeze all the output between
+the code above and the prompt below down to a ‘Squeezed text’ label.</dd>
+</dl>
</div>
</div>
<div class="section" id="editing-and-navigation">
-<h2>26.5.2. Editing and navigation<a class="headerlink" href="#editing-and-navigation" title="Permalink to this headline">¶</a></h2>
+<h2>Editing and navigation<a class="headerlink" href="#editing-and-navigation" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="editor-windows">
+<h3>Editor windows<a class="headerlink" href="#editor-windows" title="Permalink to this headline">¶</a></h3>
+<p>IDLE may open editor windows when it starts, depending on settings
+and how you start IDLE. Thereafter, use the File menu. There can be only
+one open editor window for a given file.</p>
+<p>The title bar contains the name of the file, the full path, and the version
+of Python and IDLE running the window. The status bar contains the line
+number (‘Ln’) and column number (‘Col’). Line numbers start with 1;
+column numbers with 0.</p>
+<p>IDLE assumes that files with a known .py* extension contain Python code
+and that other files do not. Run Python code with the Run menu.</p>
+</div>
+<div class="section" id="key-bindings">
+<h3>Key bindings<a class="headerlink" href="#key-bindings" title="Permalink to this headline">¶</a></h3>
<p>In this section, ‘C’ refers to the <kbd class="kbd docutils literal notranslate">Control</kbd> key on Windows and Unix and
-the <kbd class="kbd docutils literal notranslate">Command</kbd> key on Mac OSX.</p>
+the <kbd class="kbd docutils literal notranslate">Command</kbd> key on macOS.</p>
<ul>
<li><p class="first"><kbd class="kbd docutils literal notranslate">Backspace</kbd> deletes to the left; <kbd class="kbd docutils literal notranslate">Del</kbd> deletes to the right</p>
</li>
</ul>
<p>Standard keybindings (like <kbd class="kbd docutils literal notranslate">C-c</kbd> to copy and <kbd class="kbd docutils literal notranslate">C-v</kbd> to paste)
may work. Keybindings are selected in the Configure IDLE dialog.</p>
+</div>
<div class="section" id="automatic-indentation">
-<h3>26.5.2.1. Automatic indentation<a class="headerlink" href="#automatic-indentation" title="Permalink to this headline">¶</a></h3>
+<h3>Automatic indentation<a class="headerlink" href="#automatic-indentation" title="Permalink to this headline">¶</a></h3>
<p>After a block-opening statement, the next line is indented by 4 spaces (in the
Python Shell window by one tab). After certain keywords (break, return etc.)
the next line is dedented. In leading indentation, <kbd class="kbd docutils literal notranslate">Backspace</kbd> deletes up
<p>See also the indent/dedent region commands in the edit menu.</p>
</div>
<div class="section" id="completions">
-<h3>26.5.2.2. Completions<a class="headerlink" href="#completions" title="Permalink to this headline">¶</a></h3>
+<h3>Completions<a class="headerlink" href="#completions" title="Permalink to this headline">¶</a></h3>
<p>Completions are supplied for functions, classes, and attributes of classes,
both built-in and user-defined. Completions are also provided for
filenames.</p>
longer or disable the extension.</p>
</div>
<div class="section" id="calltips">
-<h3>26.5.2.3. Calltips<a class="headerlink" href="#calltips" title="Permalink to this headline">¶</a></h3>
+<h3>Calltips<a class="headerlink" href="#calltips" title="Permalink to this headline">¶</a></h3>
<p>A calltip is shown when one types <kbd class="kbd docutils literal notranslate">(</kbd> after the name of an <em>accessible</em>
function. A name expression may include dots and subscripts. A calltip
remains until it is clicked, the cursor is moved out of the argument area,
or immediately run an existing file before editing.</p>
</div>
<div class="section" id="python-shell-window">
-<h3>26.5.2.4. Python Shell window<a class="headerlink" href="#python-shell-window" title="Permalink to this headline">¶</a></h3>
+<h3>Python Shell window<a class="headerlink" href="#python-shell-window" title="Permalink to this headline">¶</a></h3>
+<p>With IDLE’s Shell, one enters, edits, and recalls complete statements.
+Most consoles and terminals only work with a single physical line at a time.</p>
+<p>When one pastes code into Shell, it is not compiled and possibly executed
+until one hits <kbd class="kbd docutils literal notranslate">Return</kbd>. One may edit pasted code first.
+If one pastes more that one statement into Shell, the result will be a
+<a class="reference internal" href="exceptions.html#SyntaxError" title="SyntaxError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">SyntaxError</span></code></a> when multiple statements are compiled as if they were one.</p>
+<p>The editing features described in previous subsections work when entering
+code interactively. IDLE’s Shell window also responds to the following keys.</p>
<ul>
<li><p class="first"><kbd class="kbd docutils literal notranslate">C-c</kbd> interrupts executing command</p>
</li>
<p>Command history</p>
<ul class="simple">
<li><kbd class="kbd docutils literal notranslate">Alt-p</kbd> retrieves previous command matching what you have typed. On
-OS X use <kbd class="kbd docutils literal notranslate">C-p</kbd>.</li>
-<li><kbd class="kbd docutils literal notranslate">Alt-n</kbd> retrieves next. On OS X use <kbd class="kbd docutils literal notranslate">C-n</kbd>.</li>
+macOS use <kbd class="kbd docutils literal notranslate">C-p</kbd>.</li>
+<li><kbd class="kbd docutils literal notranslate">Alt-n</kbd> retrieves next. On macOS use <kbd class="kbd docutils literal notranslate">C-n</kbd>.</li>
<li><kbd class="kbd docutils literal notranslate">Return</kbd> while on any previous command retrieves that command</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="text-colors">
-<h3>26.5.2.5. Text colors<a class="headerlink" href="#text-colors" title="Permalink to this headline">¶</a></h3>
+<h3>Text colors<a class="headerlink" href="#text-colors" title="Permalink to this headline">¶</a></h3>
<p>Idle defaults to black on white text, but colors text with special meanings.
For the shell, these are shell output, shell error, user output, and
user error. For Python code, at the shell prompt or in an editor, these are
</div>
</div>
<div class="section" id="startup-and-code-execution">
-<h2>26.5.3. Startup and code execution<a class="headerlink" href="#startup-and-code-execution" title="Permalink to this headline">¶</a></h2>
+<h2>Startup and code execution<a class="headerlink" href="#startup-and-code-execution" title="Permalink to this headline">¶</a></h2>
<p>Upon startup with the <code class="docutils literal notranslate"><span class="pre">-s</span></code> option, IDLE will execute the file referenced by
the environment variables <span class="target" id="index-5"></span><code class="xref std std-envvar docutils literal notranslate"><span class="pre">IDLESTARTUP</span></code> or <span class="target" id="index-6"></span><a class="reference internal" href="../using/cmdline.html#envvar-PYTHONSTARTUP"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PYTHONSTARTUP</span></code></a>.
IDLE first checks for <code class="docutils literal notranslate"><span class="pre">IDLESTARTUP</span></code>; if <code class="docutils literal notranslate"><span class="pre">IDLESTARTUP</span></code> is present the file
executed in the Tk namespace, so this file is not useful for importing
functions to be used from IDLE’s Python shell.</p>
<div class="section" id="command-line-usage">
-<h3>26.5.3.1. Command line usage<a class="headerlink" href="#command-line-usage" title="Permalink to this headline">¶</a></h3>
+<h3>Command line usage<a class="headerlink" href="#command-line-usage" title="Permalink to this headline">¶</a></h3>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>idle.py [-c command] [-d] [-e] [-h] [-i] [-r file] [-s] [-t title] [-] [arg] ...
-c command run command in the shell window
</ul>
</div>
<div class="section" id="startup-failure">
-<h3>26.5.3.2. Startup failure<a class="headerlink" href="#startup-failure" title="Permalink to this headline">¶</a></h3>
+<h3>Startup failure<a class="headerlink" href="#startup-failure" title="Permalink to this headline">¶</a></h3>
<p>IDLE uses a socket to communicate between the IDLE GUI process and the user
code execution process. A connection must be established whenever the Shell
starts or restarts. (The latter is indicated by a divider line that says
<p>If IDLE quits with no message, and it was not started from a console, try
starting from a console (<code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">idlelib)</span></code> and see if a message appears.</p>
</div>
-<div class="section" id="idle-console-differences">
-<h3>26.5.3.3. IDLE-console differences<a class="headerlink" href="#idle-console-differences" title="Permalink to this headline">¶</a></h3>
+<div class="section" id="running-user-code">
+<h3>Running user code<a class="headerlink" href="#running-user-code" title="Permalink to this headline">¶</a></h3>
<p>With rare exceptions, the result of executing Python code with IDLE is
-intended to be the same as executing the same code in a console window.
+intended to be the same as executing the same code by the default method,
+directly with Python in a text-mode system console or terminal window.
However, the different interface and operation occasionally affect
-visible results. For instance, <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code> starts with more entries.</p>
-<p>IDLE also replaces <code class="docutils literal notranslate"><span class="pre">sys.stdin</span></code>, <code class="docutils literal notranslate"><span class="pre">sys.stdout</span></code>, and <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code> with
-objects that get input from and send output to the Shell window.
-When Shell has the focus, it controls the keyboard and screen. This is
+visible results. For instance, <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code> starts with more entries,
+and <code class="docutils literal notranslate"><span class="pre">threading.activeCount()</span></code> returns 2 instead of 1.</p>
+<p>By default, IDLE runs user code in a separate OS process rather than in
+the user interface process that runs the shell and editor. In the execution
+process, it replaces <code class="docutils literal notranslate"><span class="pre">sys.stdin</span></code>, <code class="docutils literal notranslate"><span class="pre">sys.stdout</span></code>, and <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code>
+with objects that get input from and send output to the Shell window.
+The original values stored in <code class="docutils literal notranslate"><span class="pre">sys.__stdin__</span></code>, <code class="docutils literal notranslate"><span class="pre">sys.__stdout__</span></code>, and
+<code class="docutils literal notranslate"><span class="pre">sys.__stderr__</span></code> are not touched, but may be <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p>
+<p>When Shell has the focus, it controls the keyboard and screen. This is
normally transparent, but functions that directly access the keyboard
-and screen will not work. If <code class="docutils literal notranslate"><span class="pre">sys</span></code> is reset with <code class="docutils literal notranslate"><span class="pre">importlib.reload(sys)</span></code>,
-IDLE’s changes are lost and things like <code class="docutils literal notranslate"><span class="pre">input</span></code>, <code class="docutils literal notranslate"><span class="pre">raw_input</span></code>, and
-<code class="docutils literal notranslate"><span class="pre">print</span></code> will not work correctly.</p>
-<p>With IDLE’s Shell, one enters, edits, and recalls complete statements.
-Some consoles only work with a single physical line at a time. IDLE uses
-<code class="docutils literal notranslate"><span class="pre">exec</span></code> to run each statement. As a result, <code class="docutils literal notranslate"><span class="pre">'__builtins__'</span></code> is always
-defined for each statement.</p>
+and screen will not work. These include system-specific functions that
+determine whether a key has been pressed and if so, which.</p>
+<p>IDLE’s standard stream replacements are not inherited by subprocesses
+created in the execution process, whether directly by user code or by modules
+such as multiprocessing. If such subprocess use <code class="docutils literal notranslate"><span class="pre">input</span></code> from sys.stdin
+or <code class="docutils literal notranslate"><span class="pre">print</span></code> or <code class="docutils literal notranslate"><span class="pre">write</span></code> to sys.stdout or sys.stderr,
+IDLE should be started in a command line window. The secondary subprocess
+will then be attached to that window for input and output.</p>
+<p>If <code class="docutils literal notranslate"><span class="pre">sys</span></code> is reset by user code, such as with <code class="docutils literal notranslate"><span class="pre">importlib.reload(sys)</span></code>,
+IDLE’s changes are lost and input from the keyboard and output to the screen
+will not work correctly.</p>
+</div>
+<div class="section" id="user-output-in-shell">
+<h3>User output in Shell<a class="headerlink" href="#user-output-in-shell" title="Permalink to this headline">¶</a></h3>
+<p>When a program outputs text, the result is determined by the
+corresponding output device. When IDLE executes user code, <code class="docutils literal notranslate"><span class="pre">sys.stdout</span></code>
+and <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code> are connected to the display area of IDLE’s Shell. Some of
+its features are inherited from the underlying Tk Text widget. Others
+are programmed additions. Where it matters, Shell is designed for development
+rather than production runs.</p>
+<p>For instance, Shell never throws away output. A program that sends unlimited
+output to Shell will eventually fill memory, resulting in a memory error.
+In contrast, some system text windows only keep the last n lines of output.
+A Windows console, for instance, keeps a user-settable 1 to 9999 lines,
+with 300 the default.</p>
+<p>Text widgets display a subset of Unicode, the Basic Multilingual Plane (BMP).
+Which characters get a proper glyph instead of a replacement box depends on
+the operating system and installed fonts. Newline characters cause following
+text to appear on a new line, but other control characters are either
+replaced with a box or deleted. However, <code class="docutils literal notranslate"><span class="pre">repr()</span></code>, which is used for
+interactive echo of expression values, replaces control characters,
+some BMP codepoints, and all non-BMP characters with escape codes
+before they are output.</p>
+<p>Normal and error output are generally kept separate (on separate lines)
+from code input and each other. They each get different highlight colors.</p>
+<p>For SyntaxError tracebacks, the normal ‘^’ marking where the error was
+detected is replaced by coloring the text with an error highlight.
+When code run from a file causes other exceptions, one may right click
+on a traceback line to jump to the corresponding line in an IDLE editor.
+The file will be opened if necessary.</p>
+<p>Shell has a special facility for squeezing output lines down to a
+‘Squeezed text’ label. This is done automatically
+for output over N lines (N = 50 by default).
+N can be changed in the PyShell section of the General
+page of the Settings dialog. Output with fewer lines can be squeezed by
+right clicking on the output. This can be useful lines long enough to slow
+down scrolling.</p>
+<p>Squeezed output is expanded in place by double-clicking the label.
+It can also be sent to the clipboard or a separate view window by
+right-clicking the label.</p>
</div>
<div class="section" id="developing-tkinter-applications">
-<h3>26.5.3.4. Developing tkinter applications<a class="headerlink" href="#developing-tkinter-applications" title="Permalink to this headline">¶</a></h3>
+<h3>Developing tkinter applications<a class="headerlink" href="#developing-tkinter-applications" title="Permalink to this headline">¶</a></h3>
<p>IDLE is intentionally different from standard Python in order to
facilitate development of tkinter programs. Enter <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">tkinter</span> <span class="pre">as</span> <span class="pre">tk;</span>
<span class="pre">root</span> <span class="pre">=</span> <span class="pre">tk.Tk()</span></code> in standard Python and nothing appears. Enter the same
re-enable the mainloop call when running in standard Python.</p>
</div>
<div class="section" id="running-without-a-subprocess">
-<h3>26.5.3.5. Running without a subprocess<a class="headerlink" href="#running-without-a-subprocess" title="Permalink to this headline">¶</a></h3>
+<h3>Running without a subprocess<a class="headerlink" href="#running-without-a-subprocess" title="Permalink to this headline">¶</a></h3>
<p>By default, IDLE executes user code in a separate subprocess via a socket,
which uses the internal loopback interface. This connection is not
externally visible and no data is sent to or received from the Internet.
</div>
</div>
<div class="section" id="help-and-preferences">
-<h2>26.5.4. Help and preferences<a class="headerlink" href="#help-and-preferences" title="Permalink to this headline">¶</a></h2>
-<div class="section" id="additional-help-sources">
-<h3>26.5.4.1. Additional help sources<a class="headerlink" href="#additional-help-sources" title="Permalink to this headline">¶</a></h3>
-<p>IDLE includes a help menu entry called “Python Docs” that will open the
-extensive sources of help, including tutorials, available at docs.python.org.
-Selected URLs can be added or removed from the help menu at any time using the
-Configure IDLE dialog. See the IDLE help option in the help menu of IDLE for
-more information.</p>
+<h2>Help and preferences<a class="headerlink" href="#help-and-preferences" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="help-sources">
+<h3>Help sources<a class="headerlink" href="#help-sources" title="Permalink to this headline">¶</a></h3>
+<p>Help menu entry “IDLE Help” displays a formatted html version of the
+IDLE chapter of the Library Reference. The result, in a read-only
+tkinter text window, is close to what one sees in a web browser.
+Navigate through the text with a mousewheel,
+the scrollbar, or up and down arrow keys held down.
+Or click the TOC (Table of Contents) button and select a section
+header in the opened box.</p>
+<p>Help menu entry “Python Docs” opens the extensive sources of help,
+including tutorials, available at docs.python.org/x.y, where ‘x.y’
+is the currently running Python version. If your system
+has an off-line copy of the docs (this may be an installation option),
+that will be opened instead.</p>
+<p>Selected URLs can be added or removed from the help menu at any time using the
+General tab of the Configure IDLE dialog .</p>
</div>
<div class="section" id="setting-preferences">
-<h3>26.5.4.2. Setting preferences<a class="headerlink" href="#setting-preferences" title="Permalink to this headline">¶</a></h3>
+<h3>Setting preferences<a class="headerlink" href="#setting-preferences" title="Permalink to this headline">¶</a></h3>
<p>The font preferences, highlighting, keys, and general preferences can be
changed via Configure IDLE on the Option menu. Keys can be user defined;
IDLE ships with four built-in key sets. In addition, a user can create a
custom key set in the Configure IDLE dialog under the keys tab.</p>
</div>
+<div class="section" id="idle-on-macos">
+<h3>IDLE on macOS<a class="headerlink" href="#idle-on-macos" title="Permalink to this headline">¶</a></h3>
+<p>Under System Preferences: Dock, one can set “Prefer tabs when opening
+documents” to “Always”. This setting is not compatible with the tk/tkinter
+GUI framework used by IDLE, and it breaks a few IDLE features.</p>
+</div>
<div class="section" id="extensions">
-<h3>26.5.4.3. Extensions<a class="headerlink" href="#extensions" title="Permalink to this headline">¶</a></h3>
+<h3>Extensions<a class="headerlink" href="#extensions" title="Permalink to this headline">¶</a></h3>
<p>IDLE contains an extension facility. Preferences for extensions can be
changed with the Extensions tab of the preferences dialog. See the
beginning of config-extensions.def in the idlelib directory for further
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
- <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <h3><a href="../contents.html">Table of Contents</a></h3>
<ul>
-<li><a class="reference internal" href="#">26.5. IDLE</a><ul>
-<li><a class="reference internal" href="#menus">26.5.1. Menus</a><ul>
-<li><a class="reference internal" href="#file-menu-shell-and-editor">26.5.1.1. File menu (Shell and Editor)</a></li>
-<li><a class="reference internal" href="#edit-menu-shell-and-editor">26.5.1.2. Edit menu (Shell and Editor)</a></li>
-<li><a class="reference internal" href="#format-menu-editor-window-only">26.5.1.3. Format menu (Editor window only)</a></li>
-<li><a class="reference internal" href="#run-menu-editor-window-only">26.5.1.4. Run menu (Editor window only)</a></li>
-<li><a class="reference internal" href="#shell-menu-shell-window-only">26.5.1.5. Shell menu (Shell window only)</a></li>
-<li><a class="reference internal" href="#debug-menu-shell-window-only">26.5.1.6. Debug menu (Shell window only)</a></li>
-<li><a class="reference internal" href="#options-menu-shell-and-editor">26.5.1.7. Options menu (Shell and Editor)</a></li>
-<li><a class="reference internal" href="#window-menu-shell-and-editor">26.5.1.8. Window menu (Shell and Editor)</a></li>
-<li><a class="reference internal" href="#help-menu-shell-and-editor">26.5.1.9. Help menu (Shell and Editor)</a></li>
-<li><a class="reference internal" href="#context-menus">26.5.1.10. Context Menus</a></li>
+<li><a class="reference internal" href="#">IDLE</a><ul>
+<li><a class="reference internal" href="#menus">Menus</a><ul>
+<li><a class="reference internal" href="#file-menu-shell-and-editor">File menu (Shell and Editor)</a></li>
+<li><a class="reference internal" href="#edit-menu-shell-and-editor">Edit menu (Shell and Editor)</a></li>
+<li><a class="reference internal" href="#format-menu-editor-window-only">Format menu (Editor window only)</a></li>
+<li><a class="reference internal" href="#run-menu-editor-window-only">Run menu (Editor window only)</a></li>
+<li><a class="reference internal" href="#shell-menu-shell-window-only">Shell menu (Shell window only)</a></li>
+<li><a class="reference internal" href="#debug-menu-shell-window-only">Debug menu (Shell window only)</a></li>
+<li><a class="reference internal" href="#options-menu-shell-and-editor">Options menu (Shell and Editor)</a></li>
+<li><a class="reference internal" href="#window-menu-shell-and-editor">Window menu (Shell and Editor)</a></li>
+<li><a class="reference internal" href="#help-menu-shell-and-editor">Help menu (Shell and Editor)</a></li>
+<li><a class="reference internal" href="#context-menus">Context Menus</a></li>
</ul>
</li>
-<li><a class="reference internal" href="#editing-and-navigation">26.5.2. Editing and navigation</a><ul>
-<li><a class="reference internal" href="#automatic-indentation">26.5.2.1. Automatic indentation</a></li>
-<li><a class="reference internal" href="#completions">26.5.2.2. Completions</a></li>
-<li><a class="reference internal" href="#calltips">26.5.2.3. Calltips</a></li>
-<li><a class="reference internal" href="#python-shell-window">26.5.2.4. Python Shell window</a></li>
-<li><a class="reference internal" href="#text-colors">26.5.2.5. Text colors</a></li>
+<li><a class="reference internal" href="#editing-and-navigation">Editing and navigation</a><ul>
+<li><a class="reference internal" href="#editor-windows">Editor windows</a></li>
+<li><a class="reference internal" href="#key-bindings">Key bindings</a></li>
+<li><a class="reference internal" href="#automatic-indentation">Automatic indentation</a></li>
+<li><a class="reference internal" href="#completions">Completions</a></li>
+<li><a class="reference internal" href="#calltips">Calltips</a></li>
+<li><a class="reference internal" href="#python-shell-window">Python Shell window</a></li>
+<li><a class="reference internal" href="#text-colors">Text colors</a></li>
</ul>
</li>
-<li><a class="reference internal" href="#startup-and-code-execution">26.5.3. Startup and code execution</a><ul>
-<li><a class="reference internal" href="#command-line-usage">26.5.3.1. Command line usage</a></li>
-<li><a class="reference internal" href="#startup-failure">26.5.3.2. Startup failure</a></li>
-<li><a class="reference internal" href="#idle-console-differences">26.5.3.3. IDLE-console differences</a></li>
-<li><a class="reference internal" href="#developing-tkinter-applications">26.5.3.4. Developing tkinter applications</a></li>
-<li><a class="reference internal" href="#running-without-a-subprocess">26.5.3.5. Running without a subprocess</a></li>
+<li><a class="reference internal" href="#startup-and-code-execution">Startup and code execution</a><ul>
+<li><a class="reference internal" href="#command-line-usage">Command line usage</a></li>
+<li><a class="reference internal" href="#startup-failure">Startup failure</a></li>
+<li><a class="reference internal" href="#running-user-code">Running user code</a></li>
+<li><a class="reference internal" href="#user-output-in-shell">User output in Shell</a></li>
+<li><a class="reference internal" href="#developing-tkinter-applications">Developing tkinter applications</a></li>
+<li><a class="reference internal" href="#running-without-a-subprocess">Running without a subprocess</a></li>
</ul>
</li>
-<li><a class="reference internal" href="#help-and-preferences">26.5.4. Help and preferences</a><ul>
-<li><a class="reference internal" href="#additional-help-sources">26.5.4.1. Additional help sources</a></li>
-<li><a class="reference internal" href="#setting-preferences">26.5.4.2. Setting preferences</a></li>
-<li><a class="reference internal" href="#extensions">26.5.4.3. Extensions</a></li>
+<li><a class="reference internal" href="#help-and-preferences">Help and preferences</a><ul>
+<li><a class="reference internal" href="#help-sources">Help sources</a></li>
+<li><a class="reference internal" href="#setting-preferences">Setting preferences</a></li>
+<li><a class="reference internal" href="#idle-on-macos">IDLE on macOS</a></li>
+<li><a class="reference internal" href="#extensions">Extensions</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="tkinter.scrolledtext.html"
- title="previous chapter">26.4. <code class="docutils literal notranslate"><span class="pre">tkinter.scrolledtext</span></code> — Scrolled Text Widget</a></p>
+ title="previous chapter"><code class="docutils literal notranslate"><span class="pre">tkinter.scrolledtext</span></code> — Scrolled Text Widget</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="othergui.html"
- title="next chapter">26.6. Other Graphical User Interface Packages</a></p>
+ title="next chapter">Other Graphical User Interface Packages</a></p>
<div role="note" aria-label="source link">
<h3>This Page</h3>
<ul class="this-page-menu">
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
- <a href="othergui.html" title="26.6. Other Graphical User Interface Packages"
+ <a href="othergui.html" title="Other Graphical User Interface Packages"
>next</a> |</li>
<li class="right" >
- <a href="tkinter.scrolledtext.html" title="26.4. tkinter.scrolledtext — Scrolled Text Widget"
+ <a href="tkinter.scrolledtext.html" title="tkinter.scrolledtext — Scrolled Text Widget"
>previous</a> |</li>
<li><img src="../_static/py.png" alt=""
</li>
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
- <li class="nav-item nav-item-2"><a href="tk.html" >26. Graphical User Interfaces with Tk</a> »</li>
+ <li class="nav-item nav-item-2"><a href="tk.html" >Graphical User Interfaces with Tk</a> »</li>
<li class="right">
<br />
<br />
- Last updated on Jun 10, 2018.
+ Last updated on Nov 12, 2018.
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
<br />
- Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.7.4.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.8.1.
</div>
</body>
if tag in ['h1', 'h2', 'h3']:
self.indent(0) # clear tag, reset indent
if self.show:
- self.toc.append((self.header, self.text.index('insert')))
+ indent = (' ' if tag == 'h3' else
+ ' ' if tag == 'h2' else
+ '')
+ self.toc.append((indent+self.header, self.text.index('insert')))
elif tag in ['span', 'em']:
self.chartags = ''
elif tag == 'a':
if self.show and not self.hdrlink:
d = data if self.pre else data.replace('\n', ' ')
if self.tags == 'h1':
- self.hprefix = d[0:d.index(' ')]
- if self.tags in ['h1', 'h2', 'h3'] and self.hprefix != '':
- if d[0:len(self.hprefix)] == self.hprefix:
- d = d[len(self.hprefix):].strip()
- self.header += d
+ try:
+ self.hprefix = d[0:d.index(' ')]
+ except ValueError:
+ self.hprefix = ''
+ if self.tags in ['h1', 'h2', 'h3']:
+ if (self.hprefix != '' and
+ d[0:len(self.hprefix)] == self.hprefix):
+ d = d[len(self.hprefix):]
+ self.header += d.strip()
self.text.insert('end', d, (self.tags, self.chartags))
def copy_strip():
"""Copy idle.html to idlelib/help.html, stripping trailing whitespace.
- Files with trailing whitespace cannot be pushed to the hg cpython
+ Files with trailing whitespace cannot be pushed to the git cpython
repository. For 3.x (on Windows), help.html is generated, after
- editing idle.rst in the earliest maintenance version, with
+ editing idle.rst on the master branch, with
sphinx-build -bhtml . build/html
python_d.exe -c "from idlelib.help import copy_strip; copy_strip()"
- After refreshing TortoiseHG workshop to generate a diff,
- check both the diff and displayed text. Push the diff along with
- the idle.rst change and merge both into default (or an intermediate
- maintenance version).
-
- When the 'earlist' version gets its final maintenance release,
- do an update as described above, without editing idle.rst, to
- rebase help.html on the next version of idle.rst. Do not worry
- about version changes as version is not displayed. Examine other
- changes and the result of Help -> IDLE Help.
-
- If maintenance and default versions of idle.rst diverge, and
- merging does not go smoothly, then consider generating
- separate help.html files from separate idle.htmls.
+ Check build/html/library/idle.html, the help.html diff, and the text
+ displayed by Help => IDLE Help. Add a blurb and create a PR.
+
+ It can be worthwhile to occasionally generate help.html without
+ touching idle.rst. Changes to the master version and to the doc
+ build system may result in changes that should not changed
+ the displayed text, but might break HelpParser.
+
+ As long as master and maintenance versions of idle.rst remain the
+ same, help.html can be backported. The internal Python version
+ number is not displayed. If maintenance idle.rst diverges from
+ the master version, then instead of backporting help.html from
+ master, repeat the proceedure above to generate a maintenance
+ version.
"""
src = join(abspath(dirname(dirname(dirname(__file__)))),
- 'Doc', 'build', 'html', 'library', 'idle.html')
+ 'Doc', 'build', 'html', 'library', 'idle.html')
dst = join(abspath(dirname(__file__)), 'help.html')
with open(src, 'rb') as inn,\
open(dst, 'wb') as out:
given index, which is empty if there is no real one.
"""
if not self.is_in_code():
- raise ValueError("get_expression should only be called"
+ raise ValueError("get_expression should only be called "
"if index is inside a code.")
rawtext = self.rawtext
"font face of the text in the area below it.\nIn the "
"'Highlighting' tab, try different color schemes. Clicking "
"items in the sample program should update the choices above it."
- "\nIn the 'Keys', 'General' and 'Extensions' tabs, test settings"
+ "\nIn the 'Keys', 'General' and 'Extensions' tabs, test settings "
"of interest."
"\n[Ok] to close the dialog.[Apply] to apply the settings and "
"and [Cancel] to revert all changes.\nRe-run the test to ensure "
'msg': "Test for different key modifier sequences.\n"
"<nothing> is invalid.\n"
"No modifier key is invalid.\n"
- "Shift key with [a-z],[0-9], function key, move key, tab, space"
+ "Shift key with [a-z],[0-9], function key, move key, tab, space "
"is invalid.\nNo validity checking if advanced key binding "
"entry is used."
}
'file': 'percolator',
'kwds': {},
'msg': "There are two tracers which can be toggled using a checkbox.\n"
- "Toggling a tracer 'on' by checking it should print tracer"
+ "Toggling a tracer 'on' by checking it should print tracer "
"output to the console or to the IDLE shell.\n"
"If both the tracers are 'on', the output from the tracer which "
"was switched 'on' later, should be printed first\n"
_widget_redirector_spec = {
'file': 'redirector',
'kwds': {},
- 'msg': "Every text insert should be printed to the console."
+ 'msg': "Every text insert should be printed to the console "
"or the IDLE shell."
}
elif op == '!=':
return line1 != line2 or char1 != char2
else:
- raise TclError('''bad comparison operator "%s":'''
+ raise TclError('''bad comparison operator "%s": '''
'''must be <, <=, ==, >=, >, or !=''' % op)
# The following Text methods normally do something and return None.
import pyclbr
from tkinter import Tk
-from idlelib import filelist
from idlelib.tree import TreeNode
Much of IdleConf is also exercised by ConfigDialog and test_configdialog.
"""
from idlelib import config
-import copy
import sys
import os
import tempfile
from idlelib import config_key
from test.support import requires
-import sys
import unittest
from tkinter import Tk
from idlelib.idle_test.mock_idle import Func
-from idlelib.idle_test.mock_tk import Var, Mbox_func
+from idlelib.idle_test.mock_tk import Mbox_func
class ValidationTest(unittest.TestCase):
import unittest
from unittest import mock
from idlelib.idle_test.mock_idle import Func
-from tkinter import Tk, Frame, StringVar, IntVar, BooleanVar, DISABLED, NORMAL
+from tkinter import Tk, StringVar, IntVar, BooleanVar, DISABLED, NORMAL
from idlelib import config
from idlelib.configdialog import idleConf, changes, tracers
from idlelib import rpc
import unittest
-import marshal
class CodePicklerTest(unittest.TestCase):
from idlelib import zoomheight
import unittest
from test.support import requires
-from tkinter import Tk, Text
+from tkinter import Tk
from idlelib.editor import EditorWindow
# these problems, falling back to ASCII
locale_encoding = locale.nl_langinfo(locale.CODESET)
if locale_encoding is None or locale_encoding == '':
- # situation occurs on Mac OS X
+ # situation occurs on macOS
locale_encoding = 'ascii'
codecs.lookup(locale_encoding)
except (NameError, AttributeError, LookupError):
try:
locale_encoding = locale.getdefaultlocale()[1]
if locale_encoding is None or locale_encoding == '':
- # situation occurs on Mac OS X
+ # situation occurs on macOS
locale_encoding = 'ascii'
codecs.lookup(locale_encoding)
except (ValueError, LookupError):
"""
-A number of functions that enhance IDLE on Mac OSX.
+A number of functions that enhance IDLE on macOS.
"""
+from os.path import expanduser
+import plistlib
from sys import platform # Used in _init_tk_type, changed by test.
import tkinter
patchlevel = root.tk.call('info', 'patchlevel')
if patchlevel not in ('8.5.7', '8.5.9'):
return False
- return (r"WARNING: The version of Tcl/Tk ({0}) in use may"
- r" be unstable.\n"
- r"Visit http://www.python.org/download/mac/tcltk/"
- r" for current information.".format(patchlevel))
+ return ("WARNING: The version of Tcl/Tk ({0}) in use may"
+ " be unstable.\n"
+ "Visit http://www.python.org/download/mac/tcltk/"
+ " for current information.".format(patchlevel))
else:
return False
+def readSystemPreferences():
+ """
+ Fetch the macOS system preferences.
+ """
+ if platform != 'darwin':
+ return None
+
+ plist_path = expanduser('~/Library/Preferences/.GlobalPreferences.plist')
+ try:
+ with open(plist_path, 'rb') as plist_file:
+ return plistlib.load(plist_file)
+ except OSError:
+ return None
+
+
+def preferTabsPreferenceWarning():
+ """
+ Warn if "Prefer tabs when opening documents" is set to "Always".
+ """
+ if platform != 'darwin':
+ return None
+
+ prefs = readSystemPreferences()
+ if prefs and prefs.get('AppleWindowTabbingMode') == 'always':
+ return (
+ 'WARNING: The system preference "Prefer tabs when opening'
+ ' documents" is set to "Always". This will cause various problems'
+ ' with IDLE. For the best experience, change this setting when'
+ ' running IDLE (via System Preferences -> Dock).'
+ )
+ return None
+
+
## Fix the menu and related functions.
def addOpenEventSupport(root, flist):
root.bind('<<close-all-windows>>', flist.close_all_callback)
# The binding above doesn't reliably work on all versions of Tk
- # on MacOSX. Adding command definition below does seem to do the
+ # on macOS. Adding command definition below does seem to do the
# right thing for now.
root.createcommand('exit', flist.close_all_callback)
Return:
Length of text inserted.
"""
- if isinstance(s, (bytes, bytes)):
+ if isinstance(s, bytes):
s = s.decode(iomenu.encoding, "replace")
self.text.insert(mark, s, tags)
self.text.see(mark)
_chew_ordinaryre - non-special characters.
"""
import re
-import sys
# Reason last statement is continued (or C_NONE if it's not).
(C_NONE, C_BACKSLASH, C_STRING_FIRST_LINE,
# Valid arguments for the ...Awareness call below are defined in the following.
# https://msdn.microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspx
if sys.platform == 'win32':
- import ctypes
- PROCESS_SYSTEM_DPI_AWARE = 1
try:
+ import ctypes
+ PROCESS_SYSTEM_DPI_AWARE = 1
ctypes.OleDLL('shcore').SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)
- except (AttributeError, OSError):
+ except (ImportError, AttributeError, OSError):
pass
import tkinter.messagebox as tkMessageBox
import re
import socket
import subprocess
+from textwrap import TextWrapper
import threading
import time
import tokenize
self.set_line_and_column()
self.io.reset_undo()
+ def show_warning(self, msg):
+ width = self.interp.tkconsole.width
+ wrapper = TextWrapper(width=width, tabsize=8, expand_tabs=True)
+ wrapped_msg = '\n'.join(wrapper.wrap(msg))
+ if not wrapped_msg.endswith('\n'):
+ wrapped_msg += '\n'
+ self.per.bottom.insert("iomark linestart", wrapped_msg, "stderr")
+
def resetoutput(self):
source = self.text.get("iomark", "end-1c")
if self.history:
shell.interp.execfile(script)
elif shell:
# If there is a shell window and no cmd or script in progress,
- # check for problematic OS X Tk versions and print a warning
- # message in the IDLE shell window; this is less intrusive
- # than always opening a separate window.
+ # check for problematic issues and print warning message(s) in
+ # the IDLE shell window; this is less intrusive than always
+ # opening a separate window.
+
+ # Warn if using a problematic OS X Tk version.
tkversionwarning = macosx.tkVersionWarning(root)
if tkversionwarning:
- shell.interp.runcommand("print('%s')" % tkversionwarning)
+ shell.show_warning(tkversionwarning)
+
+ # Warn if the "Prefer tabs when opening documents" system
+ # preference is set to "Always".
+ prefer_tabs_preference_warning = macosx.preferTabsPreferenceWarning()
+ if prefer_tabs_preference_warning:
+ shell.show_warning(prefer_tabs_preference_warning)
while flist.inversedict: # keep IDLE running while files are open.
root.mainloop()
"exclusive")
if keyfile is not None or certfile is not None:
import warnings
- warnings.warn("keyfile and certfile are deprecated, use a"
+ warnings.warn("keyfile and certfile are deprecated, use a "
"custom ssl_context instead", DeprecationWarning, 2)
self.keyfile = keyfile
self.certfile = certfile
"""
warnings.warn("MetaPathFinder.find_module() is deprecated since Python "
- "3.4 in favor of MetaPathFinder.find_spec()"
+ "3.4 in favor of MetaPathFinder.find_spec() "
"(available since 3.4)",
DeprecationWarning,
stacklevel=2)
Alternatively, use getfullargspec() for an API with a similar namedtuple
based interface, but full support for annotations and keyword-only
parameters.
+
+ Deprecated since Python 3.5, use `inspect.getfullargspec()`.
"""
- warnings.warn("inspect.getargspec() is deprecated, "
+ warnings.warn("inspect.getargspec() is deprecated since Python 3.0, "
"use inspect.signature() or inspect.getfullargspec()",
DeprecationWarning, stacklevel=2)
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \
@classmethod
def from_function(cls, func):
- """Constructs Signature for the given python function."""
+ """Constructs Signature for the given python function.
+
+ Deprecated since Python 3.5, use `Signature.from_callable()`.
+ """
- warnings.warn("inspect.Signature.from_function() is deprecated, "
- "use Signature.from_callable()",
+ warnings.warn("inspect.Signature.from_function() is deprecated since "
+ "Python 3.5, use Signature.from_callable()",
DeprecationWarning, stacklevel=2)
return _signature_from_function(cls, func)
@classmethod
def from_builtin(cls, func):
- """Constructs Signature for the given builtin function."""
+ """Constructs Signature for the given builtin function.
+
+ Deprecated since Python 3.5, use `Signature.from_callable()`.
+ """
- warnings.warn("inspect.Signature.from_builtin() is deprecated, "
- "use Signature.from_callable()",
+ warnings.warn("inspect.Signature.from_builtin() is deprecated since "
+ "Python 3.5, use Signature.from_callable()",
DeprecationWarning, stacklevel=2)
return _signature_from_builtin(cls, func)
# call.
execfile_paren = node.children[-1].children[-1].clone()
# Construct open().read().
- open_args = ArgList([filename.clone()], rparen=execfile_paren)
+ open_args = ArgList([filename.clone(), Comma(), String('"rb"', ' ')],
+ rparen=execfile_paren)
open_call = Node(syms.power, [Name("open"), open_args])
read = [Node(syms.trailer, [Dot(), Name('read')]),
Node(syms.trailer, [LParen(), RParen()])]
def test_conversion(self):
b = """execfile("fn")"""
- a = """exec(compile(open("fn").read(), "fn", 'exec'))"""
+ a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'))"""
self.check(b, a)
b = """execfile("fn", glob)"""
- a = """exec(compile(open("fn").read(), "fn", 'exec'), glob)"""
+ a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), glob)"""
self.check(b, a)
b = """execfile("fn", glob, loc)"""
- a = """exec(compile(open("fn").read(), "fn", 'exec'), glob, loc)"""
+ a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), glob, loc)"""
self.check(b, a)
b = """execfile("fn", globals=glob)"""
- a = """exec(compile(open("fn").read(), "fn", 'exec'), globals=glob)"""
+ a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), globals=glob)"""
self.check(b, a)
b = """execfile("fn", locals=loc)"""
- a = """exec(compile(open("fn").read(), "fn", 'exec'), locals=loc)"""
+ a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), locals=loc)"""
self.check(b, a)
b = """execfile("fn", globals=glob, locals=loc)"""
- a = """exec(compile(open("fn").read(), "fn", 'exec'), globals=glob, locals=loc)"""
+ a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), globals=glob, locals=loc)"""
self.check(b, a)
def test_spacing(self):
b = """execfile( "fn" )"""
- a = """exec(compile(open( "fn" ).read(), "fn", 'exec'))"""
+ a = """exec(compile(open( "fn", "rb" ).read(), "fn", 'exec'))"""
self.check(b, a)
b = """execfile("fn", globals = glob)"""
- a = """exec(compile(open("fn").read(), "fn", 'exec'), globals = glob)"""
+ a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), globals = glob)"""
self.check(b, a)
try:
msg = self.format(record)
stream = self.stream
- stream.write(msg)
- stream.write(self.terminator)
+ # issue 35046: merged two stream.writes into one.
+ stream.write(msg + self.terminator)
self.flush()
except Exception:
self.handleError(record)
'.mht' : 'message/rfc822',
'.mhtml' : 'message/rfc822',
'.mif' : 'application/x-mif',
+ '.mjs' : 'application/javascript',
'.mov' : 'video/quicktime',
'.movie' : 'video/x-sgi-movie',
'.mp2' : 'audio/mpeg',
'''
_wrap_exception = True
- @staticmethod
- def Process(ctx, *args, **kwds):
- return ctx.Process(*args, **kwds)
+ def Process(self, *args, **kwds):
+ return self._ctx.Process(*args, **kwds)
def __init__(self, processes=None, initializer=None, initargs=(),
maxtasksperchild=None, context=None):
self._worker_handler = threading.Thread(
target=Pool._handle_workers,
- args=(self._cache, self._taskqueue, self._ctx, self.Process,
- self._processes, self._pool, self._inqueue, self._outqueue,
- self._initializer, self._initargs, self._maxtasksperchild,
- self._wrap_exception)
+ args=(self, )
)
self._worker_handler.daemon = True
self._worker_handler._state = RUN
self._worker_handler.start()
+
self._task_handler = threading.Thread(
target=Pool._handle_tasks,
args=(self._taskqueue, self._quick_put, self._outqueue,
exitpriority=15
)
- @staticmethod
- def _join_exited_workers(pool):
+ def _join_exited_workers(self):
"""Cleanup after any worker processes which have exited due to reaching
their specified lifetime. Returns True if any workers were cleaned up.
"""
cleaned = False
- for i in reversed(range(len(pool))):
- worker = pool[i]
+ for i in reversed(range(len(self._pool))):
+ worker = self._pool[i]
if worker.exitcode is not None:
# worker exited
util.debug('cleaning up worker %d' % i)
worker.join()
cleaned = True
- del pool[i]
+ del self._pool[i]
return cleaned
def _repopulate_pool(self):
- return self._repopulate_pool_static(self._ctx, self.Process,
- self._processes,
- self._pool, self._inqueue,
- self._outqueue, self._initializer,
- self._initargs,
- self._maxtasksperchild,
- self._wrap_exception)
-
- @staticmethod
- def _repopulate_pool_static(ctx, Process, processes, pool, inqueue,
- outqueue, initializer, initargs,
- maxtasksperchild, wrap_exception):
"""Bring the number of pool processes up to the specified number,
for use after reaping workers which have exited.
"""
- for i in range(processes - len(pool)):
- w = Process(ctx, target=worker,
- args=(inqueue, outqueue,
- initializer,
- initargs, maxtasksperchild,
- wrap_exception)
- )
- pool.append(w)
+ for i in range(self._processes - len(self._pool)):
+ w = self.Process(target=worker,
+ args=(self._inqueue, self._outqueue,
+ self._initializer,
+ self._initargs, self._maxtasksperchild,
+ self._wrap_exception)
+ )
+ self._pool.append(w)
w.name = w.name.replace('Process', 'PoolWorker')
w.daemon = True
w.start()
util.debug('added worker')
- @staticmethod
- def _maintain_pool(ctx, Process, processes, pool, inqueue, outqueue,
- initializer, initargs, maxtasksperchild,
- wrap_exception):
+ def _maintain_pool(self):
"""Clean up any exited workers and start replacements for them.
"""
- if Pool._join_exited_workers(pool):
- Pool._repopulate_pool_static(ctx, Process, processes, pool,
- inqueue, outqueue, initializer,
- initargs, maxtasksperchild,
- wrap_exception)
+ if self._join_exited_workers():
+ self._repopulate_pool()
def _setup_queues(self):
self._inqueue = self._ctx.SimpleQueue()
return result
@staticmethod
- def _handle_workers(cache, taskqueue, ctx, Process, processes, pool,
- inqueue, outqueue, initializer, initargs,
- maxtasksperchild, wrap_exception):
+ def _handle_workers(pool):
thread = threading.current_thread()
# Keep maintaining workers until the cache gets drained, unless the pool
# is terminated.
- while thread._state == RUN or (cache and thread._state != TERMINATE):
- Pool._maintain_pool(ctx, Process, processes, pool, inqueue,
- outqueue, initializer, initargs,
- maxtasksperchild, wrap_exception)
+ while thread._state == RUN or (pool._cache and thread._state != TERMINATE):
+ pool._maintain_pool()
time.sleep(0.1)
# send sentinel to stop workers
- taskqueue.put(None)
+ pool._taskqueue.put(None)
util.debug('worker handler exiting')
@staticmethod
_wrap_exception = False
@staticmethod
- def Process(ctx, *args, **kwds):
+ def Process(*args, **kwds):
from .dummy import Process
return Process(*args, **kwds)
def abspath(path):
"""Return the absolute version of a path."""
try:
- return _getfullpathname(path)
- except OSError:
+ return normpath(_getfullpathname(path))
+ except (OSError, ValueError):
return _abspath_fallback(path)
# realpath is a no-op on systems without islink support
if os.path.exists('/var/adm/inst-log/info'):
# SuSE Linux stores distribution information in that file
distname = 'SuSE'
- for line in open('/var/adm/inst-log/info'):
- tv = line.split()
- if len(tv) == 2:
- tag, value = tv
- else:
- continue
- if tag == 'MIN_DIST_VERSION':
- version = value.strip()
- elif tag == 'DIST_IDENT':
- values = value.split('-')
- id = values[2]
+ with open('/var/adm/inst-log/info') as f:
+ for line in f:
+ tv = line.split()
+ if len(tv) == 2:
+ tag, value = tv
+ else:
+ continue
+ if tag == 'MIN_DIST_VERSION':
+ version = value.strip()
+ elif tag == 'DIST_IDENT':
+ values = value.split('-')
+ id = values[2]
return distname, version, id
if os.path.exists('/etc/.installed'):
# Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
- for line in open('/etc/.installed'):
- pkg = line.split('-')
- if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
- # XXX does Caldera support non Intel platforms ? If yes,
- # where can we find the needed id ?
- return 'OpenLinux', pkg[1], id
+ with open('/etc/.installed') as f:
+ for line in f:
+ pkg = line.split('-')
+ if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
+ # XXX does Caldera support non Intel platforms ? If yes,
+ # where can we find the needed id ?
+ return 'OpenLinux', pkg[1], id
if os.path.isdir('/usr/lib/setup'):
# Check for slackware version tag file (thanks to Greg Andruk)
"exclusive")
if keyfile is not None or certfile is not None:
import warnings
- warnings.warn("keyfile and certfile are deprecated, use a"
+ warnings.warn("keyfile and certfile are deprecated, use a "
"custom context instead", DeprecationWarning, 2)
self.keyfile = keyfile
self.certfile = certfile
if i == 1:
if 'HOME' not in os.environ:
import pwd
- userhome = pwd.getpwuid(os.getuid()).pw_dir
+ try:
+ userhome = pwd.getpwuid(os.getuid()).pw_dir
+ except KeyError:
+ # bpo-10496: if the current user identifier doesn't exist in the
+ # password database, return the path unchanged
+ return path
else:
userhome = os.environ['HOME']
else:
try:
pwent = pwd.getpwnam(name)
except KeyError:
+ # bpo-10496: if the user name from the path doesn't exist in the
+ # password database, return the path unchanged
return path
userhome = pwent.pw_dir
if isinstance(path, bytes):
UNCHECKED_HASH = 3
+def _get_default_invalidation_mode():
+ if os.environ.get('SOURCE_DATE_EPOCH'):
+ return PycInvalidationMode.CHECKED_HASH
+ else:
+ return PycInvalidationMode.TIMESTAMP
+
+
def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1,
- invalidation_mode=PycInvalidationMode.TIMESTAMP):
+ invalidation_mode=None):
"""Byte-compile one Python source file to Python bytecode.
:param file: The source file name.
the resulting file would be regular and thus not the same type of file as
it was previously.
"""
- if os.environ.get('SOURCE_DATE_EPOCH'):
- invalidation_mode = PycInvalidationMode.CHECKED_HASH
+ if invalidation_mode is None:
+ invalidation_mode = _get_default_invalidation_mode()
if cfile is None:
if optimize >= 0:
optimization = optimize if optimize >= 1 else ''
if name == realname:
title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
else:
- if (cl and realname in cl.__dict__ and
- cl.__dict__[realname] is object):
+ if cl and inspect.getattr_static(cl, realname, []) is object:
reallink = '<a href="#%s">%s</a>' % (
cl.__name__ + '-' + realname, realname)
skipdocs = 1
if name == realname:
title = self.bold(realname)
else:
- if (cl and realname in cl.__dict__ and
- cl.__dict__[realname] is object):
+ if cl and inspect.getattr_static(cl, realname, []) is object:
skipdocs = 1
title = self.bold(name) + ' = ' + realname
argspec = None
# -*- coding: utf-8 -*-
-# Autogenerated by Sphinx on Sat Oct 20 01:59:27 2018
+# Autogenerated by Sphinx on Sun Dec 23 16:24:58 2018
topics = {'assert': 'The "assert" statement\n'
'**********************\n'
'\n'
'implementation, the built-in variable "__debug__" is "True" under\n'
'normal circumstances, "False" when optimization is requested '
'(command\n'
- 'line option -O). The current code generator emits no code for an\n'
+ 'line option "-O"). The current code generator emits no code for '
+ 'an\n'
'assert statement when optimization is requested at compile time. '
'Note\n'
'that it is unnecessary to include the source code for the '
'parentheses or square brackets, is recursively defined as '
'follows.\n'
'\n'
- '* If the target list is empty: The object must also be an '
- 'empty\n'
- ' iterable.\n'
- '\n'
- '* If the target list is a single target in parentheses: The '
- 'object\n'
- ' is assigned to that target.\n'
+ '* If the target list is a single target with no trailing '
+ 'comma,\n'
+ ' optionally in parentheses, the object is assigned to that '
+ 'target.\n'
'\n'
- '* If the target list is a comma-separated list of targets, or '
- 'a\n'
- ' single target in square brackets: The object must be an '
- 'iterable\n'
- ' with the same number of items as there are targets in the '
- 'target\n'
- ' list, and the items are assigned, from left to right, to '
- 'the\n'
- ' corresponding targets.\n'
+ '* Else: The object must be an iterable with the same number of '
+ 'items\n'
+ ' as there are targets in the target list, and the items are '
+ 'assigned,\n'
+ ' from left to right, to the corresponding targets.\n'
'\n'
' * If the target list contains one target prefixed with an\n'
' asterisk, called a “starred” target: The object must be '
'the last\n'
'"__setitem__()" or "__setattr__()" call.\n'
'\n'
- 'See also: **PEP 526** - Variable and attribute annotation '
- 'syntax\n'
- ' **PEP 484** - Type hints\n',
+ 'See also:\n'
+ '\n'
+ ' **PEP 526** - Syntax for Variable Annotations\n'
+ ' The proposal that added syntax for annotating the types '
+ 'of\n'
+ ' variables (including class variables and instance '
+ 'variables),\n'
+ ' instead of expressing them through comments.\n'
+ '\n'
+ ' **PEP 484** - Type hints\n'
+ ' The proposal that added the "typing" module to provide a '
+ 'standard\n'
+ ' syntax for type annotations that can be used in static '
+ 'analysis\n'
+ ' tools and IDEs.\n',
'async': 'Coroutines\n'
'**********\n'
'\n'
'\n'
'Execution of Python coroutines can be suspended and resumed at '
'many\n'
- 'points (see *coroutine*). In the body of a coroutine, any "await" '
- 'and\n'
- '"async" identifiers become reserved keywords; "await" expressions,\n'
- '"async for" and "async with" can only be used in coroutine bodies.\n'
+ 'points (see *coroutine*). Inside the body of a coroutine '
+ 'function,\n'
+ '"await" and "async" identifiers become reserved keywords; "await"\n'
+ 'expressions, "async for" and "async with" can only be used in\n'
+ 'coroutine function bodies.\n'
'\n'
'Functions defined with "async def" syntax are always coroutine\n'
'functions, even if they do not contain "await" or "async" '
'keywords.\n'
'\n'
- 'It is a "SyntaxError" to use "yield from" expressions in "async '
- 'def"\n'
- 'coroutines.\n'
+ 'It is a "SyntaxError" to use a "yield from" expression inside the '
+ 'body\n'
+ 'of a coroutine function.\n'
'\n'
'An example of a coroutine function:\n'
'\n'
'\n'
'See also "__aiter__()" and "__anext__()" for details.\n'
'\n'
- 'It is a "SyntaxError" to use "async for" statement outside of an\n'
- '"async def" function.\n'
+ 'It is a "SyntaxError" to use an "async for" statement outside the '
+ 'body\n'
+ 'of a coroutine function.\n'
'\n'
'\n'
'The "async with" statement\n'
'\n'
'See also "__aenter__()" and "__aexit__()" for details.\n'
'\n'
- 'It is a "SyntaxError" to use "async with" statement outside of an\n'
- '"async def" function.\n'
+ 'It is a "SyntaxError" to use an "async with" statement outside the\n'
+ 'body of a coroutine function.\n'
'\n'
- 'See also: **PEP 492** - Coroutines with async and await syntax\n'
+ 'See also:\n'
+ '\n'
+ ' **PEP 492** - Coroutines with async and await syntax\n'
+ ' The proposal that made coroutines a proper standalone concept '
+ 'in\n'
+ ' Python, and added supporting syntax.\n'
'\n'
'-[ Footnotes ]-\n'
'\n'
' there is a "finally" clause which happens to raise another\n'
' exception. That new exception causes the old one to be lost.\n'
'\n'
- '[2] Currently, control “flows off the end” except in the case of\n'
- ' an exception or the execution of a "return", "continue", or\n'
- ' "break" statement.\n'
- '\n'
- '[3] A string literal appearing as the first statement in the\n'
+ '[2] A string literal appearing as the first statement in the\n'
' function body is transformed into the function’s "__doc__"\n'
' attribute and therefore the function’s *docstring*.\n'
'\n'
- '[4] A string literal appearing as the first statement in the class\n'
+ '[3] A string literal appearing as the first statement in the class\n'
' body is transformed into the namespace’s "__doc__" item and\n'
' therefore the class’s *docstring*.\n',
'atom-identifiers': 'Identifiers (Names)\n'
'\n'
' def __setattr__(self, attr, value):\n'
" print(f'Setting {attr}...')\n"
- ' setattr(self, attr, value)\n'
+ ' super().__setattr__(attr, value)\n'
'\n'
' sys.modules[__name__].__class__ = VerboseModule\n'
'\n'
'is\n'
'returned.\n'
'\n'
- '(Note that neither "and" nor "or" restrict the value and type '
+ 'Note that neither "and" nor "or" restrict the value and type '
'they\n'
'return to "False" and "True", but rather return the last '
'evaluated\n'
'original global namespace. (Usually, the suite contains mostly\n'
'function definitions.) When the class’s suite finishes execution, '
'its\n'
- 'execution frame is discarded but its local namespace is saved. [4] '
+ 'execution frame is discarded but its local namespace is saved. [3] '
'A\n'
'class object is then created using the inheritance list for the '
'base\n'
'unexpected results. Descriptors can be used to create instance\n'
'variables with different implementation details.\n'
'\n'
- 'See also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n'
- ' Class Decorators\n',
+ 'See also:\n'
+ '\n'
+ ' **PEP 3115** - Metaclasses in Python 3000\n'
+ ' The proposal that changed the declaration of metaclasses to '
+ 'the\n'
+ ' current syntax, and the semantics for how classes with\n'
+ ' metaclasses are constructed.\n'
+ '\n'
+ ' **PEP 3129** - Class Decorators\n'
+ ' The proposal that added class decorators. Function and '
+ 'method\n'
+ ' decorators were introduced in **PEP 318**.\n',
'comparisons': 'Comparisons\n'
'***********\n'
'\n'
'returning\n'
'from a function that handled an exception.\n'
'\n'
- 'The optional "else" clause is executed if and when control flows '
- 'off\n'
- 'the end of the "try" clause. [2] Exceptions in the "else" clause '
+ 'The optional "else" clause is executed if the control flow '
+ 'leaves the\n'
+ '"try" suite, no exception was raised, and no "return", '
+ '"continue", or\n'
+ '"break" statement was executed. Exceptions in the "else" clause '
'are\n'
'not handled by the preceding "except" clauses.\n'
'\n'
'\n'
'The function definition does not execute the function body; this '
'gets\n'
- 'executed only when the function is called. [3]\n'
+ 'executed only when the function is called. [2]\n'
'\n'
'A function definition may be wrapped by one or more *decorator*\n'
'expressions. Decorator expressions are evaluated when the '
'function definitions.) When the class’s suite finishes '
'execution, its\n'
'execution frame is discarded but its local namespace is saved. '
- '[4] A\n'
+ '[3] A\n'
'class object is then created using the inheritance list for the '
'base\n'
'classes and the saved local namespace for the attribute '
'unexpected results. Descriptors can be used to create instance\n'
'variables with different implementation details.\n'
'\n'
- 'See also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n'
- ' Class Decorators\n'
+ 'See also:\n'
+ '\n'
+ ' **PEP 3115** - Metaclasses in Python 3000\n'
+ ' The proposal that changed the declaration of metaclasses to '
+ 'the\n'
+ ' current syntax, and the semantics for how classes with\n'
+ ' metaclasses are constructed.\n'
+ '\n'
+ ' **PEP 3129** - Class Decorators\n'
+ ' The proposal that added class decorators. Function and '
+ 'method\n'
+ ' decorators were introduced in **PEP 318**.\n'
'\n'
'\n'
'Coroutines\n'
'\n'
'Execution of Python coroutines can be suspended and resumed at '
'many\n'
- 'points (see *coroutine*). In the body of a coroutine, any '
- '"await" and\n'
- '"async" identifiers become reserved keywords; "await" '
- 'expressions,\n'
- '"async for" and "async with" can only be used in coroutine '
- 'bodies.\n'
+ 'points (see *coroutine*). Inside the body of a coroutine '
+ 'function,\n'
+ '"await" and "async" identifiers become reserved keywords; '
+ '"await"\n'
+ 'expressions, "async for" and "async with" can only be used in\n'
+ 'coroutine function bodies.\n'
'\n'
'Functions defined with "async def" syntax are always coroutine\n'
'functions, even if they do not contain "await" or "async" '
'keywords.\n'
'\n'
- 'It is a "SyntaxError" to use "yield from" expressions in "async '
- 'def"\n'
- 'coroutines.\n'
+ 'It is a "SyntaxError" to use a "yield from" expression inside '
+ 'the body\n'
+ 'of a coroutine function.\n'
'\n'
'An example of a coroutine function:\n'
'\n'
'\n'
'See also "__aiter__()" and "__anext__()" for details.\n'
'\n'
- 'It is a "SyntaxError" to use "async for" statement outside of '
- 'an\n'
- '"async def" function.\n'
+ 'It is a "SyntaxError" to use an "async for" statement outside '
+ 'the body\n'
+ 'of a coroutine function.\n'
'\n'
'\n'
'The "async with" statement\n'
'\n'
'See also "__aenter__()" and "__aexit__()" for details.\n'
'\n'
- 'It is a "SyntaxError" to use "async with" statement outside of '
- 'an\n'
- '"async def" function.\n'
+ 'It is a "SyntaxError" to use an "async with" statement outside '
+ 'the\n'
+ 'body of a coroutine function.\n'
+ '\n'
+ 'See also:\n'
'\n'
- 'See also: **PEP 492** - Coroutines with async and await syntax\n'
+ ' **PEP 492** - Coroutines with async and await syntax\n'
+ ' The proposal that made coroutines a proper standalone '
+ 'concept in\n'
+ ' Python, and added supporting syntax.\n'
'\n'
'-[ Footnotes ]-\n'
'\n'
' exception. That new exception causes the old one to be '
'lost.\n'
'\n'
- '[2] Currently, control “flows off the end” except in the case '
- 'of\n'
- ' an exception or the execution of a "return", "continue", or\n'
- ' "break" statement.\n'
- '\n'
- '[3] A string literal appearing as the first statement in the\n'
+ '[2] A string literal appearing as the first statement in the\n'
' function body is transformed into the function’s "__doc__"\n'
' attribute and therefore the function’s *docstring*.\n'
'\n'
- '[4] A string literal appearing as the first statement in the '
+ '[3] A string literal appearing as the first statement in the '
'class\n'
' body is transformed into the namespace’s "__doc__" item and\n'
' therefore the class’s *docstring*.\n',
' See '
'http://www.ocert.org/advisories/ocert-2011-003.html for\n'
' details.Changing hash values affects the iteration '
- 'order of\n'
- ' dicts, sets and other mappings. Python has never made '
- 'guarantees\n'
- ' about this ordering (and it typically varies between '
- '32-bit and\n'
- ' 64-bit builds).See also "PYTHONHASHSEED".\n'
+ 'order of sets.\n'
+ ' Python has never made guarantees about this ordering '
+ '(and it\n'
+ ' typically varies between 32-bit and 64-bit builds).See '
+ 'also\n'
+ ' "PYTHONHASHSEED".\n'
'\n'
' Changed in version 3.3: Hash randomization is enabled by '
'default.\n'
'argument to the interpreter) is a code block. A script command '
'(a\n'
'command specified on the interpreter command line with the '
- '‘**-c**’\n'
+ '"-c"\n'
'option) is a code block. The string argument passed to the '
'built-in\n'
'functions "eval()" and "exec()" is a code block.\n'
'\n'
'The new format syntax also supports new and different '
'options, shown\n'
- 'in the follow examples.\n'
+ 'in the following examples.\n'
'\n'
'Accessing arguments by position:\n'
'\n'
'\n'
'The function definition does not execute the function body; this '
'gets\n'
- 'executed only when the function is called. [3]\n'
+ 'executed only when the function is called. [2]\n'
'\n'
'A function definition may be wrapped by one or more *decorator*\n'
'expressions. Decorator expressions are evaluated when the '
'lambda': 'Lambdas\n'
'*******\n'
'\n'
- ' lambda_expr ::= "lambda" [parameter_list]: expression\n'
- ' lambda_expr_nocond ::= "lambda" [parameter_list]: '
+ ' lambda_expr ::= "lambda" [parameter_list] ":" '
+ 'expression\n'
+ ' lambda_expr_nocond ::= "lambda" [parameter_list] ":" '
'expression_nocond\n'
'\n'
'Lambda expressions (sometimes called lambda forms) are used to '
'of the\n'
' sequence.\n'
'\n'
- 'object.__missing__(self, key)\n'
- '\n'
- ' Called by "dict"."__getitem__()" to implement '
- '"self[key]" for dict\n'
- ' subclasses when key is not in the dictionary.\n'
- '\n'
'object.__setitem__(self, key, value)\n'
'\n'
' Called to implement assignment to "self[key]". Same '
' raised for improper *key* values as for the '
'"__getitem__()" method.\n'
'\n'
+ 'object.__missing__(self, key)\n'
+ '\n'
+ ' Called by "dict"."__getitem__()" to implement '
+ '"self[key]" for dict\n'
+ ' subclasses when key is not in the dictionary.\n'
+ '\n'
'object.__iter__(self)\n'
'\n'
' This method is called when an iterator is required for '
' See http://www.ocert.org/advisories/ocert-2011-003.html '
'for\n'
' details.Changing hash values affects the iteration '
- 'order of\n'
- ' dicts, sets and other mappings. Python has never made '
- 'guarantees\n'
- ' about this ordering (and it typically varies between '
- '32-bit and\n'
- ' 64-bit builds).See also "PYTHONHASHSEED".\n'
+ 'order of sets.\n'
+ ' Python has never made guarantees about this ordering '
+ '(and it\n'
+ ' typically varies between 32-bit and 64-bit builds).See '
+ 'also\n'
+ ' "PYTHONHASHSEED".\n'
'\n'
' Changed in version 3.3: Hash randomization is enabled by '
'default.\n'
'\n'
' def __setattr__(self, attr, value):\n'
" print(f'Setting {attr}...')\n"
- ' setattr(self, attr, value)\n'
+ ' super().__setattr__(attr, value)\n'
'\n'
' sys.modules[__name__].__class__ = VerboseModule\n'
'\n'
' Describes the implicit "__class__" closure reference\n'
'\n'
'\n'
- 'Metaclass example\n'
- '-----------------\n'
+ 'Uses for metaclasses\n'
+ '--------------------\n'
'\n'
'The potential uses for metaclasses are boundless. Some ideas '
'that have\n'
'frameworks, and\n'
'automatic resource locking/synchronization.\n'
'\n'
- 'Here is an example of a metaclass that uses an\n'
- '"collections.OrderedDict" to remember the order that class '
- 'variables\n'
- 'are defined:\n'
- '\n'
- ' class OrderedClass(type):\n'
- '\n'
- ' @classmethod\n'
- ' def __prepare__(metacls, name, bases, **kwds):\n'
- ' return collections.OrderedDict()\n'
- '\n'
- ' def __new__(cls, name, bases, namespace, **kwds):\n'
- ' result = type.__new__(cls, name, bases, '
- 'dict(namespace))\n'
- ' result.members = tuple(namespace)\n'
- ' return result\n'
- '\n'
- ' class A(metaclass=OrderedClass):\n'
- ' def one(self): pass\n'
- ' def two(self): pass\n'
- ' def three(self): pass\n'
- ' def four(self): pass\n'
- '\n'
- ' >>> A.members\n'
- " ('__module__', 'one', 'two', 'three', 'four')\n"
- '\n'
- 'When the class definition for *A* gets executed, the process '
- 'begins\n'
- 'with calling the metaclass’s "__prepare__()" method which '
- 'returns an\n'
- 'empty "collections.OrderedDict". That mapping records the '
- 'methods and\n'
- 'attributes of *A* as they are defined within the body of the '
- 'class\n'
- 'statement. Once those definitions are executed, the ordered '
- 'dictionary\n'
- 'is fully populated and the metaclass’s "__new__()" method '
- 'gets\n'
- 'invoked. That method builds the new type and it saves the '
- 'ordered\n'
- 'dictionary keys in an attribute called "members".\n'
- '\n'
'\n'
'Customizing instance and subclass checks\n'
'========================================\n'
'the\n'
' sequence.\n'
'\n'
- 'object.__missing__(self, key)\n'
- '\n'
- ' Called by "dict"."__getitem__()" to implement "self[key]" '
- 'for dict\n'
- ' subclasses when key is not in the dictionary.\n'
- '\n'
'object.__setitem__(self, key, value)\n'
'\n'
' Called to implement assignment to "self[key]". Same note '
' raised for improper *key* values as for the '
'"__getitem__()" method.\n'
'\n'
+ 'object.__missing__(self, key)\n'
+ '\n'
+ ' Called by "dict"."__getitem__()" to implement "self[key]" '
+ 'for dict\n'
+ ' subclasses when key is not in the dictionary.\n'
+ '\n'
'object.__iter__(self)\n'
'\n'
' This method is called when an iterator is required for a '
'restored to their previous values (before the call) when returning\n'
'from a function that handled an exception.\n'
'\n'
- 'The optional "else" clause is executed if and when control flows off\n'
- 'the end of the "try" clause. [2] Exceptions in the "else" clause are\n'
+ 'The optional "else" clause is executed if the control flow leaves '
+ 'the\n'
+ '"try" suite, no exception was raised, and no "return", "continue", '
+ 'or\n'
+ '"break" statement was executed. Exceptions in the "else" clause are\n'
'not handled by the preceding "except" clauses.\n'
'\n'
'If "finally" is present, it specifies a ‘cleanup’ handler. The '
'\n'
' Changed in version 3.7: Dictionary order is guaranteed to '
'be\n'
- ' insertion order. This behavior was implementation detail '
- 'of\n'
+ ' insertion order. This behavior was an implementation '
+ 'detail of\n'
' CPython from 3.6.\n'
'\n'
'See also: "types.MappingProxyType" can be used to create a '
pass
def copystat(src, dst, *, follow_symlinks=True):
- """Copy all stat info (mode bits, atime, mtime, flags) from src to dst.
+ """Copy file metadata
- If the optional flag `follow_symlinks` is not set, symlinks aren't followed if and
- only if both `src` and `dst` are symlinks.
+ Copy the permission bits, last access time, last modification time, and
+ flags from `src` to `dst`. On Linux, copystat() also copies the "extended
+ attributes" where possible. The file contents, owner, and group are
+ unaffected. `src` and `dst` are path names given as strings.
+ If the optional flag `follow_symlinks` is not set, symlinks aren't
+ followed if and only if both `src` and `dst` are symlinks.
"""
def _nop(*args, ns=None, follow_symlinks=None):
pass
return dst
def copy2(src, dst, *, follow_symlinks=True):
- """Copy data and all stat info ("cp -p src dst"). Return the file's
- destination."
+ """Copy data and metadata. Return the file's destination.
+
+ Metadata is copied with copystat(). Please see the copystat function
+ for more information.
The destination may be a directory.
"exclusive")
if keyfile is not None or certfile is not None:
import warnings
- warnings.warn("keyfile and certfile are deprecated, use a"
+ warnings.warn("keyfile and certfile are deprecated, use a "
"custom context instead", DeprecationWarning, 2)
if context is None:
context = ssl._create_stdlib_context(certfile=certfile,
"exclusive")
if keyfile is not None or certfile is not None:
import warnings
- warnings.warn("keyfile and certfile are deprecated, use a"
+ warnings.warn("keyfile and certfile are deprecated, use a "
"custom context instead", DeprecationWarning, 2)
self.keyfile = keyfile
self.certfile = certfile
while not self.__shutdown_request:
ready = selector.select(poll_interval)
+ # bpo-35017: shutdown() called during select(), exit immediately.
+ if self.__shutdown_request:
+ break
if ready:
self._handle_request_noblock()
cur.execute("pragma page_size")
row = cur.fetchone()
- def CheckSetDict(self):
- """
- See http://bugs.python.org/issue7478
-
- It was possible to successfully register callbacks that could not be
- hashed. Return codes of PyDict_SetItem were not checked properly.
- """
- class NotHashable:
- def __call__(self, *args, **kw):
- pass
- def __hash__(self):
- raise TypeError()
- var = NotHashable()
- self.assertRaises(TypeError, self.con.create_function, var)
- self.assertRaises(TypeError, self.con.create_aggregate, var)
- self.assertRaises(TypeError, self.con.set_authorizer, var)
- self.assertRaises(TypeError, self.con.set_progress_handler, var)
-
def CheckConnectionCall(self):
"""
Call a connection with a non-string SQL request: check error handling
support.gc_collect()
+class UnhashableFunc:
+ __hash__ = None
+
+ def __init__(self, return_value=None):
+ self.calls = 0
+ self.return_value = return_value
+
+ def __call__(self, *args, **kwargs):
+ self.calls += 1
+ return self.return_value
+
+
+class UnhashableCallbacksTestCase(unittest.TestCase):
+ """
+ https://bugs.python.org/issue34052
+
+ Registering unhashable callbacks raises TypeError, callbacks are not
+ registered in SQLite after such registration attempt.
+ """
+ def setUp(self):
+ self.con = sqlite.connect(':memory:')
+
+ def tearDown(self):
+ self.con.close()
+
+ def test_progress_handler(self):
+ f = UnhashableFunc(return_value=0)
+ with self.assertRaisesRegex(TypeError, 'unhashable type'):
+ self.con.set_progress_handler(f, 1)
+ self.con.execute('SELECT 1')
+ self.assertFalse(f.calls)
+
+ def test_func(self):
+ func_name = 'func_name'
+ f = UnhashableFunc()
+ with self.assertRaisesRegex(TypeError, 'unhashable type'):
+ self.con.create_function(func_name, 0, f)
+ msg = 'no such function: %s' % func_name
+ with self.assertRaisesRegex(sqlite.OperationalError, msg):
+ self.con.execute('SELECT %s()' % func_name)
+ self.assertFalse(f.calls)
+
+ def test_authorizer(self):
+ f = UnhashableFunc(return_value=sqlite.SQLITE_DENY)
+ with self.assertRaisesRegex(TypeError, 'unhashable type'):
+ self.con.set_authorizer(f)
+ self.con.execute('SELECT 1')
+ self.assertFalse(f.calls)
+
+ def test_aggr(self):
+ class UnhashableType(type):
+ __hash__ = None
+ aggr_name = 'aggr_name'
+ with self.assertRaisesRegex(TypeError, 'unhashable type'):
+ self.con.create_aggregate(aggr_name, 0, UnhashableType('Aggr', (), {}))
+ msg = 'no such function: %s' % aggr_name
+ with self.assertRaisesRegex(sqlite.OperationalError, msg):
+ self.con.execute('SELECT %s()' % aggr_name)
+
+
def suite():
regression_suite = unittest.makeSuite(RegressionTests, "Check")
- return unittest.TestSuite((regression_suite,))
+ return unittest.TestSuite((
+ regression_suite,
+ unittest.makeSuite(UnhashableCallbacksTestCase),
+ ))
def test():
runner = unittest.TextTestRunner()
return self._sslobj.session_reused
def dup(self):
- raise NotImplemented("Can't dup() %s instances" %
- self.__class__.__name__)
+ raise NotImplementedError("Can't dup() %s instances" %
+ self.__class__.__name__)
def _checkClosed(self, msg=None):
# raise an exception here if you wish to check for spurious closes
# 'inspect': 'i',
# 'interactive': 'i',
'dont_write_bytecode': 'B',
- 'no_user_site': 's',
'no_site': 'S',
- 'ignore_environment': 'E',
'verbose': 'v',
'bytes_warning': 'b',
'quiet': 'q',
if v > 0:
args.append('-' + opt * v)
+ if sys.flags.isolated:
+ args.append('-I')
+ else:
+ if sys.flags.ignore_environment:
+ args.append('-E')
+ if sys.flags.no_user_site:
+ args.append('-s')
+
# -W options
warnopts = sys.warnoptions[:]
bytes_warning = sys.flags.bytes_warning
with self.Pool(2) as p:
r = p.map_async(sqr, L)
self.assertEqual(r.get(), expected)
+ p.join()
self.assertRaises(ValueError, p.map_async, sqr, L)
@classmethod
exc = e
else:
self.fail('expected RuntimeError')
+ p.join()
self.assertIs(type(exc), RuntimeError)
self.assertEqual(exc.args, (123,))
cause = exc.__cause__
self.fail('expected SayWhenError')
self.assertIs(type(exc), SayWhenError)
self.assertIs(exc.__cause__, None)
+ p.join()
@classmethod
def _test_wrapped_exception(cls):
with self.Pool(1) as p:
with self.assertRaises(RuntimeError):
p.apply(self._test_wrapped_exception)
+ p.join()
def test_map_no_failfast(self):
# Issue #23992: the fail-fast behaviour when an exception is raised
# they were released too.
self.assertEqual(CountedObject.n_instances, 0)
- def test_del_pool(self):
- p = self.Pool(1)
- wr = weakref.ref(p)
- del p
- gc.collect()
- self.assertIsNone(wr())
def raising():
raise KeyError("key")
import os
import pickle
import random
+import re
import struct
import unittest
import _strptime
#
+pickle_loads = {pickle.loads, pickle._loads}
pickle_choices = [(pickle, pickle, proto)
for proto in range(pickle.HIGHEST_PROTOCOL + 1)]
self.assertEqual('UTC+09:30', timezone(9.5 * HOUR).tzname(None))
self.assertEqual('UTC-00:01', timezone(timedelta(minutes=-1)).tzname(None))
self.assertEqual('XYZ', timezone(-5 * HOUR, 'XYZ').tzname(None))
+ # bpo-34482: Check that surrogates are handled properly.
+ self.assertEqual('\ud800', timezone(ZERO, '\ud800').tzname(None))
# Sub-minute offsets:
self.assertEqual('UTC+01:06:40', timezone(timedelta(0, 4000)).tzname(None))
class BadInt(int):
def __mul__(self, other):
return Prod()
+ def __rmul__(self, other):
+ return Prod()
+ def __floordiv__(self, other):
+ return Prod()
+ def __rfloordiv__(self, other):
+ return Prod()
class Prod:
+ def __add__(self, other):
+ return Sum()
def __radd__(self, other):
return Sum()
class Sum(int):
def __divmod__(self, other):
- # negative remainder
- return (0, -1)
-
- timedelta(microseconds=BadInt(1))
- timedelta(hours=BadInt(1))
- timedelta(weeks=BadInt(1))
+ return divmodresult
+
+ for divmodresult in [None, (), (0, 1, 2), (0, -1)]:
+ with self.subTest(divmodresult=divmodresult):
+ # The following examples should not crash.
+ try:
+ timedelta(microseconds=BadInt(1))
+ except TypeError:
+ pass
+ try:
+ timedelta(hours=BadInt(1))
+ except TypeError:
+ pass
+ try:
+ timedelta(weeks=BadInt(1))
+ except (TypeError, ValueError):
+ pass
+ try:
+ timedelta(1) * BadInt(1)
+ except (TypeError, ValueError):
+ pass
+ try:
+ BadInt(1) * timedelta(1)
+ except TypeError:
+ pass
+ try:
+ timedelta(1) // BadInt(1)
+ except TypeError:
+ pass
#############################################################################
except ValueError:
pass
+ # bpo-34482: Check that surrogates don't cause a crash.
+ try:
+ t.strftime('%y\ud800%m')
+ except UnicodeEncodeError:
+ pass
+
#check that this standard extension works
t.strftime("%f")
self.assertEqual(orig, derived)
self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
+ def test_compat_unpickle(self):
+ tests = [
+ b"cdatetime\ndate\n(S'\\x07\\xdf\\x0b\\x1b'\ntR.",
+ b'cdatetime\ndate\n(U\x04\x07\xdf\x0b\x1btR.',
+ b'\x80\x02cdatetime\ndate\nU\x04\x07\xdf\x0b\x1b\x85R.',
+ ]
+ args = 2015, 11, 27
+ expected = self.theclass(*args)
+ for data in tests:
+ for loads in pickle_loads:
+ derived = loads(data, encoding='latin1')
+ self.assertEqual(derived, expected)
+
def test_compare(self):
t1 = self.theclass(2, 3, 4)
t2 = self.theclass(2, 3, 4)
self.assertEqual(t.isoformat('T'), "0001-02-03T04:05:01.000123")
self.assertEqual(t.isoformat(' '), "0001-02-03 04:05:01.000123")
self.assertEqual(t.isoformat('\x00'), "0001-02-03\x0004:05:01.000123")
+ # bpo-34482: Check that surrogates are handled properly.
+ self.assertEqual(t.isoformat('\ud800'),
+ "0001-02-03\ud80004:05:01.000123")
self.assertEqual(t.isoformat(timespec='hours'), "0001-02-03T04")
self.assertEqual(t.isoformat(timespec='minutes'), "0001-02-03T04:05")
self.assertEqual(t.isoformat(timespec='seconds'), "0001-02-03T04:05:01")
self.assertEqual(t.isoformat(timespec='auto'), "0001-02-03T04:05:01.000123")
self.assertEqual(t.isoformat(sep=' ', timespec='minutes'), "0001-02-03 04:05")
self.assertRaises(ValueError, t.isoformat, timespec='foo')
+ # bpo-34482: Check that surrogates are handled properly.
+ self.assertRaises(ValueError, t.isoformat, timespec='\ud800')
# str is ISO format with the separator forced to a blank.
self.assertEqual(str(t), "0001-02-03 04:05:01.000123")
derived = unpickler.loads(green)
self.assertEqual(orig, derived)
+ def test_compat_unpickle(self):
+ tests = [
+ b'cdatetime\ndatetime\n('
+ b"S'\\x07\\xdf\\x0b\\x1b\\x14;\\x01\\x00\\x10\\x00'\ntR.",
+
+ b'cdatetime\ndatetime\n('
+ b'U\n\x07\xdf\x0b\x1b\x14;\x01\x00\x10\x00tR.',
+
+ b'\x80\x02cdatetime\ndatetime\n'
+ b'U\n\x07\xdf\x0b\x1b\x14;\x01\x00\x10\x00\x85R.',
+ ]
+ args = 2015, 11, 27, 20, 59, 1, 64**2
+ expected = self.theclass(*args)
+ for data in tests:
+ for loads in pickle_loads:
+ derived = loads(data, encoding='latin1')
+ self.assertEqual(derived, expected)
+
def test_more_compare(self):
# The test_compare() inherited from TestDate covers the error cases.
# We just want to test lexicographic ordering on the members datetime
self.assertIs(type(expected), self.theclass)
self.assertIs(type(got), self.theclass)
+ # bpo-34482: Check that surrogates are handled properly.
+ inputs = [
+ ('2004-12-01\ud80013:02:47.197', '%Y-%m-%d\ud800%H:%M:%S.%f'),
+ ('2004\ud80012-01 13:02:47.197', '%Y\ud800%m-%d %H:%M:%S.%f'),
+ ('2004-12-01 13:02\ud80047.197', '%Y-%m-%d %H:%M\ud800%S.%f'),
+ ]
+ for string, format in inputs:
+ with self.subTest(string=string, format=format):
+ expected = _strptime._strptime_datetime(self.theclass, string,
+ format)
+ got = self.theclass.strptime(string, format)
+ self.assertEqual(expected, got)
+
strptime = self.theclass.strptime
self.assertEqual(strptime("+0002", "%z").utcoffset(), 2 * MINUTE)
self.assertEqual(strptime("-0002", "%z").utcoffset(), -2 * MINUTE)
t = t.replace(tzinfo=tz)
self.assertEqual(t.strftime("%z"), "-0200" + z)
+ # bpo-34482: Check that surrogates don't cause a crash.
+ try:
+ t.strftime('%y\ud800%m %H\ud800%M')
+ except UnicodeEncodeError:
+ pass
+
def test_extract(self):
dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234)
self.assertEqual(dt.date(), date(2002, 3, 4))
with self.assertRaises(ValueError):
self.theclass.fromisoformat(bad_str)
+ def test_fromisoformat_fails_surrogate(self):
+ # Test that when fromisoformat() fails with a surrogate character as
+ # the separator, the error message contains the original string
+ dtstr = "2018-01-03\ud80001:0113"
+
+ with self.assertRaisesRegex(ValueError, re.escape(repr(dtstr))):
+ self.theclass.fromisoformat(dtstr)
+
def test_fromisoformat_utc(self):
dt_str = '2014-04-19T13:21:13+00:00'
dt = self.theclass.fromisoformat(dt_str)
self.assertEqual(t.isoformat(timespec='microseconds'), "12:34:56.123456")
self.assertEqual(t.isoformat(timespec='auto'), "12:34:56.123456")
self.assertRaises(ValueError, t.isoformat, timespec='monkey')
+ # bpo-34482: Check that surrogates are handled properly.
+ self.assertRaises(ValueError, t.isoformat, timespec='\ud800')
t = self.theclass(hour=12, minute=34, second=56, microsecond=999500)
self.assertEqual(t.isoformat(timespec='milliseconds'), "12:34:56.999")
# A naive object replaces %z and %Z with empty strings.
self.assertEqual(t.strftime("'%z' '%Z'"), "'' ''")
+ # bpo-34482: Check that surrogates don't cause a crash.
+ try:
+ t.strftime('%H\ud800%M')
+ except UnicodeEncodeError:
+ pass
+
def test_format(self):
t = self.theclass(1, 2, 3, 4)
self.assertEqual(t.__format__(''), str(t))
derived = unpickler.loads(green)
self.assertEqual(orig, derived)
+ def test_compat_unpickle(self):
+ tests = [
+ b"cdatetime\ntime\n(S'\\x14;\\x10\\x00\\x10\\x00'\ntR.",
+ b'cdatetime\ntime\n(U\x06\x14;\x10\x00\x10\x00tR.',
+ b'\x80\x02cdatetime\ntime\nU\x06\x14;\x10\x00\x10\x00\x85R.',
+ ]
+ args = 20, 59, 16, 64**2
+ expected = self.theclass(*args)
+ for data in tests:
+ for loads in pickle_loads:
+ derived = loads(data, encoding='latin1')
+ self.assertEqual(derived, expected)
+
def test_bool(self):
# time is always True.
cls = self.theclass
self.assertEqual(derived.tzname(), 'cookie')
self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
+ def test_compat_unpickle(self):
+ tests = [
+ b"cdatetime\ntime\n(S'\\x05\\x06\\x07\\x01\\xe2@'\n"
+ b"ctest.datetimetester\nPicklableFixedOffset\n(tR"
+ b"(dS'_FixedOffset__offset'\ncdatetime\ntimedelta\n"
+ b"(I-1\nI68400\nI0\ntRs"
+ b"S'_FixedOffset__dstoffset'\nNs"
+ b"S'_FixedOffset__name'\nS'cookie'\nsbtR.",
+
+ b'cdatetime\ntime\n(U\x06\x05\x06\x07\x01\xe2@'
+ b'ctest.datetimetester\nPicklableFixedOffset\n)R'
+ b'}(U\x14_FixedOffset__offsetcdatetime\ntimedelta\n'
+ b'(J\xff\xff\xff\xffJ0\x0b\x01\x00K\x00tR'
+ b'U\x17_FixedOffset__dstoffsetN'
+ b'U\x12_FixedOffset__nameU\x06cookieubtR.',
+
+ b'\x80\x02cdatetime\ntime\nU\x06\x05\x06\x07\x01\xe2@'
+ b'ctest.datetimetester\nPicklableFixedOffset\n)R'
+ b'}(U\x14_FixedOffset__offsetcdatetime\ntimedelta\n'
+ b'J\xff\xff\xff\xffJ0\x0b\x01\x00K\x00\x87R'
+ b'U\x17_FixedOffset__dstoffsetN'
+ b'U\x12_FixedOffset__nameU\x06cookieub\x86R.',
+ ]
+
+ tinfo = PicklableFixedOffset(-300, 'cookie')
+ expected = self.theclass(5, 6, 7, 123456, tzinfo=tinfo)
+ for data in tests:
+ for loads in pickle_loads:
+ derived = loads(data, encoding='latin1')
+ self.assertEqual(derived, expected, repr(data))
+ self.assertIsInstance(derived.tzinfo, PicklableFixedOffset)
+ self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
+ self.assertEqual(derived.tzname(), 'cookie')
+
def test_more_bool(self):
# time is always True.
cls = self.theclass
self.assertEqual(derived.tzname(), 'cookie')
self.assertEqual(orig.__reduce__(), orig.__reduce_ex__(2))
+ def test_compat_unpickle(self):
+ tests = [
+ b'cdatetime\ndatetime\n'
+ b"(S'\\x07\\xdf\\x0b\\x1b\\x14;\\x01\\x01\\xe2@'\n"
+ b'ctest.datetimetester\nPicklableFixedOffset\n(tR'
+ b"(dS'_FixedOffset__offset'\ncdatetime\ntimedelta\n"
+ b'(I-1\nI68400\nI0\ntRs'
+ b"S'_FixedOffset__dstoffset'\nNs"
+ b"S'_FixedOffset__name'\nS'cookie'\nsbtR.",
+
+ b'cdatetime\ndatetime\n'
+ b'(U\n\x07\xdf\x0b\x1b\x14;\x01\x01\xe2@'
+ b'ctest.datetimetester\nPicklableFixedOffset\n)R'
+ b'}(U\x14_FixedOffset__offsetcdatetime\ntimedelta\n'
+ b'(J\xff\xff\xff\xffJ0\x0b\x01\x00K\x00tR'
+ b'U\x17_FixedOffset__dstoffsetN'
+ b'U\x12_FixedOffset__nameU\x06cookieubtR.',
+
+ b'\x80\x02cdatetime\ndatetime\n'
+ b'U\n\x07\xdf\x0b\x1b\x14;\x01\x01\xe2@'
+ b'ctest.datetimetester\nPicklableFixedOffset\n)R'
+ b'}(U\x14_FixedOffset__offsetcdatetime\ntimedelta\n'
+ b'J\xff\xff\xff\xffJ0\x0b\x01\x00K\x00\x87R'
+ b'U\x17_FixedOffset__dstoffsetN'
+ b'U\x12_FixedOffset__nameU\x06cookieub\x86R.',
+ ]
+ args = 2015, 11, 27, 20, 59, 1, 123456
+ tinfo = PicklableFixedOffset(-300, 'cookie')
+ expected = self.theclass(*args, **{'tzinfo': tinfo})
+ for data in tests:
+ for loads in pickle_loads:
+ derived = loads(data, encoding='latin1')
+ self.assertEqual(derived, expected)
+ self.assertIsInstance(derived.tzinfo, PicklableFixedOffset)
+ self.assertEqual(derived.utcoffset(), timedelta(minutes=-300))
+ self.assertEqual(derived.tzname(), 'cookie')
+
def test_extreme_hashes(self):
# If an attempt is made to hash these via subtracting the offset
# then hashing a datetime object, OverflowError results. The
import contextlib
import faulthandler
+import fcntl
import os
import select
import signal
# sleep_time > signal_period
sleep_time = 0.2
- @classmethod
- def setUpClass(cls):
- cls.orig_handler = signal.signal(signal.SIGALRM, lambda *args: None)
- signal.setitimer(signal.ITIMER_REAL, cls.signal_delay,
- cls.signal_period)
+ def sighandler(self, signum, frame):
+ self.signals += 1
- # Issue #25277: Use faulthandler to try to debug a hang on FreeBSD
+ def setUp(self):
+ self.signals = 0
+ self.orig_handler = signal.signal(signal.SIGALRM, self.sighandler)
+ signal.setitimer(signal.ITIMER_REAL, self.signal_delay,
+ self.signal_period)
+
+ # Use faulthandler as watchdog to debug when a test hangs
+ # (timeout of 10 minutes)
if hasattr(faulthandler, 'dump_traceback_later'):
faulthandler.dump_traceback_later(10 * 60, exit=True,
file=sys.__stderr__)
- @classmethod
- def stop_alarm(cls):
+ @staticmethod
+ def stop_alarm():
signal.setitimer(signal.ITIMER_REAL, 0, 0)
- @classmethod
- def tearDownClass(cls):
- cls.stop_alarm()
- signal.signal(signal.SIGALRM, cls.orig_handler)
+ def tearDown(self):
+ self.stop_alarm()
+ signal.signal(signal.SIGALRM, self.orig_handler)
if hasattr(faulthandler, 'cancel_dump_traceback_later'):
faulthandler.cancel_dump_traceback_later()
fp = open(path, 'w')
fp.close()
+ @unittest.skipIf(sys.platform == "darwin",
+ "hangs under macOS; see bpo-25234, bpo-35363")
def test_open(self):
self._test_open("fp = open(path, 'r')\nfp.close()",
self.python_open)
- @unittest.skipIf(sys.platform == 'darwin', "hangs under OS X; see issue #25234")
def os_open(self, path):
fd = os.open(path, os.O_WRONLY)
os.close(fd)
- @unittest.skipIf(sys.platform == "darwin", "hangs under OS X; see issue #25234")
+ @unittest.skipIf(sys.platform == "darwin",
+ "hangs under macOS; see bpo-25234, bpo-35363")
def test_os_open(self):
self._test_open("fd = os.open(path, os.O_RDONLY)\nos.close(fd)",
self.os_open)
self.assertGreaterEqual(dt, self.sleep_time)
-def test_main():
- support.run_unittest(
- OSEINTRTest,
- SocketEINTRTest,
- TimeEINTRTest,
- SignalEINTRTest,
- SelectEINTRTest)
+class FNTLEINTRTest(EINTRBaseTest):
+ def _lock(self, lock_func, lock_name):
+ self.addCleanup(support.unlink, support.TESTFN)
+ code = '\n'.join((
+ "import fcntl, time",
+ "with open('%s', 'wb') as f:" % support.TESTFN,
+ " fcntl.%s(f, fcntl.LOCK_EX)" % lock_name,
+ " time.sleep(%s)" % self.sleep_time))
+ start_time = time.monotonic()
+ proc = self.subprocess(code)
+ with kill_on_error(proc):
+ with open(support.TESTFN, 'wb') as f:
+ while True: # synchronize the subprocess
+ dt = time.monotonic() - start_time
+ if dt > 60.0:
+ raise Exception("failed to sync child in %.1f sec" % dt)
+ try:
+ lock_func(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
+ lock_func(f, fcntl.LOCK_UN)
+ time.sleep(0.01)
+ except BlockingIOError:
+ break
+ # the child locked the file just a moment ago for 'sleep_time' seconds
+ # that means that the lock below will block for 'sleep_time' minus some
+ # potential context switch delay
+ lock_func(f, fcntl.LOCK_EX)
+ dt = time.monotonic() - start_time
+ self.assertGreaterEqual(dt, self.sleep_time)
+ self.stop_alarm()
+ proc.wait()
+
+ def test_lockf(self):
+ self._lock(fcntl.lockf, "lockf")
+
+ def test_flock(self):
+ self._lock(fcntl.flock, "flock")
if __name__ == "__main__":
- test_main()
+ unittest.main()
group.add_argument('--wait', action='store_true',
help='wait for user input, e.g., allow a debugger '
'to be attached')
- group.add_argument('--slaveargs', metavar='ARGS')
+ group.add_argument('--worker-args', metavar='ARGS')
group.add_argument('-S', '--start', metavar='START',
help='the name of the test at which to start.' +
more_details)
group.add_argument('--junit-xml', dest='xmlpath', metavar='FILENAME',
help='writes JUnit-style XML results to the specified '
'file')
-
+ group.add_argument('--tempdir', dest='tempdir', metavar='PATH',
+ help='override the working directory for the test run')
return parser
if ns.match_filename:
if ns.match_tests is None:
ns.match_tests = []
- filename = os.path.join(support.SAVEDCWD, ns.match_filename)
- with open(filename) as fp:
+ with open(ns.match_filename) as fp:
for line in fp:
ns.match_tests.append(line.strip())
from test.libregrtest.runtest import (
findtests, runtest, get_abs_module,
STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED,
- INTERRUPTED, CHILD_ERROR,
+ INTERRUPTED, CHILD_ERROR, TEST_DID_NOT_RUN,
PROGRESS_MIN_TIME, format_test_result)
from test.libregrtest.setup import setup_tests
from test.libregrtest.utils import removepy, count, format_duration, printlist
self.resource_denieds = []
self.environment_changed = []
self.rerun = []
+ self.run_no_tests = []
self.first_result = None
self.interrupted = False
elif ok == RESOURCE_DENIED:
self.skipped.append(test)
self.resource_denieds.append(test)
+ elif ok == TEST_DID_NOT_RUN:
+ self.run_no_tests.append(test)
elif ok != INTERRUPTED:
raise ValueError("invalid test result: %r" % ok)
print("%s:" % count(len(self.rerun), "re-run test"))
printlist(self.rerun)
+ if self.run_no_tests:
+ print()
+ print(count(len(self.run_no_tests), "test"), "run no tests:")
+ printlist(self.run_no_tests)
+
def run_tests_sequential(self):
if self.ns.trace:
import trace
result.append("FAILURE")
elif self.ns.fail_env_changed and self.environment_changed:
result.append("ENV CHANGED")
+ elif not any((self.good, self.bad, self.skipped, self.interrupted,
+ self.environment_changed)):
+ result.append("NO TEST RUN")
if self.interrupted:
result.append("INTERRUPTED")
def main(self, tests=None, **kwargs):
global TEMPDIR
+ self.ns = self.parse_args(kwargs)
- if sysconfig.is_python_build():
- try:
- os.mkdir(TEMPDIR)
- except FileExistsError:
- pass
+ if self.ns.tempdir:
+ TEMPDIR = self.ns.tempdir
+
+ os.makedirs(TEMPDIR, exist_ok=True)
# Define a writable temp dir that will be used as cwd while running
# the tests. The name of the dir includes the pid to allow parallel
self._main(tests, kwargs)
def _main(self, tests, kwargs):
- self.ns = self.parse_args(kwargs)
-
if self.ns.huntrleaks:
warmup, repetitions, _ = self.ns.huntrleaks
if warmup < 1 or repetitions < 1:
print(msg, file=sys.stderr, flush=True)
sys.exit(2)
- if self.ns.slaveargs is not None:
- from test.libregrtest.runtest_mp import run_tests_slave
- run_tests_slave(self.ns.slaveargs)
+ if self.ns.worker_args is not None:
+ from test.libregrtest.runtest_mp import run_tests_worker
+ run_tests_worker(self.ns.worker_args)
if self.ns.wait:
input("Press any key to continue...")
RESOURCE_DENIED = -3
INTERRUPTED = -4
CHILD_ERROR = -5 # error in a child process
+TEST_DID_NOT_RUN = -6 # error in a child process
_FORMAT_TEST_RESULT = {
PASSED: '%s passed',
RESOURCE_DENIED: '%s skipped (resource denied)',
INTERRUPTED: '%s interrupted',
CHILD_ERROR: '%s crashed',
+ TEST_DID_NOT_RUN: '%s run no tests',
}
# Minimum duration of a test to display its duration or to mention that
ENV_CHANGED test failed because it changed the execution environment
FAILED test failed
PASSED test passed
+ EMPTY_TEST_SUITE test ran no subtests.
If ns.xmlpath is not None, xml_data is a list containing each
generated testsuite element.
else:
print("test", test, "failed", file=sys.stderr, flush=True)
return FAILED, test_time
+ except support.TestDidNotRun:
+ return TEST_DID_NOT_RUN, test_time
except:
msg = traceback.format_exc()
if not ns.pgo:
def run_test_in_subprocess(testname, ns):
- """Run the given test in a subprocess with --slaveargs.
+ """Run the given test in a subprocess with --worker-args.
ns is the option Namespace parsed from command-line arguments. regrtest
- is invoked in a subprocess with the --slaveargs argument; when the
+ is invoked in a subprocess with the --worker-args argument; when the
subprocess exits, its return code, stdout and stderr are returned as a
3-tuple.
"""
from subprocess import Popen, PIPE
ns_dict = vars(ns)
- slaveargs = (ns_dict, testname)
- slaveargs = json.dumps(slaveargs)
+ worker_args = (ns_dict, testname)
+ worker_args = json.dumps(worker_args)
cmd = [sys.executable, *support.args_from_interpreter_flags(),
'-u', # Unbuffered stdout and stderr
'-m', 'test.regrtest',
- '--slaveargs', slaveargs]
+ '--worker-args', worker_args]
if ns.pgo:
cmd += ['--pgo']
return retcode, stdout, stderr
-def run_tests_slave(slaveargs):
- ns_dict, testname = json.loads(slaveargs)
+def run_tests_worker(worker_args):
+ ns_dict, testname = json.loads(worker_args)
ns = types.SimpleNamespace(**ns_dict)
setup_tests(ns)
info_add('platform.python_implementation',
platform.python_implementation())
info_add('platform.platform',
- platform.platform(aliased=True, terse=True))
+ platform.platform(aliased=True))
def collect_locale(info_add):
call_func(info_add, 'os.cpu_count', os, 'cpu_count')
call_func(info_add, 'os.loadavg', os, 'getloadavg')
- # Get environment variables: filter to list
- # to not leak sensitive information
- ENV_VARS = (
+ # Environment variables used by the stdlib and tests. Don't log the full
+ # environment: filter to list to not leak sensitive information.
+ #
+ # HTTP_PROXY is not logged because it can contain a password.
+ ENV_VARS = frozenset((
+ "APPDATA",
+ "AR",
+ "ARCHFLAGS",
+ "ARFLAGS",
+ "AUDIODEV",
"CC",
+ "CFLAGS",
+ "COLUMNS",
+ "COMPUTERNAME",
"COMSPEC",
+ "CPP",
+ "CPPFLAGS",
"DISPLAY",
+ "DISTUTILS_DEBUG",
"DISTUTILS_USE_SDK",
"DYLD_LIBRARY_PATH",
+ "ENSUREPIP_OPTIONS",
+ "HISTORY_FILE",
"HOME",
"HOMEDRIVE",
"HOMEPATH",
+ "IDLESTARTUP",
"LANG",
+ "LDFLAGS",
+ "LDSHARED",
"LD_LIBRARY_PATH",
+ "LINES",
"MACOSX_DEPLOYMENT_TARGET",
+ "MAILCAPS",
"MAKEFLAGS",
+ "MIXERDEV",
"MSSDK",
"PATH",
+ "PATHEXT",
+ "PIP_CONFIG_FILE",
+ "PLAT",
+ "POSIXLY_CORRECT",
+ "PY_SAX_PARSER",
+ "ProgramFiles",
+ "ProgramFiles(x86)",
+ "RUNNING_ON_VALGRIND",
"SDK_TOOLS_BIN",
+ "SERVER_SOFTWARE",
"SHELL",
+ "SOURCE_DATE_EPOCH",
+ "SYSTEMROOT",
"TEMP",
"TERM",
+ "TILE_LIBRARY",
+ "TIX_LIBRARY",
"TMP",
"TMPDIR",
+ "TRAVIS",
+ "TZ",
"USERPROFILE",
+ "VIRTUAL_ENV",
"WAYLAND_DISPLAY",
- )
+ "WINDIR",
+ "_PYTHON_HOST_PLATFORM",
+ "_PYTHON_PROJECT_BASE",
+ "_PYTHON_SYSCONFIGDATA_NAME",
+ "__PYVENV_LAUNCHER__",
+ ))
for name, value in os.environ.items():
uname = name.upper()
if (uname in ENV_VARS
'OPT',
'PY_CFLAGS',
'PY_CFLAGS_NODIST',
+ 'PY_CORE_LDFLAGS',
'PY_LDFLAGS',
+ 'PY_LDFLAGS_NODIST',
+ 'PY_STDMODULE_CFLAGS',
'Py_DEBUG',
'Py_ENABLE_SHARED',
'SHELL',
info_add('CC.version', text)
+def collect_gdbm(info_add):
+ try:
+ from _gdbm import _GDBM_VERSION
+ except ImportError:
+ return
+
+ info_add('gdbm.GDBM_VERSION', '.'.join(map(str, _GDBM_VERSION)))
+
+
+def collect_get_config(info_add):
+ # Dump global configuration variables, _PyCoreConfig
+ # and _PyMainInterpreterConfig
+ try:
+ from _testcapi import get_global_config, get_core_config, get_main_config
+ except ImportError:
+ return
+
+ for prefix, get_config_func in (
+ ('global_config', get_global_config),
+ ('core_config', get_core_config),
+ ('main_config', get_main_config),
+ ):
+ config = get_config_func()
+ for key in sorted(config):
+ info_add('%s[%s]' % (prefix, key), repr(config[key]))
+
+
def collect_info(info):
error = False
info_add = info.add
collect_testcapi,
collect_resource,
collect_cc,
+ collect_gdbm,
+ collect_get_config,
# Collecting from tests should be last as they have side effects.
collect_test_socket,
self.got_signals['SIGUSR1'] += 1
raise SIGUSR1Exception
- def wait_signal(self, child, signame, exc_class=None):
- try:
- if child is not None:
- # This wait should be interrupted by exc_class
- # (if set)
- child.wait()
-
- timeout = 10.0
- deadline = time.monotonic() + timeout
-
- while time.monotonic() < deadline:
- if self.got_signals[signame]:
- return
- signal.pause()
- except BaseException as exc:
- if exc_class is not None and isinstance(exc, exc_class):
- # got the expected exception
+ def wait_signal(self, child, signame):
+ if child is not None:
+ # This wait should be interrupted by exc_class
+ # (if set)
+ child.wait()
+
+ timeout = 10.0
+ deadline = time.monotonic() + timeout
+
+ while time.monotonic() < deadline:
+ if self.got_signals[signame]:
return
- raise
+ signal.pause()
self.fail('signal %s not received after %s seconds'
% (signame, timeout))
self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 0,
'SIGALRM': 0})
- with self.subprocess_send_signal(pid, "SIGUSR1") as child:
- self.wait_signal(child, 'SIGUSR1', SIGUSR1Exception)
+ with self.assertRaises(SIGUSR1Exception):
+ with self.subprocess_send_signal(pid, "SIGUSR1") as child:
+ self.wait_signal(child, 'SIGUSR1')
self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 1,
'SIGALRM': 0})
child.wait()
try:
- signal.alarm(1)
- self.wait_signal(None, 'SIGALRM', KeyboardInterrupt)
+ with self.assertRaises(KeyboardInterrupt):
+ signal.alarm(1)
+ self.wait_signal(None, 'SIGALRM')
self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 1,
'SIGALRM': 0})
finally:
# globals
"PIPE_MAX_SIZE", "verbose", "max_memuse", "use_resources", "failfast",
# exceptions
- "Error", "TestFailed", "ResourceDenied",
+ "Error", "TestFailed", "TestDidNotRun", "ResourceDenied",
# imports
"import_module", "import_fresh_module", "CleanImport",
# modules
class TestFailed(Error):
"""Test failed."""
+class TestDidNotRun(Error):
+ """Test did not run any subtests."""
+
class ResourceDenied(unittest.SkipTest):
"""Test skipped because it requested a disallowed resource.
'\u20AC',
):
try:
- os.fsdecode(os.fsencode(character))
+ # If Python is set up to use the legacy 'mbcs' in Windows,
+ # 'replace' error mode is used, and encode() returns b'?'
+ # for characters missing in the ANSI codepage
+ if os.fsdecode(os.fsencode(character)) != character:
+ raise UnicodeError
except UnicodeError:
pass
else:
def _run_suite(suite):
"""Run tests from a unittest.TestSuite-derived class."""
- runner = get_test_runner(sys.stdout, verbosity=verbose)
-
- # TODO: Remove this before merging (here for easy comparison with old impl)
- #runner = unittest.TextTestRunner(sys.stdout, verbosity=2, failfast=failfast)
+ runner = get_test_runner(sys.stdout,
+ verbosity=verbose,
+ capture_output=(junit_xml_list is not None))
result = runner.run(suite)
if junit_xml_list is not None:
junit_xml_list.append(result.get_xml_element())
+ if not result.testsRun:
+ raise TestDidNotRun
if not result.wasSuccessful():
if len(result.errors) == 1 and not result.failures:
err = result.errors[0][1]
e.set('time', f'{time.perf_counter() - self.__start_time:0.6f}')
if capture:
- stdout = self._stdout_buffer.getvalue().rstrip()
- ET.SubElement(e, 'system-out').text = stdout
- stderr = self._stderr_buffer.getvalue().rstrip()
- ET.SubElement(e, 'system-err').text = stderr
+ if self._stdout_buffer is not None:
+ stdout = self._stdout_buffer.getvalue().rstrip()
+ ET.SubElement(e, 'system-out').text = stdout
+ if self._stderr_buffer is not None:
+ stderr = self._stderr_buffer.getvalue().rstrip()
+ ET.SubElement(e, 'system-err').text = stderr
for k, v in args.items():
if not k or not v:
return e
class QuietRegressionTestRunner:
- def __init__(self, stream):
+ def __init__(self, stream, buffer=False):
self.result = RegressionTestResult(stream, None, 0)
+ self.result.buffer = buffer
def run(self, test):
test(self.result)
return self.result
-def get_test_runner_class(verbosity):
+def get_test_runner_class(verbosity, buffer=False):
if verbosity:
return functools.partial(unittest.TextTestRunner,
resultclass=RegressionTestResult,
- buffer=True,
+ buffer=buffer,
verbosity=verbosity)
- return QuietRegressionTestRunner
+ return functools.partial(QuietRegressionTestRunner, buffer=buffer)
-def get_test_runner(stream, verbosity):
- return get_test_runner_class(verbosity)(stream)
+def get_test_runner(stream, verbosity, capture_output=False):
+ return get_test_runner_class(verbosity, capture_output)(stream)
if __name__ == '__main__':
class TestTests(unittest.TestCase):
for cv in ('CFLAGS', 'LDFLAGS', 'CPPFLAGS',
'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'CC',
'CXX', 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
- 'PY_CORE_CFLAGS'):
+ 'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS'):
if cv in self.env:
self.env.unset(cv)
+++ /dev/null
------BEGIN PRIVATE KEY-----
-MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMLgD0kAKDb5cFyP
-jbwNfR5CtewdXC+kMXAWD8DLxiTTvhMW7qVnlwOm36mZlszHKvsRf05lT4pegiFM
-9z2j1OlaN+ci/X7NU22TNN6crYSiN77FjYJP464j876ndSxyD+rzys386T+1r1aZ
-aggEdkj1TsSsv1zWIYKlPIjlvhuxAgMBAAECgYA0aH+T2Vf3WOPv8KdkcJg6gCRe
-yJKXOWgWRcicx/CUzOEsTxmFIDPLxqAWA3k7v0B+3vjGw5Y9lycV/5XqXNoQI14j
-y09iNsumds13u5AKkGdTJnZhQ7UKdoVHfuP44ZdOv/rJ5/VD6F4zWywpe90pcbK+
-AWDVtusgGQBSieEl1QJBAOyVrUG5l2yoUBtd2zr/kiGm/DYyXlIthQO/A3/LngDW
-5/ydGxVsT7lAVOgCsoT+0L4efTh90PjzW8LPQrPBWVMCQQDS3h/FtYYd5lfz+FNL
-9CEe1F1w9l8P749uNUD0g317zv1tatIqVCsQWHfVHNdVvfQ+vSFw38OORO00Xqs9
-1GJrAkBkoXXEkxCZoy4PteheO/8IWWLGGr6L7di6MzFl1lIqwT6D8L9oaV2vynFT
-DnKop0pa09Unhjyw57KMNmSE2SUJAkEArloTEzpgRmCq4IK2/NpCeGdHS5uqRlbh
-1VIa/xGps7EWQl5Mn8swQDel/YP3WGHTjfx7pgSegQfkyaRtGpZ9OQJAa9Vumj8m
-JAAtI0Bnga8hgQx7BhTQY4CadDxyiRGOGYhwUzYVCqkb2sbVRH9HnwUaJT7cWBY3
-RnJdHOMXWem7/w==
------END PRIVATE KEY-----
-Certificate:
- Data:
- Version: 1 (0x0)
- Serial Number: 12723342612721443281 (0xb09264b1f2da21d1)
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
- Validity
- Not Before: Jan 4 19:47:07 2013 GMT
- Not After : Nov 13 19:47:07 2022 GMT
- Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=localhost
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
- Modulus:
- 00:c2:e0:0f:49:00:28:36:f9:70:5c:8f:8d:bc:0d:
- 7d:1e:42:b5:ec:1d:5c:2f:a4:31:70:16:0f:c0:cb:
- c6:24:d3:be:13:16:ee:a5:67:97:03:a6:df:a9:99:
- 96:cc:c7:2a:fb:11:7f:4e:65:4f:8a:5e:82:21:4c:
- f7:3d:a3:d4:e9:5a:37:e7:22:fd:7e:cd:53:6d:93:
- 34:de:9c:ad:84:a2:37:be:c5:8d:82:4f:e3:ae:23:
- f3:be:a7:75:2c:72:0f:ea:f3:ca:cd:fc:e9:3f:b5:
- af:56:99:6a:08:04:76:48:f5:4e:c4:ac:bf:5c:d6:
- 21:82:a5:3c:88:e5:be:1b:b1
- Exponent: 65537 (0x10001)
- Signature Algorithm: sha1WithRSAEncryption
- 2f:42:5f:a3:09:2c:fa:51:88:c7:37:7f:ea:0e:63:f0:a2:9a:
- e5:5a:e2:c8:20:f0:3f:60:bc:c8:0f:b6:c6:76:ce:db:83:93:
- f5:a3:33:67:01:8e:04:cd:00:9a:73:fd:f3:35:86:fa:d7:13:
- e2:46:c6:9d:c0:29:53:d4:a9:90:b8:77:4b:e6:83:76:e4:92:
- d6:9c:50:cf:43:d0:c6:01:77:61:9a:de:9b:70:f7:72:cd:59:
- 00:31:69:d9:b4:ca:06:9c:6d:c3:c7:80:8c:68:e6:b5:a2:f8:
- ef:1d:bb:16:9f:77:77:ef:87:62:22:9b:4d:69:a4:3a:1a:f1:
- 21:5e:8c:32:ac:92:fd:15:6b:18:c2:7f:15:0d:98:30:ca:75:
- 8f:1a:71:df:da:1d:b2:ef:9a:e8:2d:2e:02:fd:4a:3c:aa:96:
- 0b:06:5d:35:b3:3d:24:87:4b:e0:b0:58:60:2f:45:ac:2e:48:
- 8a:b0:99:10:65:27:ff:cc:b1:d8:fd:bd:26:6b:b9:0c:05:2a:
- f4:45:63:35:51:07:ed:83:85:fe:6f:69:cb:bb:40:a8:ae:b6:
- 3b:56:4a:2d:a4:ed:6d:11:2c:4d:ed:17:24:fd:47:bc:d3:41:
- a2:d3:06:fe:0c:90:d8:d8:94:26:c4:ff:cc:a1:d8:42:77:eb:
- fc:a9:94:71
------BEGIN CERTIFICATE-----
-MIICpDCCAYwCCQCwkmSx8toh0TANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJY
-WTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNV
-BAMMDW91ci1jYS1zZXJ2ZXIwHhcNMTMwMTA0MTk0NzA3WhcNMjIxMTEzMTk0NzA3
-WjBfMQswCQYDVQQGEwJYWTEXMBUGA1UEBxMOQ2FzdGxlIEFudGhyYXgxIzAhBgNV
-BAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMRIwEAYDVQQDEwlsb2NhbGhv
-c3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMLgD0kAKDb5cFyPjbwNfR5C
-tewdXC+kMXAWD8DLxiTTvhMW7qVnlwOm36mZlszHKvsRf05lT4pegiFM9z2j1Ola
-N+ci/X7NU22TNN6crYSiN77FjYJP464j876ndSxyD+rzys386T+1r1aZaggEdkj1
-TsSsv1zWIYKlPIjlvhuxAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAC9CX6MJLPpR
-iMc3f+oOY/CimuVa4sgg8D9gvMgPtsZ2ztuDk/WjM2cBjgTNAJpz/fM1hvrXE+JG
-xp3AKVPUqZC4d0vmg3bkktacUM9D0MYBd2Ga3ptw93LNWQAxadm0ygacbcPHgIxo
-5rWi+O8duxafd3fvh2Iim01ppDoa8SFejDKskv0VaxjCfxUNmDDKdY8acd/aHbLv
-mugtLgL9SjyqlgsGXTWzPSSHS+CwWGAvRawuSIqwmRBlJ//Msdj9vSZruQwFKvRF
-YzVRB+2Dhf5vacu7QKiutjtWSi2k7W0RLE3tFyT9R7zTQaLTBv4MkNjYlCbE/8yh
-2EJ36/yplHE=
------END CERTIFICATE-----
+++ /dev/null
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 12723342612721443280 (0xb09264b1f2da21d0)
- Signature Algorithm: sha1WithRSAEncryption
- Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server
- Validity
- Not Before: Jan 4 19:47:07 2013 GMT
- Not After : Jan 2 19:47:07 2023 GMT
- Subject: C=XY, O=Python Software Foundation CA, CN=our-ca-server
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:e7:de:e9:e3:0c:9f:00:b6:a1:fd:2b:5b:96:d2:
- 6f:cc:e0:be:86:b9:20:5e:ec:03:7a:55:ab:ea:a4:
- e9:f9:49:85:d2:66:d5:ed:c7:7a:ea:56:8e:2d:8f:
- e7:42:e2:62:28:a9:9f:d6:1b:8e:eb:b5:b4:9c:9f:
- 14:ab:df:e6:94:8b:76:1d:3e:6d:24:61:ed:0c:bf:
- 00:8a:61:0c:df:5c:c8:36:73:16:00:cd:47:ba:6d:
- a4:a4:74:88:83:23:0a:19:fc:09:a7:3c:4a:4b:d3:
- e7:1d:2d:e4:ea:4c:54:21:f3:26:db:89:37:18:d4:
- 02:bb:40:32:5f:a4:ff:2d:1c:f7:d4:bb:ec:8e:cf:
- 5c:82:ac:e6:7c:08:6c:48:85:61:07:7f:25:e0:5c:
- e0:bc:34:5f:e0:b9:04:47:75:c8:47:0b:8d:bc:d6:
- c8:68:5f:33:83:62:d2:20:44:35:b1:ad:81:1a:8a:
- cd:bc:35:b0:5c:8b:47:d6:18:e9:9c:18:97:cc:01:
- 3c:29:cc:e8:1e:e4:e4:c1:b8:de:e7:c2:11:18:87:
- 5a:93:34:d8:a6:25:f7:14:71:eb:e4:21:a2:d2:0f:
- 2e:2e:d4:62:00:35:d3:d6:ef:5c:60:4b:4c:a9:14:
- e2:dd:15:58:46:37:33:26:b7:e7:2e:5d:ed:42:e4:
- c5:4d
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Subject Key Identifier:
- BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B
- X509v3 Authority Key Identifier:
- keyid:BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B
-
- X509v3 Basic Constraints:
- CA:TRUE
- Signature Algorithm: sha1WithRSAEncryption
- 7d:0a:f5:cb:8d:d3:5d:bd:99:8e:f8:2b:0f:ba:eb:c2:d9:a6:
- 27:4f:2e:7b:2f:0e:64:d8:1c:35:50:4e:ee:fc:90:b9:8d:6d:
- a8:c5:c6:06:b0:af:f3:2d:bf:3b:b8:42:07:dd:18:7d:6d:95:
- 54:57:85:18:60:47:2f:eb:78:1b:f9:e8:17:fd:5a:0d:87:17:
- 28:ac:4c:6a:e6:bc:29:f4:f4:55:70:29:42:de:85:ea:ab:6c:
- 23:06:64:30:75:02:8e:53:bc:5e:01:33:37:cc:1e:cd:b8:a4:
- fd:ca:e4:5f:65:3b:83:1c:86:f1:55:02:a0:3a:8f:db:91:b7:
- 40:14:b4:e7:8d:d2:ee:73:ba:e3:e5:34:2d:bc:94:6f:4e:24:
- 06:f7:5f:8b:0e:a7:8e:6b:de:5e:75:f4:32:9a:50:b1:44:33:
- 9a:d0:05:e2:78:82:ff:db:da:8a:63:eb:a9:dd:d1:bf:a0:61:
- ad:e3:9e:8a:24:5d:62:0e:e7:4c:91:7f:ef:df:34:36:3b:2f:
- 5d:f5:84:b2:2f:c4:6d:93:96:1a:6f:30:28:f1:da:12:9a:64:
- b4:40:33:1d:bd:de:2b:53:a8:ea:be:d6:bc:4e:96:f5:44:fb:
- 32:18:ae:d5:1f:f6:69:af:b6:4e:7b:1d:58:ec:3b:a9:53:a3:
- 5e:58:c8:9e
------BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIJALCSZLHy2iHQMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV
-BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
-MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xMzAxMDQxOTQ3MDdaFw0yMzAxMDIx
-OTQ3MDdaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg
-Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAOfe6eMMnwC2of0rW5bSb8zgvoa5IF7sA3pV
-q+qk6flJhdJm1e3HeupWji2P50LiYiipn9Ybjuu1tJyfFKvf5pSLdh0+bSRh7Qy/
-AIphDN9cyDZzFgDNR7ptpKR0iIMjChn8Cac8SkvT5x0t5OpMVCHzJtuJNxjUArtA
-Ml+k/y0c99S77I7PXIKs5nwIbEiFYQd/JeBc4Lw0X+C5BEd1yEcLjbzWyGhfM4Ni
-0iBENbGtgRqKzbw1sFyLR9YY6ZwYl8wBPCnM6B7k5MG43ufCERiHWpM02KYl9xRx
-6+QhotIPLi7UYgA109bvXGBLTKkU4t0VWEY3Mya35y5d7ULkxU0CAwEAAaNQME4w
-HQYDVR0OBBYEFLzdYtl22hvSVGvP4GabHh57VgwLMB8GA1UdIwQYMBaAFLzdYtl2
-2hvSVGvP4GabHh57VgwLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
-AH0K9cuN0129mY74Kw+668LZpidPLnsvDmTYHDVQTu78kLmNbajFxgawr/Mtvzu4
-QgfdGH1tlVRXhRhgRy/reBv56Bf9Wg2HFyisTGrmvCn09FVwKULeheqrbCMGZDB1
-Ao5TvF4BMzfMHs24pP3K5F9lO4MchvFVAqA6j9uRt0AUtOeN0u5zuuPlNC28lG9O
-JAb3X4sOp45r3l519DKaULFEM5rQBeJ4gv/b2opj66nd0b+gYa3jnookXWIO50yR
-f+/fNDY7L131hLIvxG2TlhpvMCjx2hKaZLRAMx293itTqOq+1rxOlvVE+zIYrtUf
-9mmvtk57HVjsO6lTo15YyJ4=
------END CERTIFICATE-----
+++ /dev/null
------BEGIN CERTIFICATE-----
-MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV
-BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u
-IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw
-MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH
-Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k
-YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
-gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7
-6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt
-pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw
-FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd
-BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G
-lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1
-CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX
------END CERTIFICATE-----
+++ /dev/null
------BEGIN PRIVATE KEY-----
-MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm
-LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0
-ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP
-USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt
-CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq
-SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK
-UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y
-BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ
-ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5
-oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik
-eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F
-0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS
-x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/
-SPIXQuT8RMPDVNQ=
------END PRIVATE KEY-----
loop.set_debug(debug)
if debug:
msg = ("Non-thread-safe operation invoked on an event loop other "
- "than the current one")
+ "than the current one")
with self.assertRaisesRegex(RuntimeError, msg):
loop.call_soon(cb)
with self.assertRaisesRegex(RuntimeError, msg):
self.run_loop(self.loop.sock_sendfile(sock, self.file, -1))
+class TestSelectorUtils(test_utils.TestCase):
+ def check_set_nodelay(self, sock):
+ opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
+ self.assertFalse(opt)
+
+ base_events._set_nodelay(sock)
+
+ opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
+ self.assertTrue(opt)
+
+ @unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'),
+ 'need socket.TCP_NODELAY')
+ def test_set_nodelay(self):
+ sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
+ proto=socket.IPPROTO_TCP)
+ with sock:
+ self.check_set_nodelay(sock)
+
+ sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
+ proto=socket.IPPROTO_TCP)
+ with sock:
+ sock.setblocking(False)
+ self.check_set_nodelay(sock)
+
+
+
if __name__ == '__main__':
unittest.main()
from asyncio.selector_events import _SelectorTransport
from asyncio.selector_events import _SelectorSocketTransport
from asyncio.selector_events import _SelectorDatagramTransport
-from asyncio.selector_events import _set_nodelay
from test.test_asyncio import utils as test_utils
exc_info=(ConnectionRefusedError, MOCK_ANY, MOCK_ANY))
-class TestSelectorUtils(test_utils.TestCase):
- def check_set_nodelay(self, sock):
- opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
- self.assertFalse(opt)
-
- _set_nodelay(sock)
-
- opt = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY)
- self.assertTrue(opt)
-
- @unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'),
- 'need socket.TCP_NODELAY')
- def test_set_nodelay(self):
- sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
- proto=socket.IPPROTO_TCP)
- with sock:
- self.check_set_nodelay(sock)
-
- sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
- proto=socket.IPPROTO_TCP)
- with sock:
- sock.setblocking(False)
- self.check_set_nodelay(sock)
-
-
if __name__ == '__main__':
unittest.main()
import logging
import socket
+import sys
import unittest
from unittest import mock
try:
server_context = test_utils.simple_server_sslcontext()
client_context = test_utils.simple_client_sslcontext()
+ if sys.platform.startswith('freebsd'):
+ # bpo-35031: Some FreeBSD buildbots fail to run this test
+ # as the eof was not being received by the server if the payload
+ # size is not big enough. This behaviour only appears if the
+ # client is using TLS1.3.
+ client_context.options |= ssl.OP_NO_TLSv1_3
def client(sock, addr):
sock.settimeout(self.TIMEOUT)
fullname = os.path.join(support.TEST_HOME_DIR, filename)
if os.path.isfile(fullname):
return fullname
- fullname = os.path.join(os.path.dirname(__file__), filename)
+ fullname = os.path.join(os.path.dirname(__file__), '..', filename)
if os.path.isfile(fullname):
return fullname
raise FileNotFoundError(filename)
# contains the ssl key and certificate files) differs
# between the stdlib and stand-alone asyncio.
# Prefer our own if we can find it.
- here = os.path.join(os.path.dirname(__file__), '..', 'tests')
- if not os.path.isdir(here):
- here = os.path.join(os.path.dirname(os.__file__),
- 'test', 'test_asyncio')
- keyfile = os.path.join(here, 'ssl_key.pem')
- certfile = os.path.join(here, 'ssl_cert.pem')
context = ssl.SSLContext()
- context.load_cert_chain(certfile, keyfile)
+ context.load_cert_chain(ONLYCERT, ONLYKEY)
ssock = context.wrap_socket(request, server_side=True)
try:
def break_in_func(funcname, fname=__file__, temporary=False, cond=None):
return 'break', (fname, None, temporary, cond, funcname)
-TEST_MODULE = 'test_module'
+TEST_MODULE = 'test_module_for_bdb'
TEST_MODULE_FNAME = TEST_MODULE + '.py'
def tfunc_import():
- import test_module
- test_module.main()
+ import test_module_for_bdb
+ test_module_for_bdb.main()
def tfunc_main():
lno = 2
('return', 3, 'main'), ('step', ),
('return', 1, '<module>'), ('quit', ),
]
- import test_module
+ import test_module_for_bdb
with TracerRun(self) as tracer:
- tracer.runeval('test_module.main()', globals(), locals())
+ tracer.runeval('test_module_for_bdb.main()', globals(), locals())
class IssuesTestCase(BaseTestCase):
"""Test fixed bdb issues."""
# Check that the tracer does step into the caller frame when the
# trace function is not set in that frame.
code_1 = """
- from test_module_2 import func
+ from test_module_for_bdb_2 import func
def main():
func()
lno = 5
"""
modules = {
TEST_MODULE: code_1,
- 'test_module_2': code_2,
+ 'test_module_for_bdb_2': code_2,
}
with create_modules(modules):
self.expect_set = [
('line', 2, 'tfunc_import'),
- break_in_func('func', 'test_module_2.py'),
+ break_in_func('func', 'test_module_for_bdb_2.py'),
('None', 2, 'tfunc_import'), ('continue', ),
('line', 3, 'func', ({1:1}, [])), ('step', ),
('return', 3, 'func'), ('step', ),
@unittest.skipIf(sys.flags.ignore_environment, '-E was given')
def test_envar_unimportable(self):
for envar in (
- '.', '..', '.foo', 'foo.', '.int', 'int.'
+ '.', '..', '.foo', 'foo.', '.int', 'int.',
'nosuchbuiltin',
'nosuchmodule.nosuchcallable',
):
self.assertRaises(IndexError, lambda: b[-sys.maxsize-2])
self.assertRaises(IndexError, lambda: b[-10**100])
+ def test_from_iterable(self):
+ b = self.type2test(range(256))
+ self.assertEqual(len(b), 256)
+ self.assertEqual(list(b), list(range(256)))
+
+ # Non-sequence iterable.
+ b = self.type2test({42})
+ self.assertEqual(b, b"*")
+ b = self.type2test({43, 45})
+ self.assertIn(tuple(b), {(43, 45), (45, 43)})
+
+ # Iterator that has a __length_hint__.
+ b = self.type2test(iter(range(256)))
+ self.assertEqual(len(b), 256)
+ self.assertEqual(list(b), list(range(256)))
+
+ # Iterator that doesn't have a __length_hint__.
+ b = self.type2test(i for i in range(256) if i % 2)
+ self.assertEqual(len(b), 128)
+ self.assertEqual(list(b), list(range(256))[1::2])
+
+ # Sequence without __iter__.
+ class S:
+ def __getitem__(self, i):
+ return (1, 2, 3)[i]
+ b = self.type2test(S())
+ self.assertEqual(b, b"\x01\x02\x03")
+
+ def test_from_tuple(self):
+ # There is a special case for tuples.
+ b = self.type2test(tuple(range(256)))
+ self.assertEqual(len(b), 256)
+ self.assertEqual(list(b), list(range(256)))
+ b = self.type2test((1, 2, 3))
+ self.assertEqual(b, b"\x01\x02\x03")
+
def test_from_list(self):
- ints = list(range(256))
- b = self.type2test(i for i in ints)
+ # There is a special case for lists.
+ b = self.type2test(list(range(256)))
self.assertEqual(len(b), 256)
- self.assertEqual(list(b), ints)
+ self.assertEqual(list(b), list(range(256)))
+ b = self.type2test([1, 2, 3])
+ self.assertEqual(b, b"\x01\x02\x03")
+
+ def test_from_mutating_list(self):
+ # Issue #34973: Crash in bytes constructor with mutating list.
+ class X:
+ def __index__(self):
+ a.clear()
+ return 42
+ a = [X(), X()]
+ self.assertEqual(bytes(a), b'*')
+
+ class Y:
+ def __index__(self):
+ if len(a) < 1000:
+ a.append(self)
+ return 42
+ a = [Y()]
+ self.assertEqual(bytes(a), b'*' * 1000) # should not crash
def test_from_index(self):
b = self.type2test([Indexable(), Indexable(1), Indexable(254),
def test_from_buffer(self):
a = self.type2test(array.array('B', [1, 2, 3]))
self.assertEqual(a, b"\x01\x02\x03")
+ a = self.type2test(b"\x01\x02\x03")
+ self.assertEqual(a, b"\x01\x02\x03")
- # http://bugs.python.org/issue29159
- # Fallback when __index__ raises exception other than OverflowError
+ # Issues #29159 and #34974.
+ # Fallback when __index__ raises a TypeError
class B(bytes):
def __index__(self):
raise TypeError
except (OverflowError, MemoryError):
pass
+ def test_constructor_exceptions(self):
+ # Issue #34974: bytes and bytearray constructors replace unexpected
+ # exceptions.
+ class BadInt:
+ def __index__(self):
+ 1/0
+ self.assertRaises(ZeroDivisionError, self.type2test, BadInt())
+ self.assertRaises(ZeroDivisionError, self.type2test, [BadInt()])
+
+ class BadIterable:
+ def __iter__(self):
+ 1/0
+ self.assertRaises(ZeroDivisionError, self.type2test, BadIterable())
+
def test_compare(self):
b1 = self.type2test([1, 2, 3])
b2 = self.type2test([1, 2, 3])
# Tests the attempted automatic coercion of the C locale to a UTF-8 locale
-import unittest
import locale
import os
+import shutil
+import subprocess
import sys
import sysconfig
-import shutil
+import unittest
from collections import namedtuple
import test.support
# Set our expectation for the default locale used when none is specified
EXPECT_COERCION_IN_DEFAULT_LOCALE = True
+TARGET_LOCALES = ["C.UTF-8", "C.utf8", "UTF-8"]
+
# Apply some platform dependent overrides
if sys.platform.startswith("linux"):
if test.support.is_android:
expected_warnings=[LEGACY_LOCALE_WARNING],
coercion_expected=False)
+ def test_PYTHONCOERCECLOCALE_set_to_one(self):
+ # skip the test if the LC_CTYPE locale is C or coerced
+ old_loc = locale.setlocale(locale.LC_CTYPE, None)
+ self.addCleanup(locale.setlocale, locale.LC_CTYPE, old_loc)
+ loc = locale.setlocale(locale.LC_CTYPE, "")
+ if loc == "C":
+ self.skipTest("test requires LC_CTYPE locale different than C")
+ if loc in TARGET_LOCALES :
+ self.skipTest("coerced LC_CTYPE locale: %s" % loc)
+
+ # bpo-35336: PYTHONCOERCECLOCALE=1 must not coerce the LC_CTYPE locale
+ # if it's not equal to "C"
+ code = 'import locale; print(locale.setlocale(locale.LC_CTYPE, None))'
+ env = dict(os.environ, PYTHONCOERCECLOCALE='1')
+ cmd = subprocess.run([sys.executable, '-c', code],
+ stdout=subprocess.PIPE,
+ env=env,
+ text=True)
+ self.assertEqual(cmd.stdout.rstrip(), loc)
+
+
def test_main():
test.support.run_unittest(
LocaleConfigurationTests,
r" The block was made by call #[0-9]+ to debug malloc/realloc.\n"
r" Data at p: cb cb cb .*\n"
r"\n"
+ r"Enable tracemalloc to get the memory block allocation traceback\n"
+ r"\n"
r"Fatal Python error: bad trailing pad byte")
regex = regex.format(ptr=self.PTR_REGEX)
regex = re.compile(regex, flags=re.DOTALL)
r" The block was made by call #[0-9]+ to debug malloc/realloc.\n"
r" Data at p: cb cb cb .*\n"
r"\n"
+ r"Enable tracemalloc to get the memory block allocation traceback\n"
+ r"\n"
r"Fatal Python error: bad ID: Allocated using API 'm', verified using API 'r'\n")
regex = regex.format(ptr=self.PTR_REGEX)
self.assertRegex(out, regex)
v = gen_result(data, environ)
self.assertEqual(self._qs_result, v)
+ def test_max_num_fields(self):
+ # For application/x-www-form-urlencoded
+ data = '&'.join(['a=a']*11)
+ environ = {
+ 'CONTENT_LENGTH': str(len(data)),
+ 'CONTENT_TYPE': 'application/x-www-form-urlencoded',
+ 'REQUEST_METHOD': 'POST',
+ }
+
+ with self.assertRaises(ValueError):
+ cgi.FieldStorage(
+ fp=BytesIO(data.encode()),
+ environ=environ,
+ max_num_fields=10,
+ )
+
+ # For multipart/form-data
+ data = """---123
+Content-Disposition: form-data; name="a"
+
+3
+---123
+Content-Type: application/x-www-form-urlencoded
+
+a=4
+---123
+Content-Type: application/x-www-form-urlencoded
+
+a=5
+---123--
+"""
+ environ = {
+ 'CONTENT_LENGTH': str(len(data)),
+ 'CONTENT_TYPE': 'multipart/form-data; boundary=-123',
+ 'QUERY_STRING': 'a=1&a=2',
+ 'REQUEST_METHOD': 'POST',
+ }
+
+ # 2 GET entities
+ # 1 top level POST entities
+ # 1 entity within the second POST entity
+ # 1 entity within the third POST entity
+ with self.assertRaises(ValueError):
+ cgi.FieldStorage(
+ fp=BytesIO(data.encode()),
+ environ=environ,
+ max_num_fields=4,
+ )
+ cgi.FieldStorage(
+ fp=BytesIO(data.encode()),
+ environ=environ,
+ max_num_fields=5,
+ )
+
def testQSAndFormData(self):
data = """---123
Content-Disposition: form-data; name="key2"
traceback_lines = stderr.decode().splitlines()
self.assertIn("No module named script_pkg", traceback_lines[-1])
- @unittest.skipIf(sys.platform == 'darwin' and sys._framework,
- "test not valid for macOS framework builds")
def test_nonexisting_script(self):
# bpo-34783: "./python script.py" must not crash
# if the script file doesn't exist.
# is not the actual Python executable file name.
script = 'nonexistingscript.py'
self.assertFalse(os.path.exists(script))
- # Only test the base name, since the error message can use
- # a relative path, whereas sys.executable can be an asolution path.
- program = os.path.basename(sys.executable)
proc = spawn_python(script, text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out, err = proc.communicate()
- # "./python" must be in the error message:
- # "./python: can't open file (...)"
- self.assertIn(program, err)
+ self.assertIn(": can't open file ", err)
self.assertNotEqual(proc.returncode, 0)
codec = codecs.lookup('cp123')
self.assertEqual(codec.name, 'mbcs')
+ @support.bigmemtest(size=2**31, memuse=7, dry_run=False)
+ def test_large_input(self):
+ # Test input longer than INT_MAX.
+ # Input should contain undecodable bytes before and after
+ # the INT_MAX limit.
+ encoded = (b'01234567' * (2**28-1) +
+ b'\x85\x86\xea\xeb\xec\xef\xfc\xfd\xfe\xff')
+ self.assertEqual(len(encoded), 2**31+2)
+ decoded = codecs.code_page_decode(932, encoded, 'surrogateescape', True)
+ self.assertEqual(decoded[1], len(encoded))
+ del encoded
+ self.assertEqual(len(decoded[0]), decoded[1])
+ self.assertEqual(decoded[0][:10], '0123456701')
+ self.assertEqual(decoded[0][-20:],
+ '6701234567'
+ '\udc85\udc86\udcea\udceb\udcec'
+ '\udcef\udcfc\udcfd\udcfe\udcff')
+
class ASCIITest(unittest.TestCase):
def test_encode(self):
+import dis
import math
import os
import unittest
'from sys import stdin)',
'from sys import stdin, stdout,\nstderr',
'from sys import stdin si',
- 'from sys import stdin,'
+ 'from sys import stdin,',
'from sys import (*)',
'from sys import (stdin,, stdout, stderr)',
'from sys import (stdin, stdout),',
self.check_constant(f1, frozenset({0}))
self.assertTrue(f1(0))
+ # This is a regression test for a CPython specific peephole optimizer
+ # implementation bug present in a few releases. It's assertion verifies
+ # that peephole optimization was actually done though that isn't an
+ # indication of the bugs presence or not (crashing is).
+ @support.cpython_only
+ def test_peephole_opt_unreachable_code_array_access_in_bounds(self):
+ """Regression test for issue35193 when run under clang msan."""
+ def unused_code_at_end():
+ return 3
+ raise RuntimeError("unreachable")
+ # The above function definition will trigger the out of bounds
+ # bug in the peephole optimizer as it scans opcodes past the
+ # RETURN_VALUE opcode. This does not always crash an interpreter.
+ # When you build with the clang memory sanitizer it reliably aborts.
+ self.assertEqual(
+ 'RETURN_VALUE',
+ list(dis.get_instructions(unused_code_at_end))[-1].opname)
+
def test_dont_merge_constants(self):
# Issue #25843: compile() must not merge constants which are equal
# but have a different type.
from test import support
from test.support import script_helper
-class CompileallTests(unittest.TestCase):
+from .test_py_compile import without_source_date_epoch
+from .test_py_compile import SourceDateEpochTestMeta
+
+
+class CompileallTestsBase:
def setUp(self):
self.directory = tempfile.mkdtemp()
with open(self.bad_source_path, 'w') as file:
file.write('x (\n')
- def data(self):
+ def timestamp_metadata(self):
with open(self.bc_path, 'rb') as file:
data = file.read(12)
mtime = int(os.stat(self.source_path).st_mtime)
def recreation_check(self, metadata):
"""Check that compileall recreates bytecode when the new metadata is
used."""
+ if os.environ.get('SOURCE_DATE_EPOCH'):
+ raise unittest.SkipTest('SOURCE_DATE_EPOCH is set')
py_compile.compile(self.source_path)
- self.assertEqual(*self.data())
+ self.assertEqual(*self.timestamp_metadata())
with open(self.bc_path, 'rb') as file:
bc = file.read()[len(metadata):]
with open(self.bc_path, 'wb') as file:
file.write(metadata)
file.write(bc)
- self.assertNotEqual(*self.data())
+ self.assertNotEqual(*self.timestamp_metadata())
compileall.compile_dir(self.directory, force=False, quiet=True)
- self.assertTrue(*self.data())
+ self.assertTrue(*self.timestamp_metadata())
def test_mtime(self):
# Test a change in mtime leads to a new .pyc.
self.assertRegex(line, r'Listing ([^WindowsPath|PosixPath].*)')
self.assertTrue(os.path.isfile(self.bc_path))
- @mock.patch('compileall.ProcessPoolExecutor')
+ @mock.patch('concurrent.futures.ProcessPoolExecutor')
def test_compile_pool_called(self, pool_mock):
compileall.compile_dir(self.directory, quiet=True, workers=5)
self.assertTrue(pool_mock.called)
"workers must be greater or equal to 0"):
compileall.compile_dir(self.directory, workers=-1)
- @mock.patch('compileall.ProcessPoolExecutor')
+ @mock.patch('concurrent.futures.ProcessPoolExecutor')
def test_compile_workers_cpu_count(self, pool_mock):
compileall.compile_dir(self.directory, quiet=True, workers=0)
self.assertEqual(pool_mock.call_args[1]['max_workers'], None)
- @mock.patch('compileall.ProcessPoolExecutor')
+ @mock.patch('concurrent.futures.ProcessPoolExecutor')
@mock.patch('compileall.compile_file')
def test_compile_one_worker(self, compile_file_mock, pool_mock):
compileall.compile_dir(self.directory, quiet=True)
self.assertFalse(pool_mock.called)
self.assertTrue(compile_file_mock.called)
- @mock.patch('compileall.ProcessPoolExecutor', new=None)
+ @mock.patch('concurrent.futures.ProcessPoolExecutor', new=None)
@mock.patch('compileall.compile_file')
def test_compile_missing_multiprocessing(self, compile_file_mock):
compileall.compile_dir(self.directory, quiet=True, workers=5)
self.assertTrue(compile_file_mock.called)
+
+class CompileallTestsWithSourceEpoch(CompileallTestsBase,
+ unittest.TestCase,
+ metaclass=SourceDateEpochTestMeta,
+ source_date_epoch=True):
+ pass
+
+
+class CompileallTestsWithoutSourceEpoch(CompileallTestsBase,
+ unittest.TestCase,
+ metaclass=SourceDateEpochTestMeta,
+ source_date_epoch=False):
+ pass
+
+
class EncodingTest(unittest.TestCase):
"""Issue 6716: compileall should escape source code when printing errors
to stdout."""
sys.stdout = orig_stdout
-class CommandLineTests(unittest.TestCase):
+class CommandLineTestsBase:
"""Test compileall's CLI."""
@classmethod
self.assertNotCompiled(self.initfn)
self.assertNotCompiled(self.barfn)
+ @without_source_date_epoch # timestamp invalidation test
def test_no_args_respects_force_flag(self):
self._skip_if_sys_path_not_writable()
bazfn = script_helper.make_script(self.directory, 'baz', '')
self.assertTrue(os.path.exists(self.pkgdir_cachedir))
self.assertFalse(os.path.exists(cachecachedir))
+ @without_source_date_epoch # timestamp invalidation test
def test_force(self):
self.assertRunOK('-q', self.pkgdir)
pycpath = importlib.util.cache_from_source(self.barfn)
self.assertEqual(compile_dir.call_args[-1]['workers'], None)
+class CommmandLineTestsWithSourceEpoch(CommandLineTestsBase,
+ unittest.TestCase,
+ metaclass=SourceDateEpochTestMeta,
+ source_date_epoch=True):
+ pass
+
+
+class CommmandLineTestsNoSourceEpoch(CommandLineTestsBase,
+ unittest.TestCase,
+ metaclass=SourceDateEpochTestMeta,
+ source_date_epoch=False):
+ pass
+
+
+
if __name__ == "__main__":
unittest.main()
import sys
from test.support import run_unittest, TESTFN, unlink
+import unittest
# rip off all interesting stuff from test_profile
import cProfile
assert_python_ok('-m', 'cProfile', '-m', 'timeit', '-n', '1')
+class TestCommandLine(unittest.TestCase):
+ def test_sort(self):
+ rc, out, err = assert_python_failure('-m', 'cProfile', '-s', 'demo')
+ self.assertGreater(rc, 0)
+ self.assertIn(b"option -s: invalid choice: 'demo'", err)
+
def test_main():
- run_unittest(CProfileTest)
+ run_unittest(CProfileTest, TestCommandLine)
def main():
if '-r' not in sys.argv:
replace(c, x=3)
c = replace(c, x=3, y=5)
self.assertEqual(c.x, 15)
+
+ def test_recursive_repr(self):
+ @dataclass
+ class C:
+ f: "C"
+
+ c = C(None)
+ c.f = c
+ self.assertEqual(repr(c), "TestReplace.test_recursive_repr.<locals>.C(f=...)")
+
+ def test_recursive_repr_two_attrs(self):
+ @dataclass
+ class C:
+ f: "C"
+ g: "C"
+
+ c = C(None, None)
+ c.f = c
+ c.g = c
+ self.assertEqual(repr(c), "TestReplace.test_recursive_repr_two_attrs"
+ ".<locals>.C(f=..., g=...)")
+
+ def test_recursive_repr_indirection(self):
+ @dataclass
+ class C:
+ f: "D"
+
+ @dataclass
+ class D:
+ f: "C"
+
+ c = C(None)
+ d = D(None)
+ c.f = d
+ d.f = c
+ self.assertEqual(repr(c), "TestReplace.test_recursive_repr_indirection"
+ ".<locals>.C(f=TestReplace.test_recursive_repr_indirection"
+ ".<locals>.D(f=...))")
+
+ def test_recursive_repr_indirection_two(self):
+ @dataclass
+ class C:
+ f: "D"
+
+ @dataclass
+ class D:
+ f: "E"
+
+ @dataclass
+ class E:
+ f: "C"
+
+ c = C(None)
+ d = D(None)
+ e = E(None)
+ c.f = d
+ d.f = e
+ e.f = c
+ self.assertEqual(repr(c), "TestReplace.test_recursive_repr_indirection_two"
+ ".<locals>.C(f=TestReplace.test_recursive_repr_indirection_two"
+ ".<locals>.D(f=TestReplace.test_recursive_repr_indirection_two"
+ ".<locals>.E(f=...)))")
+
+ def test_recursive_repr_two_attrs(self):
+ @dataclass
+ class C:
+ f: "C"
+ g: "C"
+
+ c = C(None, None)
+ c.f = c
+ c.g = c
+ self.assertEqual(repr(c), "TestReplace.test_recursive_repr_two_attrs"
+ ".<locals>.C(f=..., g=...)")
+
+ def test_recursive_repr_misc_attrs(self):
+ @dataclass
+ class C:
+ f: "C"
+ g: int
+
+ c = C(None, 1)
+ c.f = c
+ self.assertEqual(repr(c), "TestReplace.test_recursive_repr_misc_attrs"
+ ".<locals>.C(f=..., g=1)")
+
## def test_initvar(self):
## @dataclass
## class C:
decimal_point = locale.localeconv()['decimal_point']
thousands_sep = locale.localeconv()['thousands_sep']
if decimal_point != '\u066b':
- self.skipTest('inappropriate decimal point separator'
+ self.skipTest('inappropriate decimal point separator '
'({!a} not {!a})'.format(decimal_point, '\u066b'))
if thousands_sep != '\u066c':
- self.skipTest('inappropriate thousands separator'
+ self.skipTest('inappropriate thousands separator '
'({!a} not {!a})'.format(thousands_sep, '\u066c'))
self.assertEqual(format(Decimal('100000000.123'), 'n'),
import os
import signal
+import subprocess
+import sys
import unittest
from test import support
# thread (for reliable signal delivery).
tester = support.findfile("eintr_tester.py", subdir="eintrdata")
# use -u to try to get the full output if the test hangs or crash
- script_helper.assert_python_ok("-u", tester)
+ args = ["-u", tester, "-v"]
+ if support.verbose:
+ print()
+ print("--- run eintr_tester.py ---", flush=True)
+ # In verbose mode, the child process inherit stdout and stdout,
+ # to see output in realtime and reduce the risk of loosing output.
+ args = [sys.executable, "-E", "-X", "faulthandler", *args]
+ proc = subprocess.run(args)
+ print(f"--- eintr_tester.py completed: "
+ f"exit code {proc.returncode} ---", flush=True)
+ if proc.returncode:
+ self.fail("eintr_tester.py failed")
+ else:
+ script_helper.assert_python_ok("-u", tester, "-v")
if __name__ == "__main__":
t2 = utils.localtime(t1)
self.assertEqual(t1, t2)
+ @test.support.run_with_tz('Europe/Minsk')
def test_localtime_daylight_true_dst_true(self):
test.support.patch(self, time, 'daylight', True)
t0 = datetime.datetime(2012, 3, 12, 1, 1)
t2 = utils.localtime(t1)
self.assertEqual(t1, t2)
+ @test.support.run_with_tz('Europe/Minsk')
def test_localtime_daylight_false_dst_true(self):
test.support.patch(self, time, 'daylight', False)
t0 = datetime.datetime(2012, 3, 12, 1, 1)
import unittest
from collections import namedtuple
+import json
import os
import re
import subprocess
import sys
+import textwrap
+
+
+MS_WINDOWS = (os.name == 'nt')
class EmbeddingTestsMixin:
here = os.path.abspath(__file__)
basepath = os.path.dirname(os.path.dirname(os.path.dirname(here)))
exename = "_testembed"
- if sys.platform.startswith("win"):
+ if MS_WINDOWS:
ext = ("_d" if "_d" in sys.executable else "") + ".exe"
exename += ext
exepath = os.path.dirname(sys.executable)
"""Runs a test in the embedded interpreter"""
cmd = [self.test_exe]
cmd.extend(args)
- if env is not None and sys.platform == 'win32':
+ if env is not None and MS_WINDOWS:
# Windows requires at least the SYSTEMROOT environment variable to
# start Python.
env = env.copy()
"""
env = dict(os.environ, PYTHONPATH=os.pathsep.join(sys.path))
out, err = self.run_embedded_interpreter("pre_initialization_api", env=env)
- if sys.platform == "win32":
+ if MS_WINDOWS:
expected_path = self.test_exe
else:
expected_path = os.path.join(os.getcwd(), "spam")
class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
maxDiff = 4096
- DEFAULT_CONFIG = {
+ UTF8_MODE_ERRORS = ('surrogatepass' if MS_WINDOWS else 'surrogateescape')
+
+ # core config
+ UNTESTED_CORE_CONFIG = (
+ # FIXME: untested core configuration variables
+ 'dll_path',
+ 'executable',
+ 'module_search_paths',
+ )
+ # Mark config which should be get by get_default_config()
+ GET_DEFAULT_CONFIG = object()
+ DEFAULT_CORE_CONFIG = {
'install_signal_handlers': 1,
- 'Py_IgnoreEnvironmentFlag': 0,
+ 'ignore_environment': 0,
'use_hash_seed': 0,
'hash_seed': 0,
- 'allocator': '(null)',
+ 'allocator': None,
'dev_mode': 0,
'faulthandler': 0,
'tracemalloc': 0,
'show_alloc_count': 0,
'dump_refs': 0,
'malloc_stats': 0,
- 'utf8_mode': 0,
+ 'utf8_mode': 0,
'coerce_c_locale': 0,
'coerce_c_locale_warn': 0,
'program_name': './_testembed',
- 'argc': 0,
- 'argv': '[]',
- 'program': '(null)',
+ 'argv': [],
+ 'program': None,
- 'Py_IsolatedFlag': 0,
- 'Py_NoSiteFlag': 0,
+ 'xoptions': [],
+ 'warnoptions': [],
+
+ 'module_search_path_env': None,
+ 'home': None,
+
+ 'prefix': GET_DEFAULT_CONFIG,
+ 'base_prefix': GET_DEFAULT_CONFIG,
+ 'exec_prefix': GET_DEFAULT_CONFIG,
+ 'base_exec_prefix': GET_DEFAULT_CONFIG,
+
+ '_disable_importlib': 0,
+ }
+
+ # main config
+ UNTESTED_MAIN_CONFIG = (
+ # FIXME: untested main configuration variables
+ 'module_search_path',
+ )
+ COPY_MAIN_CONFIG = (
+ # Copy core config to main config for expected values
+ 'argv',
+ 'base_exec_prefix',
+ 'base_prefix',
+ 'exec_prefix',
+ 'executable',
+ 'install_signal_handlers',
+ 'prefix',
+ 'warnoptions',
+ # xoptions is created from core_config in check_main_config()
+ )
+
+ # global config
+ UNTESTED_GLOBAL_CONFIG = (
+ # Py_HasFileSystemDefaultEncoding value depends on the LC_CTYPE locale
+ # and the platform. It is complex to test it, and it's value doesn't
+ # really matter.
+ 'Py_HasFileSystemDefaultEncoding',
+ )
+ DEFAULT_GLOBAL_CONFIG = {
'Py_BytesWarningFlag': 0,
+ 'Py_DebugFlag': 0,
+ 'Py_DontWriteBytecodeFlag': 0,
+ 'Py_FileSystemDefaultEncodeErrors': GET_DEFAULT_CONFIG,
+ 'Py_FileSystemDefaultEncoding': GET_DEFAULT_CONFIG,
+ 'Py_FrozenFlag': 0,
+ 'Py_HashRandomizationFlag': 1,
'Py_InspectFlag': 0,
'Py_InteractiveFlag': 0,
+ 'Py_IsolatedFlag': 0,
+ 'Py_NoSiteFlag': 0,
+ 'Py_NoUserSiteDirectory': 0,
'Py_OptimizeFlag': 0,
- 'Py_DebugFlag': 0,
- 'Py_DontWriteBytecodeFlag': 0,
- 'Py_VerboseFlag': 0,
'Py_QuietFlag': 0,
- 'Py_NoUserSiteDirectory': 0,
'Py_UnbufferedStdioFlag': 0,
-
- '_disable_importlib': 0,
- 'Py_FrozenFlag': 0,
+ 'Py_VerboseFlag': 0,
}
-
- def check_config(self, testname, expected):
+ if MS_WINDOWS:
+ DEFAULT_GLOBAL_CONFIG.update({
+ 'Py_LegacyWindowsFSEncodingFlag': 0,
+ 'Py_LegacyWindowsStdioFlag': 0,
+ })
+ COPY_GLOBAL_CONFIG = [
+ # Copy core config to global config for expected values
+ # True means that the core config value is inverted (0 => 1 and 1 => 0)
+ ('Py_IgnoreEnvironmentFlag', 'ignore_environment'),
+ ('Py_UTF8Mode', 'utf8_mode'),
+ ]
+
+ def main_xoptions(self, xoptions_list):
+ xoptions = {}
+ for opt in xoptions_list:
+ if '=' in opt:
+ key, value = opt.split('=', 1)
+ xoptions[key] = value
+ else:
+ xoptions[opt] = True
+ return xoptions
+
+ def check_main_config(self, config):
+ core_config = config['core_config']
+ main_config = config['main_config']
+
+ # main config
+ for key in self.UNTESTED_MAIN_CONFIG:
+ del main_config[key]
+
+ expected = {}
+ for key in self.COPY_MAIN_CONFIG:
+ expected[key] = core_config[key]
+ expected['xoptions'] = self.main_xoptions(core_config['xoptions'])
+ self.assertEqual(main_config, expected)
+
+ def get_expected_config(self, expected_core, expected_global, env):
+ expected_core = dict(self.DEFAULT_CORE_CONFIG, **expected_core)
+ expected_global = dict(self.DEFAULT_GLOBAL_CONFIG, **expected_global)
+
+ code = textwrap.dedent('''
+ import json
+ import sys
+
+ data = {
+ 'prefix': sys.prefix,
+ 'base_prefix': sys.base_prefix,
+ 'exec_prefix': sys.exec_prefix,
+ 'base_exec_prefix': sys.base_exec_prefix,
+ 'Py_FileSystemDefaultEncoding': sys.getfilesystemencoding(),
+ 'Py_FileSystemDefaultEncodeErrors': sys.getfilesystemencodeerrors(),
+ }
+
+ data = json.dumps(data)
+ data = data.encode('utf-8')
+ sys.stdout.buffer.write(data)
+ sys.stdout.buffer.flush()
+ ''')
+
+ # Use -S to not import the site module: get the proper configuration
+ # when test_embed is run from a venv (bpo-35313)
+ args = (sys.executable, '-S', '-c', code)
+ env = dict(env)
+ if not expected_global['Py_IsolatedFlag']:
+ env['PYTHONCOERCECLOCALE'] = '0'
+ env['PYTHONUTF8'] = '0'
+ proc = subprocess.run(args, env=env,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ if proc.returncode:
+ raise Exception(f"failed to get the default config: "
+ f"stdout={proc.stdout!r} stderr={proc.stderr!r}")
+ stdout = proc.stdout.decode('utf-8')
+ config = json.loads(stdout)
+
+ for key, value in expected_core.items():
+ if value is self.GET_DEFAULT_CONFIG:
+ expected_core[key] = config[key]
+ for key, value in expected_global.items():
+ if value is self.GET_DEFAULT_CONFIG:
+ expected_global[key] = config[key]
+ return (expected_core, expected_global)
+
+ def check_core_config(self, config, expected):
+ core_config = dict(config['core_config'])
+ for key in self.UNTESTED_CORE_CONFIG:
+ core_config.pop(key, None)
+ self.assertEqual(core_config, expected)
+
+ def check_global_config(self, config, expected, env):
+ core_config = config['core_config']
+
+ for item in self.COPY_GLOBAL_CONFIG:
+ if len(item) == 3:
+ global_key, core_key, opposite = item
+ expected[global_key] = 0 if core_config[core_key] else 1
+ else:
+ global_key, core_key = item
+ expected[global_key] = core_config[core_key]
+
+ global_config = dict(config['global_config'])
+ for key in self.UNTESTED_GLOBAL_CONFIG:
+ del global_config[key]
+ self.assertEqual(global_config, expected)
+
+ def check_config(self, testname, expected_core, expected_global):
env = dict(os.environ)
+ # Remove PYTHON* environment variables to get deterministic environment
for key in list(env):
if key.startswith('PYTHON'):
del env[key]
# on the current locale
env['PYTHONCOERCECLOCALE'] = '0'
env['PYTHONUTF8'] = '0'
+
out, err = self.run_embedded_interpreter(testname, env=env)
# Ignore err
+ config = json.loads(out)
- expected = dict(self.DEFAULT_CONFIG, **expected)
- for key, value in expected.items():
- expected[key] = str(value)
-
- config = {}
- for line in out.splitlines():
- key, value = line.split(' = ', 1)
- config[key] = value
- self.assertEqual(config, expected)
+ expected_core, expected_global = self.get_expected_config(expected_core, expected_global, env)
+ self.check_core_config(config, expected_core)
+ self.check_main_config(config)
+ self.check_global_config(config, expected_global, env)
def test_init_default_config(self):
- self.check_config("init_default_config", {})
+ self.check_config("init_default_config", {}, {})
def test_init_global_config(self):
- config = {
+ core_config = {
'program_name': './globalvar',
- 'Py_NoSiteFlag': 1,
+ 'utf8_mode': 1,
+ }
+ global_config = {
'Py_BytesWarningFlag': 1,
+ 'Py_DontWriteBytecodeFlag': 1,
+ 'Py_FileSystemDefaultEncodeErrors': self.UTF8_MODE_ERRORS,
+ 'Py_FileSystemDefaultEncoding': 'utf-8',
'Py_InspectFlag': 1,
'Py_InteractiveFlag': 1,
+ 'Py_NoSiteFlag': 1,
+ 'Py_NoUserSiteDirectory': 1,
'Py_OptimizeFlag': 2,
- 'Py_DontWriteBytecodeFlag': 1,
- 'Py_VerboseFlag': 1,
'Py_QuietFlag': 1,
- 'Py_UnbufferedStdioFlag': 1,
- 'utf8_mode': 1,
- 'Py_NoUserSiteDirectory': 1,
+ 'Py_VerboseFlag': 1,
'Py_FrozenFlag': 1,
+ 'Py_UnbufferedStdioFlag': 1,
}
- self.check_config("init_global_config", config)
+ self.check_config("init_global_config", core_config, global_config)
def test_init_from_config(self):
- config = {
+ core_config = {
'install_signal_handlers': 0,
'use_hash_seed': 1,
'hash_seed': 123,
'utf8_mode': 1,
'program_name': './conf_program_name',
+ 'argv': ['-c', 'pass'],
'program': 'conf_program',
+ 'xoptions': ['core_xoption1=3', 'core_xoption2=', 'core_xoption3'],
+ 'warnoptions': ['default', 'error::ResourceWarning'],
'faulthandler': 1,
}
- self.check_config("init_from_config", config)
+ global_config = {
+ 'Py_FileSystemDefaultEncodeErrors': self.UTF8_MODE_ERRORS,
+ 'Py_FileSystemDefaultEncoding': 'utf-8',
+ 'Py_NoUserSiteDirectory': 0,
+ }
+ self.check_config("init_from_config", core_config, global_config)
def test_init_env(self):
- config = {
+ core_config = {
'use_hash_seed': 1,
'hash_seed': 42,
'allocator': 'malloc_debug',
'import_time': 1,
'malloc_stats': 1,
'utf8_mode': 1,
+ 'faulthandler': 1,
+ 'dev_mode': 1,
+ }
+ global_config = {
+ 'Py_DontWriteBytecodeFlag': 1,
+ 'Py_FileSystemDefaultEncodeErrors': self.UTF8_MODE_ERRORS,
+ 'Py_FileSystemDefaultEncoding': 'utf-8',
'Py_InspectFlag': 1,
+ 'Py_NoUserSiteDirectory': 1,
'Py_OptimizeFlag': 2,
- 'Py_DontWriteBytecodeFlag': 1,
- 'Py_VerboseFlag': 1,
'Py_UnbufferedStdioFlag': 1,
- 'Py_NoUserSiteDirectory': 1,
- 'faulthandler': 1,
- 'dev_mode': 1,
+ 'Py_VerboseFlag': 1,
}
- self.check_config("init_env", config)
+ self.check_config("init_env", core_config, global_config)
def test_init_dev_mode(self):
- config = {
+ core_config = {
'dev_mode': 1,
'faulthandler': 1,
'allocator': 'debug',
}
- self.check_config("init_dev_mode", config)
+ self.check_config("init_dev_mode", core_config, {})
def test_init_isolated(self):
- config = {
+ core_config = {
+ 'ignore_environment': 1,
+ }
+ global_config = {
'Py_IsolatedFlag': 1,
- 'Py_IgnoreEnvironmentFlag': 1,
'Py_NoUserSiteDirectory': 1,
}
- self.check_config("init_isolated", config)
+ self.check_config("init_isolated", core_config, global_config)
if __name__ == "__main__":
third = auto()
self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
+ def test_missing(self):
+ class Color(Enum):
+ red = 1
+ green = 2
+ blue = 3
+ @classmethod
+ def _missing_(cls, item):
+ if item == 'three':
+ return cls.blue
+ elif item == 'bad return':
+ # trigger internal error
+ return 5
+ elif item == 'error out':
+ raise ZeroDivisionError
+ else:
+ # trigger not found
+ return None
+ self.assertIs(Color('three'), Color.blue)
+ self.assertRaises(ValueError, Color, 7)
+ try:
+ Color('bad return')
+ except TypeError as exc:
+ self.assertTrue(isinstance(exc.__context__, ValueError))
+ else:
+ raise Exception('Exception not raised.')
+ try:
+ Color('error out')
+ except ZeroDivisionError as exc:
+ self.assertTrue(isinstance(exc.__context__, ValueError))
+ else:
+ raise Exception('Exception not raised.')
+
def test_multiple_mixin(self):
class MaxMixin:
@classproperty
import locale
import os
+import platform
import re
import subprocess
import sys
if not sysconfig.is_python_build():
raise unittest.SkipTest("test_gdb only works on source builds at the moment.")
+if 'Clang' in platform.python_compiler() and sys.platform == 'darwin':
+ raise unittest.SkipTest("test_gdb doesn't work correctly when python is"
+ " built with LLVM clang")
+
# Location of custom hooks file in a repository checkout.
checkout_hook_path = os.path.join(os.path.dirname(sys.executable),
'python-gdb.py')
'1980-01-01 00:61:00',
'01-01-1980 00:00:62',
'01-01-1980T00:00:62',
- '19800101T250000Z'
- '1980-01-01 00:00:00 -2500',
+ '19800101T250000Z',
]:
self.assertIsNone(iso2time(test),
- "iso2time(%s) is not None\n"
- "iso2time(test) %s" % (test, iso2time(test)))
+ "iso2time(%r)" % test)
class HeaderTests(unittest.TestCase):
from test.support import make_legacy_pyc, unload
+from test.test_py_compile import without_source_date_epoch
+from test.test_py_compile import SourceDateEpochTestMeta
+
class SimpleTest(abc.LoaderTests):
abc=importlib_abc, util=importlib_util)
+class SourceDateEpochTestMeta(SourceDateEpochTestMeta,
+ type(Source_SimpleTest)):
+ pass
+
+
+class SourceDateEpoch_SimpleTest(Source_SimpleTest,
+ metaclass=SourceDateEpochTestMeta,
+ source_date_epoch=True):
+ pass
+
+
class BadBytecodeTest:
def import_(self, file, module_name):
# [bad timestamp]
@util.writes_bytecode_files
+ @without_source_date_epoch
def test_old_timestamp(self):
# When the timestamp is older than the source, bytecode should be
# regenerated.
dec = self.IncrementalNewlineDecoder(None, translate=True)
_check(dec)
+ def test_translate(self):
+ # issue 35062
+ for translate in (-2, -1, 1, 2):
+ decoder = codecs.getincrementaldecoder("utf-8")()
+ decoder = self.IncrementalNewlineDecoder(decoder, translate)
+ self.check_newline_decoding_utf8(decoder)
+ decoder = codecs.getincrementaldecoder("utf-8")()
+ decoder = self.IncrementalNewlineDecoder(decoder, translate=0)
+ self.assertEqual(decoder.decode(b"\r\r\n"), "\r\r\n")
+
class CIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest):
pass
import stat
import sys
import unittest
-from test.support import TESTFN, requires, unlink
+from test.support import TESTFN, requires, unlink, bigmemtest
import io # C implementation of io
import _pyio as pyio # Python implementation of io
# size of file to create (>2 GiB; 2 GiB == 2,147,483,648 bytes)
-size = 2500000000
+size = 2_500_000_000
class LargeFileTest:
"""Test that each file function works as expected for large
raise cls.failureException('File was not truncated by opening '
'with mode "wb"')
+ # _pyio.FileIO.readall() uses a temporary bytearray then casted to bytes,
+ # so memuse=2 is needed
+ @bigmemtest(size=size, memuse=2, dry_run=False)
+ def test_large_read(self, _size):
+ # bpo-24658: Test that a read greater than 2GB does not fail.
+ with self.open(TESTFN, "rb") as f:
+ self.assertEqual(len(f.read()), size + 1)
+ self.assertEqual(f.tell(), size + 1)
+
def test_osstat(self):
self.assertEqual(os.stat(TESTFN)[stat.ST_SIZE], size+1)
import copy
import pickle
-from test.support import findfile
+from test import support
import unittest
import xml.dom.minidom
from xml.dom.minidom import getDOMImplementation
-tstfile = findfile("test.xml", subdir="xmltestdata")
+tstfile = support.findfile("test.xml", subdir="xmltestdata")
sample = ("<?xml version='1.0' encoding='us-ascii'?>\n"
"<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
" 'http://xml.python.org/system' [\n"
def testClonePIDeep(self):
self.check_clone_pi(1, "testClonePIDeep")
+ def check_clone_node_entity(self, clone_document):
+ # bpo-35052: Test user data handler in cloneNode() on a document with
+ # an entity
+ document = xml.dom.minidom.parseString("""
+ <?xml version="1.0" ?>
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd"
+ [ <!ENTITY smile "☺"> ]
+ >
+ <doc>Don't let entities make you frown ⌣</doc>
+ """.strip())
+
+ class Handler:
+ def handle(self, operation, key, data, src, dst):
+ self.operation = operation
+ self.key = key
+ self.data = data
+ self.src = src
+ self.dst = dst
+
+ handler = Handler()
+ doctype = document.doctype
+ entity = doctype.entities['smile']
+ entity.setUserData("key", "data", handler)
+
+ if clone_document:
+ # clone Document
+ clone = document.cloneNode(deep=True)
+
+ self.assertEqual(clone.documentElement.firstChild.wholeText,
+ "Don't let entities make you frown ☺")
+ operation = xml.dom.UserDataHandler.NODE_IMPORTED
+ dst = clone.doctype.entities['smile']
+ else:
+ # clone DocumentType
+ with support.swap_attr(doctype, 'ownerDocument', None):
+ clone = doctype.cloneNode(deep=True)
+
+ operation = xml.dom.UserDataHandler.NODE_CLONED
+ dst = clone.entities['smile']
+
+ self.assertEqual(handler.operation, operation)
+ self.assertEqual(handler.key, "key")
+ self.assertEqual(handler.data, "data")
+ self.assertIs(handler.src, entity)
+ self.assertIs(handler.dst, dst)
+
+ def testCloneNodeEntity(self):
+ self.check_clone_node_entity(False)
+ self.check_clone_node_entity(True)
+
def testNormalize(self):
doc = parseString("<doc/>")
root = doc.documentElement
import unittest
import test._test_multiprocessing
+import sys
from test import support
if support.PGO:
raise unittest.SkipTest("test is not helpful for PGO")
+if sys.platform == "win32":
+ raise unittest.SkipTest("fork is not available on Windows")
+
+if sys.platform == 'darwin':
+ raise unittest.SkipTest("test may crash on macOS (bpo-33725)")
test._test_multiprocessing.install_tests_in_module_dict(globals(), 'fork')
import unittest
import test._test_multiprocessing
+import sys
from test import support
if support.PGO:
raise unittest.SkipTest("test is not helpful for PGO")
+if sys.platform == "win32":
+ raise unittest.SkipTest("forkserver is not available on Windows")
+
test._test_multiprocessing.install_tests_in_module_dict(globals(), 'forkserver')
if __name__ == '__main__':
tester('ntpath.abspath("")', cwd_dir)
tester('ntpath.abspath(" ")', cwd_dir + "\\ ")
tester('ntpath.abspath("?")', cwd_dir + "\\?")
+ drive, _ = ntpath.splitdrive(cwd_dir)
+ tester('ntpath.abspath("/abc/")', drive + "\\abc")
def test_relpath(self):
tester('ntpath.relpath("a")', 'a')
nodesize = calcsize('Pn2P')
od = OrderedDict()
- check(od, basicsize + 8*p + 8 + 5*entrysize) # 8byte indices + 8*2//3 * entry table
+ check(od, basicsize + 8 + 5*entrysize) # 8byte indices + 8*2//3 * entry table
od.x = 1
- check(od, basicsize + 8*p + 8 + 5*entrysize)
+ check(od, basicsize + 8 + 5*entrysize)
od.update([(i, i) for i in range(3)])
check(od, basicsize + 8*p + 8 + 5*entrysize + 3*nodesize)
od.update([(i, i) for i in range(3, 10)])
del od['c']
self.assertEqual(list(od), list('bdeaf'))
+ def test_iterators_pickling(self):
+ OrderedDict = self.OrderedDict
+ pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
+ od = OrderedDict(pairs)
+
+ for method_name in ('keys', 'values', 'items'):
+ meth = getattr(od, method_name)
+ expected = list(meth())[1:]
+ for i in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(method_name=method_name, protocol=i):
+ it = iter(meth())
+ next(it)
+ p = pickle.dumps(it, i)
+ unpickled = pickle.loads(p)
+ self.assertEqual(list(unpickled), expected)
+ self.assertEqual(list(it), expected)
+
class PurePythonOrderedDictSubclassTests(PurePythonOrderedDictTests):
# seconds and nanoseconds parameters are mutually exclusive
with self.assertRaises(ValueError):
os.utime(self.fname, (5, 5), ns=(5, 5))
+ with self.assertRaises(TypeError):
+ os.utime(self.fname, [5, 5])
+ with self.assertRaises(TypeError):
+ os.utime(self.fname, (5,))
+ with self.assertRaises(TypeError):
+ os.utime(self.fname, (5, 5, 5))
+ with self.assertRaises(TypeError):
+ os.utime(self.fname, ns=[5, 5])
+ with self.assertRaises(TypeError):
+ os.utime(self.fname, ns=(5,))
+ with self.assertRaises(TypeError):
+ os.utime(self.fname, ns=(5, 5, 5))
+
+ if os.utime not in os.supports_follow_symlinks:
+ with self.assertRaises(NotImplementedError):
+ os.utime(self.fname, (5, 5), follow_symlinks=False)
+ if os.utime not in os.supports_fd:
+ with open(self.fname, 'wb', 0) as fp:
+ with self.assertRaises(TypeError):
+ os.utime(fp.fileno(), (5, 5))
+ if os.utime not in os.supports_dir_fd:
+ with self.assertRaises(NotImplementedError):
+ os.utime(self.fname, (5, 5), dir_fd=0)
@support.cpython_only
def test_issue31577(self):
with self.assertRaises(ValueError):
os.execve(args[0], args, newenv)
+ @unittest.skipUnless(sys.platform == "win32", "Win32-specific test")
+ def test_execve_with_empty_path(self):
+ # bpo-32890: Check GetLastError() misuse
+ try:
+ os.execve('', ['arg'], {})
+ except OSError as e:
+ self.assertTrue(e.winerror is None or e.winerror != 0)
+ else:
+ self.fail('No OSError raised')
+
@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
class Win32ErrorTests(unittest.TestCase):
# resolves to 'dirB/..' first before resolving to parent of dirB.
self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
# Now create absolute symlinks
- d = support._longpath(tempfile.mkdtemp(suffix='-dirD'))
+ d = support._longpath(tempfile.mkdtemp(suffix='-dirD', dir=os.getcwd()))
self.addCleanup(support.rmtree, d)
os.symlink(os.path.join(d), join('dirA', 'linkX'))
os.symlink(join('dirB'), os.path.join(d, 'linkY'))
from posixpath import realpath, abspath, dirname, basename
from test import support, test_genericpath
from test.support import FakePath
+from unittest import mock
try:
import posix
def test_expanduser(self):
self.assertEqual(posixpath.expanduser("foo"), "foo")
self.assertEqual(posixpath.expanduser(b"foo"), b"foo")
+
+ def test_expanduser_home_envvar(self):
with support.EnvironmentVarGuard() as env:
+ env['HOME'] = '/home/victor'
+ self.assertEqual(posixpath.expanduser("~"), "/home/victor")
+
+ # expanduser() strips trailing slash
+ env['HOME'] = '/home/victor/'
+ self.assertEqual(posixpath.expanduser("~"), "/home/victor")
+
for home in '/', '', '//', '///':
with self.subTest(home=home):
env['HOME'] = home
self.assertEqual(posixpath.expanduser("~"), "/")
self.assertEqual(posixpath.expanduser("~/"), "/")
self.assertEqual(posixpath.expanduser("~/foo"), "/foo")
- try:
- import pwd
- except ImportError:
- pass
- else:
- self.assertIsInstance(posixpath.expanduser("~/"), str)
- self.assertIsInstance(posixpath.expanduser(b"~/"), bytes)
- # if home directory == root directory, this test makes no sense
- if posixpath.expanduser("~") != '/':
- self.assertEqual(
- posixpath.expanduser("~") + "/",
- posixpath.expanduser("~/")
- )
- self.assertEqual(
- posixpath.expanduser(b"~") + b"/",
- posixpath.expanduser(b"~/")
- )
- self.assertIsInstance(posixpath.expanduser("~root/"), str)
- self.assertIsInstance(posixpath.expanduser("~foo/"), str)
- self.assertIsInstance(posixpath.expanduser(b"~root/"), bytes)
- self.assertIsInstance(posixpath.expanduser(b"~foo/"), bytes)
-
- with support.EnvironmentVarGuard() as env:
- # expanduser should fall back to using the password database
- del env['HOME']
- home = pwd.getpwuid(os.getuid()).pw_dir
- # $HOME can end with a trailing /, so strip it (see #17809)
- home = home.rstrip("/") or '/'
- self.assertEqual(posixpath.expanduser("~"), home)
+
+ def test_expanduser_pwd(self):
+ pwd = support.import_module('pwd')
+
+ self.assertIsInstance(posixpath.expanduser("~/"), str)
+ self.assertIsInstance(posixpath.expanduser(b"~/"), bytes)
+
+ # if home directory == root directory, this test makes no sense
+ if posixpath.expanduser("~") != '/':
+ self.assertEqual(
+ posixpath.expanduser("~") + "/",
+ posixpath.expanduser("~/")
+ )
+ self.assertEqual(
+ posixpath.expanduser(b"~") + b"/",
+ posixpath.expanduser(b"~/")
+ )
+ self.assertIsInstance(posixpath.expanduser("~root/"), str)
+ self.assertIsInstance(posixpath.expanduser("~foo/"), str)
+ self.assertIsInstance(posixpath.expanduser(b"~root/"), bytes)
+ self.assertIsInstance(posixpath.expanduser(b"~foo/"), bytes)
+
+ with support.EnvironmentVarGuard() as env:
+ # expanduser should fall back to using the password database
+ del env['HOME']
+
+ home = pwd.getpwuid(os.getuid()).pw_dir
+ # $HOME can end with a trailing /, so strip it (see #17809)
+ home = home.rstrip("/") or '/'
+ self.assertEqual(posixpath.expanduser("~"), home)
+
+ # bpo-10496: If the HOME environment variable is not set and the
+ # user (current identifier or name in the path) doesn't exist in
+ # the password database (pwd.getuid() or pwd.getpwnam() fail),
+ # expanduser() must return the path unchanged.
+ with mock.patch.object(pwd, 'getpwuid', side_effect=KeyError), \
+ mock.patch.object(pwd, 'getpwnam', side_effect=KeyError):
+ for path in ('~', '~/.local', '~vstinner/'):
+ self.assertEqual(posixpath.expanduser(path), path)
def test_normpath(self):
self.assertEqual(posixpath.normpath(""), ".")
+import functools
import importlib.util
import os
import py_compile
from test import support
-class PyCompileTests(unittest.TestCase):
+def without_source_date_epoch(fxn):
+ """Runs function with SOURCE_DATE_EPOCH unset."""
+ @functools.wraps(fxn)
+ def wrapper(*args, **kwargs):
+ with support.EnvironmentVarGuard() as env:
+ env.unset('SOURCE_DATE_EPOCH')
+ return fxn(*args, **kwargs)
+ return wrapper
+
+
+def with_source_date_epoch(fxn):
+ """Runs function with SOURCE_DATE_EPOCH set."""
+ @functools.wraps(fxn)
+ def wrapper(*args, **kwargs):
+ with support.EnvironmentVarGuard() as env:
+ env['SOURCE_DATE_EPOCH'] = '123456789'
+ return fxn(*args, **kwargs)
+ return wrapper
+
+
+# Run tests with SOURCE_DATE_EPOCH set or unset explicitly.
+class SourceDateEpochTestMeta(type(unittest.TestCase)):
+ def __new__(mcls, name, bases, dct, *, source_date_epoch):
+ cls = super().__new__(mcls, name, bases, dct)
+
+ for attr in dir(cls):
+ if attr.startswith('test_'):
+ meth = getattr(cls, attr)
+ if source_date_epoch:
+ wrapper = with_source_date_epoch(meth)
+ else:
+ wrapper = without_source_date_epoch(meth)
+ setattr(cls, attr, wrapper)
+
+ return cls
+
+
+class PyCompileTestsBase:
def setUp(self):
self.directory = tempfile.mkdtemp()
importlib.util.cache_from_source(bad_coding)))
def test_source_date_epoch(self):
- testtime = 123456789
- with support.EnvironmentVarGuard() as env:
- env["SOURCE_DATE_EPOCH"] = str(testtime)
- py_compile.compile(self.source_path, self.pyc_path)
+ py_compile.compile(self.source_path, self.pyc_path)
self.assertTrue(os.path.exists(self.pyc_path))
self.assertFalse(os.path.exists(self.cache_path))
with open(self.pyc_path, 'rb') as fp:
flags = importlib._bootstrap_external._classify_pyc(
fp.read(), 'test', {})
- self.assertEqual(flags, 0b11)
+ if os.environ.get('SOURCE_DATE_EPOCH'):
+ expected_flags = 0b11
+ else:
+ expected_flags = 0b00
+
+ self.assertEqual(flags, expected_flags)
@unittest.skipIf(sys.flags.optimize > 0, 'test does not work with -O')
def test_double_dot_no_clobber(self):
self.assertEqual(flags, 0b1)
+class PyCompileTestsWithSourceEpoch(PyCompileTestsBase,
+ unittest.TestCase,
+ metaclass=SourceDateEpochTestMeta,
+ source_date_epoch=True):
+ pass
+
+
+class PyCompileTestsWithoutSourceEpoch(PyCompileTestsBase,
+ unittest.TestCase,
+ metaclass=SourceDateEpochTestMeta,
+ source_date_epoch=False):
+ pass
+
+
if __name__ == "__main__":
unittest.main()
class PydocDocTest(unittest.TestCase):
+ maxDiff = None
@unittest.skipIf(sys.flags.optimize >= 2,
"Docstrings are omitted with -O2 and above")
methods = pydoc.allmethods(TestClass)
self.assertDictEqual(methods, expected)
+ def test_method_aliases(self):
+ class A:
+ def tkraise(self, aboveThis=None):
+ """Raise this widget in the stacking order."""
+ lift = tkraise
+ def a_size(self):
+ """Return size"""
+ class B(A):
+ def itemconfigure(self, tagOrId, cnf=None, **kw):
+ """Configure resources of an item TAGORID."""
+ itemconfig = itemconfigure
+ b_size = A.a_size
+
+ doc = pydoc.render_doc(B)
+ # clean up the extra text formatting that pydoc performs
+ doc = re.sub('\b.', '', doc)
+ self.assertEqual(doc, '''\
+Python Library Documentation: class B in module %s
+
+class B(A)
+ | Method resolution order:
+ | B
+ | A
+ | builtins.object
+ |\x20\x20
+ | Methods defined here:
+ |\x20\x20
+ | b_size = a_size(self)
+ |\x20\x20
+ | itemconfig = itemconfigure(self, tagOrId, cnf=None, **kw)
+ |\x20\x20
+ | itemconfigure(self, tagOrId, cnf=None, **kw)
+ | Configure resources of an item TAGORID.
+ |\x20\x20
+ | ----------------------------------------------------------------------
+ | Methods inherited from A:
+ |\x20\x20
+ | a_size(self)
+ | Return size
+ |\x20\x20
+ | lift = tkraise(self, aboveThis=None)
+ |\x20\x20
+ | tkraise(self, aboveThis=None)
+ | Raise this widget in the stacking order.
+ |\x20\x20
+ | ----------------------------------------------------------------------
+ | Data descriptors inherited from A:
+ |\x20\x20
+ | __dict__
+ | dictionary for instance variables (if defined)
+ |\x20\x20
+ | __weakref__
+ | list of weak references to the object (if defined)
+''' % __name__)
+
+ doc = pydoc.render_doc(B, renderer=pydoc.HTMLDoc())
+ self.assertEqual(doc, '''\
+Python Library Documentation: class B in module %s
+
+<p>
+<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
+<tr bgcolor="#ffc8d8">
+<td colspan=3 valign=bottom> <br>
+<font color="#000000" face="helvetica, arial"><a name="B">class <strong>B</strong></a>(A)</font></td></tr>
+\x20\x20\x20\x20
+<tr><td bgcolor="#ffc8d8"><tt> </tt></td><td> </td>
+<td width="100%%"><dl><dt>Method resolution order:</dt>
+<dd>B</dd>
+<dd>A</dd>
+<dd><a href="builtins.html#object">builtins.object</a></dd>
+</dl>
+<hr>
+Methods defined here:<br>
+<dl><dt><a name="B-b_size"><strong>b_size</strong></a> = <a href="#B-a_size">a_size</a>(self)</dt></dl>
+
+<dl><dt><a name="B-itemconfig"><strong>itemconfig</strong></a> = <a href="#B-itemconfigure">itemconfigure</a>(self, tagOrId, cnf=None, **kw)</dt></dl>
+
+<dl><dt><a name="B-itemconfigure"><strong>itemconfigure</strong></a>(self, tagOrId, cnf=None, **kw)</dt><dd><tt>Configure resources of an item TAGORID.</tt></dd></dl>
+
+<hr>
+Methods inherited from A:<br>
+<dl><dt><a name="B-a_size"><strong>a_size</strong></a>(self)</dt><dd><tt>Return size</tt></dd></dl>
+
+<dl><dt><a name="B-lift"><strong>lift</strong></a> = <a href="#B-tkraise">tkraise</a>(self, aboveThis=None)</dt></dl>
+
+<dl><dt><a name="B-tkraise"><strong>tkraise</strong></a>(self, aboveThis=None)</dt><dd><tt>Raise this widget in the stacking order.</tt></dd></dl>
+
+<hr>
+Data descriptors inherited from A:<br>
+<dl><dt><strong>__dict__</strong></dt>
+<dd><tt>dictionary for instance variables (if defined)</tt></dd>
+</dl>
+<dl><dt><strong>__weakref__</strong></dt>
+<dd><tt>list of weak references to the object (if defined)</tt></dd>
+</dl>
+</td></tr></table>\
+''' % __name__)
+
class PydocImportTest(PydocBaseTest):
self.fail('{}: unexpected excess element {} at '
'position {}'.format(test_id, x, i))
else:
- self.fail('{}: wrong element at position {};'
+ self.fail('{}: wrong element at position {}; '
'expected {}, got {}'.format(test_id, i, y, x))
def test_range(self):
import sysconfig
import tempfile
import textwrap
-import threading
import unittest
from test import libregrtest
from test import support
ns = libregrtest._parse_args(['--wait'])
self.assertTrue(ns.wait)
- def test_slaveargs(self):
- ns = libregrtest._parse_args(['--slaveargs', '[[], {}]'])
- self.assertEqual(ns.slaveargs, '[[], {}]')
- self.checkError(['--slaveargs'], 'expected one argument')
+ def test_worker_args(self):
+ ns = libregrtest._parse_args(['--worker-args', '[[], {}]'])
+ self.assertEqual(ns.worker_args, '[[], {}]')
+ self.checkError(['--worker-args'], 'expected one argument')
def test_start(self):
for opt in '-S', '--start':
self.tmptestdir = tempfile.mkdtemp()
self.addCleanup(support.rmtree, self.tmptestdir)
- def create_test(self, name=None, code=''):
+ def create_test(self, name=None, code=None):
if not name:
name = 'noop%s' % BaseTestCase.TEST_UNIQUE_ID
BaseTestCase.TEST_UNIQUE_ID += 1
+ if code is None:
+ code = textwrap.dedent("""
+ import unittest
+
+ class Tests(unittest.TestCase):
+ def test_empty_test(self):
+ pass
+ """)
+
# test_regrtest cannot be run twice in parallel because
# of setUp() and create_test()
name = self.TESTNAME_PREFIX + name
def check_executed_tests(self, output, tests, skipped=(), failed=(),
env_changed=(), omitted=(),
- rerun=(),
+ rerun=(), no_test_ran=(),
randomize=False, interrupted=False,
fail_env_changed=False):
if isinstance(tests, str):
omitted = [omitted]
if isinstance(rerun, str):
rerun = [rerun]
+ if isinstance(no_test_ran, str):
+ no_test_ran = [no_test_ran]
executed = self.parse_executed_tests(output)
if randomize:
regex = "Re-running test %r in verbose mode" % name
self.check_line(output, regex)
+ if no_test_ran:
+ regex = list_regex('%s test%s run no tests', no_test_ran)
+ self.check_line(output, regex)
+
good = (len(tests) - len(skipped) - len(failed)
- - len(omitted) - len(env_changed))
+ - len(omitted) - len(env_changed) - len(no_test_ran))
if good:
regex = r'%s test%s OK\.$' % (good, plural(good))
if not skipped and not failed and good > 1:
result.append('ENV CHANGED')
if interrupted:
result.append('INTERRUPTED')
- if not result:
+ if not any((good, result, failed, interrupted, skipped,
+ env_changed, fail_env_changed)):
+ result.append("NO TEST RUN")
+ elif not result:
result.append('SUCCESS')
result = ', '.join(result)
if rerun:
self.check_line(output, 'Tests result: %s' % result)
result = 'FAILURE then %s' % result
+
self.check_line(output, 'Tests result: %s' % result)
def parse_random_seed(self, output):
# test -u command line option
tests = {}
for resource in ('audio', 'network'):
- code = 'from test import support\nsupport.requires(%r)' % resource
+ code = textwrap.dedent("""
+ from test import support; support.requires(%r)
+ import unittest
+ class PassingTest(unittest.TestCase):
+ def test_pass(self):
+ pass
+ """ % resource)
+
tests[resource] = self.create_test(resource, code)
test_names = sorted(tests.values())
output = self.run_tests("-w", testname, exitcode=2)
self.check_executed_tests(output, [testname],
failed=testname, rerun=testname)
+ def test_no_tests_ran(self):
+ code = textwrap.dedent("""
+ import unittest
+
+ class Tests(unittest.TestCase):
+ def test_bug(self):
+ pass
+ """)
+ testname = self.create_test(code=code)
+
+ output = self.run_tests(testname, "-m", "nosuchtest", exitcode=0)
+ self.check_executed_tests(output, [testname], no_test_ran=testname)
+
+ def test_no_tests_ran_multiple_tests_nonexistent(self):
+ code = textwrap.dedent("""
+ import unittest
+
+ class Tests(unittest.TestCase):
+ def test_bug(self):
+ pass
+ """)
+ testname = self.create_test(code=code)
+ testname2 = self.create_test(code=code)
+
+ output = self.run_tests(testname, testname2, "-m", "nosuchtest", exitcode=0)
+ self.check_executed_tests(output, [testname, testname2],
+ no_test_ran=[testname, testname2])
+
+ def test_no_test_ran_some_test_exist_some_not(self):
+ code = textwrap.dedent("""
+ import unittest
+
+ class Tests(unittest.TestCase):
+ def test_bug(self):
+ pass
+ """)
+ testname = self.create_test(code=code)
+ other_code = textwrap.dedent("""
+ import unittest
+
+ class Tests(unittest.TestCase):
+ def test_other_bug(self):
+ pass
+ """)
+ testname2 = self.create_test(code=other_code)
+
+ output = self.run_tests(testname, testname2, "-m", "nosuchtest",
+ "-m", "test_other_bug", exitcode=0)
+ self.check_executed_tests(output, [testname, testname2],
+ no_test_ran=[testname])
class TestUtils(unittest.TestCase):
"""
import unittest
import test.support
+from test import support
from test.support import (captured_stderr, TESTFN, EnvironmentVarGuard,
change_cwd)
import builtins
import subprocess
import sysconfig
import tempfile
+from unittest import mock
from copy import copy
# These tests are not particularly useful if Python was invoked with -S.
# the call sets USER_BASE *and* USER_SITE
self.assertEqual(site.USER_SITE, user_site)
self.assertTrue(user_site.startswith(site.USER_BASE), user_site)
+ self.assertEqual(site.USER_BASE, site.getuserbase())
def test_getsitepackages(self):
site.PREFIXES = ['xoxo']
wanted = os.path.join('xoxo', 'lib', 'site-packages')
self.assertEqual(dirs[1], wanted)
+ def test_no_home_directory(self):
+ # bpo-10496: getuserbase() and getusersitepackages() must not fail if
+ # the current user has no home directory (if expanduser() returns the
+ # path unchanged).
+ site.USER_SITE = None
+ site.USER_BASE = None
+
+ with EnvironmentVarGuard() as environ, \
+ mock.patch('os.path.expanduser', lambda path: path):
+
+ del environ['PYTHONUSERBASE']
+ del environ['APPDATA']
+
+ user_base = site.getuserbase()
+ self.assertTrue(user_base.startswith('~' + os.sep),
+ user_base)
+
+ user_site = site.getusersitepackages()
+ self.assertTrue(user_site.startswith(user_base), user_site)
+
+ with mock.patch('os.path.isdir', return_value=False) as mock_isdir, \
+ mock.patch.object(site, 'addsitedir') as mock_addsitedir, \
+ support.swap_attr(site, 'ENABLE_USER_SITE', True):
+
+ # addusersitepackages() must not add user_site to sys.path
+ # if it is not an existing directory
+ known_paths = set()
+ site.addusersitepackages(known_paths)
+
+ mock_isdir.assert_called_once_with(user_site)
+ mock_addsitedir.assert_not_called()
+ self.assertFalse(known_paths)
+
+
class PthFile(object):
"""Helper class for handling testing of .pth files"""
try:
user, hashed_pass = logpass.split()
except ValueError as e:
- self.push('535 Splitting response {!r} into user and password'
+ self.push('535 Splitting response {!r} into user and password '
'failed: {}'.format(logpass, e))
return False
valid_hashed_pass = hmac.HMAC(
HOST = support.HOST
MSG = 'Michael Gilfix was here\u1234\r\n'.encode('utf-8') ## test unicode string and carriage return
+MAIN_TIMEOUT = 60.0
VSOCKPORT = 1234
class NonBlockingTCPTests(ThreadedTCPSocketTest):
def __init__(self, methodName='runTest'):
+ self.event = threading.Event()
ThreadedTCPSocketTest.__init__(self, methodName=methodName)
def testSetBlocking(self):
def testAccept(self):
# Testing non-blocking accept
self.serv.setblocking(0)
- try:
- conn, addr = self.serv.accept()
- except OSError:
- pass
- else:
- self.fail("Error trying to do non-blocking accept.")
- read, write, err = select.select([self.serv], [], [])
- if self.serv in read:
+
+ # connect() didn't start: non-blocking accept() fails
+ with self.assertRaises(BlockingIOError):
conn, addr = self.serv.accept()
- self.assertIsNone(conn.gettimeout())
- conn.close()
- else:
+
+ self.event.set()
+
+ read, write, err = select.select([self.serv], [], [], MAIN_TIMEOUT)
+ if self.serv not in read:
self.fail("Error trying to do accept after select.")
+ # connect() completed: non-blocking accept() doesn't block
+ conn, addr = self.serv.accept()
+ self.addCleanup(conn.close)
+ self.assertIsNone(conn.gettimeout())
+
def _testAccept(self):
- time.sleep(0.1)
+ # don't connect before event is set to check
+ # that non-blocking accept() raises BlockingIOError
+ self.event.wait()
+
self.cli.connect((HOST, self.port))
def testConnect(self):
def testRecv(self):
# Testing non-blocking recv
conn, addr = self.serv.accept()
+ self.addCleanup(conn.close)
conn.setblocking(0)
- try:
- msg = conn.recv(len(MSG))
- except OSError:
- pass
- else:
- self.fail("Error trying to do non-blocking recv.")
- read, write, err = select.select([conn], [], [])
- if conn in read:
+
+ # the server didn't send data yet: non-blocking recv() fails
+ with self.assertRaises(BlockingIOError):
msg = conn.recv(len(MSG))
- conn.close()
- self.assertEqual(msg, MSG)
- else:
+
+ self.event.set()
+
+ read, write, err = select.select([conn], [], [], MAIN_TIMEOUT)
+ if conn not in read:
self.fail("Error during select call to non-blocking socket.")
+ # the server sent data yet: non-blocking recv() doesn't block
+ msg = conn.recv(len(MSG))
+ self.assertEqual(msg, MSG)
+
def _testRecv(self):
self.cli.connect((HOST, self.port))
- time.sleep(0.1)
- self.cli.send(MSG)
+
+ # don't send anything before event is set to check
+ # that non-blocking recv() raises BlockingIOError
+ self.event.wait()
+
+ # send data: recv() will no longer block
+ self.cli.sendall(MSG)
class FileObjectClassTestCase(SocketConnectedTest):
with self.assertRaises(TypeError):
sock.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, assoclen=-1)
+ def test_length_restriction(self):
+ # bpo-35050, off-by-one error in length check
+ sock = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0)
+ self.addCleanup(sock.close)
+
+ # salg_type[14]
+ with self.assertRaises(FileNotFoundError):
+ sock.bind(("t" * 13, "name"))
+ with self.assertRaisesRegex(ValueError, "type too long"):
+ sock.bind(("t" * 14, "name"))
+
+ # salg_name[64]
+ with self.assertRaises(FileNotFoundError):
+ sock.bind(("type", "n" * 63))
+ with self.assertRaisesRegex(ValueError, "name too long"):
+ sock.bind(("type", "n" * 64))
+
+
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
class TestMSWindowsTCPFlags(unittest.TestCase):
knownTCPFlags = {
self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1)
self.assertRaises(OSError, ss.send, b'x')
self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0))
+ self.assertRaises(NotImplementedError, ss.dup)
self.assertRaises(NotImplementedError, ss.sendmsg,
[b'x'], (), 0, ('0.0.0.0', 0))
+ self.assertRaises(NotImplementedError, ss.recvmsg, 100)
+ self.assertRaises(NotImplementedError, ss.recvmsg_into,
+ [bytearray(100)])
def test_timeout(self):
# Issue #8524: when creating an SSL socket, the timeout of the
# Make sure sendmsg et al are disallowed to avoid
# inadvertent disclosure of data and/or corruption
# of the encrypted data stream
+ self.assertRaises(NotImplementedError, s.dup)
self.assertRaises(NotImplementedError, s.sendmsg, [b"data"])
self.assertRaises(NotImplementedError, s.recvmsg, 100)
self.assertRaises(NotImplementedError,
- s.recvmsg_into, bytearray(100))
+ s.recvmsg_into, [bytearray(100)])
s.write(b"over\n")
self.assertRaises(ValueError, s.recv, -1)
self.assertTrue(result.tm_year == self.time_tuple.tm_year and
result.tm_mon == self.time_tuple.tm_mon and
result.tm_mday == self.time_tuple.tm_mday,
- "Calculation of Gregorian date failed;"
+ "Calculation of Gregorian date failed; "
"%s-%s-%s != %s-%s-%s" %
(result.tm_year, result.tm_mon, result.tm_mday,
self.time_tuple.tm_year, self.time_tuple.tm_mon,
result = _strptime._strptime_time(time.strftime(format_string, self.time_tuple),
format_string)
self.assertTrue(result.tm_wday == self.time_tuple.tm_wday,
- "Calculation of day of the week failed;"
+ "Calculation of day of the week failed; "
"%s != %s" % (result.tm_wday, self.time_tuple.tm_wday))
if support.is_android:
finally:
locale.setlocale(locale.LC_TIME, locale_info)
- @support.run_with_tz('STD-1DST')
+ @support.run_with_tz('STD-1DST,M4.1.0,M10.1.0')
def test_TimeRE_recreation_timezone(self):
# The TimeRE instance should be recreated upon changing the timezone.
oldtzname = time.tzname
# pending child process
support.reap_children()
- def check_options(self, args, func):
+ def check_options(self, args, func, expected=None):
code = f'from test.support import {func}; print(repr({func}()))'
cmd = [sys.executable, *args, '-c', code]
env = {key: value for key, value in os.environ.items()
stderr=subprocess.DEVNULL,
universal_newlines=True,
env=env)
- self.assertEqual(proc.stdout.rstrip(), repr(args))
+ if expected is None:
+ expected = args
+ self.assertEqual(proc.stdout.rstrip(), repr(expected))
self.assertEqual(proc.returncode, 0)
def test_args_from_interpreter_flags(self):
['-v'],
['-b'],
['-q'],
+ ['-I'],
# same option multiple times
['-bb'],
['-vvv'],
with self.subTest(opts=opts):
self.check_options(opts, 'args_from_interpreter_flags')
+ self.check_options(['-I', '-E', '-s'], 'args_from_interpreter_flags',
+ ['-I'])
+
def test_optim_args_from_interpreter_flags(self):
# Test test.support.optim_args_from_interpreter_flags()
for opts in (
)
-def busy_wait(duration):
- deadline = time.monotonic() + duration
- while time.monotonic() < deadline:
- pass
-
-
class TimeTestCase(unittest.TestCase):
def setUp(self):
# on Windows
self.assertLess(stop - start, 0.020)
- # bpo-33723: A busy loop of 100 ms should increase process_time()
- # by at least 15 ms
- min_time = 0.015
- busy_time = 0.100
-
- # process_time() should include CPU time spent in any thread
- start = time.process_time()
- busy_wait(busy_time)
- stop = time.process_time()
- self.assertGreaterEqual(stop - start, min_time)
-
- t = threading.Thread(target=busy_wait, args=(busy_time,))
- start = time.process_time()
- t.start()
- t.join()
- stop = time.process_time()
- self.assertGreaterEqual(stop - start, min_time)
-
info = time.get_clock_info('process_time')
self.assertTrue(info.monotonic)
self.assertFalse(info.adjustable)
# on Windows
self.assertLess(stop - start, 0.020)
- # bpo-33723: A busy loop of 100 ms should increase thread_time()
- # by at least 15 ms
- min_time = 0.015
- busy_time = 0.100
-
- # thread_time() should include CPU time spent in current thread...
- start = time.thread_time()
- busy_wait(busy_time)
- stop = time.thread_time()
- self.assertGreaterEqual(stop - start, min_time)
-
- # ...but not in other threads
- t = threading.Thread(target=busy_wait, args=(busy_time,))
- start = time.thread_time()
- t.start()
- t.join()
- stop = time.thread_time()
- self.assertLess(stop - start, min_time)
-
info = time.get_clock_info('thread_time')
self.assertTrue(info.monotonic)
self.assertFalse(info.adjustable)
self.assertIsSubclass(MyDefDict, collections.defaultdict)
self.assertNotIsSubclass(collections.defaultdict, MyDefDict)
+ def test_ordereddict_instantiation(self):
+ self.assertIs(type(typing.OrderedDict()), collections.OrderedDict)
+ self.assertIs(type(typing.OrderedDict[KT, VT]()), collections.OrderedDict)
+ self.assertIs(type(typing.OrderedDict[str, int]()), collections.OrderedDict)
+
+ def test_ordereddict_subclass(self):
+
+ class MyOrdDict(typing.OrderedDict[str, int]):
+ pass
+
+ od = MyOrdDict()
+ self.assertIsInstance(od, MyOrdDict)
+
+ self.assertIsSubclass(MyOrdDict, collections.OrderedDict)
+ self.assertNotIsSubclass(collections.OrderedDict, MyOrdDict)
+
@skipUnless(sys.version_info >= (3, 3), 'ChainMap was added in 3.3')
def test_chainmap_instantiation(self):
self.assertIs(type(typing.ChainMap()), collections.ChainMap)
return _retry_thrice(func, exc, *args, **kwargs)
return wrapped
+# bpo-35411: FTP tests of test_urllib2net randomly fail
+# with "425 Security: Bad IP connecting" on Travis CI
+skip_ftp_test_on_travis = unittest.skipIf('TRAVIS' in os.environ,
+ 'bpo-35411: skip FTP test '
+ 'on Travis CI')
+
+
# Connecting to remote hosts is flaky. Make it more robust by retrying
# the connection several times.
_urlopen_with_retry = _wrap_with_retry_thrice(urllib.request.urlopen,
# XXX The rest of these tests aren't very good -- they don't check much.
# They do sometimes catch some major disasters, though.
+ @skip_ftp_test_on_travis
def test_ftp(self):
urls = [
'ftp://www.pythontest.net/README',
FTP_HOST = 'ftp://www.pythontest.net/'
+ @skip_ftp_test_on_travis
def test_ftp_basic(self):
self.assertIsNone(socket.getdefaulttimeout())
with support.transient_internet(self.FTP_HOST, timeout=None):
self.addCleanup(u.close)
self.assertIsNone(u.fp.fp.raw._sock.gettimeout())
+ @skip_ftp_test_on_travis
def test_ftp_default_timeout(self):
self.assertIsNone(socket.getdefaulttimeout())
with support.transient_internet(self.FTP_HOST):
socket.setdefaulttimeout(None)
self.assertEqual(u.fp.fp.raw._sock.gettimeout(), 60)
+ @skip_ftp_test_on_travis
def test_ftp_no_timeout(self):
self.assertIsNone(socket.getdefaulttimeout())
with support.transient_internet(self.FTP_HOST):
socket.setdefaulttimeout(None)
self.assertIsNone(u.fp.fp.raw._sock.gettimeout())
+ @skip_ftp_test_on_travis
def test_ftp_timeout(self):
with support.transient_internet(self.FTP_HOST):
u = _urlopen_with_retry(self.FTP_HOST, timeout=60)
errors="ignore")
self.assertEqual(result, [('key', '\u0141-')])
+ def test_parse_qsl_max_num_fields(self):
+ with self.assertRaises(ValueError):
+ urllib.parse.parse_qs('&'.join(['a=a']*11), max_num_fields=10)
+ with self.assertRaises(ValueError):
+ urllib.parse.parse_qs(';'.join(['a=a']*11), max_num_fields=10)
+ urllib.parse.parse_qs('&'.join(['a=a']*10), max_num_fields=10)
+
def test_urlencode_sequences(self):
# Other tests incidentally urlencode things; test non-covered cases:
# Sequence and object values.
out, err = p.communicate()
if p.returncode:
raise subprocess.CalledProcessError(
- p.returncode, cmd, None, out, err)
+ p.returncode, cmd, out, err)
return out, err
class BaseTest(unittest.TestCase):
self.assertIn('include-system-site-packages = %s\n' % s, data)
@unittest.skipUnless(can_symlink(), 'Needs symlinks')
+ @unittest.skipIf(os.name == 'nt', 'Symlinks are never used on Windows')
def test_symlinking(self):
"""
Test symlinking works as expected
func()
"""))
- res = assert_python_ok('-Wd', '-X', 'tracemalloc=2', support.TESTFN)
+ def run(*args):
+ res = assert_python_ok(*args)
+ stderr = res.err.decode('ascii', 'replace')
+ stderr = '\n'.join(stderr.splitlines())
- stderr = res.err.decode('ascii', 'replace')
- # normalize newlines
- stderr = '\n'.join(stderr.splitlines())
- stderr = re.sub('<.*>', '<...>', stderr)
+ # normalize newlines
+ stderr = re.sub('<.*>', '<...>', stderr)
+ return stderr
+
+ # tracemalloc disabled
+ stderr = run('-Wd', support.TESTFN)
+ expected = textwrap.dedent('''
+ {fname}:5: ResourceWarning: unclosed file <...>
+ f = None
+ ResourceWarning: Enable tracemalloc to get the object allocation traceback
+ ''')
+ expected = expected.format(fname=support.TESTFN).strip()
+ self.assertEqual(stderr, expected)
+
+ # tracemalloc enabled
+ stderr = run('-Wd', '-X', 'tracemalloc=2', support.TESTFN)
expected = textwrap.dedent('''
{fname}:5: ResourceWarning: unclosed file <...>
f = None
webbrowser = support.import_fresh_module('webbrowser')
webbrowser.get()
+ def test_environment_preferred(self):
+ webbrowser = support.import_fresh_module('webbrowser')
+ try:
+ webbrowser.get()
+ least_preferred_browser = webbrowser.get(webbrowser._tryorder[-1]).name
+ except (webbrowser.Error, AttributeError, IndexError) as err:
+ self.skipTest(str(err))
+
+ with support.EnvironmentVarGuard() as env:
+ env["BROWSER"] = least_preferred_browser
+ webbrowser = support.import_fresh_module('webbrowser')
+ self.assertEqual(webbrowser.get().name, least_preferred_browser)
+
+ with support.EnvironmentVarGuard() as env:
+ env["BROWSER"] = sys.executable
+ webbrowser = support.import_fresh_module('webbrowser')
+ self.assertEqual(webbrowser.get().name, sys.executable)
+
if __name__=='__main__':
unittest.main()
mye = MyElement('joe')
self.assertEqual(mye.newmethod(), 'joe')
+ def test_Element_subclass_find(self):
+ class MyElement(ET.Element):
+ pass
+
+ e = ET.Element('foo')
+ e.text = 'text'
+ sub = MyElement('bar')
+ sub.text = 'subtext'
+ e.append(sub)
+ self.assertEqual(e.findtext('bar'), 'subtext')
+ self.assertEqual(e.find('bar').tag, 'bar')
+ found = list(e.findall('bar'))
+ self.assertEqual(len(found), 1, found)
+ self.assertEqual(found[0].tag, 'bar')
+
class ElementFindTest(unittest.TestCase):
def test_find_simple(self):
elem.tail = X()
elem.__setstate__({'tag': 42}) # shouldn't cause an assertion failure
+ def test_setstate_leaks(self):
+ # Test reference leaks
+ elem = cET.Element.__new__(cET.Element)
+ for i in range(100):
+ elem.__setstate__({'tag': 'foo', 'attrib': {'bar': 42},
+ '_children': [cET.Element('child')],
+ 'text': 'text goes here',
+ 'tail': 'opposite of head'})
+
+ self.assertEqual(elem.tag, 'foo')
+ self.assertEqual(elem.text, 'text goes here')
+ self.assertEqual(elem.tail, 'opposite of head')
+ self.assertEqual(list(elem.attrib.items()), [('bar', 42)])
+ self.assertEqual(len(elem), 1)
+ self.assertEqual(elem[0].tag, 'child')
+
@unittest.skipUnless(cET, 'requires _elementtree')
class TestAliasWorking(unittest.TestCase):
select to commands. If the selection isn't currently in
the spinbox, then a new selection is created to include
the characters between index and the most recent selection
- anchor point, inclusive. Returns an empty string.
+ anchor point, inclusive.
"""
return self.selection("adjust", index)
"""Clear the selection
If the selection isn't in this widget then the
- command has no effect. Returns an empty string.
+ command has no effect.
"""
return self.selection("clear")
"""Sets or gets the currently selected element.
If a spinbutton element is specified, it will be
- displayed depressed
+ displayed depressed.
"""
- return self.selection("element", element)
+ return self.tk.call(self._w, 'selection', 'element', element)
###########################################################################
def deco(test):
@functools.wraps(test)
def newtest(self):
- if get_tk_patchlevel() < (8, 6, 5):
+ if get_tk_patchlevel() < version:
self.skipTest('requires Tcl version >= ' +
- '.'.join(map(str, get_tk_patchlevel())))
+ '.'.join(map(str, version)))
test(self)
return newtest
return deco
self.assertRaises(TypeError, widget.bbox)
self.assertRaises(TypeError, widget.bbox, 0, 1)
+ def test_selection_element(self):
+ widget = self.create()
+ self.assertEqual(widget.selection_element(), "none")
+ widget.selection_element("buttonup")
+ self.assertEqual(widget.selection_element(), "buttonup")
+ widget.selection_element("buttondown")
+ self.assertEqual(widget.selection_element(), "buttondown")
+
@add_standard_options(StandardOptionsTests)
class TextTest(AbstractWidgetTest, unittest.TestCase):
try:
outfile = open(path, "w", encoding=encoding)
except OSError as err:
- print(("trace: Could not open %r for writing: %s"
+ print(("trace: Could not open %r for writing: %s "
"- skipping" % (path, err)), file=sys.stderr)
return 0, 0
grp = parser.add_argument_group('Filters',
'Can be specified multiple times')
grp.add_argument('--ignore-module', action='append', default=[],
- help='Ignore the given module(s) and its submodules'
+ help='Ignore the given module(s) and its submodules '
'(if it is a package). Accepts comma separated list of '
'module names.')
grp.add_argument('--ignore-dir', action='append', default=[],
Arguments:
fun -- a function with two arguments, the coordinates of the
clicked point on the canvas.
- num -- the number of the mouse-button, defaults to 1
+ btn -- the number of the mouse-button, defaults to 1
Example (for a TurtleScreen instance named screen)
Arguments:
fun -- a function with two arguments, to which will be assigned
the coordinates of the clicked point on the canvas.
- num -- number of the mouse-button defaults to 1 (left mouse button).
+ btn -- number of the mouse-button defaults to 1 (left mouse button).
add -- True or False. If True, new binding will be added, otherwise
it will replace a former binding.
Arguments:
fun -- a function with two arguments, to which will be assigned
the coordinates of the clicked point on the canvas.
- num -- number of the mouse-button defaults to 1 (left mouse button).
+ btn -- number of the mouse-button defaults to 1 (left mouse button).
Example (for a MyTurtle instance named joe):
>>> class MyTurtle(Turtle):
Arguments:
fun -- a function with two arguments, to which will be assigned
the coordinates of the clicked point on the canvas.
- num -- number of the mouse-button defaults to 1 (left mouse button).
+ btn -- number of the mouse-button defaults to 1 (left mouse button).
Every sequence of mouse-move-events on a turtle is preceded by a
mouse-click event on that turtle.
if (isinstance(arg, _GenericAlias) and
arg.__origin__ in invalid_generic_forms):
raise TypeError(f"{arg} is not valid as type argument")
- if (isinstance(arg, _SpecialForm) and arg is not Any or
+ if (isinstance(arg, _SpecialForm) and arg not in (Any, NoReturn) or
arg in (Generic, _Protocol)):
raise TypeError(f"Plain {arg} is not valid as type argument")
if isinstance(arg, (type, TypeVar, ForwardRef)):
AsyncContextManager = _alias(contextlib.AbstractAsyncContextManager, T_co)
Dict = _alias(dict, (KT, VT), inst=False)
DefaultDict = _alias(collections.defaultdict, (KT, VT))
+OrderedDict = _alias(collections.OrderedDict, (KT, VT))
Counter = _alias(collections.Counter, T)
ChainMap = _alias(collections.ChainMap, (KT, VT))
Generator = _alias(collections.abc.Generator, (T_co, T_contra, V_co))
self._mock_side_effect = None
for child in self._mock_children.values():
- if isinstance(child, _SpecState):
+ if isinstance(child, _SpecState) or child is _deleted:
continue
child.reset_mock(visited)
self = _mock_self
self.called = True
self.call_count += 1
- _new_name = self._mock_new_name
- _new_parent = self._mock_new_parent
+ # handle call_args
_call = _Call((args, kwargs), two=True)
self.call_args = _call
self.call_args_list.append(_call)
- self.mock_calls.append(_Call(('', args, kwargs)))
seen = set()
- skip_next_dot = _new_name == '()'
+
+ # initial stuff for method_calls:
do_method_calls = self._mock_parent is not None
- name = self._mock_name
- while _new_parent is not None:
- this_mock_call = _Call((_new_name, args, kwargs))
- if _new_parent._mock_new_name:
- dot = '.'
- if skip_next_dot:
- dot = ''
+ method_call_name = self._mock_name
- skip_next_dot = False
- if _new_parent._mock_new_name == '()':
- skip_next_dot = True
+ # initial stuff for mock_calls:
+ mock_call_name = self._mock_new_name
+ is_a_call = mock_call_name == '()'
+ self.mock_calls.append(_Call(('', args, kwargs)))
- _new_name = _new_parent._mock_new_name + dot + _new_name
+ # follow up the chain of mocks:
+ _new_parent = self._mock_new_parent
+ while _new_parent is not None:
+ # handle method_calls:
if do_method_calls:
- if _new_name == name:
- this_method_call = this_mock_call
- else:
- this_method_call = _Call((name, args, kwargs))
- _new_parent.method_calls.append(this_method_call)
-
+ _new_parent.method_calls.append(_Call((method_call_name, args, kwargs)))
do_method_calls = _new_parent._mock_parent is not None
if do_method_calls:
- name = _new_parent._mock_name + '.' + name
+ method_call_name = _new_parent._mock_name + '.' + method_call_name
+ # handle mock_calls:
+ this_mock_call = _Call((mock_call_name, args, kwargs))
_new_parent.mock_calls.append(this_mock_call)
+
+ if _new_parent._mock_new_name:
+ if is_a_call:
+ dot = ''
+ else:
+ dot = '.'
+ is_a_call = _new_parent._mock_new_name == '()'
+ mock_call_name = _new_parent._mock_new_name + dot + mock_call_name
+
+ # follow the parental chain:
_new_parent = _new_parent._mock_new_parent
- # use ids here so as not to call __hash__ on the mocks
+ # check we're not in an infinite loop:
+ # ( use ids here so as not to call __hash__ on the mocks)
_new_parent_id = id(_new_parent)
if _new_parent_id in seen:
break
seen.add(_new_parent_id)
- ret_val = DEFAULT
effect = self.side_effect
if effect is not None:
if _is_exception(effect):
raise effect
-
- if not _callable(effect):
+ elif not _callable(effect):
result = next(effect)
if _is_exception(result):
raise result
- if result is DEFAULT:
- result = self.return_value
+ else:
+ result = effect(*args, **kwargs)
+
+ if result is not DEFAULT:
return result
- ret_val = effect(*args, **kwargs)
+ if self._mock_return_value is not DEFAULT:
+ return self.return_value
- if (self._mock_wraps is not None and
- self._mock_return_value is DEFAULT):
+ if self._mock_wraps is not None:
return self._mock_wraps(*args, **kwargs)
- if ret_val is DEFAULT:
- ret_val = self.return_value
- return ret_val
+
+ return self.return_value
_unsupported_magics = {
'__getattr__', '__setattr__',
- '__init__', '__new__', '__prepare__'
+ '__init__', '__new__', '__prepare__',
'__instancecheck__', '__subclasscheck__',
'__del__'
}
def __init__(self, value=(), name=None, parent=None, two=False,
from_kall=True):
- self.name = name
- self.parent = parent
- self.from_kall = from_kall
+ self._mock_name = name
+ self._mock_parent = parent
+ self._mock_from_kall = from_kall
def __eq__(self, other):
else:
self_name, self_args, self_kwargs = self
+ if (getattr(self, '_mock_parent', None) and getattr(other, '_mock_parent', None)
+ and self._mock_parent != other._mock_parent):
+ return False
+
other_name = ''
if len_other == 0:
other_args, other_kwargs = (), {}
def __call__(self, *args, **kwargs):
- if self.name is None:
+ if self._mock_name is None:
return _Call(('', args, kwargs), name='()')
- name = self.name + '()'
- return _Call((self.name, args, kwargs), name=name, parent=self)
+ name = self._mock_name + '()'
+ return _Call((self._mock_name, args, kwargs), name=name, parent=self)
def __getattr__(self, attr):
- if self.name is None:
+ if self._mock_name is None:
return _Call(name=attr, from_kall=False)
- name = '%s.%s' % (self.name, attr)
+ name = '%s.%s' % (self._mock_name, attr)
return _Call(name=name, parent=self, from_kall=False)
return self.__getattr__('index')(*args, **kwargs)
def __repr__(self):
- if not self.from_kall:
- name = self.name or 'call'
+ if not self._mock_from_kall:
+ name = self._mock_name or 'call'
if name.startswith('()'):
name = 'call%s' % name
return name
vals = []
thing = self
while thing is not None:
- if thing.from_kall:
+ if thing._mock_from_kall:
vals.append(thing)
- thing = thing.parent
+ thing = thing._mock_parent
return _CallList(reversed(vals))
def seal(mock):
- """Disable the automatic generation of "submocks"
+ """Disable the automatic generation of child mocks.
Given an input Mock, seals it to ensure no further mocks will be generated
when accessing an attribute that was not already defined.
- Submocks are defined as all mocks which were created DIRECTLY from the
- parent. If a mock is assigned to an attribute of an existing mock,
- it is not considered a submock.
-
+ The operation recursively seals the mock passed in, meaning that
+ the mock itself, any mocks generated by accessing one of its attributes,
+ and all assigned mocks without a name or spec will be sealed.
"""
mock._mock_sealed = True
for attr in dir(mock):
result.foo.assert_called_once_with(3, 2, 1)
- def test_create_autopsec(self):
+ def test_create_autospec(self):
mock = create_autospec(X)
instance = mock()
self.assertRaises(TypeError, instance)
)
from datetime import datetime
+from functools import partial
class SomeClass(object):
def one(self, a, b):
self.assertEqual(mock.mock_calls, last_call.call_list())
+ def test_extended_not_equal(self):
+ a = call(x=1).foo
+ b = call(x=2).foo
+ self.assertEqual(a, a)
+ self.assertEqual(b, b)
+ self.assertNotEqual(a, b)
+
+
+ def test_nested_calls_not_equal(self):
+ a = call(x=1).foo().bar
+ b = call(x=2).foo().bar
+ self.assertEqual(a, a)
+ self.assertEqual(b, b)
+ self.assertNotEqual(a, b)
+
+
def test_call_list(self):
mock = MagicMock()
mock(1)
mocked.assert_called_once_with(4, 5, 6)
+ def test_autospec_getattr_partial_function(self):
+ # bpo-32153 : getattr returning partial functions without
+ # __name__ should not create AttributeError in create_autospec
+ class Foo:
+
+ def __getattr__(self, attribute):
+ return partial(lambda name: name, attribute)
+
+ proxy = Foo()
+ autospec = create_autospec(proxy)
+ self.assertFalse(hasattr(autospec, '__name__'))
+
+
class TestCallList(unittest.TestCase):
def test_args_list_contains_call_list(self):
from unittest.mock import (
call, DEFAULT, patch, sentinel,
MagicMock, Mock, NonCallableMock,
- NonCallableMagicMock, _CallList,
+ NonCallableMagicMock, _Call, _CallList,
create_autospec
)
real.assert_called_with(1, 2, fish=3)
+ def test_wraps_prevents_automatic_creation_of_mocks(self):
+ class Real(object):
+ pass
+
+ real = Real()
+ mock = Mock(wraps=real)
+
+ self.assertRaises(AttributeError, lambda: mock.new_attr())
+
+
def test_wraps_call_with_nondefault_return_value(self):
real = Mock()
self.assertEqual(result, Real.attribute.frog())
+ def test_customize_wrapped_object_with_side_effect_iterable_with_default(self):
+ class Real(object):
+ def method(self):
+ return sentinel.ORIGINAL_VALUE
+
+ real = Real()
+ mock = Mock(wraps=real)
+ mock.method.side_effect = [sentinel.VALUE1, DEFAULT]
+
+ self.assertEqual(mock.method(), sentinel.VALUE1)
+ self.assertEqual(mock.method(), sentinel.ORIGINAL_VALUE)
+ self.assertRaises(StopIteration, mock.method)
+
+
+ def test_customize_wrapped_object_with_side_effect_iterable(self):
+ class Real(object):
+ def method(self):
+ raise NotImplementedError()
+
+ real = Real()
+ mock = Mock(wraps=real)
+ mock.method.side_effect = [sentinel.VALUE1, sentinel.VALUE2]
+
+ self.assertEqual(mock.method(), sentinel.VALUE1)
+ self.assertEqual(mock.method(), sentinel.VALUE2)
+ self.assertRaises(StopIteration, mock.method)
+
+
+ def test_customize_wrapped_object_with_side_effect_exception(self):
+ class Real(object):
+ def method(self):
+ raise NotImplementedError()
+
+ real = Real()
+ mock = Mock(wraps=real)
+ mock.method.side_effect = RuntimeError
+
+ self.assertRaises(RuntimeError, mock.method)
+
+
+ def test_customize_wrapped_object_with_side_effect_function(self):
+ class Real(object):
+ def method(self):
+ raise NotImplementedError()
+
+ def side_effect():
+ return sentinel.VALUE
+
+ real = Real()
+ mock = Mock(wraps=real)
+ mock.method.side_effect = side_effect
+
+ self.assertEqual(mock.method(), sentinel.VALUE)
+
+
+ def test_customize_wrapped_object_with_return_value(self):
+ class Real(object):
+ def method(self):
+ raise NotImplementedError()
+
+ real = Real()
+ mock = Mock(wraps=real)
+ mock.method.return_value = sentinel.VALUE
+
+ self.assertEqual(mock.method(), sentinel.VALUE)
+
+
+ def test_customize_wrapped_object_with_return_value_and_side_effect(self):
+ # side_effect should always take precedence over return_value.
+ class Real(object):
+ def method(self):
+ raise NotImplementedError()
+
+ real = Real()
+ mock = Mock(wraps=real)
+ mock.method.side_effect = [sentinel.VALUE1, sentinel.VALUE2]
+ mock.method.return_value = sentinel.WRONG_VALUE
+
+ self.assertEqual(mock.method(), sentinel.VALUE1)
+ self.assertEqual(mock.method(), sentinel.VALUE2)
+ self.assertRaises(StopIteration, mock.method)
+
+
+ def test_customize_wrapped_object_with_return_value_and_side_effect2(self):
+ # side_effect can return DEFAULT to default to return_value
+ class Real(object):
+ def method(self):
+ raise NotImplementedError()
+
+ real = Real()
+ mock = Mock(wraps=real)
+ mock.method.side_effect = lambda: DEFAULT
+ mock.method.return_value = sentinel.VALUE
+
+ self.assertEqual(mock.method(), sentinel.VALUE)
+
+
+ def test_customize_wrapped_object_with_return_value_and_side_effect_default(self):
+ class Real(object):
+ def method(self):
+ raise NotImplementedError()
+
+ real = Real()
+ mock = Mock(wraps=real)
+ mock.method.side_effect = [sentinel.VALUE1, DEFAULT]
+ mock.method.return_value = sentinel.RETURN
+
+ self.assertEqual(mock.method(), sentinel.VALUE1)
+ self.assertEqual(mock.method(), sentinel.RETURN)
+ self.assertRaises(StopIteration, mock.method)
+
+
def test_exceptional_side_effect(self):
mock = Mock(side_effect=AttributeError)
self.assertRaises(AttributeError, mock)
call().__int__().call_list())
+ def test_child_mock_call_equal(self):
+ m = Mock()
+ result = m()
+ result.wibble()
+ # parent looks like this:
+ self.assertEqual(m.mock_calls, [call(), call().wibble()])
+ # but child should look like this:
+ self.assertEqual(result.mock_calls, [call.wibble()])
+
+
+ def test_mock_call_not_equal_leaf(self):
+ m = Mock()
+ m.foo().something()
+ self.assertNotEqual(m.mock_calls[1], call.foo().different())
+ self.assertEqual(m.mock_calls[0], call.foo())
+
+
+ def test_mock_call_not_equal_non_leaf(self):
+ m = Mock()
+ m.foo().bar()
+ self.assertNotEqual(m.mock_calls[1], call.baz().bar())
+ self.assertNotEqual(m.mock_calls[0], call.baz())
+
+
+ def test_mock_call_not_equal_non_leaf_params_different(self):
+ m = Mock()
+ m.foo(x=1).bar()
+ # This isn't ideal, but there's no way to fix it without breaking backwards compatibility:
+ self.assertEqual(m.mock_calls[1], call.foo(x=2).bar())
+
+
+ def test_mock_call_not_equal_non_leaf_attr(self):
+ m = Mock()
+ m.foo.bar()
+ self.assertNotEqual(m.mock_calls[0], call.baz.bar())
+
+
+ def test_mock_call_not_equal_non_leaf_call_versus_attr(self):
+ m = Mock()
+ m.foo.bar()
+ self.assertNotEqual(m.mock_calls[0], call.foo().bar())
+
+
+ def test_mock_call_repr(self):
+ m = Mock()
+ m.foo().bar().baz.bob()
+ self.assertEqual(repr(m.mock_calls[0]), 'call.foo()')
+ self.assertEqual(repr(m.mock_calls[1]), 'call.foo().bar()')
+ self.assertEqual(repr(m.mock_calls[2]), 'call.foo().bar().baz.bob()')
+
+
def test_subclassing(self):
class Subclass(Mock):
pass
self.assertRaises(AttributeError, getattr, mock, 'f')
+ def test_reset_mock_does_not_raise_on_attr_deletion(self):
+ # bpo-31177: reset_mock should not raise AttributeError when attributes
+ # were deleted in a mock instance
+ mock = Mock()
+ mock.child = True
+ del mock.child
+ mock.reset_mock()
+ self.assertFalse(hasattr(mock, 'child'))
+
+
def test_class_assignable(self):
for mock in Mock(), MagicMock():
self.assertNotIsInstance(mock, int)
self.assertIsInstance(mock, int)
mock.foo
+ def test_name_attribute_of_call(self):
+ # bpo-35357: _Call should not disclose any attributes whose names
+ # may clash with popular ones (such as ".name")
+ self.assertIsNotNone(call.name)
+ self.assertEqual(type(call.name), _Call)
+ self.assertEqual(type(call.name().name), _Call)
+
+ def test_parent_attribute_of_call(self):
+ # bpo-35357: _Call should not disclose any attributes whose names
+ # may clash with popular ones (such as ".parent")
+ self.assertIsNotNone(call.parent)
+ self.assertEqual(type(call.parent), _Call)
+ self.assertEqual(type(call.parent().parent), _Call)
+
if __name__ == '__main__':
unittest.main()
from unittest.test.testmock import support
from unittest.test.testmock.support import SomeClass, is_instance
+from test.test_importlib.util import uncache
from unittest.mock import (
NonCallableMock, CallableMixin, sentinel,
MagicMock, Mock, NonCallableMagicMock, patch, _patch,
def test_patch_imports_lazily(self):
- sys.modules.pop('squizz', None)
-
p1 = patch('squizz.squozz')
self.assertRaises(ImportError, p1.start)
- squizz = Mock()
- squizz.squozz = 6
- sys.modules['squizz'] = squizz
- p1 = patch('squizz.squozz')
- squizz.squozz = 3
- p1.start()
- p1.stop()
- self.assertEqual(squizz.squozz, 3)
+ with uncache('squizz'):
+ squizz = Mock()
+ sys.modules['squizz'] = squizz
+ squizz.squozz = 6
+ p1 = patch('squizz.squozz')
+ squizz.squozz = 3
+ p1.start()
+ p1.stop()
+ self.assertEqual(squizz.squozz, 3)
def test_patch_propogrates_exc_on_exit(self):
class holder:
def test(mock):
raise RuntimeError
- self.assertRaises(RuntimeError, test)
+ with uncache('squizz'):
+ squizz = Mock()
+ sys.modules['squizz'] = squizz
+
+ self.assertRaises(RuntimeError, test)
+
self.assertIs(holder.exc_info[0], RuntimeError)
self.assertIsNotNone(holder.exc_info[1],
'exception value not propgated')
def parse_qs(qs, keep_blank_values=False, strict_parsing=False,
- encoding='utf-8', errors='replace'):
+ encoding='utf-8', errors='replace', max_num_fields=None):
"""Parse a query given as a string argument.
Arguments:
encoding and errors: specify how to decode percent-encoded sequences
into Unicode characters, as accepted by the bytes.decode() method.
+ max_num_fields: int. If set, then throws a ValueError if there
+ are more than n fields read by parse_qsl().
+
Returns a dictionary.
"""
parsed_result = {}
pairs = parse_qsl(qs, keep_blank_values, strict_parsing,
- encoding=encoding, errors=errors)
+ encoding=encoding, errors=errors,
+ max_num_fields=max_num_fields)
for name, value in pairs:
if name in parsed_result:
parsed_result[name].append(value)
def parse_qsl(qs, keep_blank_values=False, strict_parsing=False,
- encoding='utf-8', errors='replace'):
+ encoding='utf-8', errors='replace', max_num_fields=None):
"""Parse a query given as a string argument.
Arguments:
encoding and errors: specify how to decode percent-encoded sequences
into Unicode characters, as accepted by the bytes.decode() method.
+ max_num_fields: int. If set, then throws a ValueError
+ if there are more than n fields read by parse_qsl().
+
Returns a list, as G-d intended.
"""
qs, _coerce_result = _coerce_args(qs)
+
+ # If max_num_fields is defined then check that the number of fields
+ # is less than max_num_fields. This prevents a memory exhaustion DOS
+ # attack via post bodies with many fields.
+ if max_num_fields is not None:
+ num_fields = 1 + qs.count('&') + qs.count(';')
+ if max_num_fields < num_fields:
+ raise ValueError('Max number of fields exceeded')
+
pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
r = []
for name_value in pairs:
global _opener
if cafile or capath or cadefault:
import warnings
- warnings.warn("cafile, cpath and cadefault are deprecated, use a "
+ warnings.warn("cafile, capath and cadefault are deprecated, use a "
"custom context instead.", DeprecationWarning, 2)
if context is not None:
raise ValueError(
import shutil
import subprocess
import sys
+import sysconfig
import types
logger = logging.getLogger(__name__)
self.system_site_packages = False
self.create_configuration(context)
self.setup_python(context)
+ if not self.upgrade:
+ self.setup_scripts(context)
if self.with_pip:
self._setup_pip(context)
if not self.upgrade:
- self.setup_scripts(context)
self.post_setup(context)
if true_system_site_packages:
# We had set it to False before, now
f.write('include-system-site-packages = %s\n' % incl)
f.write('version = %d.%d.%d\n' % sys.version_info[:3])
- if os.name == 'nt':
- def include_binary(self, f):
- if f.endswith(('.pyd', '.dll')):
- result = True
- else:
- result = f.startswith('python') and f.endswith('.exe')
- return result
-
def symlink_or_copy(self, src, dst, relative_symlinks_ok=False):
"""
Try symlinking a file, and if that fails, fall back to copying.
binpath = context.bin_path
path = context.env_exe
copier = self.symlink_or_copy
- copier(context.executable, path)
dirname = context.python_dir
if os.name != 'nt':
+ copier(context.executable, path)
if not os.path.islink(path):
os.chmod(path, 0o755)
for suffix in ('python', 'python3'):
if not os.path.islink(path):
os.chmod(path, 0o755)
else:
- subdir = 'DLLs'
- include = self.include_binary
- files = [f for f in os.listdir(dirname) if include(f)]
- for f in files:
- src = os.path.join(dirname, f)
- dst = os.path.join(binpath, f)
- if dst != context.env_exe: # already done, above
- copier(src, dst)
- dirname = os.path.join(dirname, subdir)
- if os.path.isdir(dirname):
- files = [f for f in os.listdir(dirname) if include(f)]
- for f in files:
- src = os.path.join(dirname, f)
- dst = os.path.join(binpath, f)
- copier(src, dst)
- # copy init.tcl over
- for root, dirs, files in os.walk(context.python_dir):
- if 'init.tcl' in files:
- tcldir = os.path.basename(root)
- tcldir = os.path.join(context.env_dir, 'Lib', tcldir)
- if not os.path.exists(tcldir):
- os.makedirs(tcldir)
- src = os.path.join(root, 'init.tcl')
- dst = os.path.join(tcldir, 'init.tcl')
- shutil.copyfile(src, dst)
- break
+ # For normal cases, the venvlauncher will be copied from
+ # our scripts folder. For builds, we need to copy it
+ # manually.
+ if sysconfig.is_python_build(True):
+ suffix = '.exe'
+ if context.python_exe.lower().endswith('_d.exe'):
+ suffix = '_d.exe'
+
+ src = os.path.join(dirname, "venvlauncher" + suffix)
+ dst = os.path.join(binpath, context.python_exe)
+ copier(src, dst)
+
+ src = os.path.join(dirname, "venvwlauncher" + suffix)
+ dst = os.path.join(binpath, "pythonw" + suffix)
+ copier(src, dst)
+
+ # copy init.tcl over
+ for root, dirs, files in os.walk(context.python_dir):
+ if 'init.tcl' in files:
+ tcldir = os.path.basename(root)
+ tcldir = os.path.join(context.env_dir, 'Lib', tcldir)
+ if not os.path.exists(tcldir):
+ os.makedirs(tcldir)
+ src = os.path.join(root, 'init.tcl')
+ dst = os.path.join(tcldir, 'init.tcl')
+ shutil.copyfile(src, dst)
+ break
def _setup_pip(self, context):
"""Installs or upgrades pip in a virtual environment"""
dstfile = os.path.join(dstdir, f)
with open(srcfile, 'rb') as f:
data = f.read()
- if not srcfile.endswith('.exe'):
+ if not srcfile.endswith(('.exe', '.pdb')):
try:
data = data.decode('utf-8')
data = self.replace_variables(data, context)
pass
def _formatwarnmsg_impl(msg):
- s = ("%s:%s: %s: %s\n"
- % (msg.filename, msg.lineno, msg.category.__name__,
- msg.message))
+ category = msg.category.__name__
+ s = f"{msg.filename}:{msg.lineno}: {category}: {msg.message}\n"
if msg.line is None:
try:
if msg.source is not None:
try:
import tracemalloc
- tb = tracemalloc.get_object_traceback(msg.source)
+ # Logging a warning should not raise a new exception:
+ # catch Exception, not only ImportError and RecursionError.
except Exception:
- # When a warning is logged during Python shutdown, tracemalloc
- # and the import machinery don't work anymore
+ # don't suggest to enable tracemalloc if it's not available
+ tracing = True
tb = None
+ else:
+ tracing = tracemalloc.is_tracing()
+ try:
+ tb = tracemalloc.get_object_traceback(msg.source)
+ except Exception:
+ # When a warning is logged during Python shutdown, tracemalloc
+ # and the import machinery don't work anymore
+ tb = None
if tb is not None:
s += 'Object allocated at (most recent call last):\n'
if line:
line = line.strip()
s += ' %s\n' % line
+ elif not tracing:
+ s += (f'{category}: Enable tracemalloc to get the object '
+ f'allocation traceback\n')
return s
# Keep a reference to check if the function was replaced
return open(url, 2)
-def _synthesize(browser, *, preferred=True):
+def _synthesize(browser, *, preferred=False):
"""Attempt to synthesize a controller base on existing controllers.
This is useful to create a controller when a user specifies a path to
# and prepend to _tryorder
for cmdline in userchoices:
if cmdline != '':
- cmd = _synthesize(cmdline, preferred=False)
+ cmd = _synthesize(cmdline, preferred=True)
if cmd[1] is None:
register(cmdline, None, GenericBrowser(cmdline), preferred=True)
# should be published by posting to xml-sig@python.org, and are
# subsequently recorded in this file.
+import sys
+
well_known_implementations = {
'minidom':'xml.dom.minidom',
'4DOM': 'xml.dom.DOMImplementation',
return mod.getDOMImplementation()
elif name:
return registered[name]()
- elif "PYTHON_DOM" in os.environ:
+ elif not sys.flags.ignore_environment and "PYTHON_DOM" in os.environ:
return getDOMImplementation(name = os.environ["PYTHON_DOM"])
# User did not specify a name, try implementations in arbitrary
entity.encoding = e.encoding
entity.version = e.version
clone.entities._seq.append(entity)
- e._call_user_data_handler(operation, n, entity)
+ e._call_user_data_handler(operation, e, entity)
self._call_user_data_handler(operation, self, clone)
return clone
else:
entity.ownerDocument = newOwnerDocument
clone.entities._seq.append(entity)
if hasattr(e, '_call_user_data_handler'):
- e._call_user_data_handler(operation, n, entity)
+ e._call_user_data_handler(operation, e, entity)
else:
# Note the cloning of Document and DocumentType nodes is
# implementation specific. minidom handles those cases
import xml.sax.expatreader
import os, sys
-if "PY_SAX_PARSER" in os.environ:
+if not sys.flags.ignore_environment and "PY_SAX_PARSER" in os.environ:
default_parser_list = os.environ["PY_SAX_PARSER"].split(",")
del os
return ''.join(result)
def FileHeader(self, zip64=None):
- """Return the per-file header as a string."""
+ """Return the per-file header as a bytes object."""
dt = self.date_time
dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
self._didModify = True
def read(self, name, pwd=None):
- """Return file bytes (as a string) for name."""
+ """Return file bytes for name."""
with self.open(name, "r", pwd) as fp:
return fp.read()
result.extend([
dict(
- name="OpenSSL 1.1.0i",
- url="https://www.openssl.org/source/openssl-1.1.0i.tar.gz",
- checksum='9495126aafd2659d357ea66a969c3fe1',
+ name="OpenSSL 1.1.0j",
+ url="https://www.openssl.org/source/openssl-1.1.0j.tar.gz",
+ checksum='b4ca5b78ae6ae79da80790b30dbedbdc',
buildrecipe=build_universal_openssl,
configure=None,
install=None,
if internalTk():
result.extend([
dict(
- name="Tcl 8.6.8",
- url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tcl8.6.8-src.tar.gz",
- checksum='81656d3367af032e0ae6157eff134f89',
+ name="Tcl 8.6.9",
+ url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tcl8.6.9-src.tar.gz",
+ checksum='aa0a121d95a0e7b73a036f26028538d4',
buildDir="unix",
configure_pre=[
'--enable-shared',
},
),
dict(
- name="Tk 8.6.8",
- url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tk8.6.8-src.tar.gz",
- checksum='5e0faecba458ee1386078fb228d008ba',
- patches=[
- "tk868_on_10_8_10_9.patch",
- ],
+ name="Tk 8.6.9.1",
+ url="ftp://ftp.tcl.tk/pub/tcl//tcl8_6/tk8.6.9.1-src.tar.gz",
+ checksum='9efe3976468352dc894dae0c4e785a8e',
buildDir="unix",
configure_pre=[
'--enable-aqua',
work for current Tcl and Tk source releases where the basename of
the archive ends with "-src" but the uncompressed directory does not.
For now, just special case Tcl and Tk tar.gz downloads.
+ Another special case: the tk8.6.9.1 tarball extracts to tk8.6.9.
"""
curdir = os.getcwd()
try:
if ((retval.startswith('tcl') or retval.startswith('tk'))
and retval.endswith('-src')):
retval = retval[:-4]
+ if retval == 'tk8.6.9.1':
+ retval = 'tk8.6.9'
if os.path.exists(retval):
shutil.rmtree(retval)
fp = os.popen("tar zxf %s 2>&1"%(shellQuote(archiveName),), 'r')
imagepath = imagepath + '.dmg'
os.mkdir(outdir)
+
+ # Try to mitigate race condition in certain versions of macOS, e.g. 10.9,
+ # when hdiutil create fails with "Resource busy". For now, just retry
+ # the create a few times and hope that it eventually works.
+
volname='Python %s'%(getFullVersion())
- runCommand("hdiutil create -format UDRW -volname %s -srcfolder %s %s"%(
+ cmd = ("hdiutil create -format UDRW -volname %s -srcfolder %s -size 100m %s"%(
shellQuote(volname),
shellQuote(os.path.join(WORKDIR, 'installer')),
shellQuote(imagepath + ".tmp.dmg" )))
-
- # Try to mitigate race condition in certain versions of macOS, e.g. 10.9,
- # when hdiutil fails with "Resource busy"
-
- time.sleep(10)
+ for i in range(5):
+ fd = os.popen(cmd, 'r')
+ data = fd.read()
+ xit = fd.close()
+ if not xit:
+ break
+ sys.stdout.write(data)
+ print(" -- retrying hdiutil create")
+ time.sleep(5)
+ else:
+ raise RuntimeError("command failed: %s"%(commandline,))
if not os.path.exists(os.path.join(WORKDIR, "mnt")):
os.mkdir(os.path.join(WORKDIR, "mnt"))
-{\rtf1\ansi\ansicpg1252\cocoartf1561\cocoasubrtf400
-\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\rtf1\ansi\ansicpg1252\cocoartf1671\cocoasubrtf100
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fmodern\fcharset0 CourierNewPSMT;
+}
{\colortbl;\red255\green255\blue255;}
{\*\expandedcolortbl;;}
\paperw11905\paperh16837\margl1440\margr1440\vieww12200\viewh10880\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0
\f0\fs24 \cf0 This package will install
-\b Python $FULL_VERSION
-\b0 for
-\b macOS $MACOSX_DEPLOYMENT_TARGET
-\b0 .\
+\f1\b Python $FULL_VERSION
+\f0\b0 for
+\f1\b macOS $MACOSX_DEPLOYMENT_TARGET
+\f0\b0 .\
\
-\b Python for macOS
-\b0 consists of the Python programming language interpreter, plus a set of programs to allow easy access to it for macOS users including an integrated development environment
-\b IDLE
-\b0 .\
+\f1\b Python for macOS
+\f0\b0 consists of the Python programming language interpreter, plus a set of programs to allow easy access to it for macOS users including an integrated development environment
+\f1\b IDLE
+\f0\b0 .\
+\
+At the end of this install, click on
+\f2 Install Certificates
+\f0 for SSL root certificates\
\
-\b NEW in 3.7.0:
-\b0 two installer variants (10.9+ 64-bit-only, 10.6+ 64-/32-bit), built-in Tcl/Tk 8.6 support (no additional third-party downloads!), OpenSSL 1.1.0, and more!\
+\f1\b NEW in 3.7.0:
+\f0\b0 two installer variants (10.9+ 64-bit-only, 10.6+ 64-/32-bit), built-in Tcl/Tk 8.6 support (no additional third-party downloads!), OpenSSL 1.1.0, and more!\
}
\ No newline at end of file
+++ /dev/null
-Fix build failure with +quartz variant on OS X 10.8 and 10.9.
-Even though Gestalt was deprecated in OS X 10.8, it should work fine
-through OS X 10.9, and its replacement NSOperatingSystemVersion was
-not introduced until OS X 10.10.
-
-Patch from MacPorts project and reported upstream:
-https://trac.macports.org/ticket/55649
---- tk8.6.8/macosx/tkMacOSXXStubs.c.orig 2017-12-06 09:25:08.000000000 -0600
-+++ tk8.6.8-patched/macosx/tkMacOSXXStubs.c 2018-01-06 19:34:17.000000000 -0600
-@@ -175,7 +175,7 @@
- {
- int major, minor, patch;
-
--#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
-+#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
- Gestalt(gestaltSystemVersionMajor, (SInt32*)&major);
- Gestalt(gestaltSystemVersionMinor, (SInt32*)&minor);
- Gestalt(gestaltSystemVersionBugFix, (SInt32*)&patch);
# Use it when a compiler flag should _not_ be part of the distutils CFLAGS
# once Python is installed (Issue #21121).
CONFIGURE_CFLAGS_NODIST=@CFLAGS_NODIST@
+# LDFLAGS_NODIST is used in the same manner as CFLAGS_NODIST.
+# Use it when a linker flag should _not_ be part of the distutils LDFLAGS
+# once Python is installed (bpo-35257)
+CONFIGURE_LDFLAGS_NODIST=@LDFLAGS_NODIST@
CONFIGURE_CPPFLAGS= @CPPFLAGS@
CONFIGURE_LDFLAGS= @LDFLAGS@
# Avoid assigning CFLAGS, LDFLAGS, etc. so users can use them on the
# environment variables
PY_CPPFLAGS= $(BASECPPFLAGS) -I. -I$(srcdir)/Include $(CONFIGURE_CPPFLAGS) $(CPPFLAGS)
PY_LDFLAGS= $(CONFIGURE_LDFLAGS) $(LDFLAGS)
+PY_LDFLAGS_NODIST=$(CONFIGURE_LDFLAGS_NODIST) $(LDFLAGS_NODIST)
NO_AS_NEEDED= @NO_AS_NEEDED@
LDLAST= @LDLAST@
SGI_ABI= @SGI_ABI@
CFLAGSFORSHARED=@CFLAGSFORSHARED@
# C flags used for building the interpreter object files
PY_STDMODULE_CFLAGS= $(PY_CFLAGS) $(PY_CFLAGS_NODIST) $(PY_CPPFLAGS) $(CFLAGSFORSHARED)
+PY_BUILTIN_MODULE_CFLAGS= $(PY_STDMODULE_CFLAGS) -DPy_BUILD_CORE_BUILTIN
PY_CORE_CFLAGS= $(PY_STDMODULE_CFLAGS) -DPy_BUILD_CORE
+# Linker flags used for building the interpreter object files
+PY_CORE_LDFLAGS=$(PY_LDFLAGS) $(PY_LDFLAGS_NODIST)
# Strict or non-strict aliasing flags used to compile dtoa.c, see above
CFLAGS_ALIASING=@CFLAGS_ALIASING@
SHLIB_SUFFIX= @SHLIB_SUFFIX@
EXT_SUFFIX= @EXT_SUFFIX@
LDSHARED= @LDSHARED@ $(PY_LDFLAGS)
-BLDSHARED= @BLDSHARED@ $(PY_LDFLAGS)
+BLDSHARED= @BLDSHARED@ $(PY_CORE_LDFLAGS)
LDCXXSHARED= @LDCXXSHARED@
DESTSHARED= $(BINLIBDEST)/lib-dynload
touch $@
build_all_generate_profile:
- $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS) $(PGO_PROF_GEN_FLAG)" LDFLAGS="$(LDFLAGS) $(PGO_PROF_GEN_FLAG)" LIBS="$(LIBS)"
+ $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LDFLAGS_NODIST="$(LDFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LIBS="$(LIBS)"
run_profile_task:
@ # FIXME: can't run for a cross build
profile-opt: profile-run-stamp
@echo "Rebuilding with profile guided optimizations:"
-rm -f profile-clean-stamp
- $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS) $(PGO_PROF_USE_FLAG)" LDFLAGS="$(LDFLAGS)"
+ $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_USE_FLAG)" LDFLAGS_NODIST="$(LDFLAGS_NODIST)"
# Compile and run with gcov
.PHONY=coverage coverage-lcov coverage-report
# Build the interpreter
$(BUILDPYTHON): Programs/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
- $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
+ $(LINKCC) $(PY_CORE_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
platform: $(BUILDPYTHON) pybuilddir.txt
$(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import sys ; from sysconfig import get_platform ; print("%s-%d.%d" % (get_platform(), *sys.version_info[:2]))' >platform
$(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^
libpython$(LDVERSION).dylib: $(LIBRARY_OBJS)
- $(CC) -dynamiclib -Wl,-single_module $(PY_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \
+ $(CC) -dynamiclib -Wl,-single_module $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \
libpython$(VERSION).sl: $(LIBRARY_OBJS)
$(LIBRARY) \
$(RESSRCDIR)/Info.plist
$(INSTALL) -d -m $(DIRMODE) $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)
- $(CC) -o $(LDLIBRARY) $(PY_LDFLAGS) -dynamiclib \
+ $(CC) -o $(LDLIBRARY) $(PY_CORE_LDFLAGS) -dynamiclib \
-all_load $(LIBRARY) -Wl,-single_module \
-install_name $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK) \
-compatibility_version $(VERSION) \
fi
Programs/_testembed: Programs/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
- $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
+ $(LINKCC) $(PY_CORE_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
############################################################################
# Importlib
Programs/_freeze_importlib.o: Programs/_freeze_importlib.c Makefile
Programs/_freeze_importlib: Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN)
- $(LINKCC) $(PY_LDFLAGS) -o $@ Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
+ $(LINKCC) $(PY_CORE_LDFLAGS) -o $@ Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
.PHONY: regen-importlib
regen-importlib: Programs/_freeze_importlib
$(IO_OBJS): $(IO_H)
$(PGEN): $(PGENOBJS)
- $(CC) $(OPT) $(PY_LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN)
+ $(CC) $(OPT) $(PY_CORE_LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN)
.PHONY: regen-grammar
regen-grammar: $(PGEN)
else true; \
fi; \
done
+ @if test ! -d $(DESTDIR)$(INCLUDEPY)/internal; then \
+ echo "Creating directory $(DESTDIR)$(INCLUDEPY)/internal"; \
+ $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(INCLUDEPY)/internal; \
+ else true; \
+ fi
@for i in $(srcdir)/Include/*.h; \
do \
echo $(INSTALL_DATA) $$i $(INCLUDEPY); \
$(INSTALL_DATA) $$i $(DESTDIR)$(INCLUDEPY); \
done
+ @for i in $(srcdir)/Include/internal/*.h; \
+ do \
+ echo $(INSTALL_DATA) $$i $(INCLUDEPY)/internal; \
+ $(INSTALL_DATA) $$i $(DESTDIR)$(INCLUDEPY)/internal; \
+ done
$(INSTALL_DATA) pyconfig.h $(DESTDIR)$(CONFINCLUDEPY)/pyconfig.h
# Install the library and miscellaneous stuff needed for extending/embedding
Jonathan Niehof
Gustavo Niemeyer
Oscar Nierstrasz
+Lysandros Nikolaou
Hrvoje Nikšić
Gregory Nofi
Jesse Noller
Python News
+++++++++++
+What's New in Python 3.7.2 final?
+=================================
+
+*Release date: 2018-12-23*
+
+Library
+-------
+
+- bpo-31715: Associate ``.mjs`` file extension with
+ ``application/javascript`` MIME Type.
+
+Build
+-----
+
+- bpo-35499: ``make profile-opt`` no longer replaces ``CFLAGS_NODIST`` with
+ ``CFLAGS``. It now adds profile-guided optimization (PGO) flags to
+ ``CFLAGS_NODIST``: existing ``CFLAGS_NODIST`` flags are kept.
+
+- bpo-35257: Avoid leaking the linker flags from Link Time Optimizations
+ (LTO) into distutils when compiling C extensions.
+
+C API
+-----
+
+- bpo-35259: Conditionally declare :c:func:`Py_FinalizeEx()` (new in 3.6)
+ based on Py_LIMITED_API. Patch by Arthur Neufeld.
+
+
+What's New in Python 3.7.2 release candidate 1?
+===============================================
+
+*Release date: 2018-12-11*
+
+Security
+--------
+
+- bpo-34812: The :option:`-I` command line option (run Python in isolated
+ mode) is now also copied by the :mod:`multiprocessing` and
+ :mod:`distutils` modules when spawning child processes. Previously, only
+ :option:`-E` and :option:`-s` options (enabled by :option:`-I`) were
+ copied.
+
+- bpo-34791: The xml.sax and xml.dom.domreg no longer use environment
+ variables to override parser implementations when
+ sys.flags.ignore_environment is set by -E or -I arguments.
+
+Core and Builtins
+-----------------
+
+- bpo-35444: Fixed error handling in pickling methods when fail to look up
+ builtin "getattr".
+
+- bpo-35436: Fix various issues with memory allocation error handling.
+ Patch by Zackery Spytz.
+
+- bpo-35357: Internal attributes' names of unittest.mock._Call and
+ unittest.mock.MagicProxy (name, parent & from_kall) are now prefixed with
+ _mock_ in order to prevent clashes with widely used object attributes.
+ Fixed minor typo in test function name.
+
+- bpo-35372: Fixed the code page decoder for input longer than 2 GiB
+ containing undecodable bytes.
+
+- bpo-35336: Fix PYTHONCOERCECLOCALE=1 environment variable: only coerce the
+ C locale if the LC_CTYPE locale is "C".
+
+- bpo-33954: For :meth:`str.format`, :meth:`float.__format__` and
+ :meth:`complex.__format__` methods for non-ASCII decimal point when using
+ the "n" formatter.
+
+- bpo-35269: Fix a possible segfault involving a newly-created coroutine.
+ Patch by Zackery Spytz.
+
+- bpo-35214: Fixed an out of bounds memory access when parsing a truncated
+ unicode escape sequence at the end of a string such as ``'\N'``. It would
+ read one byte beyond the end of the memory allocation.
+
+- bpo-35214: The interpreter and extension modules have had annotations
+ added so that they work properly under clang's Memory Sanitizer. A new
+ configure flag --with-memory-sanitizer has been added to make test builds
+ of this nature easier to perform.
+
+- bpo-35193: Fix an off by one error in the bytecode peephole optimizer
+ where it could read bytes beyond the end of bounds of an array when
+ removing unreachable code. This bug was present in every release of Python
+ 3.6 and 3.7 until now.
+
+- bpo-29341: Clarify in the docstrings of :mod:`os` methods that path-like
+ objects are also accepted as input parameters.
+
+- bpo-35050: :mod:`socket`: Fix off-by-one bug in length check for
+ ``AF_ALG`` name and type.
+
+- bpo-34974: :class:`bytes` and :class:`bytearray` constructors no longer
+ convert unexpected exceptions (e.g. :exc:`MemoryError` and
+ :exc:`KeyboardInterrupt`) to :exc:`TypeError`.
+
+- bpo-34973: Fixed crash in :func:`bytes` when the :class:`list` argument is
+ mutated while it is iterated.
+
+- bpo-34824: Fix a possible null pointer dereference in Modules/_ssl.c.
+ Patch by Zackery Spytz.
+
+- bpo-1621: Do not assume signed integer overflow behavior (C undefined
+ behavior) when performing set hash table resizing.
+
+Library
+-------
+
+- bpo-35052: Fix xml.dom.minidom cloneNode() on a document with an entity:
+ pass the correct arguments to the user data handler of an entity.
+
+- bpo-35330: When a :class:`Mock` instance was used to wrap an object, if
+ `side_effect` is used in one of the mocks of it methods, don't call the
+ original implementation and return the result of using the side effect the
+ same way that it is done with return_value.
+
+- bpo-34172: Revert the fix for this issue previously released in 3.7.1
+ pending further investigation: Fix a reference issue inside
+ multiprocessing.Pool that caused the pool to remain alive if it was
+ deleted without being closed or terminated explicitly.
+
+- bpo-10496: :func:`posixpath.expanduser` now returns the input *path*
+ unchanged if the ``HOME`` environment variable is not set and the current
+ user has no home directory (if the current user identifier doesn't exist
+ in the password database). This change fix the :mod:`site` module if the
+ current user doesn't exist in the password database (if the user has no
+ home directory).
+
+- bpo-35310: Fix a bug in :func:`select.select` where, in some cases, the
+ file descriptor sequences were returned unmodified after a signal
+ interruption, even though the file descriptors might not be ready yet.
+ :func:`select.select` will now always return empty lists if a timeout has
+ occurred. Patch by Oran Avraham.
+
+- bpo-35380: Enable TCP_NODELAY on Windows for proactor asyncio event loop.
+
+- bpo-35341: Add generic version of ``collections.OrderedDict`` to the
+ ``typing`` module. Patch by Ismo Toijala.
+
+- bpo-35371: Fixed possible crash in ``os.utime()`` on Windows when pass
+ incorrect arguments.
+
+- bpo-27903: Fix ``ResourceWarning`` in :func:`platform.dist` on SuSE and
+ Caldera OpenLinux. Patch by Ville Skyttä.
+
+- bpo-35308: Fix regression in ``webbrowser`` where default browsers may be
+ preferred over browsers in the ``BROWSER`` environment variable.
+
+- bpo-28604: :func:`locale.localeconv` now sets temporarily the ``LC_CTYPE``
+ locale to the ``LC_MONETARY`` locale if the two locales are different and
+ monetary strings are non-ASCII. This temporary change affects other
+ threads.
+
+- bpo-35277: Update ensurepip to install pip 18.1 and setuptools 40.6.2.
+
+- bpo-35226: Recursively check arguments when testing for equality of
+ :class:`unittest.mock.call` objects and add note that tracking of
+ parameters used to create ancestors of mocks in ``mock_calls`` is not
+ possible.
+
+- bpo-29564: The warnings module now suggests to enable tracemalloc if the
+ source is specified, the tracemalloc module is available, but tracemalloc
+ is not tracing memory allocations.
+
+- bpo-35189: Modify the following fnctl function to retry if interrupted by
+ a signal (EINTR): flock, lockf, fnctl
+
+- bpo-35062: Fix incorrect parsing of
+ :class:`_io.IncrementalNewlineDecoder`'s *translate* argument.
+
+- bpo-35079: Improve difflib.SequenceManager.get_matching_blocks doc by
+ adding 'non-overlapping' and changing '!=' to '<'.
+
+- bpo-35017: :meth:`socketserver.BaseServer.serve_forever` now exits
+ immediately if it's :meth:`~socketserver.BaseServer.shutdown` method is
+ called while it is polling for new events.
+
+- bpo-31047: Fix ``ntpath.abspath`` regression where it didn't remove a
+ trailing separator on Windows. Patch by Tim Graham.
+
+- bpo-34794: Fixed a leak in Tkinter when pass the Python wrapper around
+ Tcl_Obj back to Tcl/Tk.
+
+- bpo-35008: Fixed references leaks when call the ``__setstate__()`` method
+ of :class:`xml.etree.ElementTree.Element` in the C implementation for
+ already initialized element.
+
+- bpo-23420: Verify the value for the parameter '-s' of the cProfile CLI.
+ Patch by Robert Kuska
+
+- bpo-33947: dataclasses now handle recursive reprs without raising
+ RecursionError.
+
+- bpo-16965: The :term:`2to3` :2to3fixer:`execfile` fixer now opens the file
+ with mode ``'rb'``. Patch by Zackery Spytz.
+
+- bpo-34966: :mod:`pydoc` now supports aliases not only to methods defined
+ in the end class, but also to inherited methods. The docstring is not
+ duplicated for aliases.
+
+- bpo-34941: Methods ``find()``, ``findtext()`` and ``findall()`` of the
+ ``Element`` class in the :mod:`xml.etree.ElementTree` module are now able
+ to find children which are instances of ``Element`` subclasses.
+
+- bpo-34936: Fix ``TclError`` in ``tkinter.Spinbox.selection_element()``.
+ Patch by Juliette Monsel.
+
+- bpo-34866: Adding ``max_num_fields`` to ``cgi.FieldStorage`` to make DOS
+ attacks harder by limiting the number of ``MiniFieldStorage`` objects
+ created by ``FieldStorage``.
+
+- bpo-34022: The :envvar:`SOURCE_DATE_EPOCH` environment variable no longer
+ overrides the value of the *invalidation_mode* argument to
+ :func:`py_compile.compile`, and determines its default value instead.
+
+- bpo-34738: ZIP files created by :mod:`distutils` will now include entries
+ for directories.
+
+- bpo-31177: Fix bug that prevented using :meth:`reset_mock
+ <unittest.mock.Mock.reset_mock>` on mock instances with deleted attributes
+
+- bpo-34536: `Enum._missing_`: raise `ValueError` if None returned and
+ `TypeError` if non-member is returned.
+
+- bpo-34604: Fix possible mojibake in the error message of `pwd.getpwnam`
+ and `grp.getgrnam` using string representation because of invisible
+ characters or trailing whitespaces. Patch by William Grzybowski.
+
+- bpo-34574: OrderedDict iterators are not exhausted during pickling
+ anymore. Patch by Sergey Fedoseev.
+
+- bpo-34052: :meth:`sqlite3.Connection.create_aggregate`,
+ :meth:`sqlite3.Connection.create_function`,
+ :meth:`sqlite3.Connection.set_authorizer`,
+ :meth:`sqlite3.Connection.set_progress_handler` methods raises TypeError
+ when unhashable objects are passed as callable. These methods now don't
+ pass such objects to SQLite API. Previous behavior could lead to
+ segfaults. Patch by Sergey Fedoseev.
+
+- bpo-29877: compileall: import ProcessPoolExecutor only when needed,
+ preventing hangs on low resource platforms
+
+- bpo-22005: Implemented unpickling instances of
+ :class:`~datetime.datetime`, :class:`~datetime.date` and
+ :class:`~datetime.time` pickled by Python 2. ``encoding='latin1'`` should
+ be used for successful decoding.
+
+Documentation
+-------------
+
+- bpo-35089: Remove mention of ``typing.io`` and ``typing.re``. Their types
+ should be imported from ``typing`` directly.
+
+- bpo-35038: Fix the documentation about an unexisting `f_restricted`
+ attribute in the frame object. Patch by Stéphane Wirtel
+
+- bpo-35044: Fix the documentation with the role ``exc`` for the
+ appropriated exception. Patch by Stéphane Wirtel
+
+- bpo-35035: Rename documentation for :mod:`email.utils` to
+ ``email.utils.rst``.
+
+- bpo-34967: Use app.add_object_type() instead of the deprecated Sphinx
+ function app.description_unit()
+
+- bpo-11233: Create availability directive for documentation. Original
+ patch by Georg Brandl.
+
+- bpo-33594: Document ``getargspec``, ``from_function`` and ``from_builtin``
+ as deprecated in their respective docstring, and include version since
+ deprecation in DeprecationWarning message.
+
+- bpo-32613: Update the faq/windows.html to use the py command from PEP 397
+ instead of python.
+
+Tests
+-----
+
+- bpo-33725: test_multiprocessing_fork may crash on recent versions of
+ macOS. Until the issue is resolved, skip the test on macOS.
+
+- bpo-35352: Modify test_asyncio to use the certificate set from the test
+ directory.
+
+- bpo-35317: Fix ``mktime()`` overflow error in ``test_email``: run
+ ``test_localtime_daylight_true_dst_true()`` and
+ ``test_localtime_daylight_false_dst_true()`` with a specific timezone.
+
+- bpo-21263: After several reports that test_gdb does not work properly on
+ macOS and since gdb is not shipped by default anymore, test_gdb is now
+ skipped on macOS when LLVM Clang has been used to compile Python. Patch by
+ Lysandros Nikolaou
+
+- bpo-34279: regrtest issue a warning when no tests have been executed in a
+ particular test file. Also, a new final result state is issued if no test
+ have been executed across all test files. Patch by Pablo Galindo.
+
+Build
+-----
+
+- bpo-35296: The Windows installer (MSI) now also install internal header
+ files (``Include/internal/`` subdirectory).
+
+- bpo-35351: When building Python with clang and LTO, LTO flags are no
+ longer passed into CFLAGS to build third-party C extensions through
+ distutils.
+
+- bpo-35139: Fix a compiler error when statically linking `pyexpat` in
+ `Modules/Setup`.
+
+- bpo-35011: Restores the use of pyexpatns.h to isolate our embedded copy of
+ the expat C library so that its symbols do not conflict at link or dynamic
+ loading time with an embedding application or other extension modules with
+ their own version of libexpat.
+
+- bpo-28015: Have --with-lto works correctly with clang.
+
+- bpo-33015: Fix an undefined behaviour in the pthread implementation of
+ :c:func:`PyThread_start_new_thread`: add a function wrapper to always
+ return ``NULL``.
+
+Windows
+-------
+
+- bpo-35401: Updates Windows build to OpenSSL 1.1.0j
+
+- bpo-34977: venv on Windows will now use a python.exe redirector rather
+ than copying the actual binaries from the base environment.
+
+- bpo-34977: Adds support for building a Windows App Store package
+
+- bpo-35067: Remove _distutils_findvs module and use vswhere.exe instead.
+
+- bpo-34532: Fixes exit code of list version arguments for py.exe.
+
+- bpo-32890: Fix usage of GetLastError() instead of errno in os.execve() and
+ os.truncate().
+
+macOS
+-----
+
+- bpo-35402: Update macOS installer to use Tcl/Tk 8.6.9.1.
+
+- bpo-35401: Update macOS installer to use OpenSSL 1.1.0j.
+
+- bpo-35025: Properly guard the use of the ``CLOCK_GETTIME`` et al. macros
+ in ``timemodule`` on macOS.
+
+- bpo-24658: On macOS, fix reading from and writing into a file with a size
+ larger than 2 GiB.
+
+IDLE
+----
+
+- bpo-35213: Where appropriate, use 'macOS' in idlelib.
+
+- bpo-34864: On macOS, warn if the system preference "Prefer tabs when
+ opening documents" is set to "Always".
+
+- bpo-34864: Document two IDLE on MacOS issues. The System Preferences Dock
+ "prefer tabs always" setting disables some IDLE features. Menus are a bit
+ different than as described for Windows and Linux.
+
+- bpo-35202: Remove unused imports from lib/idlelib
+
+- bpo-33000: Document that IDLE's shell has no line limit. A program that
+ runs indefinitely can overfill memory.
+
+- bpo-23220: Explain how IDLE's Shell displays output.
+
+- bpo-35099: Improve the doc about IDLE running user code. The section is
+ renamed from "IDLE -- console differences" is renamed "Running user code".
+ It mostly covers the implications of using custom sys.stdxxx objects.
+
+- bpo-35097: Add IDLE doc subsection explaining editor windows. Topics
+ include opening, title and status bar, .py* extension, and running.
+
+- bpo-35093: Document the IDLE document viewer in the IDLE doc. Add a
+ paragraph in "Help and preferences", "Help sources" subsection.
+
+- bpo-35088: Update idlelib.help.copy_string docstring. We now use git and
+ backporting instead of hg and forward merging.
+
+- bpo-35087: Update idlelib help files for the current doc build. The main
+ change is the elimination of chapter-section numbers.
+
+Tools/Demos
+-----------
+
+- bpo-34989: python-gdb.py now handles errors on computing the line number
+ of a Python frame.
+
+C API
+-----
+
+- bpo-35322: Fix memory leak in :c:func:`PyUnicode_EncodeLocale` and
+ :c:func:`PyUnicode_EncodeFSDefault` on error handling.
+
+- bpo-35296: ``make install`` now also installs the internal API:
+ ``Include/internal/*.h`` header files.
+
+- bpo-34725: Adds _Py_SetProgramFullPath so embedders may override
+ sys.executable
+
+
What's New in Python 3.7.1 final?
=================================
- bpo-34120: Fix unresponsiveness after closing certain windows and dialogs.
- bpo-33975: Avoid small type when running htests. Since part of the purpose
- of human- viewed tests is to determine that widgets look right, it is
+ of human-viewed tests is to determine that widgets look right, it is
important that they look the same for testing as when running IDLE.
- bpo-33905: Add test for idlelib.stackview.StackBrowser.
infinite loop DoS), CVE-2016-9063 (Integer overflow, re-fix),
CVE-2016-0718 (Fix regression bugs from 2.2.0's fix to CVE-2016-0718) and
CVE-2012-0876 (Counter hash flooding with SipHash). Note: the
- CVE-2016-5300 (Use os- specific entropy sources like getrandom) doesn't
+ CVE-2016-5300 (Use os-specific entropy sources like getrandom) doesn't
impact Python, since Python already gets entropy from the OS to set the
expat secret using ``XML_SetHashSalt()``.
- bpo-29169: Update zlib to 1.2.11.
- bpo-30879: os.listdir() and os.scandir() now emit bytes names when called
- with bytes- like argument.
+ with bytes-like argument.
- bpo-30746: Prohibited the '=' character in environment variable names in
``os.putenv()`` and ``os.spawn*()``.
when Ctrl-C is received.
- bpo-28556: Various updates to typing module: add typing.NoReturn type, use
- WrapperDescriptorType, minor bug-fixes. Original PRs by Jim Fasarakis-
- Hilliard and Ivan Levkivskyi.
+ WrapperDescriptorType, minor bug-fixes. Original PRs by Jim
+ Fasarakis-Hilliard and Ivan Levkivskyi.
- bpo-30205: Fix getsockname() for unbound AF_UNIX sockets on Linux.
- bpo-29243: Prevent unnecessary rebuilding of Python during ``make test``,
``make install`` and some other make targets when configured with
- ``--enable- optimizations``.
+ ``--enable-optimizations``.
- bpo-23404: Don't regenerate generated files based on file modification
time anymore: the action is now explicit. Replace ``make touch`` with
when decode astral characters. Patch by Xiang Zhang.
- bpo-19398: Extra slash no longer added to sys.path components in case of
- empty compile- time PYTHONPATH components.
+ empty compile-time PYTHONPATH components.
- bpo-28426: Fixed potential crash in PyUnicode_AsDecodedObject() in debug
build.
- bpo-27419: Standard __import__() no longer look up "__import__" in globals
or builtins for importing submodules or "from import". Fixed handling an
- error of non- string package name.
+ error of non-string package name.
- bpo-27083: Respect the PYTHONCASEOK environment variable under Windows.
- bpo-10513: Fix a regression in Connection.commit(). Statements should not
be reset after a commit.
-- A new version of typing.py from https://github.com/python/typing: -
- Collection (only for 3.6) (Issue #27598) - Add FrozenSet to __all__
- (upstream #261) - fix crash in _get_type_vars() (upstream #259) - Remove
- the dict constraint in ForwardRef._eval_type (upstream #252)
+- A new version of typing.py from https://github.com/python/typing:
+ Collection (only for 3.6) (Issue #27598). Add FrozenSet to __all__
+ (upstream #261). Fix crash in _get_type_vars() (upstream #259). Remove the
+ dict constraint in ForwardRef._eval_type (upstream #252).
- bpo-27539: Fix unnormalised ``Fraction.__pow__`` result in the case of
negative exponent and negative base.
- bpo-27983: Cause lack of llvm-profdata tool when using clang as required
for PGO linking to be a configure time error rather than make time when
- --with- optimizations is enabled. Also improve our ability to find the
- llvm- profdata tool on MacOS and some Linuxes.
+ --with-optimizations is enabled. Also improve our ability to find the
+ llvm-profdata tool on MacOS and some Linuxes.
- bpo-26307: The profile-opt build now applies PGO to the built-in modules.
Hsuan Yen.
- bpo-27641: The configure script now inserts comments into the makefile to
- prevent the pgen and _freeze_importlib executables from being cross-
- compiled.
+ prevent the pgen and _freeze_importlib executables from being
+ cross-compiled.
- bpo-26662: Set PYTHON_FOR_GEN in configure as the Python program to be
used for file generation during the build.
- bpo-17214: The "urllib.request" module now percent-encodes non-ASCII bytes
found in redirect target URLs. Some servers send Location header fields
- with non- ASCII bytes, but "http.client" requires the request target to be
- ASCII- encodable, otherwise a UnicodeEncodeError is raised. Based on
- patch by Christian Heimes.
+ with non-ASCII bytes, but "http.client" requires the request target to be
+ ASCII-encodable, otherwise a UnicodeEncodeError is raised. Based on patch
+ by Christian Heimes.
- bpo-26892: Honor debuglevel flag in urllib.request.HTTPHandler. Patch
contributed by Chi Hsuan Yen.
de Gaye.
- bpo-22359: Disable the rules for running _freeze_importlib and pgen when
- cross- compiling. The output of these programs is normally saved with the
+ cross-compiling. The output of these programs is normally saved with the
source code anyway, and is still regenerated when doing a native build.
Patch by Xavier de Gaye.
- bpo-25003: On Solaris 11.3 or newer, os.urandom() now uses the getrandom()
function instead of the getentropy() function. The getentropy() function
is blocking to generate very good quality entropy, os.urandom() doesn't
- need such high- quality entropy.
+ need such high-quality entropy.
- bpo-25182: The stdprinter (used as sys.stderr before the io module is
imported at startup) now uses the backslashreplace error handler.
- bpo-25173: Associate tkinter messageboxes with a specific widget. For Mac
OSX, make them a 'sheet'. Patch by Mark Roseman.
-- bpo-25198: Enhance the initial html viewer now used for Idle Help. *
- Properly indent fixed-pitch text (patch by Mark Roseman). * Give code
- snippet a very Sphinx- like light blueish-gray background. * Re-use
- initial width and height set by users for shell and editor. * When the
- Table of Contents (TOC) menu is used, put the section header at the top of
- the screen.
+- bpo-25198: Enhance the initial html viewer now used for Idle Help.
+ Properly indent fixed-pitch text (patch by Mark Roseman). Give code
+ snippet a very Sphinx-like light blueish-gray background. Re-use initial
+ width and height set by users for shell and editor. When the Table of
+ Contents (TOC) menu is used, put the section header at the top of the
+ screen.
- bpo-25225: Condense and rewrite Idle doc section on text colors.
inside a data segment.
- bpo-15014: SMTP.auth() and SMTP.login() now support RFC 4954's optional
- initial- response argument to the SMTP AUTH command.
+ initial-response argument to the SMTP AUTH command.
- bpo-24669: Fix inspect.getsource() for 'async def' functions. Patch by Kai
Groner.
called. Based on patch by Martin Panter.
- bpo-20387: Restore semantic round-trip correctness in tokenize/untokenize
- for tab- indented blocks.
+ for tab-indented blocks.
- bpo-24456: Fixed possible buffer over-read in adpcm2lin() and lin2adpcm()
functions of the audioop module.
-------
- bpo-14260: The groupindex attribute of regular expression pattern object
- now is non- modifiable mapping.
+ now is non-modifiable mapping.
- bpo-23792: Ignore KeyboardInterrupt when the pydoc pager is active. This
mimics the behavior of the standard unix pagers, and prevents pipepager
- bpo-5411: Added support for the "xztar" format in the shutil module.
- bpo-21121: Don't force 3rd party C extensions to be built with
- -Werror=declaration- after-statement.
+ -Werror=declaration-after-statement.
- bpo-21975: Fixed crash when using uninitialized sqlite3.Row (in particular
when unpickling pickled sqlite3.Row). sqlite3.Row is now initialized in
- bpo-20378: Improve repr of inspect.Signature and inspect.Parameter.
- bpo-20816: Fix inspect.getcallargs() to raise correct TypeError for
- missing keyword- only arguments. Patch by Jeremiah Lowin.
+ missing keyword-only arguments. Patch by Jeremiah Lowin.
- bpo-20817: Fix inspect.getcallargs() to fail correctly if more than 3
arguments are missing. Patch by Jeremiah Lowin.
- bpo-21811: Anticipated fixes to support OS X versions > 10.9.
- bpo-21166: Prevent possible segfaults and other random failures of python
- --generate- posix-vars in pybuilddir.txt build target.
+ --generate-posix-vars in pybuilddir.txt build target.
- bpo-18096: Fix library order returned by python-config.
# Interface to the Expat XML parser
# More information on Expat can be found at www.libexpat.org.
#
-#pyexpat expat/xmlparse.c expat/xmlrole.c expat/xmltok.c pyexpat.c -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI
+#pyexpat expat/xmlparse.c expat/xmlrole.c expat/xmltok.c pyexpat.c -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DXML_POOR_ENTROPY=1 -DUSE_PYEXPAT_CAPI
# Hye-Shik Chang's CJKCodecs
// Weakref callback may remove entry from set.
// So we take snapshot of registry first.
PyObject **copy = PyMem_Malloc(sizeof(PyObject*) * registry_size);
+ if (copy == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
PyObject *key;
Py_ssize_t pos = 0;
Py_hash_t hash;
}
static PyObject *
-FutureObj_get_blocking(FutureObj *fut)
+FutureObj_get_blocking(FutureObj *fut, void *Py_UNUSED(ignored))
{
if (future_is_alive(fut) && fut->fut_blocking) {
Py_RETURN_TRUE;
}
static int
-FutureObj_set_blocking(FutureObj *fut, PyObject *val)
+FutureObj_set_blocking(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored))
{
if (future_ensure_alive(fut)) {
return -1;
}
static PyObject *
-FutureObj_get_log_traceback(FutureObj *fut)
+FutureObj_get_log_traceback(FutureObj *fut, void *Py_UNUSED(ignored))
{
ENSURE_FUTURE_ALIVE(fut)
if (fut->fut_log_tb) {
}
static int
-FutureObj_set_log_traceback(FutureObj *fut, PyObject *val)
+FutureObj_set_log_traceback(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored))
{
int is_true = PyObject_IsTrue(val);
if (is_true < 0) {
}
static PyObject *
-FutureObj_get_loop(FutureObj *fut)
+FutureObj_get_loop(FutureObj *fut, void *Py_UNUSED(ignored))
{
if (!future_is_alive(fut)) {
Py_RETURN_NONE;
}
static PyObject *
-FutureObj_get_callbacks(FutureObj *fut)
+FutureObj_get_callbacks(FutureObj *fut, void *Py_UNUSED(ignored))
{
Py_ssize_t i;
}
static PyObject *
-FutureObj_get_result(FutureObj *fut)
+FutureObj_get_result(FutureObj *fut, void *Py_UNUSED(ignored))
{
ENSURE_FUTURE_ALIVE(fut)
if (fut->fut_result == NULL) {
}
static PyObject *
-FutureObj_get_exception(FutureObj *fut)
+FutureObj_get_exception(FutureObj *fut, void *Py_UNUSED(ignored))
{
ENSURE_FUTURE_ALIVE(fut)
if (fut->fut_exception == NULL) {
}
static PyObject *
-FutureObj_get_source_traceback(FutureObj *fut)
+FutureObj_get_source_traceback(FutureObj *fut, void *Py_UNUSED(ignored))
{
if (!future_is_alive(fut) || fut->fut_source_tb == NULL) {
Py_RETURN_NONE;
}
static PyObject *
-FutureObj_get_state(FutureObj *fut)
+FutureObj_get_state(FutureObj *fut, void *Py_UNUSED(ignored))
{
_Py_IDENTIFIER(PENDING);
_Py_IDENTIFIER(CANCELLED);
}
static PyObject *
-TaskStepMethWrapper_get___self__(TaskStepMethWrapper *o)
+TaskStepMethWrapper_get___self__(TaskStepMethWrapper *o, void *Py_UNUSED(ignored))
{
if (o->sw_task) {
Py_INCREF(o->sw_task);
}
static PyObject *
-TaskObj_get_log_destroy_pending(TaskObj *task)
+TaskObj_get_log_destroy_pending(TaskObj *task, void *Py_UNUSED(ignored))
{
if (task->task_log_destroy_pending) {
Py_RETURN_TRUE;
}
static int
-TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val)
+TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val, void *Py_UNUSED(ignored))
{
int is_true = PyObject_IsTrue(val);
if (is_true < 0) {
}
static PyObject *
-TaskObj_get_must_cancel(TaskObj *task)
+TaskObj_get_must_cancel(TaskObj *task, void *Py_UNUSED(ignored))
{
if (task->task_must_cancel) {
Py_RETURN_TRUE;
}
static PyObject *
-TaskObj_get_coro(TaskObj *task)
+TaskObj_get_coro(TaskObj *task, void *Py_UNUSED(ignored))
{
if (task->task_coro) {
Py_INCREF(task->task_coro);
}
static PyObject *
-TaskObj_get_fut_waiter(TaskObj *task)
+TaskObj_get_fut_waiter(TaskObj *task, void *Py_UNUSED(ignored))
{
if (task->task_fut_waiter) {
Py_INCREF(task->task_fut_waiter);
{
if (items < 0 || size < 0)
return NULL;
- if ((size_t)items > (size_t)PY_SSIZE_T_MAX / (size_t)size)
+ if (size != 0 && (size_t)items > (size_t)PY_SSIZE_T_MAX / (size_t)size)
return NULL;
/* PyMem_Malloc() cannot be used: compress() and decompress()
release the GIL */
- return PyMem_RawMalloc(items * size);
+ return PyMem_RawMalloc((size_t)items * (size_t)size);
}
static void
}
static PyObject *
-deque_reduce(dequeobject *deque)
+deque_reduce(dequeobject *deque, PyObject *Py_UNUSED(ignored))
{
PyObject *dict, *it;
_Py_IDENTIFIER(__dict__);
}
static PyObject *
-deque_get_maxlen(dequeobject *deque)
+deque_get_maxlen(dequeobject *deque, void *Py_UNUSED(ignored))
{
if (deque->maxlen < 0)
Py_RETURN_NONE;
}
static PyObject *
-Dialect_get_lineterminator(DialectObj *self)
+Dialect_get_lineterminator(DialectObj *self, void *Py_UNUSED(ignored))
{
return get_string(self->lineterminator);
}
static PyObject *
-Dialect_get_delimiter(DialectObj *self)
+Dialect_get_delimiter(DialectObj *self, void *Py_UNUSED(ignored))
{
return get_nullchar_as_None(self->delimiter);
}
static PyObject *
-Dialect_get_escapechar(DialectObj *self)
+Dialect_get_escapechar(DialectObj *self, void *Py_UNUSED(ignored))
{
return get_nullchar_as_None(self->escapechar);
}
static PyObject *
-Dialect_get_quotechar(DialectObj *self)
+Dialect_get_quotechar(DialectObj *self, void *Py_UNUSED(ignored))
{
return get_nullchar_as_None(self->quotechar);
}
static PyObject *
-Dialect_get_quoting(DialectObj *self)
+Dialect_get_quoting(DialectObj *self, void *Py_UNUSED(ignored))
{
return PyLong_FromLong(self->quoting);
}
}
result = PyMem_Malloc(3);
- if (result == NULL)
+ if (result == NULL) {
+ PyErr_NoMemory();
return NULL;
+ }
result[0] = big_endian ? '>' : '<';
result[1] = pep_code;
if (prefix)
prefix_len += strlen(prefix);
new_prefix = PyMem_Malloc(prefix_len);
- if (new_prefix == NULL)
+ if (new_prefix == NULL) {
+ PyErr_NoMemory();
return NULL;
+ }
new_prefix[0] = '\0';
if (prefix)
strcpy(new_prefix, prefix);
*/
static int
-CharArray_set_raw(CDataObject *self, PyObject *value)
+CharArray_set_raw(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
{
char *ptr;
Py_ssize_t size;
}
static PyObject *
-CharArray_get_raw(CDataObject *self)
+CharArray_get_raw(CDataObject *self, void *Py_UNUSED(ignored))
{
return PyBytes_FromStringAndSize(self->b_ptr, self->b_size);
}
static PyObject *
-CharArray_get_value(CDataObject *self)
+CharArray_get_value(CDataObject *self, void *Py_UNUSED(ignored))
{
Py_ssize_t i;
char *ptr = self->b_ptr;
}
static int
-CharArray_set_value(CDataObject *self, PyObject *value)
+CharArray_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
{
char *ptr;
Py_ssize_t size;
#ifdef CTYPES_UNICODE
static PyObject *
-WCharArray_get_value(CDataObject *self)
+WCharArray_get_value(CDataObject *self, void *Py_UNUSED(ignored))
{
Py_ssize_t i;
wchar_t *ptr = (wchar_t *)self->b_ptr;
}
static int
-WCharArray_set_value(CDataObject *self, PyObject *value)
+WCharArray_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
{
Py_ssize_t result = 0;
Py_UNICODE *wstr;
#else
suffix = PyUnicode_InternFromString("_be");
#endif
+ if (suffix == NULL) {
+ Py_DECREF(swapped_args);
+ return NULL;
+ }
newname = PyUnicode_Concat(name, suffix);
if (newname == NULL) {
*/
static int
-PyCFuncPtr_set_errcheck(PyCFuncPtrObject *self, PyObject *ob)
+PyCFuncPtr_set_errcheck(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored))
{
if (ob && !PyCallable_Check(ob)) {
PyErr_SetString(PyExc_TypeError,
}
static PyObject *
-PyCFuncPtr_get_errcheck(PyCFuncPtrObject *self)
+PyCFuncPtr_get_errcheck(PyCFuncPtrObject *self, void *Py_UNUSED(ignored))
{
if (self->errcheck) {
Py_INCREF(self->errcheck);
}
static int
-PyCFuncPtr_set_restype(PyCFuncPtrObject *self, PyObject *ob)
+PyCFuncPtr_set_restype(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored))
{
if (ob == NULL) {
Py_CLEAR(self->restype);
}
static PyObject *
-PyCFuncPtr_get_restype(PyCFuncPtrObject *self)
+PyCFuncPtr_get_restype(PyCFuncPtrObject *self, void *Py_UNUSED(ignored))
{
StgDictObject *dict;
if (self->restype) {
}
static int
-PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob)
+PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored))
{
PyObject *converters;
}
static PyObject *
-PyCFuncPtr_get_argtypes(PyCFuncPtrObject *self)
+PyCFuncPtr_get_argtypes(PyCFuncPtrObject *self, void *Py_UNUSED(ignored))
{
StgDictObject *dict;
if (self->argtypes) {
*/
static int
-Simple_set_value(CDataObject *self, PyObject *value)
+Simple_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
{
PyObject *result;
StgDictObject *dict = PyObject_stgdict((PyObject *)self);
if (!PyArg_UnpackTuple(args, "__init__", 0, 1, &value))
return -1;
if (value)
- return Simple_set_value(self, value);
+ return Simple_set_value(self, value, NULL);
return 0;
}
static PyObject *
-Simple_get_value(CDataObject *self)
+Simple_get_value(CDataObject *self, void *Py_UNUSED(ignored))
{
StgDictObject *dict;
dict = PyObject_stgdict((PyObject *)self);
return self;
}
/* call stgdict->getfunc */
- return Simple_get_value((CDataObject *)self);
+ return Simple_get_value((CDataObject *)self, NULL);
}
static PyMethodDef Simple_methods[] = {
Py_TYPE(self)->tp_name, self);
}
- val = Simple_get_value(self);
+ val = Simple_get_value(self, NULL);
if (val == NULL)
return NULL;
p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nArgs);
if (p == NULL) {
- PyErr_NoMemory();
return NULL;
}
#include <alloca.h>
#endif
+#ifdef _Py_MEMORY_SANITIZER
+#include <sanitizer/msan_interface.h>
+#endif
+
#if defined(_DEBUG) || defined(__MINGW32__)
/* Don't use structured exception handling on Windows if this is defined.
MingW, AFAIK, doesn't support it.
PyObject_Del(self);
}
+static int
+is_literal_char(unsigned char c)
+{
+ return c < 128 && _PyUnicode_IsPrintable(c) && c != '\\' && c != '\'';
+}
+
static PyObject *
PyCArg_repr(PyCArgObject *self)
{
#ifdef MS_WIN32
"<cparam '%c' (%I64d)>",
#else
- "<cparam '%c' (%qd)>",
+ "<cparam '%c' (%lld)>",
#endif
self->tag, self->value.q);
break;
break;
case 'c':
- sprintf(buffer, "<cparam '%c' (%c)>",
- self->tag, self->value.c);
+ if (is_literal_char((unsigned char)self->value.c)) {
+ sprintf(buffer, "<cparam '%c' ('%c')>",
+ self->tag, self->value.c);
+ }
+ else {
+ sprintf(buffer, "<cparam '%c' ('\\x%02x')>",
+ self->tag, (unsigned char)self->value.c);
+ }
break;
/* Hm, are these 'z' and 'Z' codes useful at all?
break;
default:
- sprintf(buffer, "<cparam '%c' at %p>",
- self->tag, self);
+ if (is_literal_char((unsigned char)self->tag)) {
+ sprintf(buffer, "<cparam '%c' at %p>",
+ (unsigned char)self->tag, self);
+ }
+ else {
+ sprintf(buffer, "<cparam 0x%02x at %p>",
+ (unsigned char)self->tag, self);
+ }
break;
}
return PyUnicode_FromString(buffer);
rtype = _ctypes_get_ffi_type(restype);
resbuf = alloca(max(rtype->size, sizeof(ffi_arg)));
+#ifdef _Py_MEMORY_SANITIZER
+ /* ffi_call actually initializes resbuf, but from asm, which
+ * MemorySanitizer can't detect. Avoid false positives from MSan. */
+ if (resbuf != NULL) {
+ __msan_unpoison(resbuf, max(rtype->size, sizeof(ffi_arg)));
+ }
+#endif
avalues = (void **)alloca(sizeof(void *) * argcount);
atypes = (ffi_type **)alloca(sizeof(ffi_type *) * argcount);
if (!resbuf || !avalues || !atypes) {
PARSESTR - format string for argument parsing
*/
-#define Window_NoArgNoReturnFunction(X) \
- static PyObject *PyCursesWindow_ ## X \
- (PyCursesWindowObject *self, PyObject *args) \
+#define Window_NoArgNoReturnFunction(X) \
+ static PyObject *PyCursesWindow_ ## X \
+ (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \
{ return PyCursesCheckERR(X(self->win), # X); }
#define Window_NoArgTrueFalseFunction(X) \
static PyObject * PyCursesWindow_ ## X \
- (PyCursesWindowObject *self) \
+ (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \
{ \
if (X (self->win) == FALSE) { Py_RETURN_FALSE; } \
else { Py_RETURN_TRUE; } }
#define Window_NoArgNoReturnVoidFunction(X) \
static PyObject * PyCursesWindow_ ## X \
- (PyCursesWindowObject *self) \
+ (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \
{ \
X(self->win); Py_RETURN_NONE; }
#define Window_NoArg2TupleReturnFunction(X, TYPE, ERGSTR) \
static PyObject * PyCursesWindow_ ## X \
- (PyCursesWindowObject *self) \
+ (PyCursesWindowObject *self, PyObject *Py_UNUSED(ignored)) \
{ \
TYPE arg1, arg2; \
X(self->win,arg1,arg2); return Py_BuildValue(ERGSTR, arg1, arg2); }
}
static int
-PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value)
+PyCursesWindow_set_encoding(PyCursesWindowObject *self, PyObject *value, void *Py_UNUSED(ignored))
{
PyObject *ascii;
char *encoding;
* String parsing utilities and helper functions
*/
-static const char*
-parse_digits(const char* ptr, int* var, size_t num_digits)
+static const char *
+parse_digits(const char *ptr, int *var, size_t num_digits)
{
for (size_t i = 0; i < num_digits; ++i) {
unsigned int tmp = (unsigned int)(*(ptr++) - '0');
return ptr;
}
-static int parse_isoformat_date(const char *dtstr,
- int* year, int *month, int* day) {
+static int
+parse_isoformat_date(const char *dtstr, int *year, int *month, int *day)
+{
/* Parse the date components of the result of date.isoformat()
- *
- * Return codes:
- * 0: Success
- * -1: Failed to parse date component
- * -2: Failed to parse dateseparator
- */
+ *
+ * Return codes:
+ * 0: Success
+ * -1: Failed to parse date component
+ * -2: Failed to parse dateseparator
+ */
const char *p = dtstr;
p = parse_digits(p, year, 4);
if (NULL == p) {
}
static int
-parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end,
- int* hour, int* minute, int *second, int *microsecond) {
+parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour,
+ int *minute, int *second, int *microsecond)
+{
const char *p = tstr;
const char *p_end = tstr_end;
int *vals[3] = {hour, minute, second};
char c = *(p++);
if (p >= p_end) {
return c != '\0';
- } else if (c == ':') {
+ }
+ else if (c == ':') {
continue;
- } else if (c == '.') {
+ }
+ else if (c == '.') {
break;
- } else {
- return -4; // Malformed time separator
+ }
+ else {
+ return -4; // Malformed time separator
}
}
}
static int
-parse_isoformat_time(const char *dtstr, size_t dtlen,
- int* hour, int *minute, int *second, int *microsecond,
- int* tzoffset, int *tzmicrosecond) {
+parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute,
+ int *second, int *microsecond, int *tzoffset,
+ int *tzmicrosecond)
+{
// Parse the time portion of a datetime.isoformat() string
//
// Return codes:
if (*tzinfo_pos == '+' || *tzinfo_pos == '-') {
break;
}
- } while(++tzinfo_pos < p_end);
+ } while (++tzinfo_pos < p_end);
- int rv = parse_hh_mm_ss_ff(dtstr, tzinfo_pos,
- hour, minute, second, microsecond);
+ int rv = parse_hh_mm_ss_ff(dtstr, tzinfo_pos, hour, minute, second,
+ microsecond);
if (rv < 0) {
return rv;
- } else if (tzinfo_pos == p_end) {
+ }
+ else if (tzinfo_pos == p_end) {
// We know that there's no time zone, so if there's stuff at the
// end of the string it's an error.
if (rv == 1) {
return -5;
- } else {
+ }
+ else {
return 0;
}
}
return -5;
}
- int tzsign = (*tzinfo_pos == '-')?-1:1;
+ int tzsign = (*tzinfo_pos == '-') ? -1 : 1;
tzinfo_pos++;
int tzhour = 0, tzminute = 0, tzsecond = 0;
- rv = parse_hh_mm_ss_ff(tzinfo_pos, p_end,
- &tzhour, &tzminute, &tzsecond, tzmicrosecond);
+ rv = parse_hh_mm_ss_ff(tzinfo_pos, p_end, &tzhour, &tzminute, &tzsecond,
+ tzmicrosecond);
*tzoffset = tzsign * ((tzhour * 3600) + (tzminute * 60) + tzsecond);
*tzmicrosecond *= tzsign;
- return rv?-5:1;
+ return rv ? -5 : 1;
}
-
/* ---------------------------------------------------------------------------
* Create various objects, mostly without range checking.
*/
return NULL;
}
- self = (PyDateTime_Date *) (type->tp_alloc(type, 0));
+ self = (PyDateTime_Date *)(type->tp_alloc(type, 0));
if (self != NULL)
set_date_fields(self, year, month, day);
- return (PyObject *) self;
+ return (PyObject *)self;
}
#define new_date(year, month, day) \
new_date_ex(year, month, day, &PyDateTime_DateType)
// Forward declaration
-static PyObject * new_datetime_ex(int, int, int, int, int, int, int,
- PyObject*, PyTypeObject*);
+static PyObject *
+new_datetime_ex(int, int, int, int, int, int, int, PyObject *, PyTypeObject *);
/* Create date instance with no range checking, or call subclass constructor */
static PyObject *
-new_date_subclass_ex(int year, int month, int day, PyObject *cls) {
+new_date_subclass_ex(int year, int month, int day, PyObject *cls)
+{
PyObject *result;
// We have "fast path" constructors for two subclasses: date and datetime
if ((PyTypeObject *)cls == &PyDateTime_DateType) {
result = new_date_ex(year, month, day, (PyTypeObject *)cls);
- } else if ((PyTypeObject *)cls == &PyDateTime_DateTimeType) {
+ }
+ else if ((PyTypeObject *)cls == &PyDateTime_DateTimeType) {
result = new_datetime_ex(year, month, day, 0, 0, 0, 0, Py_None,
(PyTypeObject *)cls);
- } else {
+ }
+ else {
result = PyObject_CallFunction(cls, "iii", year, month, day);
}
}
static inline PyObject *
-tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds) {
+tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds)
+{
PyObject *tzinfo;
if (rv == 1) {
// Create a timezone from offset in seconds (0 returns UTC)
}
tzinfo = new_timezone(delta, NULL);
Py_DECREF(delta);
- } else {
+ }
+ else {
tzinfo = Py_None;
Py_INCREF(Py_None);
}
return result;
}
+static PyObject *
+checked_divmod(PyObject *a, PyObject *b)
+{
+ PyObject *result = PyNumber_Divmod(a, b);
+ if (result != NULL) {
+ if (!PyTuple_Check(result)) {
+ PyErr_Format(PyExc_TypeError,
+ "divmod() returned non-tuple (type %.200s)",
+ result->ob_type->tp_name);
+ Py_DECREF(result);
+ return NULL;
+ }
+ if (PyTuple_GET_SIZE(result) != 2) {
+ PyErr_Format(PyExc_TypeError,
+ "divmod() returned a tuple of size %zd",
+ PyTuple_GET_SIZE(result));
+ Py_DECREF(result);
+ return NULL;
+ }
+ }
+ return result;
+}
+
/* Convert a number of us (as a Python int) to a timedelta.
*/
static PyObject *
int us;
int s;
int d;
- long temp;
PyObject *tuple = NULL;
PyObject *num = NULL;
PyObject *result = NULL;
- assert(PyLong_CheckExact(pyus));
- tuple = PyNumber_Divmod(pyus, us_per_second);
- if (tuple == NULL)
+ tuple = checked_divmod(pyus, us_per_second);
+ if (tuple == NULL) {
goto Done;
+ }
- num = PyTuple_GetItem(tuple, 1); /* us */
- if (num == NULL)
- goto Done;
- temp = PyLong_AsLong(num);
+ num = PyTuple_GET_ITEM(tuple, 1); /* us */
+ us = _PyLong_AsInt(num);
num = NULL;
- if (temp == -1 && PyErr_Occurred())
- goto Done;
- assert(0 <= temp && temp < 1000000);
- us = (int)temp;
- if (us < 0) {
- /* The divisor was positive, so this must be an error. */
- assert(PyErr_Occurred());
+ if (us == -1 && PyErr_Occurred()) {
goto Done;
}
+ if (!(0 <= us && us < 1000000)) {
+ goto BadDivmod;
+ }
- num = PyTuple_GetItem(tuple, 0); /* leftover seconds */
- if (num == NULL)
- goto Done;
+ num = PyTuple_GET_ITEM(tuple, 0); /* leftover seconds */
Py_INCREF(num);
Py_DECREF(tuple);
- tuple = PyNumber_Divmod(num, seconds_per_day);
+ tuple = checked_divmod(num, seconds_per_day);
if (tuple == NULL)
goto Done;
Py_DECREF(num);
- num = PyTuple_GetItem(tuple, 1); /* seconds */
- if (num == NULL)
- goto Done;
- temp = PyLong_AsLong(num);
+ num = PyTuple_GET_ITEM(tuple, 1); /* seconds */
+ s = _PyLong_AsInt(num);
num = NULL;
- if (temp == -1 && PyErr_Occurred())
- goto Done;
- assert(0 <= temp && temp < 24*3600);
- s = (int)temp;
-
- if (s < 0) {
- /* The divisor was positive, so this must be an error. */
- assert(PyErr_Occurred());
+ if (s == -1 && PyErr_Occurred()) {
goto Done;
}
+ if (!(0 <= s && s < 24*3600)) {
+ goto BadDivmod;
+ }
- num = PyTuple_GetItem(tuple, 0); /* leftover days */
- if (num == NULL)
- goto Done;
+ num = PyTuple_GET_ITEM(tuple, 0); /* leftover days */
Py_INCREF(num);
- temp = PyLong_AsLong(num);
- if (temp == -1 && PyErr_Occurred())
- goto Done;
- d = (int)temp;
- if ((long)d != temp) {
- PyErr_SetString(PyExc_OverflowError, "normalized days too "
- "large to fit in a C int");
+ d = _PyLong_AsInt(num);
+ if (d == -1 && PyErr_Occurred()) {
goto Done;
}
result = new_delta_ex(d, s, us, 0, type);
Py_XDECREF(tuple);
Py_XDECREF(num);
return result;
+
+BadDivmod:
+ PyErr_SetString(PyExc_TypeError,
+ "divmod() returned a value out of range");
+ goto Done;
}
#define microseconds_to_delta(pymicros) \
if (pyus_in == NULL)
return NULL;
- pyus_out = PyNumber_Multiply(pyus_in, intobj);
+ pyus_out = PyNumber_Multiply(intobj, pyus_in);
Py_DECREF(pyus_in);
if (pyus_out == NULL)
return NULL;
return NULL;
}
- divmod = PyNumber_Divmod(pyus_left, pyus_right);
+ divmod = checked_divmod(pyus_left, pyus_right);
Py_DECREF(pyus_left);
Py_DECREF(pyus_right);
if (divmod == NULL)
return NULL;
- assert(PyTuple_Size(divmod) == 2);
delta = microseconds_to_delta(PyTuple_GET_ITEM(divmod, 1));
if (delta == NULL) {
Py_DECREF(divmod);
assert(num != NULL);
if (PyLong_Check(num)) {
- prod = PyNumber_Multiply(factor, num);
+ prod = PyNumber_Multiply(num, factor);
if (prod == NULL)
return NULL;
- assert(PyLong_CheckExact(prod));
sum = PyNumber_Add(sofar, prod);
Py_DECREF(prod);
- assert(sum == NULL || PyLong_CheckExact(sum));
return sum;
}
Py_DECREF(sum);
Py_DECREF(x);
*leftover += fracpart;
- assert(y == NULL || PyLong_CheckExact(y));
return y;
}
};
static const char delta_doc[] =
-PyDoc_STR("Difference between two datetime values.");
+PyDoc_STR("Difference between two datetime values.\n\n"
+ "timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, "
+ "minutes=0, hours=0, weeks=0)\n\n"
+ "All arguments are optional and default to 0.\n"
+ "Arguments may be integers or floats, and may be positive or negative.");
static PyNumberMethods delta_as_number = {
delta_add, /* nb_add */
static char *date_kws[] = {"year", "month", "day", NULL};
static PyObject *
+date_from_pickle(PyTypeObject *type, PyObject *state)
+{
+ PyDateTime_Date *me;
+
+ me = (PyDateTime_Date *) (type->tp_alloc(type, 0));
+ if (me != NULL) {
+ const char *pdata = PyBytes_AS_STRING(state);
+ memcpy(me->data, pdata, _PyDateTime_DATE_DATASIZE);
+ me->hashcode = -1;
+ }
+ return (PyObject *)me;
+}
+
+static PyObject *
date_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
PyObject *self = NULL;
- PyObject *state;
int year;
int month;
int day;
/* Check for invocation from pickle with __getstate__ state */
- if (PyTuple_GET_SIZE(args) == 1 &&
- PyBytes_Check(state = PyTuple_GET_ITEM(args, 0)) &&
- PyBytes_GET_SIZE(state) == _PyDateTime_DATE_DATASIZE &&
- MONTH_IS_SANE(PyBytes_AS_STRING(state)[2]))
- {
- PyDateTime_Date *me;
-
- me = (PyDateTime_Date *) (type->tp_alloc(type, 0));
- if (me != NULL) {
- char *pdata = PyBytes_AS_STRING(state);
- memcpy(me->data, pdata, _PyDateTime_DATE_DATASIZE);
- me->hashcode = -1;
+ if (PyTuple_GET_SIZE(args) == 1) {
+ PyObject *state = PyTuple_GET_ITEM(args, 0);
+ if (PyBytes_Check(state)) {
+ if (PyBytes_GET_SIZE(state) == _PyDateTime_DATE_DATASIZE &&
+ MONTH_IS_SANE(PyBytes_AS_STRING(state)[2]))
+ {
+ return date_from_pickle(type, state);
+ }
+ }
+ else if (PyUnicode_Check(state)) {
+ if (PyUnicode_READY(state)) {
+ return NULL;
+ }
+ if (PyUnicode_GET_LENGTH(state) == _PyDateTime_DATE_DATASIZE &&
+ MONTH_IS_SANE(PyUnicode_READ_CHAR(state, 2)))
+ {
+ state = PyUnicode_AsLatin1String(state);
+ if (state == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
+ /* More informative error message. */
+ PyErr_SetString(PyExc_ValueError,
+ "Failed to encode latin1 string when unpickling "
+ "a date object. "
+ "pickle.load(data, encoding='latin1') is assumed.");
+ }
+ return NULL;
+ }
+ self = date_from_pickle(type, state);
+ Py_DECREF(state);
+ return self;
+ }
}
- return (PyObject *)me;
}
if (PyArg_ParseTupleAndKeywords(args, kw, "iii", date_kws,
/* Return the new date from a string as generated by date.isoformat() */
static PyObject *
-date_fromisoformat(PyObject *cls, PyObject *dtstr) {
+date_fromisoformat(PyObject *cls, PyObject *dtstr)
+{
assert(dtstr != NULL);
if (!PyUnicode_Check(dtstr)) {
- PyErr_SetString(PyExc_TypeError, "fromisoformat: argument must be str");
+ PyErr_SetString(PyExc_TypeError,
+ "fromisoformat: argument must be str");
return NULL;
}
Py_ssize_t len;
- const char * dt_ptr = PyUnicode_AsUTF8AndSize(dtstr, &len);
+ const char *dt_ptr = PyUnicode_AsUTF8AndSize(dtstr, &len);
if (dt_ptr == NULL) {
goto invalid_string_error;
}
int rv;
if (len == 10) {
rv = parse_isoformat_date(dt_ptr, &year, &month, &day);
- } else {
+ }
+ else {
rv = -1;
}
return new_date_subclass_ex(year, month, day, cls);
invalid_string_error:
- PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R",
- dtstr);
+ PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr);
return NULL;
}
-
/*
* Date arithmetic.
*/
return result;
Inconsistent:
- PyErr_SetString(PyExc_ValueError, "fromutc: tz.dst() gave"
+ PyErr_SetString(PyExc_ValueError, "fromutc: tz.dst() gave "
"inconsistent results; cannot convert");
/* fall through to failure */
"tzinfo", "fold", NULL};
static PyObject *
+time_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo)
+{
+ PyDateTime_Time *me;
+ char aware = (char)(tzinfo != Py_None);
+
+ if (aware && check_tzinfo_subclass(tzinfo) < 0) {
+ PyErr_SetString(PyExc_TypeError, "bad tzinfo state arg");
+ return NULL;
+ }
+
+ me = (PyDateTime_Time *) (type->tp_alloc(type, aware));
+ if (me != NULL) {
+ const char *pdata = PyBytes_AS_STRING(state);
+
+ memcpy(me->data, pdata, _PyDateTime_TIME_DATASIZE);
+ me->hashcode = -1;
+ me->hastzinfo = aware;
+ if (aware) {
+ Py_INCREF(tzinfo);
+ me->tzinfo = tzinfo;
+ }
+ if (pdata[0] & (1 << 7)) {
+ me->data[0] -= 128;
+ me->fold = 1;
+ }
+ else {
+ me->fold = 0;
+ }
+ }
+ return (PyObject *)me;
+}
+
+static PyObject *
time_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
PyObject *self = NULL;
- PyObject *state;
int hour = 0;
int minute = 0;
int second = 0;
int fold = 0;
/* Check for invocation from pickle with __getstate__ state */
- if (PyTuple_GET_SIZE(args) >= 1 &&
- PyTuple_GET_SIZE(args) <= 2 &&
- PyBytes_Check(state = PyTuple_GET_ITEM(args, 0)) &&
- PyBytes_GET_SIZE(state) == _PyDateTime_TIME_DATASIZE &&
- (0x7F & ((unsigned char) (PyBytes_AS_STRING(state)[0]))) < 24)
- {
- PyDateTime_Time *me;
- char aware;
-
+ if (PyTuple_GET_SIZE(args) >= 1 && PyTuple_GET_SIZE(args) <= 2) {
+ PyObject *state = PyTuple_GET_ITEM(args, 0);
if (PyTuple_GET_SIZE(args) == 2) {
tzinfo = PyTuple_GET_ITEM(args, 1);
- if (check_tzinfo_subclass(tzinfo) < 0) {
- PyErr_SetString(PyExc_TypeError, "bad "
- "tzinfo state arg");
- return NULL;
- }
}
- aware = (char)(tzinfo != Py_None);
- me = (PyDateTime_Time *) (type->tp_alloc(type, aware));
- if (me != NULL) {
- char *pdata = PyBytes_AS_STRING(state);
-
- memcpy(me->data, pdata, _PyDateTime_TIME_DATASIZE);
- me->hashcode = -1;
- me->hastzinfo = aware;
- if (aware) {
- Py_INCREF(tzinfo);
- me->tzinfo = tzinfo;
+ if (PyBytes_Check(state)) {
+ if (PyBytes_GET_SIZE(state) == _PyDateTime_TIME_DATASIZE &&
+ (0x7F & ((unsigned char) (PyBytes_AS_STRING(state)[0]))) < 24)
+ {
+ return time_from_pickle(type, state, tzinfo);
}
- if (pdata[0] & (1 << 7)) {
- me->data[0] -= 128;
- me->fold = 1;
+ }
+ else if (PyUnicode_Check(state)) {
+ if (PyUnicode_READY(state)) {
+ return NULL;
}
- else {
- me->fold = 0;
+ if (PyUnicode_GET_LENGTH(state) == _PyDateTime_TIME_DATASIZE &&
+ (0x7F & PyUnicode_READ_CHAR(state, 2)) < 24)
+ {
+ state = PyUnicode_AsLatin1String(state);
+ if (state == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
+ /* More informative error message. */
+ PyErr_SetString(PyExc_ValueError,
+ "Failed to encode latin1 string when unpickling "
+ "a time object. "
+ "pickle.load(data, encoding='latin1') is assumed.");
+ }
+ return NULL;
+ }
+ self = time_from_pickle(type, state, tzinfo);
+ Py_DECREF(state);
+ return self;
}
}
- return (PyObject *)me;
+ tzinfo = Py_None;
}
if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO$i", time_kws,
};
static PyObject *
+datetime_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo)
+{
+ PyDateTime_DateTime *me;
+ char aware = (char)(tzinfo != Py_None);
+
+ if (aware && check_tzinfo_subclass(tzinfo) < 0) {
+ PyErr_SetString(PyExc_TypeError, "bad tzinfo state arg");
+ return NULL;
+ }
+
+ me = (PyDateTime_DateTime *) (type->tp_alloc(type , aware));
+ if (me != NULL) {
+ const char *pdata = PyBytes_AS_STRING(state);
+
+ memcpy(me->data, pdata, _PyDateTime_DATETIME_DATASIZE);
+ me->hashcode = -1;
+ me->hastzinfo = aware;
+ if (aware) {
+ Py_INCREF(tzinfo);
+ me->tzinfo = tzinfo;
+ }
+ if (pdata[2] & (1 << 7)) {
+ me->data[2] -= 128;
+ me->fold = 1;
+ }
+ else {
+ me->fold = 0;
+ }
+ }
+ return (PyObject *)me;
+}
+
+static PyObject *
datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{
PyObject *self = NULL;
- PyObject *state;
int year;
int month;
int day;
PyObject *tzinfo = Py_None;
/* Check for invocation from pickle with __getstate__ state */
- if (PyTuple_GET_SIZE(args) >= 1 &&
- PyTuple_GET_SIZE(args) <= 2 &&
- PyBytes_Check(state = PyTuple_GET_ITEM(args, 0)) &&
- PyBytes_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE &&
- MONTH_IS_SANE(PyBytes_AS_STRING(state)[2] & 0x7F))
- {
- PyDateTime_DateTime *me;
- char aware;
-
+ if (PyTuple_GET_SIZE(args) >= 1 && PyTuple_GET_SIZE(args) <= 2) {
+ PyObject *state = PyTuple_GET_ITEM(args, 0);
if (PyTuple_GET_SIZE(args) == 2) {
tzinfo = PyTuple_GET_ITEM(args, 1);
- if (check_tzinfo_subclass(tzinfo) < 0) {
- PyErr_SetString(PyExc_TypeError, "bad "
- "tzinfo state arg");
- return NULL;
- }
}
- aware = (char)(tzinfo != Py_None);
- me = (PyDateTime_DateTime *) (type->tp_alloc(type , aware));
- if (me != NULL) {
- char *pdata = PyBytes_AS_STRING(state);
-
- memcpy(me->data, pdata, _PyDateTime_DATETIME_DATASIZE);
- me->hashcode = -1;
- me->hastzinfo = aware;
- if (aware) {
- Py_INCREF(tzinfo);
- me->tzinfo = tzinfo;
+ if (PyBytes_Check(state)) {
+ if (PyBytes_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE &&
+ MONTH_IS_SANE(PyBytes_AS_STRING(state)[2] & 0x7F))
+ {
+ return datetime_from_pickle(type, state, tzinfo);
}
- if (pdata[2] & (1 << 7)) {
- me->data[2] -= 128;
- me->fold = 1;
+ }
+ else if (PyUnicode_Check(state)) {
+ if (PyUnicode_READY(state)) {
+ return NULL;
}
- else {
- me->fold = 0;
+ if (PyUnicode_GET_LENGTH(state) == _PyDateTime_DATETIME_DATASIZE &&
+ MONTH_IS_SANE(PyUnicode_READ_CHAR(state, 2) & 0x7F))
+ {
+ state = PyUnicode_AsLatin1String(state);
+ if (state == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
+ /* More informative error message. */
+ PyErr_SetString(PyExc_ValueError,
+ "Failed to encode latin1 string when unpickling "
+ "a datetime object. "
+ "pickle.load(data, encoding='latin1') is assumed.");
+ }
+ return NULL;
+ }
+ self = datetime_from_pickle(type, state, tzinfo);
+ Py_DECREF(state);
+ return self;
}
}
- return (PyObject *)me;
+ tzinfo = Py_None;
}
if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO$i", datetime_kws,
}
static PyObject *
-_sanitize_isoformat_str(PyObject *dtstr, int *needs_decref) {
+_sanitize_isoformat_str(PyObject *dtstr)
+{
// `fromisoformat` allows surrogate characters in exactly one position,
// the separator; to allow datetime_fromisoformat to make the simplifying
// assumption that all valid strings can be encoded in UTF-8, this function
// replaces any surrogate character separators with `T`.
+ //
+ // The result of this, if not NULL, returns a new reference
Py_ssize_t len = PyUnicode_GetLength(dtstr);
- *needs_decref = 0;
- if (len <= 10 || !Py_UNICODE_IS_SURROGATE(PyUnicode_READ_CHAR(dtstr, 10))) {
+ if (len < 0) {
+ return NULL;
+ }
+
+ if (len <= 10 ||
+ !Py_UNICODE_IS_SURROGATE(PyUnicode_READ_CHAR(dtstr, 10))) {
+ Py_INCREF(dtstr);
return dtstr;
}
- PyObject *str_out = PyUnicode_New(len, PyUnicode_MAX_CHAR_VALUE(dtstr));
+ PyObject *str_out = _PyUnicode_Copy(dtstr);
if (str_out == NULL) {
return NULL;
}
- if (PyUnicode_CopyCharacters(str_out, 0, dtstr, 0, len) == -1 ||
- PyUnicode_WriteChar(str_out, 10, (Py_UCS4)'T')) {
+ if (PyUnicode_WriteChar(str_out, 10, (Py_UCS4)'T')) {
Py_DECREF(str_out);
return NULL;
}
- *needs_decref = 1;
return str_out;
}
static PyObject *
-datetime_fromisoformat(PyObject* cls, PyObject *dtstr) {
+datetime_fromisoformat(PyObject *cls, PyObject *dtstr)
+{
assert(dtstr != NULL);
if (!PyUnicode_Check(dtstr)) {
- PyErr_SetString(PyExc_TypeError, "fromisoformat: argument must be str");
+ PyErr_SetString(PyExc_TypeError,
+ "fromisoformat: argument must be str");
return NULL;
}
- int needs_decref = 0;
- dtstr = _sanitize_isoformat_str(dtstr, &needs_decref);
- if (dtstr == NULL) {
+ PyObject *dtstr_clean = _sanitize_isoformat_str(dtstr);
+ if (dtstr_clean == NULL) {
goto error;
}
Py_ssize_t len;
- const char * dt_ptr = PyUnicode_AsUTF8AndSize(dtstr, &len);
+ const char *dt_ptr = PyUnicode_AsUTF8AndSize(dtstr_clean, &len);
if (dt_ptr == NULL) {
- goto invalid_string_error;
+ if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
+ // Encoding errors are invalid string errors at this point
+ goto invalid_string_error;
+ }
+ else {
+ goto error;
+ }
}
const char *p = dt_ptr;
// In UTF-8, the length of multi-byte characters is encoded in the MSB
if ((p[10] & 0x80) == 0) {
p += 11;
- } else {
- switch(p[10] & 0xf0) {
+ }
+ else {
+ switch (p[10] & 0xf0) {
case 0xe0:
p += 13;
break;
}
len -= (p - dt_ptr);
- rv = parse_isoformat_time(p, len,
- &hour, &minute, &second, µsecond,
- &tzoffset, &tzusec);
+ rv = parse_isoformat_time(p, len, &hour, &minute, &second,
+ µsecond, &tzoffset, &tzusec);
}
if (rv < 0) {
goto invalid_string_error;
}
- PyObject* tzinfo = tzinfo_from_isoformat_results(rv, tzoffset, tzusec);
+ PyObject *tzinfo = tzinfo_from_isoformat_results(rv, tzoffset, tzusec);
if (tzinfo == NULL) {
goto error;
}
second, microsecond, tzinfo, cls);
Py_DECREF(tzinfo);
- if (needs_decref) {
- Py_DECREF(dtstr);
- }
+ Py_DECREF(dtstr_clean);
return dt;
invalid_string_error:
PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr);
error:
- if (needs_decref) {
- Py_DECREF(dtstr);
- }
+ Py_XDECREF(dtstr_clean);
return NULL;
}
-
/*
* Destructor.
*/
mpd_t *mpd_qnew(void);
mpd_t *mpd_new(mpd_context_t *ctx);
mpd_t *mpd_qnew_size(mpd_ssize_t size);
-void mpd_del(mpd_t *dec);
+EXTINLINE void mpd_del(mpd_t *dec);
-void mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len);
-int mpd_qresize(mpd_t *result, mpd_ssize_t size, uint32_t *status);
-int mpd_qresize_zero(mpd_t *result, mpd_ssize_t size, uint32_t *status);
-void mpd_minalloc(mpd_t *result);
+EXTINLINE void mpd_uint_zero(mpd_uint_t *dest, mpd_size_t len);
+EXTINLINE int mpd_qresize(mpd_t *result, mpd_ssize_t size, uint32_t *status);
+EXTINLINE int mpd_qresize_zero(mpd_t *result, mpd_ssize_t size, uint32_t *status);
+EXTINLINE void mpd_minalloc(mpd_t *result);
int mpd_resize(mpd_t *result, mpd_ssize_t size, mpd_context_t *ctx);
int mpd_resize_zero(mpd_t *result, mpd_ssize_t size, mpd_context_t *ctx);
#define Element_CheckExact(op) (Py_TYPE(op) == &Element_Type)
+#define Element_Check(op) PyObject_TypeCheck(op, &Element_Type)
+
/* -------------------------------------------------------------------- */
/* Element constructors and destructor */
}
LOCAL(void)
-dealloc_extra(ElementObject* self)
+dealloc_extra(ElementObjectExtra *extra)
{
- ElementObjectExtra *myextra;
Py_ssize_t i;
+ if (!extra)
+ return;
+
+ Py_DECREF(extra->attrib);
+
+ for (i = 0; i < extra->length; i++)
+ Py_DECREF(extra->children[i]);
+
+ if (extra->children != extra->_children)
+ PyObject_Free(extra->children);
+
+ PyObject_Free(extra);
+}
+
+LOCAL(void)
+clear_extra(ElementObject* self)
+{
+ ElementObjectExtra *myextra;
+
if (!self->extra)
return;
myextra = self->extra;
self->extra = NULL;
- Py_DECREF(myextra->attrib);
-
- for (i = 0; i < myextra->length; i++)
- Py_DECREF(myextra->children[i]);
-
- if (myextra->children != myextra->_children)
- PyObject_Free(myextra->children);
-
- PyObject_Free(myextra);
+ dealloc_extra(myextra);
}
/* Convenience internal function to create new Element objects with the given
get_attrib_from_keywords(PyObject *kwds)
{
PyObject *attrib_str = PyUnicode_FromString("attrib");
+ if (attrib_str == NULL) {
+ return NULL;
+ }
PyObject *attrib = PyDict_GetItem(kwds, attrib_str);
if (attrib) {
return NULL;
}
attrib = PyDict_Copy(attrib);
- PyDict_DelItem(kwds, attrib_str);
+ if (attrib && PyDict_DelItem(kwds, attrib_str) < 0) {
+ Py_DECREF(attrib);
+ attrib = NULL;
+ }
} else {
attrib = PyDict_New();
}
Py_DECREF(attrib_str);
- /* attrib can be NULL if PyDict_New failed */
- if (attrib)
- if (PyDict_Update(attrib, kwds) < 0)
- return NULL;
+ if (attrib != NULL && PyDict_Update(attrib, kwds) < 0) {
+ Py_DECREF(attrib);
+ return NULL;
+ }
return attrib;
}
Py_ssize_t size;
PyObject* *children;
+ assert(extra >= 0);
/* make sure self->children can hold the given number of extra
elements. set an exception and return -1 if allocation failed */
attrib = PyDict_Copy(attrib);
if (!attrib)
return NULL;
- if (kwds) {
- if (PyDict_Update(attrib, kwds) < 0) {
- return NULL;
- }
+ if (kwds != NULL && PyDict_Update(attrib, kwds) < 0) {
+ Py_DECREF(attrib);
+ return NULL;
}
} else if (kwds) {
/* have keyword args */
/* After dropping all references from extra, it's no longer valid anyway,
* so fully deallocate it.
*/
- dealloc_extra(self);
+ clear_extra(self);
return 0;
}
_elementtree_Element_clear_impl(ElementObject *self)
/*[clinic end generated code: output=8bcd7a51f94cfff6 input=3c719ff94bf45dd6]*/
{
- dealloc_extra(self);
+ clear_extra(self);
Py_INCREF(Py_None);
_set_joined_ptr(&self->text, Py_None);
Py_INCREF(JOIN_OBJ(self->tail));
_set_joined_ptr(&element->tail, self->tail);
+ assert(!element->extra || !element->extra->length);
if (self->extra) {
if (element_resize(element, self->extra->length) < 0) {
Py_DECREF(element);
element->extra->children[i] = self->extra->children[i];
}
+ assert(!element->extra->length);
element->extra->length = self->extra->length;
}
goto error;
_set_joined_ptr(&element->tail, JOIN_SET(tail, JOIN_GET(self->tail)));
+ assert(!element->extra || !element->extra->length);
if (self->extra) {
if (element_resize(element, self->extra->length) < 0)
goto error;
element->extra->children[i] = child;
}
+ assert(!element->extra->length);
element->extra->length = self->extra->length;
}
PyObject *children)
{
Py_ssize_t i, nchildren;
+ ElementObjectExtra *oldextra = NULL;
if (!tag) {
PyErr_SetString(PyExc_TypeError, "tag may not be NULL");
_set_joined_ptr(&self->tail, tail);
/* Handle ATTRIB and CHILDREN. */
- if (!children && !attrib)
+ if (!children && !attrib) {
Py_RETURN_NONE;
+ }
/* Compute 'nchildren'. */
if (children) {
PyErr_SetString(PyExc_TypeError, "'_children' is not a list");
return NULL;
}
- nchildren = PyList_Size(children);
- }
- else {
- nchildren = 0;
- }
+ nchildren = PyList_GET_SIZE(children);
- /* Allocate 'extra'. */
- if (element_resize(self, nchildren)) {
- return NULL;
- }
- assert(self->extra && self->extra->allocated >= nchildren);
+ /* (Re-)allocate 'extra'.
+ Avoid DECREFs calling into this code again (cycles, etc.)
+ */
+ oldextra = self->extra;
+ self->extra = NULL;
+ if (element_resize(self, nchildren)) {
+ assert(!self->extra || !self->extra->length);
+ clear_extra(self);
+ self->extra = oldextra;
+ return NULL;
+ }
+ assert(self->extra);
+ assert(self->extra->allocated >= nchildren);
+ if (oldextra) {
+ assert(self->extra->attrib == Py_None);
+ self->extra->attrib = oldextra->attrib;
+ oldextra->attrib = Py_None;
+ }
- /* Copy children */
- for (i = 0; i < nchildren; i++) {
- self->extra->children[i] = PyList_GET_ITEM(children, i);
- Py_INCREF(self->extra->children[i]);
- }
+ /* Copy children */
+ for (i = 0; i < nchildren; i++) {
+ self->extra->children[i] = PyList_GET_ITEM(children, i);
+ Py_INCREF(self->extra->children[i]);
+ }
- self->extra->length = nchildren;
- self->extra->allocated = nchildren;
+ assert(!self->extra->length);
+ self->extra->length = nchildren;
+ }
+ else {
+ if (element_resize(self, 0)) {
+ return NULL;
+ }
+ }
/* Stash attrib. */
if (attrib) {
Py_INCREF(attrib);
Py_XSETREF(self->extra->attrib, attrib);
}
+ dealloc_extra(oldextra);
Py_RETURN_NONE;
}
for (i = 0; i < PySequence_Fast_GET_SIZE(seq); i++) {
PyObject* element = PySequence_Fast_GET_ITEM(seq, i);
Py_INCREF(element);
- if (!PyObject_TypeCheck(element, (PyTypeObject *)&Element_Type)) {
+ if (!Element_Check(element)) {
PyErr_Format(
PyExc_TypeError,
"expected an Element, not \"%.200s\"",
for (i = 0; i < self->extra->length; i++) {
PyObject* item = self->extra->children[i];
int rc;
- if (!Element_CheckExact(item))
+ if (!Element_Check(item))
continue;
Py_INCREF(item);
rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ);
}
for (i = 0; i < self->extra->length; i++) {
- ElementObject* item = (ElementObject*) self->extra->children[i];
+ PyObject *item = self->extra->children[i];
int rc;
- if (!Element_CheckExact(item))
+ if (!Element_Check(item))
continue;
Py_INCREF(item);
- rc = PyObject_RichCompareBool(item->tag, path, Py_EQ);
+ rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ);
if (rc > 0) {
- PyObject* text = element_get_text(item);
+ PyObject* text = element_get_text((ElementObject*)item);
if (text == Py_None) {
Py_DECREF(item);
return PyUnicode_New(0, 0);
{
Py_ssize_t i;
PyObject* out;
- PyObject* tag = path;
elementtreestate *st = ET_STATE_GLOBAL;
- if (checkpath(tag) || namespaces != Py_None) {
+ if (checkpath(path) || namespaces != Py_None) {
_Py_IDENTIFIER(findall);
return _PyObject_CallMethodIdObjArgs(
- st->elementpath_obj, &PyId_findall, self, tag, namespaces, NULL
+ st->elementpath_obj, &PyId_findall, self, path, namespaces, NULL
);
}
for (i = 0; i < self->extra->length; i++) {
PyObject* item = self->extra->children[i];
int rc;
- if (!Element_CheckExact(item))
+ if (!Element_Check(item))
continue;
Py_INCREF(item);
- rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, tag, Py_EQ);
+ rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ);
if (rc != 0 && (rc < 0 || PyList_Append(out, item) < 0)) {
Py_DECREF(item);
Py_DECREF(out);
* scheduled for removal.
*/
if (!(recycle = PyList_New(slicelen))) {
- PyErr_NoMemory();
return -1;
}
self->extra->length -= slicelen;
/* Discard the recycle list with all the deleted sub-elements */
- Py_XDECREF(recycle);
+ Py_DECREF(recycle);
return 0;
}
continue;
}
- if (!PyObject_TypeCheck(extra->children[child_index], &Element_Type)) {
+ if (!Element_Check(extra->children[child_index])) {
PyErr_Format(PyExc_AttributeError,
"'%.100s' object has no attribute 'iter'",
Py_TYPE(extra->children[child_index])->tp_name);
if (!target) {
Py_CLEAR(self->entity);
Py_CLEAR(self->names);
- EXPAT(ParserFree)(self->parser);
return -1;
}
}
}
PyDoc_STRVAR(EVP_digest__doc__,
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
static PyObject *
EVP_digest(EVPobject *self, PyObject *unused)
}
static PyObject *
-bytesio_get_closed(bytesio *self)
+bytesio_get_closed(bytesio *self, void *Py_UNUSED(ignored))
{
if (self->buf == NULL) {
Py_RETURN_TRUE;
if (size < 0)
return _io_FileIO_readall_impl(self);
-#ifdef MS_WINDOWS
- /* On Windows, the count parameter of read() is an int */
- if (size > INT_MAX)
- size = INT_MAX;
-#endif
+ if (size > _PY_READ_MAX) {
+ size = _PY_READ_MAX;
+ }
bytes = PyBytes_FromStringAndSize(NULL, size);
if (bytes == NULL)
}
Py_INCREF(self->errors);
- self->translate = translate;
+ self->translate = translate ? 1 : 0;
self->seennl = 0;
self->pendingcr = 0;
/* Check if something is in the read buffer */
if (self->decoded_chars != NULL) {
if (encoding != Py_None || errors != Py_None || newline_obj != NULL) {
- _unsupported("It is not possible to set the encoding or newline"
+ _unsupported("It is not possible to set the encoding or newline "
"of stream after the first read");
return NULL;
}
}
bufsize = newsize;
- buf = PyMem_Realloc(buf, (bufsize + 1) * sizeof(wchar_t));
- if (!buf) {
+ wchar_t *tmp = PyMem_Realloc(buf,
+ (bufsize + 1) * sizeof(wchar_t));
+ if (tmp == NULL) {
PyMem_Free(buf);
return NULL;
}
+ buf = tmp;
}
subbuf = read_console_w(self->handle, bufsize - len, &n);
do {
i++;
val = PyLong_FromLong(s[i]);
- if (!val)
- break;
- if (PyList_SetItem(result, i, val)) {
- Py_DECREF(val);
- val = NULL;
- break;
+ if (val == NULL) {
+ Py_DECREF(result);
+ return NULL;
}
+ PyList_SET_ITEM(result, i, val);
} while (s[i] != '\0' && s[i] != CHAR_MAX);
- if (!val) {
- Py_DECREF(result);
- return NULL;
- }
-
return result;
}
return result_object;
}
+static int
+locale_is_ascii(const char *str)
+{
+ return (strlen(str) == 1 && ((unsigned char)str[0]) <= 127);
+}
+
+static int
+locale_decode_monetary(PyObject *dict, struct lconv *lc)
+{
+ int change_locale;
+ change_locale = (!locale_is_ascii(lc->int_curr_symbol)
+ || !locale_is_ascii(lc->currency_symbol)
+ || !locale_is_ascii(lc->mon_decimal_point)
+ || !locale_is_ascii(lc->mon_thousands_sep));
+
+ /* Keep a copy of the LC_CTYPE locale */
+ char *oldloc = NULL, *loc = NULL;
+ if (change_locale) {
+ oldloc = setlocale(LC_CTYPE, NULL);
+ if (!oldloc) {
+ PyErr_SetString(PyExc_RuntimeWarning,
+ "failed to get LC_CTYPE locale");
+ return -1;
+ }
+
+ oldloc = _PyMem_Strdup(oldloc);
+ if (!oldloc) {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ loc = setlocale(LC_MONETARY, NULL);
+ if (loc != NULL && strcmp(loc, oldloc) == 0) {
+ loc = NULL;
+ }
+
+ if (loc != NULL) {
+ /* Only set the locale temporarily the LC_CTYPE locale
+ to the LC_MONETARY locale if the two locales are different and
+ at least one string is non-ASCII. */
+ setlocale(LC_CTYPE, loc);
+ }
+ }
+
+ int res = -1;
+
+#define RESULT_STRING(ATTR) \
+ do { \
+ PyObject *obj; \
+ obj = PyUnicode_DecodeLocale(lc->ATTR, NULL); \
+ if (obj == NULL) { \
+ goto done; \
+ } \
+ if (PyDict_SetItemString(dict, Py_STRINGIFY(ATTR), obj) < 0) { \
+ Py_DECREF(obj); \
+ goto done; \
+ } \
+ Py_DECREF(obj); \
+ } while (0)
+
+ RESULT_STRING(int_curr_symbol);
+ RESULT_STRING(currency_symbol);
+ RESULT_STRING(mon_decimal_point);
+ RESULT_STRING(mon_thousands_sep);
+#undef RESULT_STRING
+
+ res = 0;
+
+done:
+ if (loc != NULL) {
+ setlocale(LC_CTYPE, oldloc);
+ }
+ PyMem_Free(oldloc);
+ return res;
+}
+
PyDoc_STRVAR(localeconv__doc__,
"() -> dict. Returns numeric and monetary locale-specific parameters.");
RESULT(#i, x); \
} while (0)
- /* Monetary information */
- RESULT_STRING(int_curr_symbol);
- RESULT_STRING(currency_symbol);
- RESULT_STRING(mon_decimal_point);
- RESULT_STRING(mon_thousands_sep);
+ /* Monetary information: LC_MONETARY encoding */
+ if (locale_decode_monetary(result, l) < 0) {
+ goto failed;
+ }
x = copy_grouping(l->mon_grouping);
RESULT("mon_grouping", x);
RESULT_INT(p_sign_posn);
RESULT_INT(n_sign_posn);
- /* Numeric information */
+ /* Numeric information: LC_NUMERIC encoding */
PyObject *decimal_point, *thousands_sep;
const char *grouping;
if (_Py_GetLocaleconvNumeric(&decimal_point,
failed:
Py_DECREF(result);
return NULL;
+
+#undef RESULT
+#undef RESULT_STRING
+#undef RESULT_INT
}
#if defined(HAVE_WCSCOLL)
static void*
PyLzma_Malloc(void *opaque, size_t items, size_t size)
{
- if (items > (size_t)PY_SSIZE_T_MAX / size)
+ if (size != 0 && items > (size_t)PY_SSIZE_T_MAX / size)
return NULL;
/* PyMem_Malloc() cannot be used:
the GIL is not held when lzma_code() is called */
if (!unlink) {
name_copy = PyMem_Malloc(strlen(name) + 1);
- if (name_copy == NULL)
- goto failure;
+ if (name_copy == NULL) {
+ return PyErr_NoMemory();
+ }
strcpy(name_copy, name);
}
if (handle != SEM_FAILED)
SEM_CLOSE(handle);
PyMem_Free(name_copy);
- _PyMp_SetError(NULL, MP_STANDARD_ERROR);
+ if (!PyErr_Occurred()) {
+ _PyMp_SetError(NULL, MP_STANDARD_ERROR);
+ }
return NULL;
}
goto done;
if (i >= numtotalargs) {
i = -1;
+ Py_DECREF(onerepr);
break;
}
PyTuple_SET_ITEM(argreprs, i, onerepr);
static int
_Pickle_InitState(PickleState *st)
{
- PyObject *builtins;
PyObject *copyreg = NULL;
PyObject *compat_pickle = NULL;
PyObject *codecs = NULL;
PyObject *functools = NULL;
+ _Py_IDENTIFIER(getattr);
- builtins = PyEval_GetBuiltins();
- if (builtins == NULL)
- goto error;
- st->getattr = PyDict_GetItemString(builtins, "getattr");
+ st->getattr = _PyEval_GetBuiltinId(&PyId_getattr);
if (st->getattr == NULL)
goto error;
- Py_INCREF(st->getattr);
copyreg = PyImport_ImportModule("copyreg");
if (!copyreg)
if (obj != NULL) {
obj_class = get_class(obj);
- p = obj_class != cls; /* true iff a problem */
+ if (obj_class == NULL) {
+ return -1;
+ }
+ p = obj_class != cls;
Py_DECREF(obj_class);
if (p) {
PyErr_SetString(st->PicklingError, "args[0] from "
/*****************************************************************************/
static PyObject *
-Pickler_get_memo(PicklerObject *self)
+Pickler_get_memo(PicklerObject *self, void *Py_UNUSED(ignored))
{
return PicklerMemoProxy_New(self);
}
static int
-Pickler_set_memo(PicklerObject *self, PyObject *obj)
+Pickler_set_memo(PicklerObject *self, PyObject *obj, void *Py_UNUSED(ignored))
{
PyMemoTable *new_memo = NULL;
}
else {
PyErr_Format(PyExc_TypeError,
- "'memo' attribute must be a PicklerMemoProxy object"
+ "'memo' attribute must be a PicklerMemoProxy object "
"or dict, not %.200s", Py_TYPE(obj)->tp_name);
return -1;
}
}
static PyObject *
-Pickler_get_persid(PicklerObject *self)
+Pickler_get_persid(PicklerObject *self, void *Py_UNUSED(ignored))
{
if (self->pers_func == NULL) {
PyErr_SetString(PyExc_AttributeError, "persistent_id");
}
static int
-Pickler_set_persid(PicklerObject *self, PyObject *value)
+Pickler_set_persid(PicklerObject *self, PyObject *value, void *Py_UNUSED(ignored))
{
if (value == NULL) {
PyErr_SetString(PyExc_TypeError,
static PyObject *
-Unpickler_get_memo(UnpicklerObject *self)
+Unpickler_get_memo(UnpicklerObject *self, void *Py_UNUSED(ignored))
{
return UnpicklerMemoProxy_New(self);
}
static int
-Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
+Unpickler_set_memo(UnpicklerObject *self, PyObject *obj, void *Py_UNUSED(ignored))
{
PyObject **new_memo;
size_t new_memo_size = 0;
}
else {
PyErr_Format(PyExc_TypeError,
- "'memo' attribute must be an UnpicklerMemoProxy object"
+ "'memo' attribute must be an UnpicklerMemoProxy object "
"or dict, not %.200s", Py_TYPE(obj)->tp_name);
return -1;
}
}
static PyObject *
-Unpickler_get_persload(UnpicklerObject *self)
+Unpickler_get_persload(UnpicklerObject *self, void *Py_UNUSED(ignored))
{
if (self->pers_func == NULL) {
PyErr_SetString(PyExc_AttributeError, "persistent_load");
}
static int
-Unpickler_set_persload(UnpicklerObject *self, PyObject *value)
+Unpickler_set_persload(UnpicklerObject *self, PyObject *value, void *Py_UNUSED(ignored))
{
if (value == NULL) {
PyErr_SetString(PyExc_TypeError,
#include <dirent.h>
#endif
+#ifdef _Py_MEMORY_SANITIZER
+# include <sanitizer/msan_interface.h>
+#endif
+
#if defined(__ANDROID__) && __ANDROID_API__ < 21 && !defined(SYS_getdents64)
# include <sys/linux-syscalls.h>
# define SYS_getdents64 __NR_getdents64
sizeof(buffer))) > 0) {
struct linux_dirent64 *entry;
int offset;
+#ifdef _Py_MEMORY_SANITIZER
+ __msan_unpoison(buffer, bytes);
+#endif
for (offset = 0; offset < bytes; offset += entry->d_reclen) {
int fd;
entry = (struct linux_dirent64 *)(buffer + offset);
NULL
};
-static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level);
+static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level, void *Py_UNUSED(ignored));
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
Py_INCREF(isolation_level);
}
Py_CLEAR(self->isolation_level);
- if (pysqlite_connection_set_isolation_level(self, isolation_level) < 0) {
+ if (pysqlite_connection_set_isolation_level(self, isolation_level, NULL) < 0) {
Py_DECREF(isolation_level);
return -1;
}
return NULL;
}
+ if (PyDict_SetItem(self->function_pinboard, func, Py_None) == -1) {
+ return NULL;
+ }
rc = sqlite3_create_function(self->db, name, narg, SQLITE_UTF8, (void*)func, _pysqlite_func_callback, NULL, NULL);
if (rc != SQLITE_OK) {
/* Workaround for SQLite bug: no error code or string is available here */
PyErr_SetString(pysqlite_OperationalError, "Error creating function");
return NULL;
- } else {
- if (PyDict_SetItem(self->function_pinboard, func, Py_None) == -1)
- return NULL;
-
- Py_RETURN_NONE;
}
+ Py_RETURN_NONE;
}
PyObject* pysqlite_connection_create_aggregate(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
return NULL;
}
+ if (PyDict_SetItem(self->function_pinboard, aggregate_class, Py_None) == -1) {
+ return NULL;
+ }
rc = sqlite3_create_function(self->db, name, n_arg, SQLITE_UTF8, (void*)aggregate_class, 0, &_pysqlite_step_callback, &_pysqlite_final_callback);
if (rc != SQLITE_OK) {
/* Workaround for SQLite bug: no error code or string is available here */
PyErr_SetString(pysqlite_OperationalError, "Error creating aggregate");
return NULL;
- } else {
- if (PyDict_SetItem(self->function_pinboard, aggregate_class, Py_None) == -1)
- return NULL;
-
- Py_RETURN_NONE;
}
+ Py_RETURN_NONE;
}
static int _authorizer_callback(void* user_arg, int action, const char* arg1, const char* arg2 , const char* dbname, const char* access_attempt_source)
return NULL;
}
+ if (PyDict_SetItem(self->function_pinboard, authorizer_cb, Py_None) == -1) {
+ return NULL;
+ }
rc = sqlite3_set_authorizer(self->db, _authorizer_callback, (void*)authorizer_cb);
-
if (rc != SQLITE_OK) {
PyErr_SetString(pysqlite_OperationalError, "Error setting authorizer callback");
return NULL;
- } else {
- if (PyDict_SetItem(self->function_pinboard, authorizer_cb, Py_None) == -1)
- return NULL;
-
- Py_RETURN_NONE;
}
+ Py_RETURN_NONE;
}
static PyObject* pysqlite_connection_set_progress_handler(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
/* None clears the progress handler previously set */
sqlite3_progress_handler(self->db, 0, 0, (void*)0);
} else {
- sqlite3_progress_handler(self->db, n, _progress_handler, progress_handler);
if (PyDict_SetItem(self->function_pinboard, progress_handler, Py_None) == -1)
return NULL;
+ sqlite3_progress_handler(self->db, n, _progress_handler, progress_handler);
}
Py_RETURN_NONE;
Py_RETURN_FALSE;
}
-static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level)
+static int
+pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level, void *Py_UNUSED(ignored))
{
if (isolation_level == Py_None) {
PyObject *res = pysqlite_connection_commit(self, NULL);
}
}
-Py_ssize_t pysqlite_row_length(pysqlite_Row* self, PyObject* args, PyObject* kwargs)
+static Py_ssize_t
+pysqlite_row_length(pysqlite_Row* self)
{
return PyTuple_GET_SIZE(self->data);
}
/* PatternObject's 'groupindex' method. */
static PyObject *
-pattern_groupindex(PatternObject *self)
+pattern_groupindex(PatternObject *self, void *Py_UNUSED(ignored))
{
if (self->groupindex == NULL)
return PyDict_New();
For 0 returns the entire match.");
static PyObject *
-match_lastindex_get(MatchObject *self)
+match_lastindex_get(MatchObject *self, void *Py_UNUSED(ignored))
{
if (self->lastindex >= 0)
return PyLong_FromSsize_t(self->lastindex);
}
static PyObject *
-match_lastgroup_get(MatchObject *self)
+match_lastgroup_get(MatchObject *self, void *Py_UNUSED(ignored))
{
if (self->pattern->indexgroup &&
self->lastindex >= 0 &&
}
static PyObject *
-match_regs_get(MatchObject *self)
+match_regs_get(MatchObject *self, void *Py_UNUSED(ignored))
{
if (self->regs) {
Py_INCREF(self->regs);
PySSL_BEGIN_ALLOW_THREADS
self->ssl = SSL_new(ctx);
PySSL_END_ALLOW_THREADS
+ if (self->ssl == NULL) {
+ Py_DECREF(self);
+ _setSSLError(NULL, 0, __FILE__, __LINE__);
+ return NULL;
+ }
SSL_set_app_data(self->ssl, self);
if (sock) {
SSL_set_fd(self->ssl, Py_SAFE_DOWNCAST(sock->sock_fd, SOCKET_T, int));
/* get a memory buffer */
biobuf = BIO_new(BIO_s_mem());
+ if (biobuf == NULL) {
+ PyErr_SetString(PySSLErrorObject, "failed to allocate BIO");
+ return NULL;
+ }
names = (GENERAL_NAMES *)X509_get_ext_d2i(
certificate, NID_subject_alt_name, NULL, NULL);
/* get a memory buffer */
biobuf = BIO_new(BIO_s_mem());
+ if (biobuf == NULL) {
+ PyErr_SetString(PySSLErrorObject, "failed to allocate BIO");
+ goto fail0;
+ }
(void) BIO_reset(biobuf);
serialNumber = X509_get_serialNumber(certificate);
return result;
nbytes = BIO_read(self->bio, PyBytes_AS_STRING(result), len);
- /* There should never be any short reads but check anyway. */
- if ((nbytes < len) && (_PyBytes_Resize(&result, len) < 0)) {
+ if (nbytes < 0) {
Py_DECREF(result);
+ _setSSLError(NULL, 0, __FILE__, __LINE__);
return NULL;
}
+ /* There should never be any short reads but check anyway. */
+ if (nbytes < len) {
+ _PyBytes_Resize(&result, nbytes);
+ }
+
return result;
}
return 0;
}
-static int
+static void
ndarray_releasebuf(NDArrayObject *self, Py_buffer *view)
{
if (!ND_IS_CONSUMER(self)) {
if (--ndbuf->exports == 0 && ndbuf != self->head)
ndbuf_delete(self, ndbuf);
}
-
- return 0;
}
static PyBufferProcs ndarray_as_buffer = {
}
static PyObject *
-test_buildvalue_N(PyObject *self, PyObject *noargs)
+test_buildvalue_N(PyObject *self, PyObject *Py_UNUSED(ignored))
{
PyObject *arg, *res;
/* Some tests of PyUnicode_FromFormat(). This needs more tests. */
static PyObject *
-test_string_from_format(PyObject *self, PyObject *args)
+test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
{
PyObject *result;
char *msg;
} known_capsule;
static PyObject *
-test_capsule(PyObject *self, PyObject *args)
+test_capsule(PyObject *self, PyObject *Py_UNUSED(ignored))
{
PyObject *object;
const char *error = NULL;
}
static PyObject *
-test_from_contiguous(PyObject* self, PyObject *noargs)
+test_from_contiguous(PyObject* self, PyObject *Py_UNUSED(ignored))
{
int data[9] = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
int init[5] = {0, 1, 2, 3, 4};
extern PyTypeObject _PyBytesIOBuffer_Type;
static PyObject *
-test_pep3118_obsolete_write_locks(PyObject* self, PyObject *noargs)
+test_pep3118_obsolete_write_locks(PyObject* self, PyObject *Py_UNUSED(ignored))
{
PyTypeObject *type = &_PyBytesIOBuffer_Type;
PyObject *b;
}
+static PyObject *
+get_global_config(PyObject *self, PyObject *Py_UNUSED(args))
+{
+ return _Py_GetGlobalVariablesAsDict();
+}
+
+
+static PyObject *
+get_core_config(PyObject *self, PyObject *Py_UNUSED(args))
+{
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
+ const _PyCoreConfig *config = &interp->core_config;
+ return _PyCoreConfig_AsDict(config);
+}
+
+
+static PyObject *
+get_main_config(PyObject *self, PyObject *Py_UNUSED(args))
+{
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
+ const _PyMainInterpreterConfig *config = &interp->config;
+ return _PyMainInterpreterConfig_AsDict(config);
+}
+
+
static PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS},
{"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS},
{"get_mapping_items", get_mapping_items, METH_O},
{"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
{"hamt", new_hamt, METH_NOARGS},
+ {"get_global_config", get_global_config, METH_NOARGS},
+ {"get_core_config", get_core_config, METH_NOARGS},
+ {"get_main_config", get_main_config, METH_NOARGS},
{NULL, NULL} /* sentinel */
};
for(tstate = PyInterpreterState_ThreadHead(tstate->interp);
tstate;
tstate = PyThreadState_Next(tstate))
- if (tstate->dict &&
- PyDict_GetItem(tstate->dict, self->key))
- PyDict_DelItem(tstate->dict, self->key);
+ if (tstate->dict && PyDict_GetItem(tstate->dict, self->key)) {
+ if (PyDict_DelItem(tstate->dict, self->key)) {
+ PyErr_Clear();
+ }
+ }
}
return 0;
}
}
static PyObject *
-PyTclObject_str(PyTclObject *self, void *ignored)
+PyTclObject_str(PyTclObject *self)
{
if (self->string) {
Py_INCREF(self->string);
static PyObject *
PyTclObject_repr(PyTclObject *self)
{
- PyObject *repr, *str = PyTclObject_str(self, NULL);
+ PyObject *repr, *str = PyTclObject_str(self);
if (str == NULL)
return NULL;
repr = PyUnicode_FromFormat("<%s object: %R>",
}
if (PyTclObject_Check(value)) {
- Tcl_Obj *v = ((PyTclObject*)value)->value;
- Tcl_IncrRefCount(v);
- return v;
+ return ((PyTclObject*)value)->value;
}
{
traceback_t *traceback;
int i;
+ if (!tracemalloc_config.tracing) {
+ PUTS(fd, "Enable tracemalloc to get the memory block "
+ "allocation traceback\n\n");
+ return;
+ }
+
traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
if (traceback == NULL)
return;
if (array_resize(self, old_size + n) == -1)
return NULL;
for (i = 0; i < n; i++) {
- PyObject *v = PyList_GetItem(list, i);
+ PyObject *v = PyList_GET_ITEM(list, i);
if ((*self->ob_descr->setitem)(self,
Py_SIZE(self) - n + i, v) != 0) {
array_resize(self, old_size);
return NULL;
}
+ if (n != PyList_GET_SIZE(list)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "list changed size during iteration");
+ array_resize(self, old_size);
+ return NULL;
+ }
}
}
Py_RETURN_NONE;
PyObject *v = getarrayitem((PyObject *)self, i);
if (v == NULL)
goto error;
- if (PyList_SetItem(list, i, v) < 0)
- goto error;
+ PyList_SET_ITEM(list, i, v);
}
return list;
if (c == 0xf8f0)
OUTBYTE1(0xa0);
else
- OUTBYTE1(c - 0xfef1 + 0xfd);
+ OUTBYTE1(c - 0xf8f1 + 0xfd);
NEXT(1, 1);
continue;
}
}
static PyObject *
-codecctx_errors_get(MultibyteStatefulCodecContext *self)
+codecctx_errors_get(MultibyteStatefulCodecContext *self, void *Py_UNUSED(ignored))
{
const char *errors;
"digest($self, /)\n"
"--\n"
"\n"
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
#define MD5TYPE_DIGEST_METHODDEF \
{"digest", (PyCFunction)MD5Type_digest, METH_NOARGS, MD5Type_digest__doc__},
exit:
return return_value;
}
-/*[clinic end generated code: output=50a95670913de8fb input=a9049054013a1b77]*/
+/*[clinic end generated code: output=72aa003c308e26cf input=a9049054013a1b77]*/
"Perform a stat system call on the given path.\n"
"\n"
" path\n"
-" Path to be examined; can be string, bytes, path-like object or\n"
+" Path to be examined; can be string, bytes, a path-like object or\n"
" open-file-descriptor int.\n"
" dir_fd\n"
" If not None, it should be a file descriptor open to a directory,\n"
"Use the real uid/gid to test for access to a path.\n"
"\n"
" path\n"
-" Path to be tested; can be string or bytes\n"
+" Path to be tested; can be string, bytes, or a path-like object.\n"
" mode\n"
" Operating-system mode bitfield. Can be F_OK to test existence,\n"
" or the inclusive-OR of R_OK, W_OK, and X_OK.\n"
"Change the access permissions of a file.\n"
"\n"
" path\n"
-" Path to be modified. May always be specified as a str or bytes.\n"
+" Path to be modified. May always be specified as a str, bytes, or a path-like object.\n"
" On some platforms, path may also be specified as an open file descriptor.\n"
" If this functionality is unavailable, using it raises an exception.\n"
" mode\n"
"Change the owner and group id of path to the numeric uid and gid.\\\n"
"\n"
" path\n"
-" Path to be examined; can be string, bytes, or open-file-descriptor int.\n"
+" Path to be examined; can be string, bytes, a path-like object, or open-file-descriptor int.\n"
" dir_fd\n"
" If not None, it should be a file descriptor open to a directory,\n"
" and path should be relative; path will then be relative to that\n"
"\n"
"Return a list containing the names of the files in the directory.\n"
"\n"
-"path can be specified as either str or bytes. If path is bytes,\n"
+"path can be specified as either str, bytes, or a path-like object. If path is bytes,\n"
" the filenames returned will also be bytes; in all other circumstances\n"
" the filenames returned will be str.\n"
"If path is None, uses the path=\'.\'.\n"
"\n"
"Return the value of extended attribute attribute on path.\n"
"\n"
-"path may be either a string or an open file descriptor.\n"
+"path may be either a string, a path-like object, or an open file descriptor.\n"
"If follow_symlinks is False, and the last element of the path is a symbolic\n"
" link, getxattr will examine the symbolic link itself instead of the file\n"
" the link points to.");
"\n"
"Set extended attribute attribute on path to value.\n"
"\n"
-"path may be either a string or an open file descriptor.\n"
+"path may be either a string, a path-like object, or an open file descriptor.\n"
"If follow_symlinks is False, and the last element of the path is a symbolic\n"
" link, setxattr will modify the symbolic link itself instead of the file\n"
" the link points to.");
"\n"
"Remove extended attribute attribute on path.\n"
"\n"
-"path may be either a string or an open file descriptor.\n"
+"path may be either a string, a path-like object, or an open file descriptor.\n"
"If follow_symlinks is False, and the last element of the path is a symbolic\n"
" link, removexattr will modify the symbolic link itself instead of the file\n"
" the link points to.");
"\n"
"Return a list of extended attributes on path.\n"
"\n"
-"path may be either None, a string, or an open file descriptor.\n"
+"path may be either None, a string, a path-like object, or an open file descriptor.\n"
"if path is None, listxattr will examine the current directory.\n"
"If follow_symlinks is False, and the last element of the path is a symbolic\n"
" link, listxattr will examine the symbolic link itself instead of the file\n"
"\n"
"Return an iterator of DirEntry objects for given path.\n"
"\n"
-"path can be specified as either str, bytes or path-like object. If path\n"
+"path can be specified as either str, bytes, or a path-like object. If path\n"
"is bytes, the names of yielded DirEntry objects will also be bytes; in\n"
"all other circumstances they will be str.\n"
"\n"
#ifndef OS_GETRANDOM_METHODDEF
#define OS_GETRANDOM_METHODDEF
#endif /* !defined(OS_GETRANDOM_METHODDEF) */
-/*[clinic end generated code: output=c966c821d557b7c0 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=c6ca6ad4afa64454 input=a9049054013a1b77]*/
"digest($self, /)\n"
"--\n"
"\n"
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
#define SHA1TYPE_DIGEST_METHODDEF \
{"digest", (PyCFunction)SHA1Type_digest, METH_NOARGS, SHA1Type_digest__doc__},
exit:
return return_value;
}
-/*[clinic end generated code: output=9ee2aec7bb2b9e72 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=81d2424c0585bfd4 input=a9049054013a1b77]*/
"digest($self, /)\n"
"--\n"
"\n"
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
#define SHA256TYPE_DIGEST_METHODDEF \
{"digest", (PyCFunction)SHA256Type_digest, METH_NOARGS, SHA256Type_digest__doc__},
exit:
return return_value;
}
-/*[clinic end generated code: output=4b90199bc9f7cc88 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=0086286cffcbc31c input=a9049054013a1b77]*/
"digest($self, /)\n"
"--\n"
"\n"
-"Return the digest value as a string of binary data.");
+"Return the digest value as a bytes object.");
#define SHA512TYPE_DIGEST_METHODDEF \
{"digest", (PyCFunction)SHA512Type_digest, METH_NOARGS, SHA512Type_digest__doc__},
exit:
return return_value;
}
-/*[clinic end generated code: output=f963a543bf3c72e8 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=fcc3306fb6672222 input=a9049054013a1b77]*/
/* External API definitions */
+/* Namespace external symbols to allow multiple libexpat version to
+ co-exist. */
+#include "pyexpatns.h"
+
#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
# define XML_USE_MSC_EXTENSIONS 1
#endif
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#if !defined(_WIN32) && defined(HAVE_EXPAT_CONFIG_H)
+# include <pyconfig.h>
+#endif
#include <stddef.h>
#include <string.h> /* memcpy */
#ifdef HAVE_SIGALTSTACK
if (stack.ss_sp != NULL) {
/* Fetch the current alt stack */
- stack_t current_stack;
+ stack_t current_stack = {};
if (sigaltstack(NULL, ¤t_stack) == 0) {
if (current_stack.ss_sp == stack.ss_sp) {
/* The current alt stack is the one that we installed.
char *str;
Py_ssize_t len;
char buf[1024];
+ int async_err = 0;
if (arg != NULL) {
int parse_result;
return NULL;
}
memcpy(buf, str, len);
- Py_BEGIN_ALLOW_THREADS
- ret = fcntl(fd, code, buf);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ ret = fcntl(fd, code, buf);
+ Py_END_ALLOW_THREADS
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (ret < 0) {
- PyErr_SetFromErrno(PyExc_OSError);
- return NULL;
+ return !async_err ? PyErr_SetFromErrno(PyExc_OSError) : NULL;
}
return PyBytes_FromStringAndSize(buf, len);
}
}
}
- Py_BEGIN_ALLOW_THREADS
- ret = fcntl(fd, code, (int)int_arg);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ ret = fcntl(fd, code, (int)int_arg);
+ Py_END_ALLOW_THREADS
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (ret < 0) {
- PyErr_SetFromErrno(PyExc_OSError);
- return NULL;
+ return !async_err ? PyErr_SetFromErrno(PyExc_OSError) : NULL;
}
return PyLong_FromLong((long)ret);
}
/*[clinic end generated code: output=84059e2b37d2fc64 input=b70a0a41ca22a8a0]*/
{
int ret;
+ int async_err = 0;
#ifdef HAVE_FLOCK
- Py_BEGIN_ALLOW_THREADS
- ret = flock(fd, code);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ ret = flock(fd, code);
+ Py_END_ALLOW_THREADS
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
#else
#ifndef LOCK_SH
return NULL;
}
l.l_whence = l.l_start = l.l_len = 0;
- Py_BEGIN_ALLOW_THREADS
- ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
+ Py_END_ALLOW_THREADS
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
}
#endif /* HAVE_FLOCK */
if (ret < 0) {
- PyErr_SetFromErrno(PyExc_OSError);
- return NULL;
+ return !async_err ? PyErr_SetFromErrno(PyExc_OSError) : NULL;
}
Py_RETURN_NONE;
}
/*[clinic end generated code: output=4985e7a172e7461a input=3a5dc01b04371f1a]*/
{
int ret;
+ int async_err = 0;
#ifndef LOCK_SH
#define LOCK_SH 1 /* shared lock */
return NULL;
}
l.l_whence = whence;
- Py_BEGIN_ALLOW_THREADS
- ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
+ Py_END_ALLOW_THREADS
+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
}
if (ret < 0) {
- PyErr_SetFromErrno(PyExc_OSError);
- return NULL;
+ return !async_err ? PyErr_SetFromErrno(PyExc_OSError) : NULL;
}
Py_RETURN_NONE;
}
goto out;
if ((p = getgrnam(name_chars)) == NULL) {
- PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %S", name);
+ PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %R", name);
goto out;
}
retval = mkgrent(p);
}
+static _PyInitError
+config_init_executable(_PyCoreConfig *config)
+{
+ assert(config->executable == NULL);
+
+ /* If Py_SetProgramFullPath() was called, use its value */
+ const wchar_t *program_full_path = _Py_path_config.program_full_path;
+ if (program_full_path != NULL) {
+ config->executable = _PyMem_RawWcsdup(program_full_path);
+ if (config->executable == NULL) {
+ return _Py_INIT_NO_MEMORY();
+ }
+ return _Py_INIT_OK();
+ }
+
+ return _Py_INIT_OK();
+}
+
+
static void
pymain_header(_PyMain *pymain)
{
static PyObject*
-wstrlist_as_pylist(int len, wchar_t **list)
+_Py_wstrlist_as_pylist(int len, wchar_t **list)
{
assert(list != NULL || len < 1);
}
+PyObject *
+_Py_GetGlobalVariablesAsDict(void)
+{
+ PyObject *dict, *obj;
+
+ dict = PyDict_New();
+ if (dict == NULL) {
+ return NULL;
+ }
+
+#define SET_ITEM(KEY, EXPR) \
+ do { \
+ obj = (EXPR); \
+ if (obj == NULL) { \
+ return NULL; \
+ } \
+ int res = PyDict_SetItemString(dict, (KEY), obj); \
+ Py_DECREF(obj); \
+ if (res < 0) { \
+ goto fail; \
+ } \
+ } while (0)
+#define SET_ITEM_INT(VAR) \
+ SET_ITEM(#VAR, PyLong_FromLong(VAR))
+#define FROM_STRING(STR) \
+ ((STR != NULL) ? \
+ PyUnicode_FromString(STR) \
+ : (Py_INCREF(Py_None), Py_None))
+#define SET_ITEM_STR(VAR) \
+ SET_ITEM(#VAR, FROM_STRING(VAR))
+
+ SET_ITEM_STR(Py_FileSystemDefaultEncoding);
+ SET_ITEM_INT(Py_HasFileSystemDefaultEncoding);
+ SET_ITEM_STR(Py_FileSystemDefaultEncodeErrors);
+
+ SET_ITEM_INT(Py_UTF8Mode);
+ SET_ITEM_INT(Py_DebugFlag);
+ SET_ITEM_INT(Py_VerboseFlag);
+ SET_ITEM_INT(Py_QuietFlag);
+ SET_ITEM_INT(Py_InteractiveFlag);
+ SET_ITEM_INT(Py_InspectFlag);
+
+ SET_ITEM_INT(Py_OptimizeFlag);
+ SET_ITEM_INT(Py_NoSiteFlag);
+ SET_ITEM_INT(Py_BytesWarningFlag);
+ SET_ITEM_INT(Py_FrozenFlag);
+ SET_ITEM_INT(Py_IgnoreEnvironmentFlag);
+ SET_ITEM_INT(Py_DontWriteBytecodeFlag);
+ SET_ITEM_INT(Py_NoUserSiteDirectory);
+ SET_ITEM_INT(Py_UnbufferedStdioFlag);
+ SET_ITEM_INT(Py_HashRandomizationFlag);
+ SET_ITEM_INT(Py_IsolatedFlag);
+
+#ifdef MS_WINDOWS
+ SET_ITEM_INT(Py_LegacyWindowsFSEncodingFlag);
+ SET_ITEM_INT(Py_LegacyWindowsStdioFlag);
+#endif
+
+ return dict;
+
+fail:
+ Py_DECREF(dict);
+ return NULL;
+
+#undef FROM_STRING
+#undef SET_ITEM
+#undef SET_ITEM_INT
+#undef SET_ITEM_STR
+}
+
+
void
_PyCoreConfig_GetGlobalConfig(_PyCoreConfig *config)
{
static void
config_init_locale(_PyCoreConfig *config)
{
- if (config->coerce_c_locale < 0) {
+ /* Test also if coerce_c_locale equals 1: PYTHONCOERCECLOCALE=1 doesn't
+ imply that the C locale is always coerced. It is only coerced if
+ if the LC_CTYPE locale is "C". */
+ if (config->coerce_c_locale != 0) {
/* The C locale enables the C locale coercion (PEP 538) */
if (_Py_LegacyLocaleDetected()) {
config->coerce_c_locale = 1;
}
+ else {
+ config->coerce_c_locale = 0;
+ }
}
#ifndef MS_WINDOWS
}
}
- if (config->utf8_mode < 0 || config->coerce_c_locale < 0) {
+ if (config->executable == NULL) {
+ err = config_init_executable(config);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+ }
+
+ if (config->coerce_c_locale != 0 || config->utf8_mode < 0) {
config_init_locale(config);
}
}
+PyObject *
+_PyCoreConfig_AsDict(const _PyCoreConfig *config)
+{
+ PyObject *dict, *obj;
+
+ dict = PyDict_New();
+ if (dict == NULL) {
+ return NULL;
+ }
+
+#define SET_ITEM(KEY, EXPR) \
+ do { \
+ obj = (EXPR); \
+ if (obj == NULL) { \
+ return NULL; \
+ } \
+ int res = PyDict_SetItemString(dict, (KEY), obj); \
+ Py_DECREF(obj); \
+ if (res < 0) { \
+ goto fail; \
+ } \
+ } while (0)
+#define FROM_STRING(STR) \
+ ((STR != NULL) ? \
+ PyUnicode_FromString(STR) \
+ : (Py_INCREF(Py_None), Py_None))
+#define SET_ITEM_INT(ATTR) \
+ SET_ITEM(#ATTR, PyLong_FromLong(config->ATTR))
+#define SET_ITEM_UINT(ATTR) \
+ SET_ITEM(#ATTR, PyLong_FromUnsignedLong(config->ATTR))
+#define SET_ITEM_STR(ATTR) \
+ SET_ITEM(#ATTR, FROM_STRING(config->ATTR))
+#define FROM_WSTRING(STR) \
+ ((STR != NULL) ? \
+ PyUnicode_FromWideChar(STR, -1) \
+ : (Py_INCREF(Py_None), Py_None))
+#define SET_ITEM_WSTR(ATTR) \
+ SET_ITEM(#ATTR, FROM_WSTRING(config->ATTR))
+#define SET_ITEM_WSTRLIST(NOPTION, OPTIONS) \
+ SET_ITEM(#OPTIONS, _Py_wstrlist_as_pylist(config->NOPTION, config->OPTIONS))
+
+ SET_ITEM_INT(install_signal_handlers);
+ SET_ITEM_INT(ignore_environment);
+ SET_ITEM_INT(use_hash_seed);
+ SET_ITEM_UINT(hash_seed);
+ SET_ITEM_STR(allocator);
+ SET_ITEM_INT(dev_mode);
+ SET_ITEM_INT(faulthandler);
+ SET_ITEM_INT(tracemalloc);
+ SET_ITEM_INT(import_time);
+ SET_ITEM_INT(show_ref_count);
+ SET_ITEM_INT(show_alloc_count);
+ SET_ITEM_INT(dump_refs);
+ SET_ITEM_INT(malloc_stats);
+ SET_ITEM_INT(coerce_c_locale);
+ SET_ITEM_INT(coerce_c_locale_warn);
+ SET_ITEM_INT(utf8_mode);
+ SET_ITEM_WSTR(program_name);
+ SET_ITEM_WSTRLIST(argc, argv);
+ SET_ITEM_WSTR(program);
+ SET_ITEM_WSTRLIST(nxoption, xoptions);
+ SET_ITEM_WSTRLIST(nwarnoption, warnoptions);
+ SET_ITEM_WSTR(module_search_path_env);
+ SET_ITEM_WSTR(home);
+ SET_ITEM_WSTRLIST(nmodule_search_path, module_search_paths);
+ SET_ITEM_WSTR(executable);
+ SET_ITEM_WSTR(prefix);
+ SET_ITEM_WSTR(base_prefix);
+ SET_ITEM_WSTR(exec_prefix);
+ SET_ITEM_WSTR(base_exec_prefix);
+ SET_ITEM_INT(_disable_importlib);
+
+ return dict;
+
+fail:
+ Py_DECREF(dict);
+ return NULL;
+
+#undef FROM_STRING
+#undef FROM_WSTRING
+#undef SET_ITEM
+#undef SET_ITEM_INT
+#undef SET_ITEM_UINT
+#undef SET_ITEM_STR
+#undef SET_ITEM_WSTR
+#undef SET_ITEM_WSTRLIST
+}
+
+
void
_PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *config)
{
{
_PyMainInterpreterConfig_Clear(config);
-#define COPY_ATTR(ATTR) \
+#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
+#define COPY_OBJ_ATTR(ATTR) \
do { \
if (config2->ATTR != NULL) { \
config->ATTR = config_copy_attr(config2->ATTR); \
} \
} while (0)
- COPY_ATTR(argv);
- COPY_ATTR(executable);
- COPY_ATTR(prefix);
- COPY_ATTR(base_prefix);
- COPY_ATTR(exec_prefix);
- COPY_ATTR(base_exec_prefix);
- COPY_ATTR(warnoptions);
- COPY_ATTR(xoptions);
- COPY_ATTR(module_search_path);
+ COPY_ATTR(install_signal_handlers);
+ COPY_OBJ_ATTR(argv);
+ COPY_OBJ_ATTR(executable);
+ COPY_OBJ_ATTR(prefix);
+ COPY_OBJ_ATTR(base_prefix);
+ COPY_OBJ_ATTR(exec_prefix);
+ COPY_OBJ_ATTR(base_exec_prefix);
+ COPY_OBJ_ATTR(warnoptions);
+ COPY_OBJ_ATTR(xoptions);
+ COPY_OBJ_ATTR(module_search_path);
#undef COPY_ATTR
+#undef COPY_OBJ_ATTR
return 0;
}
+PyObject*
+_PyMainInterpreterConfig_AsDict(const _PyMainInterpreterConfig *config)
+{
+ PyObject *dict, *obj;
+ int res;
+
+ dict = PyDict_New();
+ if (dict == NULL) {
+ return NULL;
+ }
+
+#define SET_ITEM_INT(ATTR) \
+ do { \
+ obj = PyLong_FromLong(config->ATTR); \
+ if (obj == NULL) { \
+ goto fail; \
+ } \
+ res = PyDict_SetItemString(dict, #ATTR, obj); \
+ Py_DECREF(obj); \
+ if (res < 0) { \
+ goto fail; \
+ } \
+ } while (0)
+
+#define SET_ITEM_OBJ(ATTR) \
+ do { \
+ obj = config->ATTR; \
+ if (obj == NULL) { \
+ obj = Py_None; \
+ } \
+ res = PyDict_SetItemString(dict, #ATTR, obj); \
+ if (res < 0) { \
+ goto fail; \
+ } \
+ } while (0)
+
+ SET_ITEM_INT(install_signal_handlers);
+ SET_ITEM_OBJ(argv);
+ SET_ITEM_OBJ(executable);
+ SET_ITEM_OBJ(prefix);
+ SET_ITEM_OBJ(base_prefix);
+ SET_ITEM_OBJ(exec_prefix);
+ SET_ITEM_OBJ(base_exec_prefix);
+ SET_ITEM_OBJ(warnoptions);
+ SET_ITEM_OBJ(xoptions);
+ SET_ITEM_OBJ(module_search_path);
+
+ return dict;
+
+fail:
+ Py_DECREF(dict);
+ return NULL;
+
+#undef SET_ITEM_OBJ
+}
_PyInitError
#define COPY_WSTRLIST(ATTR, LEN, LIST) \
do { \
if (ATTR == NULL) { \
- ATTR = wstrlist_as_pylist(LEN, LIST); \
+ ATTR = _Py_wstrlist_as_pylist(LEN, LIST); \
if (ATTR == NULL) { \
return _Py_INIT_NO_MEMORY(); \
} \
case $doconfig in
no) cc="$cc \$(CCSHARED) \$(PY_CFLAGS) \$(PY_CPPFLAGS)";;
*)
- cc="$cc \$(PY_STDMODULE_CFLAGS)";;
+ cc="$cc \$(PY_BUILTIN_MODULE_CFLAGS)";;
esac
rule="$obj: $src; $cc $cpps -c $src -o $obj"
echo "$rule" >>$rulesf
/*[clinic input]
MD5Type.digest
-Return the digest value as a string of binary data.
+Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
MD5Type_digest_impl(MD5object *self)
-/*[clinic end generated code: output=eb691dc4190a07ec input=7b96e65389412a34]*/
+/*[clinic end generated code: output=eb691dc4190a07ec input=bc0c4397c2994be6]*/
{
unsigned char digest[MD5_DIGESTSIZE];
struct md5_state temp;
}
static PyObject *
-mmap_closed_get(mmap_object *self)
+mmap_closed_get(mmap_object *self, void *Py_UNUSED(ignored))
{
#ifdef MS_WINDOWS
return PyBool_FromLong(self->map_handle == NULL ? 1 : 0);
PyObject *str = PyUnicode_FromString(maps->map);
if (!str || PyList_Append(list, str) < 0)
{
+ Py_XDECREF(str);
Py_DECREF(list);
list = NULL;
break;
#endif /* MS_WINDOWS */
static PyObject *
+posix_path_object_error(PyObject *path)
+{
+ return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
+}
+
+static PyObject *
path_object_error(PyObject *path)
{
#ifdef MS_WINDOWS
return PyErr_SetExcFromWindowsErrWithFilenameObject(
PyExc_OSError, 0, path);
#else
- return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
+ return posix_path_object_error(path);
#endif
}
}
static PyObject *
+posix_path_error(path_t *path)
+{
+ return posix_path_object_error(path->object);
+}
+
+static PyObject *
path_error2(path_t *path, path_t *path2)
{
return path_object_error2(path->object, path2->object);
os.stat
path : path_t(allow_fd=True)
- Path to be examined; can be string, bytes, path-like object or
+ Path to be examined; can be string, bytes, a path-like object or
open-file-descriptor int.
*
static PyObject *
os_stat_impl(PyObject *module, path_t *path, int dir_fd, int follow_symlinks)
-/*[clinic end generated code: output=7d4976e6f18a59c5 input=270bd64e7bb3c8f7]*/
+/*[clinic end generated code: output=7d4976e6f18a59c5 input=01d362ebcc06996b]*/
{
return posix_do_stat("stat", path, dir_fd, follow_symlinks);
}
os.access -> bool
path: path_t
- Path to be tested; can be string or bytes
+ Path to be tested; can be string, bytes, or a path-like object.
mode: int
Operating-system mode bitfield. Can be F_OK to test existence,
static int
os_access_impl(PyObject *module, path_t *path, int mode, int dir_fd,
int effective_ids, int follow_symlinks)
-/*[clinic end generated code: output=cf84158bc90b1a77 input=8e8c3a6ba791fee3]*/
+/*[clinic end generated code: output=cf84158bc90b1a77 input=3ffe4e650ee3bf20]*/
{
int return_value;
os.chmod
path: path_t(allow_fd='PATH_HAVE_FCHMOD')
- Path to be modified. May always be specified as a str or bytes.
+ Path to be modified. May always be specified as a str, bytes, or a path-like object.
On some platforms, path may also be specified as an open file descriptor.
If this functionality is unavailable, using it raises an exception.
static PyObject *
os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd,
int follow_symlinks)
-/*[clinic end generated code: output=5cf6a94915cc7bff input=7f1618e5e15cc196]*/
+/*[clinic end generated code: output=5cf6a94915cc7bff input=989081551c00293b]*/
{
int result;
os.chown
path : path_t(allow_fd='PATH_HAVE_FCHOWN')
- Path to be examined; can be string, bytes, or open-file-descriptor int.
+ Path to be examined; can be string, bytes, a path-like object, or open-file-descriptor int.
uid: uid_t
static PyObject *
os_chown_impl(PyObject *module, path_t *path, uid_t uid, gid_t gid,
int dir_fd, int follow_symlinks)
-/*[clinic end generated code: output=4beadab0db5f70cd input=a61cc35574814d5d]*/
+/*[clinic end generated code: output=4beadab0db5f70cd input=b08c5ec67996a97d]*/
{
int result;
Return a list containing the names of the files in the directory.
-path can be specified as either str or bytes. If path is bytes,
+path can be specified as either str, bytes, or a path-like object. If path is bytes,
the filenames returned will also be bytes; in all other circumstances
the filenames returned will be str.
If path is None, uses the path='.'.
static PyObject *
os_listdir_impl(PyObject *module, path_t *path)
-/*[clinic end generated code: output=293045673fcd1a75 input=09e300416e3cd729]*/
+/*[clinic end generated code: output=293045673fcd1a75 input=e3f58030f538295d]*/
{
#if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR)
return _listdir_windows_no_opendir(path, NULL);
int result;
#endif
- PyObject *return_value = NULL;
utime_t utime;
memset(&utime, 0, sizeof(utime_t));
PyErr_SetString(PyExc_ValueError,
"utime: you may specify either 'times'"
" or 'ns' but not both");
- goto exit;
+ return NULL;
}
if (times && (times != Py_None)) {
PyErr_SetString(PyExc_TypeError,
"utime: 'times' must be either"
" a tuple of two ints or None");
- goto exit;
+ return NULL;
}
utime.now = 0;
if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 0),
&a_sec, &a_nsec, _PyTime_ROUND_FLOOR) == -1 ||
_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 1),
&m_sec, &m_nsec, _PyTime_ROUND_FLOOR) == -1) {
- goto exit;
+ return NULL;
}
utime.atime_s = a_sec;
utime.atime_ns = a_nsec;
if (!PyTuple_CheckExact(ns) || (PyTuple_Size(ns) != 2)) {
PyErr_SetString(PyExc_TypeError,
"utime: 'ns' must be a tuple of two ints");
- goto exit;
+ return NULL;
}
utime.now = 0;
if (!split_py_long_to_s_and_ns(PyTuple_GET_ITEM(ns, 0),
&utime.atime_s, &utime.atime_ns) ||
!split_py_long_to_s_and_ns(PyTuple_GET_ITEM(ns, 1),
&utime.mtime_s, &utime.mtime_ns)) {
- goto exit;
+ return NULL;
}
}
else {
#if !defined(UTIME_HAVE_NOFOLLOW_SYMLINKS)
if (follow_symlinks_specified("utime", follow_symlinks))
- goto exit;
+ return NULL;
#endif
if (path_and_dir_fd_invalid("utime", path, dir_fd) ||
dir_fd_and_fd_invalid("utime", dir_fd, path->fd) ||
fd_and_follow_symlinks_invalid("utime", path->fd, follow_symlinks))
- goto exit;
+ return NULL;
#if !defined(HAVE_UTIMENSAT)
if ((dir_fd != DEFAULT_DIR_FD) && (!follow_symlinks)) {
PyErr_SetString(PyExc_ValueError,
"utime: cannot use dir_fd and follow_symlinks "
"together on this platform");
- goto exit;
+ return NULL;
}
#endif
Py_END_ALLOW_THREADS
if (hFile == INVALID_HANDLE_VALUE) {
path_error(path);
- goto exit;
+ return NULL;
}
if (utime.now) {
something is wrong with the file, when it also
could be the time stamp that gives a problem. */
PyErr_SetFromWindowsErr(0);
- goto exit;
+ CloseHandle(hFile);
+ return NULL;
}
+ CloseHandle(hFile);
#else /* MS_WINDOWS */
Py_BEGIN_ALLOW_THREADS
if (result < 0) {
/* see previous comment about not putting filename in error here */
- return_value = posix_error();
- goto exit;
+ posix_error();
+ return NULL;
}
#endif /* MS_WINDOWS */
- Py_INCREF(Py_None);
- return_value = Py_None;
-
-exit:
-#ifdef MS_WINDOWS
- if (hFile != INVALID_HANDLE_VALUE)
- CloseHandle(hFile);
-#endif
- return return_value;
+ Py_RETURN_NONE;
}
/* Process operations */
/* If we get here it's definitely an error */
- path_error(path);
+ posix_path_error(path);
free_string_array(envlist, envc);
fail:
} else {
alt_grouplist = PyMem_New(gid_t, n);
if (alt_grouplist == NULL) {
- errno = EINVAL;
- return posix_error();
+ return PyErr_NoMemory();
}
}
} else {
alt_grouplist = PyMem_New(gid_t, n);
if (alt_grouplist == NULL) {
- errno = EINVAL;
- return posix_error();
+ return PyErr_NoMemory();
}
n = getgroups(n, alt_grouplist);
if (n == -1) {
return posix_error();
}
-#ifdef MS_WINDOWS
- /* On Windows, the count parameter of read() is an int */
- if (length > INT_MAX)
- length = INT_MAX;
-#endif
+ length = Py_MIN(length, _PY_READ_MAX);
buffer = PyBytes_FromStringAndSize((char *)NULL, length);
if (buffer == NULL)
_Py_END_SUPPRESS_IPH
Py_END_ALLOW_THREADS
if (result < 0)
- return path_error(path);
+ return posix_path_error(path);
Py_RETURN_NONE;
}
Return the value of extended attribute attribute on path.
-path may be either a string or an open file descriptor.
+path may be either a string, a path-like object, or an open file descriptor.
If follow_symlinks is False, and the last element of the path is a symbolic
link, getxattr will examine the symbolic link itself instead of the file
the link points to.
static PyObject *
os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute,
int follow_symlinks)
-/*[clinic end generated code: output=5f2f44200a43cff2 input=8c8ea3bab78d89c2]*/
+/*[clinic end generated code: output=5f2f44200a43cff2 input=025789491708f7eb]*/
{
Py_ssize_t i;
PyObject *buffer = NULL;
Set extended attribute attribute on path to value.
-path may be either a string or an open file descriptor.
+path may be either a string, a path-like object, or an open file descriptor.
If follow_symlinks is False, and the last element of the path is a symbolic
link, setxattr will modify the symbolic link itself instead of the file
the link points to.
static PyObject *
os_setxattr_impl(PyObject *module, path_t *path, path_t *attribute,
Py_buffer *value, int flags, int follow_symlinks)
-/*[clinic end generated code: output=98b83f63fdde26bb input=f0d26833992015c2]*/
+/*[clinic end generated code: output=98b83f63fdde26bb input=c17c0103009042f0]*/
{
ssize_t result;
Remove extended attribute attribute on path.
-path may be either a string or an open file descriptor.
+path may be either a string, a path-like object, or an open file descriptor.
If follow_symlinks is False, and the last element of the path is a symbolic
link, removexattr will modify the symbolic link itself instead of the file
the link points to.
static PyObject *
os_removexattr_impl(PyObject *module, path_t *path, path_t *attribute,
int follow_symlinks)
-/*[clinic end generated code: output=521a51817980cda6 input=cdb54834161e3329]*/
+/*[clinic end generated code: output=521a51817980cda6 input=3d9a7d36fe2f7c4e]*/
{
ssize_t result;
Return a list of extended attributes on path.
-path may be either None, a string, or an open file descriptor.
+path may be either None, a string, a path-like object, or an open file descriptor.
if path is None, listxattr will examine the current directory.
If follow_symlinks is False, and the last element of the path is a symbolic
link, listxattr will examine the symbolic link itself instead of the file
static PyObject *
os_listxattr_impl(PyObject *module, path_t *path, int follow_symlinks)
-/*[clinic end generated code: output=bebdb4e2ad0ce435 input=08cca53ac0b07c13]*/
+/*[clinic end generated code: output=bebdb4e2ad0ce435 input=9826edf9fdb90869]*/
{
Py_ssize_t i;
PyObject *result = NULL;
Return an iterator of DirEntry objects for given path.
-path can be specified as either str, bytes or path-like object. If path
+path can be specified as either str, bytes, or a path-like object. If path
is bytes, the names of yielded DirEntry objects will also be bytes; in
all other circumstances they will be str.
static PyObject *
os_scandir_impl(PyObject *module, path_t *path)
-/*[clinic end generated code: output=6eb2668b675ca89e input=b139dc1c57f60846]*/
+/*[clinic end generated code: output=6eb2668b675ca89e input=6bdd312708fc3bb0]*/
{
ScandirIterator *iterator;
#ifdef MS_WINDOWS
goto out;
if ((p = getpwnam(name)) == NULL) {
PyErr_Format(PyExc_KeyError,
- "getpwnam(): name not found: %S", arg);
+ "getpwnam(): name not found: %R", arg);
goto out;
}
retval = mkpwent(p);
if (!value) {
if (PyDict_SetItem(self->intern, result, result) == 0)
return result;
- else
+ else {
+ Py_DECREF(result);
return NULL;
+ }
}
Py_INCREF(value);
Py_DECREF(result);
flag_error(self);
Py_DECREF(n);
Py_DECREF(v);
+ Py_DECREF(container);
return;
}
else {
}
}
args = string_intern(self, name);
- if (args != NULL)
- args = Py_BuildValue("(NN)", args, container);
if (args == NULL) {
Py_DECREF(container);
return;
}
+ args = Py_BuildValue("(NN)", args, container);
+ if (args == NULL) {
+ return;
+ }
/* Container is now a borrowed reference; ignore it. */
self->in_callback = 1;
rv = call_with_frame("StartElement", __LINE__,
}
args = Py_BuildValue("NN", nameobj, modelobj);
if (args == NULL) {
- Py_DECREF(modelobj);
flag_error(self);
goto finally;
}
s = decode(matches[i+1]);
if (s == NULL)
goto error;
- if (PyList_SetItem(m, i, s) == -1)
- goto error;
+ PyList_SET_ITEM(m, i, s);
}
sub = decode(matches[0]);
r = PyObject_CallFunction(readlinestate_global->completion_display_matches_hook,
if (tvp) {
timeout = deadline - _PyTime_GetMonotonicClock();
if (timeout < 0) {
+ /* bpo-35310: lists were unmodified -- clear them explicitly */
+ FD_ZERO(&ifdset);
+ FD_ZERO(&ofdset);
+ FD_ZERO(&efdset);
n = 0;
break;
}
goto error;
}
PyTuple_SET_ITEM(value, 1, num);
- if ((PyList_SetItem(result_list, j, value)) == -1) {
- Py_DECREF(value);
- goto error;
- }
+ PyList_SET_ITEM(result_list, j, value);
i++;
}
return result_list;
Py_DECREF(num2);
if (value == NULL)
goto error;
- if ((PyList_SetItem(result_list, i, value)) == -1) {
- Py_DECREF(value);
- goto error;
- }
+ PyList_SET_ITEM(result_list, i, value);
}
return result_list;
object will raise an exception.");
static PyObject*
-devpoll_get_closed(devpollObject *self)
+devpoll_get_closed(devpollObject *self, void *Py_UNUSED(ignored))
{
if (self->fd_devpoll < 0)
Py_RETURN_TRUE;
object will raise an exception.");
static PyObject*
-pyepoll_get_closed(pyEpoll_Object *self)
+pyepoll_get_closed(pyEpoll_Object *self, void *Py_UNUSED(ignored))
{
if (self->epfd < 0)
Py_RETURN_TRUE;
object will raise an exception.");
static PyObject*
-kqueue_queue_get_closed(kqueue_queue_Object *self)
+kqueue_queue_get_closed(kqueue_queue_Object *self, void *Py_UNUSED(ignored))
{
if (self->kqfd < 0)
Py_RETURN_TRUE;
/*[clinic input]
SHA1Type.digest
-Return the digest value as a string of binary data.
+Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
SHA1Type_digest_impl(SHA1object *self)
-/*[clinic end generated code: output=2f05302a7aa2b5cb input=205d47e1927fd009]*/
+/*[clinic end generated code: output=2f05302a7aa2b5cb input=13824b35407444bd]*/
{
unsigned char digest[SHA1_DIGESTSIZE];
struct sha1_state temp;
/*[clinic input]
SHA256Type.digest
-Return the digest value as a string of binary data.
+Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
SHA256Type_digest_impl(SHAobject *self)
-/*[clinic end generated code: output=46616a5e909fbc3d input=1fb752e58954157d]*/
+/*[clinic end generated code: output=46616a5e909fbc3d input=f1f4cfea5cbde35c]*/
{
unsigned char digest[SHA_DIGESTSIZE];
SHAobject temp;
/*[clinic input]
SHA512Type.digest
-Return the digest value as a string of binary data.
+Return the digest value as a bytes object.
[clinic start generated code]*/
static PyObject *
SHA512Type_digest_impl(SHAobject *self)
-/*[clinic end generated code: output=1080bbeeef7dde1b input=60c2cede9e023018]*/
+/*[clinic end generated code: output=1080bbeeef7dde1b input=f6470dd359071f4b]*/
{
unsigned char digest[SHA_DIGESTSIZE];
SHAobject temp;
else {
if (PyDict_GetItemString(
dict,
- win_runtime_flags[i].flag_name) != NULL) {
- PyDict_DelItemString(
- dict,
- win_runtime_flags[i].flag_name);
+ win_runtime_flags[i].flag_name) != NULL)
+ {
+ if (PyDict_DelItemString(
+ dict,
+ win_runtime_flags[i].flag_name))
+ {
+ PyErr_Clear();
+ }
}
}
}
if (!PyArg_ParseTuple(args, "ss|HH:getsockaddrarg",
&type, &name, &sa->salg_feat, &sa->salg_mask))
+ {
return 0;
- /* sockaddr_alg has fixed-sized char arrays for type and name */
- if (strlen(type) > sizeof(sa->salg_type)) {
+ }
+ /* sockaddr_alg has fixed-sized char arrays for type, and name
+ * both must be NULL terminated.
+ */
+ if (strlen(type) >= sizeof(sa->salg_type)) {
PyErr_SetString(PyExc_ValueError, "AF_ALG type too long.");
return 0;
}
strncpy((char *)sa->salg_type, type, sizeof(sa->salg_type));
- if (strlen(name) > sizeof(sa->salg_name)) {
+ if (strlen(name) >= sizeof(sa->salg_name)) {
PyErr_SetString(PyExc_ValueError, "AF_ALG name too long.");
return 0;
}
if (single == NULL)
goto err;
- if (PyList_Append(all, single))
+ if (PyList_Append(all, single)) {
+ Py_DECREF(single);
goto err;
- Py_XDECREF(single);
+ }
+ Py_DECREF(single);
}
Py_XDECREF(idna);
if (res0)
PyList_SetItem(v, 3, PyLong_FromLong((long)mode.c_lflag));
PyList_SetItem(v, 4, PyLong_FromLong((long)ispeed));
PyList_SetItem(v, 5, PyLong_FromLong((long)ospeed));
- PyList_SetItem(v, 6, cc);
- if (PyErr_Occurred()){
+ if (PyErr_Occurred()) {
Py_DECREF(v);
goto err;
}
+ PyList_SetItem(v, 6, cc);
return v;
err:
Py_DECREF(cc);
#endif /* HAVE_MKTIME */
#ifdef HAVE_WORKING_TZSET
-static void PyInit_timezone(PyObject *module);
+static int init_timezone(PyObject *module);
static PyObject *
time_tzset(PyObject *self, PyObject *unused)
tzset();
/* Reset timezone, altzone, daylight and tzname */
- PyInit_timezone(m);
+ if (init_timezone(m) < 0) {
+ return NULL;
+ }
Py_DECREF(m);
if (PyErr_Occurred())
return NULL;
#endif
}
-static int
+static time_t
get_gmtoff(time_t t, struct tm *p)
{
#ifdef HAVE_STRUCT_TM_TM_ZONE
}
#endif /* !defined(HAVE_TZNAME) || defined(__GLIBC__) || defined(__CYGWIN__) */
-static void
-PyInit_timezone(PyObject *m) {
+static int
+init_timezone(PyObject *m)
+{
+ assert(!PyErr_Occurred());
+
/* This code moved from PyInit_time wholesale to allow calling it from
time_tzset. In the future, some parts of it can be moved back
(for platforms that don't HAVE_WORKING_TZSET, when we know what they
#endif
PyModule_AddIntConstant(m, "daylight", daylight);
otz0 = PyUnicode_DecodeLocale(tzname[0], "surrogateescape");
+ if (otz0 == NULL) {
+ return -1;
+ }
otz1 = PyUnicode_DecodeLocale(tzname[1], "surrogateescape");
- PyModule_AddObject(m, "tzname", Py_BuildValue("(NN)", otz0, otz1));
+ if (otz1 == NULL) {
+ Py_DECREF(otz0);
+ return -1;
+ }
+ PyObject *tzname_obj = Py_BuildValue("(NN)", otz0, otz1);
+ if (tzname_obj == NULL) {
+ return -1;
+ }
+ PyModule_AddObject(m, "tzname", tzname_obj);
#else /* !HAVE_TZNAME || __GLIBC__ || __CYGWIN__*/
{
#define YEAR ((time_t)((365 * 24 + 6) * 3600))
time_t t;
struct tm p;
- long janzone, julyzone;
+ time_t janzone_t, julyzone_t;
char janname[10], julyname[10];
t = (time((time_t *)0) / YEAR) * YEAR;
_PyTime_localtime(t, &p);
get_zone(janname, 9, &p);
- janzone = -get_gmtoff(t, &p);
+ janzone_t = -get_gmtoff(t, &p);
janname[9] = '\0';
t += YEAR/2;
_PyTime_localtime(t, &p);
get_zone(julyname, 9, &p);
- julyzone = -get_gmtoff(t, &p);
+ julyzone_t = -get_gmtoff(t, &p);
julyname[9] = '\0';
+ /* Sanity check, don't check for the validity of timezones.
+ In practice, it should be more in range -12 hours .. +14 hours. */
+#define MAX_TIMEZONE (48 * 3600)
+ if (janzone_t < -MAX_TIMEZONE || janzone_t > MAX_TIMEZONE
+ || julyzone_t < -MAX_TIMEZONE || julyzone_t > MAX_TIMEZONE)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "invalid GMT offset");
+ return -1;
+ }
+ int janzone = (int)janzone_t;
+ int julyzone = (int)julyzone_t;
+
if( janzone < julyzone ) {
/* DST is reversed in the southern hemisphere */
PyModule_AddIntConstant(m, "timezone", julyzone);
Py_BuildValue("(zz)", _tzname[0], _tzname[1]));
#endif /* __CYGWIN__ */
#endif /* !HAVE_TZNAME || __GLIBC__ || __CYGWIN__*/
+
+ if (PyErr_Occurred()) {
+ return -1;
+ }
+ return 0;
}
return NULL;
/* Set, or reset, module variables like time.timezone */
- PyInit_timezone(m);
+ if (init_timezone(m) < 0) {
+ return NULL;
+ }
+
+#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_CLOCK_GETRES)
#ifdef CLOCK_REALTIME
PyModule_AddIntMacro(m, CLOCK_REALTIME);
PyModule_AddIntMacro(m, CLOCK_UPTIME);
#endif
+#endif /* defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_CLOCK_GETRES) */
+
if (!initialized) {
if (PyStructSequence_InitType2(&StructTimeType,
&struct_time_type_desc) < 0)
PyModule_AddIntConstant(m, "_STRUCT_TM_ITEMS", 11);
PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType);
initialized = 1;
+
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
return m;
}
}
static PyObject *
-spamlist_state_get(spamlistobject *self)
+spamlist_state_get(spamlistobject *self, void *Py_UNUSED(ignored))
{
return PyLong_FromLong(self->state);
}
static void*
PyZlib_Malloc(voidpf ctx, uInt items, uInt size)
{
- if (items > (size_t)PY_SSIZE_T_MAX / size)
+ if (size != 0 && items > (size_t)PY_SSIZE_T_MAX / size)
return NULL;
/* PyMem_Malloc() cannot be used: the GIL is not held when
inflate() and deflate() are called */
- return PyMem_RawMalloc(items * size);
+ return PyMem_RawMalloc((size_t)items * (size_t)size);
}
static void
} else {
PyObject *index = PyNumber_Index(arg);
if (index == NULL) {
- PyErr_Format(PyExc_TypeError, "an integer is required");
*value = -1;
return 0;
}
if (PyIndex_Check(arg)) {
count = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
if (count == -1 && PyErr_Occurred()) {
- if (PyErr_ExceptionMatches(PyExc_OverflowError))
+ if (!PyErr_ExceptionMatches(PyExc_TypeError))
return -1;
PyErr_Clear(); /* fall through */
}
if (PyIndex_Check(x)) {
size = PyNumber_AsSsize_t(x, PyExc_OverflowError);
if (size == -1 && PyErr_Occurred()) {
- if (PyErr_ExceptionMatches(PyExc_OverflowError))
+ if (!PyErr_ExceptionMatches(PyExc_TypeError))
return NULL;
PyErr_Clear(); /* fall through */
}
return NULL;
}
-#define _PyBytes_FROM_LIST_BODY(x, GET_ITEM) \
- do { \
- PyObject *bytes; \
- Py_ssize_t i; \
- Py_ssize_t value; \
- char *str; \
- PyObject *item; \
- \
- bytes = PyBytes_FromStringAndSize(NULL, Py_SIZE(x)); \
- if (bytes == NULL) \
- return NULL; \
- str = ((PyBytesObject *)bytes)->ob_sval; \
- \
- for (i = 0; i < Py_SIZE(x); i++) { \
- item = GET_ITEM((x), i); \
- value = PyNumber_AsSsize_t(item, NULL); \
- if (value == -1 && PyErr_Occurred()) \
- goto error; \
- \
- if (value < 0 || value >= 256) { \
- PyErr_SetString(PyExc_ValueError, \
- "bytes must be in range(0, 256)"); \
- goto error; \
- } \
- *str++ = (char) value; \
- } \
- return bytes; \
- \
- error: \
- Py_DECREF(bytes); \
- return NULL; \
- } while (0)
-
static PyObject*
_PyBytes_FromList(PyObject *x)
{
- _PyBytes_FROM_LIST_BODY(x, PyList_GET_ITEM);
+ Py_ssize_t i, size = PyList_GET_SIZE(x);
+ Py_ssize_t value;
+ char *str;
+ PyObject *item;
+ _PyBytesWriter writer;
+
+ _PyBytesWriter_Init(&writer);
+ str = _PyBytesWriter_Alloc(&writer, size);
+ if (str == NULL)
+ return NULL;
+ writer.overallocate = 1;
+ size = writer.allocated;
+
+ for (i = 0; i < PyList_GET_SIZE(x); i++) {
+ item = PyList_GET_ITEM(x, i);
+ Py_INCREF(item);
+ value = PyNumber_AsSsize_t(item, NULL);
+ Py_DECREF(item);
+ if (value == -1 && PyErr_Occurred())
+ goto error;
+
+ if (value < 0 || value >= 256) {
+ PyErr_SetString(PyExc_ValueError,
+ "bytes must be in range(0, 256)");
+ goto error;
+ }
+
+ if (i >= size) {
+ str = _PyBytesWriter_Resize(&writer, str, size+1);
+ if (str == NULL)
+ return NULL;
+ size = writer.allocated;
+ }
+ *str++ = (char) value;
+ }
+ return _PyBytesWriter_Finish(&writer, str);
+
+ error:
+ _PyBytesWriter_Dealloc(&writer);
+ return NULL;
}
static PyObject*
_PyBytes_FromTuple(PyObject *x)
{
- _PyBytes_FROM_LIST_BODY(x, PyTuple_GET_ITEM);
+ PyObject *bytes;
+ Py_ssize_t i, size = PyTuple_GET_SIZE(x);
+ Py_ssize_t value;
+ char *str;
+ PyObject *item;
+
+ bytes = PyBytes_FromStringAndSize(NULL, size);
+ if (bytes == NULL)
+ return NULL;
+ str = ((PyBytesObject *)bytes)->ob_sval;
+
+ for (i = 0; i < size; i++) {
+ item = PyTuple_GET_ITEM(x, i);
+ value = PyNumber_AsSsize_t(item, NULL);
+ if (value == -1 && PyErr_Occurred())
+ goto error;
+
+ if (value < 0 || value >= 256) {
+ PyErr_SetString(PyExc_ValueError,
+ "bytes must be in range(0, 256)");
+ goto error;
+ }
+ *str++ = (char) value;
+ }
+ return bytes;
+
+ error:
+ Py_DECREF(bytes);
+ return NULL;
}
static PyObject *
Py_DECREF(it);
return result;
}
+ if (!PyErr_ExceptionMatches(PyExc_TypeError)) {
+ return NULL;
+ }
}
PyErr_Format(PyExc_TypeError,
char *name_dup = (char *)PyMem_MALLOC(name_length);
if (!name_dup) {
- return NULL;
+ return PyErr_NoMemory();
}
memcpy(name_dup, name, name_length);
}
static int
-cell_set_contents(PyCellObject *op, PyObject *obj)
+cell_set_contents(PyCellObject *op, PyObject *obj, void *Py_UNUSED(ignored))
{
Py_XINCREF(obj);
Py_XSETREF(op->ob_ref, obj);
{
PyObject *self = PyMethod_GET_SELF(im);
PyObject *func = PyMethod_GET_FUNCTION(im);
- PyObject *builtins;
- PyObject *getattr;
PyObject *funcname;
_Py_IDENTIFIER(getattr);
if (funcname == NULL) {
return NULL;
}
- builtins = PyEval_GetBuiltins();
- getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
- return Py_BuildValue("O(ON)", getattr, self, funcname);
+ return Py_BuildValue("N(ON)", _PyEval_GetBuiltinId(&PyId_getattr),
+ self, funcname);
}
static PyMethodDef method_methods[] = {
wrapperfunc wrapper = descr->d_base->wrapper;
if (descr->d_base->flags & PyWrapperFlag_KEYWORDS) {
- wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper;
+ wrapperfunc_kwds wk = (wrapperfunc_kwds)(void(*)(void))wrapper;
return (*wk)(self, args, descr->d_wrapped, kwds);
}
}
static PyObject *
-descr_get_qualname(PyDescrObject *descr)
+descr_get_qualname(PyDescrObject *descr, void *Py_UNUSED(ignored))
{
if (descr->d_qualname == NULL)
descr->d_qualname = calculate_qualname(descr);
static PyObject *
descr_reduce(PyDescrObject *descr)
{
- PyObject *builtins;
- PyObject *getattr;
_Py_IDENTIFIER(getattr);
-
- builtins = PyEval_GetBuiltins();
- getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
- return Py_BuildValue("O(OO)", getattr, PyDescr_TYPE(descr),
- PyDescr_NAME(descr));
+ return Py_BuildValue("N(OO)", _PyEval_GetBuiltinId(&PyId_getattr),
+ PyDescr_TYPE(descr), PyDescr_NAME(descr));
}
static PyMethodDef descr_methods[] = {
static PyObject *
wrapper_reduce(wrapperobject *wp)
{
- PyObject *builtins;
- PyObject *getattr;
_Py_IDENTIFIER(getattr);
-
- builtins = PyEval_GetBuiltins();
- getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
- return Py_BuildValue("O(OO)", getattr, wp->self, PyDescr_NAME(wp->descr));
+ return Py_BuildValue("N(OO)", _PyEval_GetBuiltinId(&PyId_getattr),
+ wp->self, PyDescr_NAME(wp->descr));
}
static PyMethodDef wrapper_methods[] = {
};
static PyObject *
-wrapper_objclass(wrapperobject *wp)
+wrapper_objclass(wrapperobject *wp, void *Py_UNUSED(ignored))
{
PyObject *c = (PyObject *)PyDescr_TYPE(wp->descr);
}
static PyObject *
-wrapper_name(wrapperobject *wp)
+wrapper_name(wrapperobject *wp, void *Py_UNUSED(ignored))
{
const char *s = wp->descr->d_base->name;
}
static PyObject *
-wrapper_doc(wrapperobject *wp, void *closure)
+wrapper_doc(wrapperobject *wp, void *Py_UNUSED(ignored))
{
return _PyType_GetDocFromInternalDoc(wp->descr->d_base->name, wp->descr->d_base->doc);
}
static PyObject *
-wrapper_text_signature(wrapperobject *wp, void *closure)
+wrapper_text_signature(wrapperobject *wp, void *Py_UNUSED(ignored))
{
return _PyType_GetTextSignatureFromInternalDoc(wp->descr->d_base->name, wp->descr->d_base->doc);
}
static PyObject *
-wrapper_qualname(wrapperobject *wp)
+wrapper_qualname(wrapperobject *wp, void *Py_UNUSED(ignored))
{
- return descr_get_qualname((PyDescrObject *)wp->descr);
+ return descr_get_qualname((PyDescrObject *)wp->descr, NULL);
}
static PyGetSetDef wrapper_getsets[] = {
};
static PyObject *
-BaseException_get_args(PyBaseExceptionObject *self)
+BaseException_get_args(PyBaseExceptionObject *self, void *Py_UNUSED(ignored))
{
if (self->args == NULL) {
Py_RETURN_NONE;
}
static int
-BaseException_set_args(PyBaseExceptionObject *self, PyObject *val)
+BaseException_set_args(PyBaseExceptionObject *self, PyObject *val, void *Py_UNUSED(ignored))
{
PyObject *seq;
if (val == NULL) {
}
static PyObject *
-BaseException_get_tb(PyBaseExceptionObject *self)
+BaseException_get_tb(PyBaseExceptionObject *self, void *Py_UNUSED(ignored))
{
if (self->traceback == NULL) {
Py_RETURN_NONE;
}
static int
-BaseException_set_tb(PyBaseExceptionObject *self, PyObject *tb)
+BaseException_set_tb(PyBaseExceptionObject *self, PyObject *tb, void *Py_UNUSED(ignored))
{
if (tb == NULL) {
PyErr_SetString(PyExc_TypeError, "__traceback__ may not be deleted");
}
static PyObject *
-BaseException_get_context(PyObject *self) {
+BaseException_get_context(PyObject *self, void *Py_UNUSED(ignored))
+{
PyObject *res = PyException_GetContext(self);
if (res)
return res; /* new reference already returned above */
}
static int
-BaseException_set_context(PyObject *self, PyObject *arg) {
+BaseException_set_context(PyObject *self, PyObject *arg, void *Py_UNUSED(ignored))
+{
if (arg == NULL) {
PyErr_SetString(PyExc_TypeError, "__context__ may not be deleted");
return -1;
}
static PyObject *
-BaseException_get_cause(PyObject *self) {
+BaseException_get_cause(PyObject *self, void *Py_UNUSED(ignored))
+{
PyObject *res = PyException_GetCause(self);
if (res)
return res; /* new reference already returned above */
}
static int
-BaseException_set_cause(PyObject *self, PyObject *arg) {
+BaseException_set_cause(PyObject *self, PyObject *arg, void *Py_UNUSED(ignored))
+{
if (arg == NULL) {
PyErr_SetString(PyExc_TypeError, "__cause__ may not be deleted");
return -1;
{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
{"args", (getter)BaseException_get_args, (setter)BaseException_set_args},
{"__traceback__", (getter)BaseException_get_tb, (setter)BaseException_set_tb},
- {"__context__", (getter)BaseException_get_context,
- (setter)BaseException_set_context, PyDoc_STR("exception context")},
- {"__cause__", (getter)BaseException_get_cause,
- (setter)BaseException_set_cause, PyDoc_STR("exception cause")},
+ {"__context__", BaseException_get_context,
+ BaseException_set_context, PyDoc_STR("exception context")},
+ {"__cause__", BaseException_get_cause,
+ BaseException_set_cause, PyDoc_STR("exception cause")},
{NULL},
};
int
PyException_SetTraceback(PyObject *self, PyObject *tb) {
- return BaseException_set_tb((PyBaseExceptionObject *)self, tb);
+ return BaseException_set_tb((PyBaseExceptionObject *)self, tb, NULL);
}
PyObject *
#define PY_SSIZE_T_CLEAN
#include "Python.h"
-#ifdef HAVE_GETC_UNLOCKED
+#if defined(HAVE_GETC_UNLOCKED) && !defined(_Py_MEMORY_SANITIZER)
+/* clang MemorySanitizer doesn't yet understand getc_unlocked. */
#define GETC(f) getc_unlocked(f)
#define FLOCKFILE(f) flockfile(f)
#define FUNLOCKFILE(f) funlockfile(f)
* that time.
*/
static int
-frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno)
+frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignored))
{
int new_lineno = 0; /* The new value of f_lineno */
long l_new_lineno;
return 0;
}
-static void
+static int
frame_tp_clear(PyFrameObject *f)
{
PyObject **fastlocals, **p, **oldtop;
for (p = f->f_valuestack; p < oldtop; p++)
Py_CLEAR(*p);
}
+ return 0;
}
static PyObject *
_PyGen_Finalize(f->f_gen);
assert(f->f_gen == NULL);
}
- frame_tp_clear(f);
+ (void)frame_tp_clear(f);
Py_RETURN_NONE;
}
};
static PyObject *
-func_get_code(PyFunctionObject *op)
+func_get_code(PyFunctionObject *op, void *Py_UNUSED(ignored))
{
Py_INCREF(op->func_code);
return op->func_code;
}
static int
-func_set_code(PyFunctionObject *op, PyObject *value)
+func_set_code(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
{
Py_ssize_t nfree, nclosure;
}
static PyObject *
-func_get_name(PyFunctionObject *op)
+func_get_name(PyFunctionObject *op, void *Py_UNUSED(ignored))
{
Py_INCREF(op->func_name);
return op->func_name;
}
static int
-func_set_name(PyFunctionObject *op, PyObject *value)
+func_set_name(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
{
/* Not legal to del f.func_name or to set it to anything
* other than a string object. */
}
static PyObject *
-func_get_qualname(PyFunctionObject *op)
+func_get_qualname(PyFunctionObject *op, void *Py_UNUSED(ignored))
{
Py_INCREF(op->func_qualname);
return op->func_qualname;
}
static int
-func_set_qualname(PyFunctionObject *op, PyObject *value)
+func_set_qualname(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
{
/* Not legal to del f.__qualname__ or to set it to anything
* other than a string object. */
}
static PyObject *
-func_get_defaults(PyFunctionObject *op)
+func_get_defaults(PyFunctionObject *op, void *Py_UNUSED(ignored))
{
if (op->func_defaults == NULL) {
Py_RETURN_NONE;
}
static int
-func_set_defaults(PyFunctionObject *op, PyObject *value)
+func_set_defaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
{
/* Legal to del f.func_defaults.
* Can only set func_defaults to NULL or a tuple. */
}
static PyObject *
-func_get_kwdefaults(PyFunctionObject *op)
+func_get_kwdefaults(PyFunctionObject *op, void *Py_UNUSED(ignored))
{
if (op->func_kwdefaults == NULL) {
Py_RETURN_NONE;
}
static int
-func_set_kwdefaults(PyFunctionObject *op, PyObject *value)
+func_set_kwdefaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
{
if (value == Py_None)
value = NULL;
}
static PyObject *
-func_get_annotations(PyFunctionObject *op)
+func_get_annotations(PyFunctionObject *op, void *Py_UNUSED(ignored))
{
if (op->func_annotations == NULL) {
op->func_annotations = PyDict_New();
}
static int
-func_set_annotations(PyFunctionObject *op, PyObject *value)
+func_set_annotations(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
{
if (value == Py_None)
value = NULL;
}
static PyObject *
-gen_get_name(PyGenObject *op)
+gen_get_name(PyGenObject *op, void *Py_UNUSED(ignored))
{
Py_INCREF(op->gi_name);
return op->gi_name;
}
static int
-gen_set_name(PyGenObject *op, PyObject *value)
+gen_set_name(PyGenObject *op, PyObject *value, void *Py_UNUSED(ignored))
{
/* Not legal to del gen.gi_name or to set it to anything
* other than a string object. */
}
static PyObject *
-gen_get_qualname(PyGenObject *op)
+gen_get_qualname(PyGenObject *op, void *Py_UNUSED(ignored))
{
Py_INCREF(op->gi_qualname);
return op->gi_qualname;
}
static int
-gen_set_qualname(PyGenObject *op, PyObject *value)
+gen_set_qualname(PyGenObject *op, PyObject *value, void *Py_UNUSED(ignored))
{
/* Not legal to del gen.__qualname__ or to set it to anything
* other than a string object. */
}
static PyObject *
-gen_getyieldfrom(PyGenObject *gen)
+gen_getyieldfrom(PyGenObject *gen, void *Py_UNUSED(ignored))
{
PyObject *yf = _PyGen_yf(gen);
if (yf == NULL)
}
static PyObject *
-coro_get_cr_await(PyCoroObject *coro)
+coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored))
{
PyObject *yf = _PyGen_yf((PyGenObject *) coro);
if (yf == NULL)
((PyCoroObject *)coro)->cr_origin = NULL;
} else {
PyObject *cr_origin = compute_cr_origin(origin_depth);
+ ((PyCoroObject *)coro)->cr_origin = cr_origin;
if (!cr_origin) {
Py_DECREF(coro);
return NULL;
}
- ((PyCoroObject *)coro)->cr_origin = cr_origin;
}
return coro;
}
static PyObject *
-memory_obj_get(PyMemoryViewObject *self)
+memory_obj_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
{
Py_buffer *view = &self->view;
}
static PyObject *
-memory_nbytes_get(PyMemoryViewObject *self)
+memory_nbytes_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
{
CHECK_RELEASED(self);
return PyLong_FromSsize_t(self->view.len);
}
static PyObject *
-memory_format_get(PyMemoryViewObject *self)
+memory_format_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
{
CHECK_RELEASED(self);
return PyUnicode_FromString(self->view.format);
}
static PyObject *
-memory_itemsize_get(PyMemoryViewObject *self)
+memory_itemsize_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
{
CHECK_RELEASED(self);
return PyLong_FromSsize_t(self->view.itemsize);
}
static PyObject *
-memory_shape_get(PyMemoryViewObject *self)
+memory_shape_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
{
CHECK_RELEASED(self);
return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
}
static PyObject *
-memory_strides_get(PyMemoryViewObject *self)
+memory_strides_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
{
CHECK_RELEASED(self);
return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
}
static PyObject *
-memory_suboffsets_get(PyMemoryViewObject *self)
+memory_suboffsets_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
{
CHECK_RELEASED(self);
return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
}
static PyObject *
-memory_readonly_get(PyMemoryViewObject *self)
+memory_readonly_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
{
CHECK_RELEASED(self);
return PyBool_FromLong(self->view.readonly);
}
static PyObject *
-memory_ndim_get(PyMemoryViewObject *self)
+memory_ndim_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
{
CHECK_RELEASED(self);
return PyLong_FromLong(self->view.ndim);
static PyObject *
meth_reduce(PyCFunctionObject *m)
{
- PyObject *builtins;
- PyObject *getattr;
_Py_IDENTIFIER(getattr);
if (m->m_self == NULL || PyModule_Check(m->m_self))
return PyUnicode_FromString(m->m_ml->ml_name);
- builtins = PyEval_GetBuiltins();
- getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
- return Py_BuildValue("O(Os)", getattr, m->m_self, m->m_ml->ml_name);
+ return Py_BuildValue("N(Os)", _PyEval_GetBuiltinId(&PyId_getattr),
+ m->m_self, m->m_ml->ml_name);
}
static PyMethodDef meth_methods[] = {
PyObject *value, *item;
value = PyDict_GetItem(d, key);
- assert(value != NULL);
-
- item = PyUnicode_FromFormat("%S=%R", key, value);
- if (item == NULL) {
- loop_error = 1;
- }
- else {
- loop_error = PyList_Append(pairs, item);
- Py_DECREF(item);
+ if (value != NULL) {
+ item = PyUnicode_FromFormat("%S=%R", key, value);
+ if (item == NULL) {
+ loop_error = 1;
+ }
+ else {
+ loop_error = PyList_Append(pairs, item);
+ Py_DECREF(item);
+ }
}
}
}
+/* Heuristic checking if the object memory has been deallocated.
+ Rely on the debug hooks on Python memory allocators which fills the memory
+ with DEADBYTE (0xDB) when memory is deallocated.
+
+ The function can be used to prevent segmentation fault on dereferencing
+ pointers like 0xdbdbdbdbdbdbdbdb. Such pointer is very unlikely to be mapped
+ in memory. */
+int
+_PyObject_IsFreed(PyObject *op)
+{
+ uintptr_t ptr = (uintptr_t)op;
+ if (_PyMem_IsFreed(&ptr, sizeof(ptr))) {
+ return 1;
+ }
+ int freed = _PyMem_IsFreed(&op->ob_type, sizeof(op->ob_type));
+ /* ignore op->ob_ref: the value can have be modified
+ by Py_INCREF() and Py_DECREF(). */
+#ifdef Py_TRACE_REFS
+ freed &= _PyMem_IsFreed(&op->_ob_next, sizeof(op->_ob_next));
+ freed &= _PyMem_IsFreed(&op->_ob_prev, sizeof(op->_ob_prev));
+#endif
+ return freed;
+}
+
+
/* For debugging convenience. See Misc/gdbinit for some useful gdb hooks */
void
_PyObject_Dump(PyObject* op)
{
- if (op == NULL)
- fprintf(stderr, "NULL\n");
- else {
- PyGILState_STATE gil;
- PyObject *error_type, *error_value, *error_traceback;
-
- fprintf(stderr, "object : ");
- gil = PyGILState_Ensure();
-
- PyErr_Fetch(&error_type, &error_value, &error_traceback);
- (void)PyObject_Print(op, stderr, 0);
- PyErr_Restore(error_type, error_value, error_traceback);
-
- PyGILState_Release(gil);
- /* XXX(twouters) cast refcount to long until %zd is
- universally available */
- fprintf(stderr, "\n"
- "type : %s\n"
- "refcount: %ld\n"
- "address : %p\n",
- Py_TYPE(op)==NULL ? "NULL" : Py_TYPE(op)->tp_name,
- (long)op->ob_refcnt,
- op);
+ if (op == NULL) {
+ fprintf(stderr, "<NULL object>\n");
+ fflush(stderr);
+ return;
+ }
+
+ if (_PyObject_IsFreed(op)) {
+ /* It seems like the object memory has been freed:
+ don't access it to prevent a segmentation fault. */
+ fprintf(stderr, "<freed object>\n");
+ return;
}
+
+ PyGILState_STATE gil;
+ PyObject *error_type, *error_value, *error_traceback;
+
+ fprintf(stderr, "object : ");
+ fflush(stderr);
+ gil = PyGILState_Ensure();
+
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ (void)PyObject_Print(op, stderr, 0);
+ fflush(stderr);
+ PyErr_Restore(error_type, error_value, error_traceback);
+
+ PyGILState_Release(gil);
+ /* XXX(twouters) cast refcount to long until %zd is
+ universally available */
+ fprintf(stderr, "\n"
+ "type : %s\n"
+ "refcount: %ld\n"
+ "address : %p\n",
+ Py_TYPE(op)==NULL ? "NULL" : Py_TYPE(op)->tp_name,
+ (long)op->ob_refcnt,
+ op);
+ fflush(stderr);
}
PyObject *
static void _PyMem_SetupDebugHooksDomain(PyMemAllocatorDomain domain);
#if defined(__has_feature) /* Clang */
- #if __has_feature(address_sanitizer) /* is ASAN enabled? */
- #define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS \
+# if __has_feature(address_sanitizer) /* is ASAN enabled? */
+# define _Py_NO_ADDRESS_SAFETY_ANALYSIS \
__attribute__((no_address_safety_analysis))
- #else
- #define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
- #endif
-#else
- #if defined(__SANITIZE_ADDRESS__) /* GCC 4.8.x, is ASAN enabled? */
- #define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS \
+# endif
+# if __has_feature(thread_sanitizer) /* is TSAN enabled? */
+# define _Py_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
+# endif
+# if __has_feature(memory_sanitizer) /* is MSAN enabled? */
+# define _Py_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
+# endif
+#elif defined(__GNUC__)
+# if defined(__SANITIZE_ADDRESS__) /* GCC 4.8+, is ASAN enabled? */
+# define _Py_NO_ADDRESS_SAFETY_ANALYSIS \
__attribute__((no_address_safety_analysis))
- #else
- #define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
- #endif
+# endif
+ // TSAN is supported since GCC 4.8, but __SANITIZE_THREAD__ macro
+ // is provided only since GCC 7.
+# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
+# define _Py_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
+# endif
+#endif
+
+#ifndef _Py_NO_ADDRESS_SAFETY_ANALYSIS
+# define _Py_NO_ADDRESS_SAFETY_ANALYSIS
+#endif
+#ifndef _Py_NO_SANITIZE_THREAD
+# define _Py_NO_SANITIZE_THREAD
+#endif
+#ifndef _Py_NO_SANITIZE_MEMORY
+# define _Py_NO_SANITIZE_MEMORY
#endif
#ifdef WITH_PYMALLOC
extremely desirable that it be this fast.
*/
-static bool ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
+static bool _Py_NO_ADDRESS_SAFETY_ANALYSIS
+ _Py_NO_SANITIZE_THREAD
+ _Py_NO_SANITIZE_MEMORY
address_in_range(void *p, poolp pool)
{
// Since address_in_range may be reading from memory which was not allocated
}
+/* Heuristic checking if the memory has been freed. Rely on the debug hooks on
+ Python memory allocators which fills the memory with DEADBYTE (0xDB) when
+ memory is deallocated. */
+int
+_PyMem_IsFreed(void *ptr, size_t size)
+{
+ unsigned char *bytes = ptr;
+ for (size_t i=0; i < size; i++) {
+ if (bytes[i] != DEADBYTE) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
/* The debug free first checks the 2*SST bytes on each end for sanity (in
particular, that the FORBIDDENBYTEs with the api ID are still intact).
Then fills the original bytes with DEADBYTE.
* _odict_find_node(od, key)
* _odict_keys_equal(od1, od2)
-Used, but specific to the linked-list implementation:
-
-* _odict_free_fast_nodes(od)
-
And here's a look at how the linked-list relates to the OrderedDict API:
============ === === ==== ==== ==== === ==== ===== ==== ==== === ==== === ===
tp_dictoffset (offset)
tp_init odict_init
tp_alloc (repeated)
-tp_new odict_new
================= ================
================= ================
#define _odict_FOREACH(od, node) \
for (node = _odict_FIRST(od); node != NULL; node = _odictnode_NEXT(node))
-#define _odict_FAST_SIZE(od) ((PyDictObject *)od)->ma_keys->dk_size
-
-static void
-_odict_free_fast_nodes(PyODictObject *od) {
- if (od->od_fast_nodes) {
- PyMem_FREE(od->od_fast_nodes);
- }
-}
-
/* Return the index into the hash table, regardless of a valid node. */
static Py_ssize_t
_odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
/* Replace od->od_fast_nodes with a new table matching the size of dict's. */
static int
-_odict_resize(PyODictObject *od) {
+_odict_resize(PyODictObject *od)
+{
Py_ssize_t size, i;
_ODictNode **fast_nodes, *node;
}
/* Replace the old fast nodes table. */
- _odict_free_fast_nodes(od);
+ PyMem_FREE(od->od_fast_nodes);
od->od_fast_nodes = fast_nodes;
od->od_fast_nodes_size = size;
od->od_resize_sentinel = ((PyDictObject *)od)->ma_keys;
index = _odict_get_index(od, key, hash);
if (index < 0)
return NULL;
+ assert(od->od_fast_nodes != NULL);
return od->od_fast_nodes[index];
}
index = _odict_get_index(od, key, hash);
if (index < 0)
return NULL;
+ assert(od->od_fast_nodes != NULL);
return od->od_fast_nodes[index];
}
Py_DECREF(key);
return -1;
}
- else if (od->od_fast_nodes[i] != NULL) {
+ assert(od->od_fast_nodes != NULL);
+ if (od->od_fast_nodes[i] != NULL) {
/* We already have a node for the key so there's no need to add one. */
Py_DECREF(key);
return 0;
if (i < 0)
return PyErr_Occurred() ? -1 : 0;
+ assert(od->od_fast_nodes != NULL);
if (node == NULL)
node = od->od_fast_nodes[i];
assert(node == od->od_fast_nodes[i]);
{
_ODictNode *node, *next;
- _odict_free_fast_nodes(od);
+ PyMem_FREE(od->od_fast_nodes);
od->od_fast_nodes = NULL;
+ od->od_fast_nodes_size = 0;
+ od->od_resize_sentinel = NULL;
node = _odict_FIRST(od);
_odict_FIRST(od) = NULL;
odict_sizeof(PyODictObject *od)
{
Py_ssize_t res = _PyDict_SizeOf((PyDictObject *)od);
- res += sizeof(_ODictNode *) * _odict_FAST_SIZE(od); /* od_fast_nodes */
+ res += sizeof(_ODictNode *) * od->od_fast_nodes_size; /* od_fast_nodes */
if (!_odict_EMPTY(od)) {
res += sizeof(_ODictNode) * PyODict_SIZE(od); /* linked-list */
}
"od.clear() -> None. Remove all items from od.");
static PyObject *
-odict_clear(register PyODictObject *od)
+odict_clear(register PyODictObject *od, PyObject *Py_UNUSED(ignored))
{
PyDict_Clear((PyObject *)od);
_odict_clear_nodes(od);
- if (_odict_resize(od) < 0)
- return NULL;
Py_RETURN_NONE;
}
static int
odict_tp_clear(PyODictObject *od)
{
- PyObject *res;
Py_CLEAR(od->od_inst_dict);
Py_CLEAR(od->od_weakreflist);
- res = odict_clear(od);
- if (res == NULL)
- return -1;
- Py_DECREF(res);
+ PyDict_Clear((PyObject *)od);
+ _odict_clear_nodes(od);
return 0;
}
}
}
-/* tp_new */
-
-static PyObject *
-odict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyODictObject *od;
-
- od = (PyODictObject *)PyDict_Type.tp_new(type, args, kwds);
- if (od == NULL)
- return NULL;
-
- /* type constructor fills the memory with zeros (see
- PyType_GenericAlloc()), there is no need to set them to zero again */
- if (_odict_resize(od) < 0) {
- Py_DECREF(od);
- return NULL;
- }
-
- return (PyObject*)od;
-}
-
/* PyODict_Type */
PyTypeObject PyODict_Type = {
offsetof(PyODictObject, od_inst_dict), /* tp_dictoffset */
(initproc)odict_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
- (newfunc)odict_new, /* tp_new */
+ 0, /* tp_new */
0, /* tp_free */
};
*/
PyObject *
-PyODict_New(void) {
- return odict_new(&PyODict_Type, NULL, NULL);
+PyODict_New(void)
+{
+ return PyDict_Type.tp_new(&PyODict_Type, NULL, NULL);
}
static int
PyDoc_STRVAR(reduce_doc, "Return state information for pickling");
static PyObject *
-odictiter_reduce(odictiterobject *di)
+odictiter_reduce(odictiterobject *di, PyObject *Py_UNUSED(ignored))
{
- PyObject *list, *iter;
-
- list = PyList_New(0);
- if (!list)
- return NULL;
+ /* copy the iterator state */
+ odictiterobject tmp = *di;
+ Py_XINCREF(tmp.di_odict);
+ Py_XINCREF(tmp.di_current);
/* iterate the temporary into a list */
- for(;;) {
- PyObject *element = odictiter_iternext(di);
- if (element) {
- if (PyList_Append(list, element)) {
- Py_DECREF(element);
- Py_DECREF(list);
- return NULL;
- }
- Py_DECREF(element);
- }
- else {
- /* done iterating? */
- break;
- }
- }
- if (PyErr_Occurred()) {
- Py_DECREF(list);
- return NULL;
- }
- iter = _PyObject_GetBuiltin("iter");
- if (iter == NULL) {
- Py_DECREF(list);
+ PyObject *list = PySequence_List((PyObject*)&tmp);
+ Py_XDECREF(tmp.di_odict);
+ Py_XDECREF(tmp.di_current);
+ if (list == NULL) {
return NULL;
}
- return Py_BuildValue("N(N)", iter, list);
+ return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), list);
}
static PyMethodDef odictiter_methods[] = {
it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type);
if (it == NULL)
return NULL;
+ it->index = it->start = it->step = NULL;
/* start + (len - 1) * step */
it->len = range->length;
static int
set_table_resize(PySetObject *so, Py_ssize_t minused)
{
- Py_ssize_t newsize;
setentry *oldtable, *newtable, *entry;
Py_ssize_t oldmask = so->mask;
size_t newmask;
/* Find the smallest table size > minused. */
/* XXX speed-up with intrinsics */
- for (newsize = PySet_MINSIZE;
- newsize <= minused && newsize > 0;
- newsize <<= 1)
- ;
- if (newsize <= 0) {
- PyErr_NoMemory();
- return -1;
+ size_t newsize = PySet_MINSIZE;
+ while (newsize <= (size_t)minused) {
+ newsize <<= 1; // The largest possible value is PY_SSIZE_T_MAX + 1.
}
/* Get space for a new table. */
-/* stringlib: locale related helpers implementation */
-
-#include <locale.h>
-
-#if !STRINGLIB_IS_UNICODE
-# error "localeutil.h is specific to Unicode"
-#endif
+/* _PyUnicode_InsertThousandsGrouping() helper functions */
typedef struct {
const char *grouping;
char previous;
Py_ssize_t i; /* Where we're currently pointing in grouping. */
-} STRINGLIB(GroupGenerator);
+} GroupGenerator;
+
static void
-STRINGLIB(GroupGenerator_init)(STRINGLIB(GroupGenerator) *self, const char *grouping)
+GroupGenerator_init(GroupGenerator *self, const char *grouping)
{
self->grouping = grouping;
self->i = 0;
self->previous = 0;
}
+
/* Returns the next grouping, or 0 to signify end. */
static Py_ssize_t
-STRINGLIB(GroupGenerator_next)(STRINGLIB(GroupGenerator) *self)
+GroupGenerator_next(GroupGenerator *self)
{
/* Note that we don't really do much error checking here. If a
grouping string contains just CHAR_MAX, for example, then just
}
}
+
/* Fill in some digits, leading zeros, and thousands separator. All
are optional, depending on when we're called. */
static void
-STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end,
- Py_ssize_t n_chars, Py_ssize_t n_zeros, STRINGLIB_CHAR* thousands_sep,
- Py_ssize_t thousands_sep_len)
+InsertThousandsGrouping_fill(_PyUnicodeWriter *writer, Py_ssize_t *buffer_pos,
+ PyObject *digits, Py_ssize_t *digits_pos,
+ Py_ssize_t n_chars, Py_ssize_t n_zeros,
+ PyObject *thousands_sep, Py_ssize_t thousands_sep_len,
+ Py_UCS4 *maxchar)
{
- Py_ssize_t i;
+ if (!writer) {
+ /* if maxchar > 127, maxchar is already set */
+ if (*maxchar == 127 && thousands_sep) {
+ Py_UCS4 maxchar2 = PyUnicode_MAX_CHAR_VALUE(thousands_sep);
+ *maxchar = Py_MAX(*maxchar, maxchar2);
+ }
+ return;
+ }
if (thousands_sep) {
- *buffer_end -= thousands_sep_len;
+ *buffer_pos -= thousands_sep_len;
/* Copy the thousands_sep chars into the buffer. */
- memcpy(*buffer_end, thousands_sep,
- thousands_sep_len * STRINGLIB_SIZEOF_CHAR);
- }
-
- *buffer_end -= n_chars;
- *digits_end -= n_chars;
- memcpy(*buffer_end, *digits_end, n_chars * sizeof(STRINGLIB_CHAR));
-
- *buffer_end -= n_zeros;
- for (i = 0; i < n_zeros; i++)
- (*buffer_end)[i] = '0';
-}
-
-/**
- * InsertThousandsGrouping:
- * @buffer: A pointer to the start of a string.
- * @n_buffer: Number of characters in @buffer.
- * @digits: A pointer to the digits we're reading from. If count
- * is non-NULL, this is unused.
- * @n_digits: The number of digits in the string, in which we want
- * to put the grouping chars.
- * @min_width: The minimum width of the digits in the output string.
- * Output will be zero-padded on the left to fill.
- * @grouping: see definition in localeconv().
- * @thousands_sep: see definition in localeconv().
- *
- * There are 2 modes: counting and filling. If @buffer is NULL,
- * we are in counting mode, else filling mode.
- * If counting, the required buffer size is returned.
- * If filling, we know the buffer will be large enough, so we don't
- * need to pass in the buffer size.
- * Inserts thousand grouping characters (as defined by grouping and
- * thousands_sep) into the string between buffer and buffer+n_digits.
- *
- * Return value: 0 on error, else 1. Note that no error can occur if
- * count is non-NULL.
- *
- * This name won't be used, the includer of this file should define
- * it to be the actual function name, based on unicode or string.
- *
- * As closely as possible, this code mimics the logic in decimal.py's
- _insert_thousands_sep().
- **/
-static Py_ssize_t
-STRINGLIB(InsertThousandsGrouping)(
- STRINGLIB_CHAR *buffer,
- Py_ssize_t n_buffer,
- STRINGLIB_CHAR *digits,
- Py_ssize_t n_digits,
- Py_ssize_t min_width,
- const char *grouping,
- STRINGLIB_CHAR *thousands_sep,
- Py_ssize_t thousands_sep_len)
-{
- Py_ssize_t count = 0;
- Py_ssize_t n_zeros;
- int loop_broken = 0;
- int use_separator = 0; /* First time through, don't append the
- separator. They only go between
- groups. */
- STRINGLIB_CHAR *buffer_end = NULL;
- STRINGLIB_CHAR *digits_end = NULL;
- Py_ssize_t l;
- Py_ssize_t n_chars;
- Py_ssize_t remaining = n_digits; /* Number of chars remaining to
- be looked at */
- /* A generator that returns all of the grouping widths, until it
- returns 0. */
- STRINGLIB(GroupGenerator) groupgen;
- STRINGLIB(GroupGenerator_init)(&groupgen, grouping);
-
- if (buffer) {
- buffer_end = buffer + n_buffer;
- digits_end = digits + n_digits;
- }
-
- while ((l = STRINGLIB(GroupGenerator_next)(&groupgen)) > 0) {
- l = Py_MIN(l, Py_MAX(Py_MAX(remaining, min_width), 1));
- n_zeros = Py_MAX(0, l - remaining);
- n_chars = Py_MAX(0, Py_MIN(remaining, l));
-
- /* Use n_zero zero's and n_chars chars */
-
- /* Count only, don't do anything. */
- count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
-
- if (buffer) {
- /* Copy into the output buffer. */
- STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros,
- use_separator ? thousands_sep : NULL, thousands_sep_len);
- }
-
- /* Use a separator next time. */
- use_separator = 1;
-
- remaining -= n_chars;
- min_width -= l;
-
- if (remaining <= 0 && min_width <= 0) {
- loop_broken = 1;
- break;
- }
- min_width -= thousands_sep_len;
+ _PyUnicode_FastCopyCharacters(writer->buffer, *buffer_pos,
+ thousands_sep, 0,
+ thousands_sep_len);
}
- if (!loop_broken) {
- /* We left the loop without using a break statement. */
- l = Py_MAX(Py_MAX(remaining, min_width), 1);
- n_zeros = Py_MAX(0, l - remaining);
- n_chars = Py_MAX(0, Py_MIN(remaining, l));
-
- /* Use n_zero zero's and n_chars chars */
- count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
- if (buffer) {
- /* Copy into the output buffer. */
- STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros,
- use_separator ? thousands_sep : NULL, thousands_sep_len);
- }
+ *buffer_pos -= n_chars;
+ *digits_pos -= n_chars;
+ _PyUnicode_FastCopyCharacters(writer->buffer, *buffer_pos,
+ digits, *digits_pos,
+ n_chars);
+
+ if (n_zeros) {
+ *buffer_pos -= n_zeros;
+ enum PyUnicode_Kind kind = PyUnicode_KIND(writer->buffer);
+ void *data = PyUnicode_DATA(writer->buffer);
+ FILL(kind, data, '0', *buffer_pos, n_zeros);
}
- return count;
}
-
"__repr__($self, /)\n--\n\nReturn repr(self)."),
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc,
"__hash__($self, /)\n--\n\nReturn hash(self)."),
- FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call,
+ FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)(void(*)(void))wrap_call,
"__call__($self, /, *args, **kwargs)\n--\n\nCall self as a function.",
PyWrapperFlag_KEYWORDS),
TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc,
TPSLOT("__delete__", tp_descr_set, slot_tp_descr_set,
wrap_descr_delete,
"__delete__($self, instance, /)\n--\n\nDelete an attribute of instance."),
- FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init,
+ FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)(void(*)(void))wrap_init,
"__init__($self, /, *args, **kwargs)\n--\n\n"
"Initialize self. See help(type(self)) for accurate signature.",
PyWrapperFlag_KEYWORDS),
return unicode_empty; \
} while (0)
+#define FILL(kind, data, value, start, length) \
+ do { \
+ assert(0 <= start); \
+ assert(kind != PyUnicode_WCHAR_KIND); \
+ switch (kind) { \
+ case PyUnicode_1BYTE_KIND: { \
+ assert(value <= 0xff); \
+ Py_UCS1 ch = (unsigned char)value; \
+ Py_UCS1 *to = (Py_UCS1 *)data + start; \
+ memset(to, ch, length); \
+ break; \
+ } \
+ case PyUnicode_2BYTE_KIND: { \
+ assert(value <= 0xffff); \
+ Py_UCS2 ch = (Py_UCS2)value; \
+ Py_UCS2 *to = (Py_UCS2 *)data + start; \
+ const Py_UCS2 *end = to + length; \
+ for (; to < end; ++to) *to = ch; \
+ break; \
+ } \
+ case PyUnicode_4BYTE_KIND: { \
+ assert(value <= MAX_UNICODE); \
+ Py_UCS4 ch = value; \
+ Py_UCS4 * to = (Py_UCS4 *)data + start; \
+ const Py_UCS4 *end = to + length; \
+ for (; to < end; ++to) *to = ch; \
+ break; \
+ } \
+ default: Py_UNREACHABLE(); \
+ } \
+ } while (0)
+
+
/* Forward declaration */
static inline int
_PyUnicodeWriter_WriteCharInline(_PyUnicodeWriter *writer, Py_UCS4 ch);
#include "stringlib/count.h"
#include "stringlib/find.h"
#include "stringlib/find_max_char.h"
-#include "stringlib/localeutil.h"
#include "stringlib/undef.h"
#include "stringlib/ucs1lib.h"
#include "stringlib/find.h"
#include "stringlib/replace.h"
#include "stringlib/find_max_char.h"
-#include "stringlib/localeutil.h"
#include "stringlib/undef.h"
#include "stringlib/ucs2lib.h"
#include "stringlib/find.h"
#include "stringlib/replace.h"
#include "stringlib/find_max_char.h"
-#include "stringlib/localeutil.h"
#include "stringlib/undef.h"
#include "stringlib/ucs4lib.h"
#include "stringlib/find.h"
#include "stringlib/replace.h"
#include "stringlib/find_max_char.h"
-#include "stringlib/localeutil.h"
#include "stringlib/undef.h"
#include "stringlib/unicodedefs.h"
return NULL;
}
- Py_ssize_t wlen2 = wcslen(wstr);
- if (wlen2 != wlen) {
- PyMem_Free(wstr);
+ if ((size_t)wlen != wcslen(wstr)) {
PyErr_SetString(PyExc_ValueError, "embedded null character");
+ PyMem_Free(wstr);
return NULL;
}
const char *reason;
int res = _Py_EncodeLocaleEx(wstr, &str, &error_pos, &reason,
current_locale, surrogateescape);
+ PyMem_Free(wstr);
+
if (res != 0) {
if (res == -2) {
PyObject *exc;
PyCodec_StrictErrors(exc);
Py_DECREF(exc);
}
- return NULL;
}
else {
PyErr_NoMemory();
- PyMem_Free(wstr);
- return NULL;
}
+ return NULL;
}
- PyMem_Free(wstr);
PyObject *bytes = PyBytes_FromString(str);
PyMem_RawFree(str);
}
message = "malformed \\N character escape";
- if (*s == '{') {
+ if (s < end && *s == '{') {
const char *start = ++s;
size_t namelen;
/* look for the closing brace */
"in the target code page.";
/* each step cannot decode more than 1 character, but a character can be
represented as a surrogate pair */
- wchar_t buffer[2], *startout, *out;
+ wchar_t buffer[2], *out;
int insize;
Py_ssize_t outsize;
PyObject *errorHandler = NULL;
*v = (PyObject*)_PyUnicode_New(size * Py_ARRAY_LENGTH(buffer));
if (*v == NULL)
goto error;
- startout = PyUnicode_AS_UNICODE(*v);
+ out = PyUnicode_AS_UNICODE(*v);
}
else {
/* Extend unicode object */
}
if (unicode_resize(v, n + size * Py_ARRAY_LENGTH(buffer)) < 0)
goto error;
- startout = PyUnicode_AS_UNICODE(*v) + n;
+ out = PyUnicode_AS_UNICODE(*v) + n;
}
/* Decode the byte string character per character */
- out = startout;
while (in < endin)
{
/* Decode a character */
*out = 0;
/* Extend unicode object */
- outsize = out - startout;
+ outsize = out - PyUnicode_AS_UNICODE(*v);
assert(outsize <= PyUnicode_WSTR_LENGTH(*v));
if (unicode_resize(v, outsize) < 0)
goto error;
return result;
}
+/* _PyUnicode_InsertThousandsGrouping() helper functions */
+#include "stringlib/localeutil.h"
+
+/**
+ * InsertThousandsGrouping:
+ * @writer: Unicode writer.
+ * @n_buffer: Number of characters in @buffer.
+ * @digits: Digits we're reading from. If count is non-NULL, this is unused.
+ * @d_pos: Start of digits string.
+ * @n_digits: The number of digits in the string, in which we want
+ * to put the grouping chars.
+ * @min_width: The minimum width of the digits in the output string.
+ * Output will be zero-padded on the left to fill.
+ * @grouping: see definition in localeconv().
+ * @thousands_sep: see definition in localeconv().
+ *
+ * There are 2 modes: counting and filling. If @writer is NULL,
+ * we are in counting mode, else filling mode.
+ * If counting, the required buffer size is returned.
+ * If filling, we know the buffer will be large enough, so we don't
+ * need to pass in the buffer size.
+ * Inserts thousand grouping characters (as defined by grouping and
+ * thousands_sep) into @writer.
+ *
+ * Return value: -1 on error, number of characters otherwise.
+ **/
Py_ssize_t
_PyUnicode_InsertThousandsGrouping(
- PyObject *unicode, Py_ssize_t index,
+ _PyUnicodeWriter *writer,
Py_ssize_t n_buffer,
- void *digits, Py_ssize_t n_digits,
+ PyObject *digits,
+ Py_ssize_t d_pos,
+ Py_ssize_t n_digits,
Py_ssize_t min_width,
- const char *grouping, PyObject *thousands_sep,
+ const char *grouping,
+ PyObject *thousands_sep,
Py_UCS4 *maxchar)
{
- unsigned int kind, thousands_sep_kind;
- char *data, *thousands_sep_data;
- Py_ssize_t thousands_sep_len;
- Py_ssize_t len;
-
- if (unicode != NULL) {
- kind = PyUnicode_KIND(unicode);
- data = (char *) PyUnicode_DATA(unicode) + index * kind;
+ if (writer) {
+ assert(digits != NULL);
+ assert(maxchar == NULL);
}
else {
- kind = PyUnicode_1BYTE_KIND;
- data = NULL;
- }
- thousands_sep_kind = PyUnicode_KIND(thousands_sep);
- thousands_sep_data = PyUnicode_DATA(thousands_sep);
- thousands_sep_len = PyUnicode_GET_LENGTH(thousands_sep);
- if (unicode != NULL && thousands_sep_kind != kind) {
- if (thousands_sep_kind < kind) {
- thousands_sep_data = _PyUnicode_AsKind(thousands_sep, kind);
- if (!thousands_sep_data)
- return -1;
- }
- else {
- data = _PyUnicode_AsKind(unicode, thousands_sep_kind);
- if (!data)
- return -1;
+ assert(digits == NULL);
+ assert(maxchar != NULL);
+ }
+ assert(0 <= d_pos);
+ assert(0 <= n_digits);
+ assert(0 <= min_width);
+ assert(grouping != NULL);
+
+ if (digits != NULL) {
+ if (PyUnicode_READY(digits) == -1) {
+ return -1;
}
}
+ if (PyUnicode_READY(thousands_sep) == -1) {
+ return -1;
+ }
- switch (kind) {
- case PyUnicode_1BYTE_KIND:
- if (unicode != NULL && PyUnicode_IS_ASCII(unicode))
- len = asciilib_InsertThousandsGrouping(
- (Py_UCS1 *) data, n_buffer, (Py_UCS1 *) digits, n_digits,
- min_width, grouping,
- (Py_UCS1 *) thousands_sep_data, thousands_sep_len);
- else
- len = ucs1lib_InsertThousandsGrouping(
- (Py_UCS1*)data, n_buffer, (Py_UCS1*)digits, n_digits,
- min_width, grouping,
- (Py_UCS1 *) thousands_sep_data, thousands_sep_len);
- break;
- case PyUnicode_2BYTE_KIND:
- len = ucs2lib_InsertThousandsGrouping(
- (Py_UCS2 *) data, n_buffer, (Py_UCS2 *) digits, n_digits,
- min_width, grouping,
- (Py_UCS2 *) thousands_sep_data, thousands_sep_len);
- break;
- case PyUnicode_4BYTE_KIND:
- len = ucs4lib_InsertThousandsGrouping(
- (Py_UCS4 *) data, n_buffer, (Py_UCS4 *) digits, n_digits,
- min_width, grouping,
- (Py_UCS4 *) thousands_sep_data, thousands_sep_len);
- break;
- default:
- Py_UNREACHABLE();
+ Py_ssize_t count = 0;
+ Py_ssize_t n_zeros;
+ int loop_broken = 0;
+ int use_separator = 0; /* First time through, don't append the
+ separator. They only go between
+ groups. */
+ Py_ssize_t buffer_pos;
+ Py_ssize_t digits_pos;
+ Py_ssize_t len;
+ Py_ssize_t n_chars;
+ Py_ssize_t remaining = n_digits; /* Number of chars remaining to
+ be looked at */
+ /* A generator that returns all of the grouping widths, until it
+ returns 0. */
+ GroupGenerator groupgen;
+ GroupGenerator_init(&groupgen, grouping);
+ const Py_ssize_t thousands_sep_len = PyUnicode_GET_LENGTH(thousands_sep);
+
+ /* if digits are not grouped, thousands separator
+ should be an empty string */
+ assert(!(grouping[0] == CHAR_MAX && thousands_sep_len != 0));
+
+ digits_pos = d_pos + n_digits;
+ if (writer) {
+ buffer_pos = writer->pos + n_buffer;
+ assert(buffer_pos <= PyUnicode_GET_LENGTH(writer->buffer));
+ assert(digits_pos <= PyUnicode_GET_LENGTH(digits));
}
- if (unicode != NULL && thousands_sep_kind != kind) {
- if (thousands_sep_kind < kind)
- PyMem_Free(thousands_sep_data);
- else
- PyMem_Free(data);
+ else {
+ buffer_pos = n_buffer;
}
- if (unicode == NULL) {
+
+ if (!writer) {
*maxchar = 127;
- if (len != n_digits) {
- *maxchar = Py_MAX(*maxchar,
- PyUnicode_MAX_CHAR_VALUE(thousands_sep));
+ }
+
+ while ((len = GroupGenerator_next(&groupgen)) > 0) {
+ len = Py_MIN(len, Py_MAX(Py_MAX(remaining, min_width), 1));
+ n_zeros = Py_MAX(0, len - remaining);
+ n_chars = Py_MAX(0, Py_MIN(remaining, len));
+
+ /* Use n_zero zero's and n_chars chars */
+
+ /* Count only, don't do anything. */
+ count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
+
+ /* Copy into the writer. */
+ InsertThousandsGrouping_fill(writer, &buffer_pos,
+ digits, &digits_pos,
+ n_chars, n_zeros,
+ use_separator ? thousands_sep : NULL,
+ thousands_sep_len, maxchar);
+
+ /* Use a separator next time. */
+ use_separator = 1;
+
+ remaining -= n_chars;
+ min_width -= len;
+
+ if (remaining <= 0 && min_width <= 0) {
+ loop_broken = 1;
+ break;
}
+ min_width -= thousands_sep_len;
+ }
+ if (!loop_broken) {
+ /* We left the loop without using a break statement. */
+
+ len = Py_MAX(Py_MAX(remaining, min_width), 1);
+ n_zeros = Py_MAX(0, len - remaining);
+ n_chars = Py_MAX(0, Py_MIN(remaining, len));
+
+ /* Use n_zero zero's and n_chars chars */
+ count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars;
+
+ /* Copy into the writer. */
+ InsertThousandsGrouping_fill(writer, &buffer_pos,
+ digits, &digits_pos,
+ n_chars, n_zeros,
+ use_separator ? thousands_sep : NULL,
+ thousands_sep_len, maxchar);
}
- return len;
+ return count;
}
return NULL;
}
-#define FILL(kind, data, value, start, length) \
- do { \
- Py_ssize_t i_ = 0; \
- assert(kind != PyUnicode_WCHAR_KIND); \
- switch ((kind)) { \
- case PyUnicode_1BYTE_KIND: { \
- unsigned char * to_ = (unsigned char *)((data)) + (start); \
- memset(to_, (unsigned char)value, (length)); \
- break; \
- } \
- case PyUnicode_2BYTE_KIND: { \
- Py_UCS2 * to_ = (Py_UCS2 *)((data)) + (start); \
- for (; i_ < (length); ++i_, ++to_) *to_ = (value); \
- break; \
- } \
- case PyUnicode_4BYTE_KIND: { \
- Py_UCS4 * to_ = (Py_UCS4 *)((data)) + (start); \
- for (; i_ < (length); ++i_, ++to_) *to_ = (value); \
- break; \
- } \
- default: Py_UNREACHABLE(); \
- } \
- } while (0)
-
void
_PyUnicode_FastFill(PyObject *unicode, Py_ssize_t start, Py_ssize_t length,
Py_UCS4 fill_char)
{
const enum PyUnicode_Kind kind = PyUnicode_KIND(unicode);
- const void *data = PyUnicode_DATA(unicode);
+ void *data = PyUnicode_DATA(unicode);
assert(PyUnicode_IS_READY(unicode));
assert(unicode_modifiable(unicode));
assert(fill_char <= PyUnicode_MAX_CHAR_VALUE(unicode));
+++ /dev/null
-//
-// Helper library for location Visual Studio installations
-// using the COM-based query API.
-//
-// Copyright (c) Microsoft Corporation
-// Licensed to PSF under a contributor agreement
-//
-
-// Version history
-// 2017-05: Initial contribution (Steve Dower)
-
-#include <Windows.h>
-#include <Strsafe.h>
-#include "external\include\Setup.Configuration.h"
-
-#include <Python.h>
-
-static PyObject *error_from_hr(HRESULT hr)
-{
- if (FAILED(hr))
- PyErr_Format(PyExc_OSError, "Error %08x", hr);
- assert(PyErr_Occurred());
- return nullptr;
-}
-
-static PyObject *get_install_name(ISetupInstance2 *inst)
-{
- HRESULT hr;
- BSTR name;
- PyObject *str = nullptr;
- if (FAILED(hr = inst->GetDisplayName(LOCALE_USER_DEFAULT, &name)))
- goto error;
- str = PyUnicode_FromWideChar(name, SysStringLen(name));
- SysFreeString(name);
- return str;
-error:
-
- return error_from_hr(hr);
-}
-
-static PyObject *get_install_version(ISetupInstance *inst)
-{
- HRESULT hr;
- BSTR ver;
- PyObject *str = nullptr;
- if (FAILED(hr = inst->GetInstallationVersion(&ver)))
- goto error;
- str = PyUnicode_FromWideChar(ver, SysStringLen(ver));
- SysFreeString(ver);
- return str;
-error:
-
- return error_from_hr(hr);
-}
-
-static PyObject *get_install_path(ISetupInstance *inst)
-{
- HRESULT hr;
- BSTR path;
- PyObject *str = nullptr;
- if (FAILED(hr = inst->GetInstallationPath(&path)))
- goto error;
- str = PyUnicode_FromWideChar(path, SysStringLen(path));
- SysFreeString(path);
- return str;
-error:
-
- return error_from_hr(hr);
-}
-
-static PyObject *get_installed_packages(ISetupInstance2 *inst)
-{
- HRESULT hr;
- PyObject *res = nullptr;
- LPSAFEARRAY sa_packages = nullptr;
- LONG ub = 0;
- IUnknown **packages = nullptr;
- PyObject *str = nullptr;
-
- if (FAILED(hr = inst->GetPackages(&sa_packages)) ||
- FAILED(hr = SafeArrayAccessData(sa_packages, (void**)&packages)) ||
- FAILED(SafeArrayGetUBound(sa_packages, 1, &ub)) ||
- !(res = PyList_New(0)))
- goto error;
-
- for (LONG i = 0; i < ub; ++i) {
- ISetupPackageReference *package = nullptr;
- BSTR id = nullptr;
- PyObject *str = nullptr;
-
- if (FAILED(hr = packages[i]->QueryInterface(&package)) ||
- FAILED(hr = package->GetId(&id)))
- goto iter_error;
-
- str = PyUnicode_FromWideChar(id, SysStringLen(id));
- SysFreeString(id);
-
- if (!str || PyList_Append(res, str) < 0)
- goto iter_error;
-
- Py_CLEAR(str);
- package->Release();
- continue;
-
- iter_error:
- if (package) package->Release();
- Py_XDECREF(str);
-
- goto error;
- }
-
- SafeArrayUnaccessData(sa_packages);
- SafeArrayDestroy(sa_packages);
-
- return res;
-error:
- if (sa_packages && packages) SafeArrayUnaccessData(sa_packages);
- if (sa_packages) SafeArrayDestroy(sa_packages);
- Py_XDECREF(res);
-
- return error_from_hr(hr);
-}
-
-static PyObject *find_all_instances()
-{
- ISetupConfiguration *sc = nullptr;
- ISetupConfiguration2 *sc2 = nullptr;
- IEnumSetupInstances *enm = nullptr;
- ISetupInstance *inst = nullptr;
- ISetupInstance2 *inst2 = nullptr;
- PyObject *res = nullptr;
- ULONG fetched;
- HRESULT hr;
-
- if (!(res = PyList_New(0)))
- goto error;
-
- if (FAILED(hr = CoCreateInstance(
- __uuidof(SetupConfiguration),
- NULL,
- CLSCTX_INPROC_SERVER,
- __uuidof(ISetupConfiguration),
- (LPVOID*)&sc
- )) && hr != REGDB_E_CLASSNOTREG)
- goto error;
-
- // If the class is not registered, there are no VS instances installed
- if (hr == REGDB_E_CLASSNOTREG)
- return res;
-
- if (FAILED(hr = sc->QueryInterface(&sc2)) ||
- FAILED(hr = sc2->EnumAllInstances(&enm)))
- goto error;
-
- while (SUCCEEDED(enm->Next(1, &inst, &fetched)) && fetched) {
- PyObject *name = nullptr;
- PyObject *version = nullptr;
- PyObject *path = nullptr;
- PyObject *packages = nullptr;
- PyObject *tuple = nullptr;
-
- if (FAILED(hr = inst->QueryInterface(&inst2)) ||
- !(name = get_install_name(inst2)) ||
- !(version = get_install_version(inst)) ||
- !(path = get_install_path(inst)) ||
- !(packages = get_installed_packages(inst2)) ||
- !(tuple = PyTuple_Pack(4, name, version, path, packages)) ||
- PyList_Append(res, tuple) < 0)
- goto iter_error;
-
- Py_DECREF(tuple);
- Py_DECREF(packages);
- Py_DECREF(path);
- Py_DECREF(version);
- Py_DECREF(name);
- continue;
- iter_error:
- if (inst2) inst2->Release();
- Py_XDECREF(tuple);
- Py_XDECREF(packages);
- Py_XDECREF(path);
- Py_XDECREF(version);
- Py_XDECREF(name);
- goto error;
- }
-
- enm->Release();
- sc2->Release();
- sc->Release();
- return res;
-
-error:
- if (enm) enm->Release();
- if (sc2) sc2->Release();
- if (sc) sc->Release();
- Py_XDECREF(res);
-
- return error_from_hr(hr);
-}
-
-PyDoc_STRVAR(findvs_findall_doc, "findall()\
-\
-Finds all installed versions of Visual Studio.\
-\
-This function will initialize COM temporarily. To avoid impact on other parts\
-of your application, use a new thread to make this call.");
-
-static PyObject *findvs_findall(PyObject *self, PyObject *args, PyObject *kwargs)
-{
- HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
- if (hr == RPC_E_CHANGED_MODE)
- hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
- if (FAILED(hr))
- return error_from_hr(hr);
- PyObject *res = find_all_instances();
- CoUninitialize();
- return res;
-}
-
-// List of functions to add to findvs in exec_findvs().
-static PyMethodDef findvs_functions[] = {
- { "findall", (PyCFunction)findvs_findall, METH_VARARGS | METH_KEYWORDS, findvs_findall_doc },
- { NULL, NULL, 0, NULL }
-};
-
-// Initialize findvs. May be called multiple times, so avoid
-// using static state.
-static int exec_findvs(PyObject *module)
-{
- PyModule_AddFunctions(module, findvs_functions);
-
- return 0; // success
-}
-
-PyDoc_STRVAR(findvs_doc, "The _distutils_findvs helper module");
-
-static PyModuleDef_Slot findvs_slots[] = {
- { Py_mod_exec, exec_findvs },
- { 0, NULL }
-};
-
-static PyModuleDef findvs_def = {
- PyModuleDef_HEAD_INIT,
- "_distutils_findvs",
- findvs_doc,
- 0, // m_size
- NULL, // m_methods
- findvs_slots,
- NULL, // m_traverse
- NULL, // m_clear
- NULL, // m_free
-};
-
-extern "C" {
- PyMODINIT_FUNC PyInit__distutils_findvs(void)
- {
- return PyModuleDef_Init(&findvs_def);
- }
-}
--- /dev/null
+<CustomCapabilityDescriptor xmlns="http://schemas.microsoft.com/appx/2016/sccd" xmlns:s="http://schemas.microsoft.com/appx/2016/sccd"><CustomCapabilities><CustomCapability Name="Microsoft.classicAppCompat_8wekyb3d8bbwe"></CustomCapability></CustomCapabilities><AuthorizedEntities><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.7_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.14_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.15_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.7_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.14_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.15_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity></AuthorizedEntities></CustomCapabilityDescriptor>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<CustomCapabilityDescriptor xmlns="http://schemas.microsoft.com/appx/2016/sccd" xmlns:s="http://schemas.microsoft.com/appx/2016/sccd">
+ <CustomCapabilities>
+ <CustomCapability Name="Microsoft.classicAppCompat_8wekyb3d8bbwe"/>
+ </CustomCapabilities>
+ <AuthorizedEntities>
+ <!--PFN for store installation-->
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.7_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.14_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.15_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.7_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.14_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"/>
+ <AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.15_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"/>
+ </AuthorizedEntities>
+ <!--Once signed, this file can no longer be modified-->
+ <Catalog>MIIq5AYJKoZIhvcNAQcCoIIq1TCCKtECAQExDzANBglghkgBZQMEAgEFADCCARAGCSsGAQQBgjcKAaCCAQEwgf4wDAYKKwYBBAGCNwwBAQQQaM+L42jwBUGvBczrtolMmhcNMTgxMTMwMDA1OTAzWjAOBgorBgEEAYI3DAEDBQAwgbwwKgQUWKcU3R38DGPlKK33XGIwKtVL1r4xEjAQBgorBgEEAYI3DAIDMQKCADCBjQQg3K+KBOQX7HfxjRNZC9cx8gIPkEhPRO1nJFRdWQrVEJ4xaTAQBgorBgEEAYI3DAIDMQKCADBVBgorBgEEAYI3AgEEMUcwRTAQBgorBgEEAYI3AgEZogKAADAxMA0GCWCGSAFlAwQCAQUABCDcr4oE5Bfsd/GNE1kL1zHyAg+QSE9E7WckVF1ZCtUQnqCCFFAwggZSMIIEOqADAgECAhMzAAMu49KhfNamygpWAAIAAy7jMA0GCSqGSIb3DQEBCwUAMIGMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMQ0wCwYDVQQLEwRNT1BSMScwJQYDVQQDEx5NaWNyb3NvZnQgTWFya2V0cGxhY2UgQ0EgRyAwMTMwHhcNMTgxMTMwMDA1NTA1WhcNMTgxMjAzMDA1NTA1WjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwpcimfAx3HEpba1GLL/gDaRVddHE5PXTRmwlgaz8kt6/rq5rlrPFnCnbIc5818v0xJIznastbmrq26xyCEHyMLBKnyneTKE36I7+TGjcY0D7ow+o2vY7LDKMCTGlh31fx1Tvrl+5xTbWX5jdLU/3MB5faeOGh+0Knzwx1KDoXWgPtfXnD8I5jxJieoWoCwCjKTJgBOklLy9nbOalxf0h+xQRy2p5fj+PxAwQPgHWft36AF7/IMbt9FcXMtg4xdpnTYz4OV3dFOPz4m3M8HwVgNMv89W/1Ozc7uOyZt0Ij1baT6r2L3IjYg5ftzpGqaDOFcWlyDFSdhMR6BIKW8xEpAgMBAAGjggHCMIIBvjAYBgNVHSUBAf8EDjAMBgorBgEEAYI3TBwBMB0GA1UdDgQWBBRdpGYiCytx83FYzPSl+o97YzpxGzAPBgNVHREECDAGggRNT1BSMB8GA1UdIwQYMBaAFEnYB1RFhpclHtZZcRLDcpt0OE3oMGIGA1UdHwRbMFkwV6BVoFOGUWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyME1hcmtldHBsYWNlJTIwQ0ElMjBHJTIwMDEzKDIpLmNybDBvBggrBgEFBQcBAQRjMGEwXwYIKwYBBQUHMAKGU2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwTWFya2V0cGxhY2UlMjBDQSUyMEclMjAwMTMoMikuY3J0MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgXgMDwGCSsGAQQBgjcVBwQvMC0GJSsGAQQBgjcVCIOS9kTqrxCDkY0wgqzgLIKinDE0g+6NOIaE7wACAWQCARYwIAYJKwYBBAGCNxUKAQH/BBAwDjAMBgorBgEEAYI3TBwBMA0GCSqGSIb3DQEBCwUAA4ICAQB3Dk3rXH52CDq/z1fwqn9xI5WGjGmu6oAE4HSc3sNdFrSVMMGm4gTlYGWSZ0wJUUf16mVr/rdXhxuR3MZn+m4Bhdl8KQqYjYbIvCUVj0o9nZ+yT6foeY8bKnB+K5h6rol+mjDj5IfcutC4x2Kx5RrtDtRTSoKA63iZ74DYngPpBGBBgaS2c/QzgqPRAMMRqy2KBDP0miCnpR3F4YlzHGyOZwyHhESjYd9kwF47+msuHS04JZpnGHIvBppKN9XQzH3WezNnnX3lz4AyAUMsMFuARqEnacUhrAHL9n5zMv9CzxDYN1r1/aDh/788RuGuZM+E3NtmbxJJ7j6T5/VtXNBRgKtIq8d2+11j6qvKLigOTxSC25/A70BZBEvllLFnvc1vA2LrC9drwt1KpSmWie1nvpilw7o+gHMOG9utUxGha2VuVizuVNGCywTRRjvmGS1QqTfaun1URVrLfnDINXuTgN1Vwp0J5IGpJ3D8yj01NDQ/RworE+3W/R531NBYova9QRhU/igEw/Aa/q8wjZ4Pzxr9oBIo0Ta3Tv6qIggaWXw0U9+F0J7SCqIhn0d0ATO+E1Qs/SxZIAICLwmqzoLYUAh8q153esBs4uesueqgt5ueyHK8V3WjMS4wxEyVN5ZMET3hFtEshsZC31tLDdjq750U4SgQVmoYSm3F3ZOKQDCCBtcwggS/oAMCAQICCmESRKIAAAAAAAIwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDExMB4XDTExMDMyODIxMDkzOVoXDTMxMDMyODIxMTkzOVowfTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEnMCUGA1UEAxMeTWljcm9zb2Z0IE1hcmtldFBsYWNlIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAubUaSwGYVsE3MAnPfvmozUhAB3qxBABgJRW1vDp4+tVinXxD32f7k1K89JQ6zDOgS/iDgULC+yFK1K/1Qjac/0M7P6c8v5LSjnWGlERLa/qY32j46S7SLQcit3g2jgoTTO03eUG+9yHZUTGV/FJdRYB8uXhrznJBa+Y+yGwiQKF+m6XFeBH/KORoKFx+dmMoy9EWJ/m/o9IiUj2kzm9C691+vZ/I2w0Bj93W9SPPkV2PCNHlzgfIAoeajWpHmi38Wi3xZHonkzAVBHxPsCBppOoNsWvmAfUM7eBthkSPvFruekyDCPNEYhfGqgqtqLkoBebXLZCOVybF7wTQaLvse60//3P003icRcCoQYgY4NAqrF7j80o5U7DkeXxcB0xvengsaKgiAaV1DKkRbpe98wCqr1AASvm5rAJUYMU+mXmOieV2EelY2jGrenWe9FQpNXYV1NoWBh0WKoFxttoWYAnF705bIWtSZsz08ZfK6WLX4GXNLcPBlgCzfTm1sdKYASWdBbH2haaNhPapFhQQBJHKwnVW2iXErImhuPi45W3MVTZ5D9ASshZx69cLYY6xAdIa+89Kf/uRrsGOVZfahDuDw+NI183iAyzC8z/QRt2P32LYxP0xrCdqVh+DJo2i4NoE8Uk1usCdbVRuBMBQl/AwpOTq7IMvHGElf65CqzUCAwEAAaOCAUswggFHMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBQPU8s/FmEl/mCJHdO5fOiQrbOU0TAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCjuZmM8ZVNDgp9wHsL4RY8KJ8nLinvxFTphNGCrxaLknkYG5pmMhVlX+UB/tSiW8W13W60nggz9u5xwMx7v/1t/Tgm6g2brVyOKI5A7u6/2SIJwkJKFw953K0YIKVT28w9zl8dSJnmRnyR0G86ncWbF6CLQ6A6lBQ9o2mTGVqDr4m35WKAnc6YxUUM1y74mbzFFZr63VHsCcOp3pXWnUqAY1rb6Q6NX1b3clncKqLFm0EjKHcQ56grTbwuuB7pMdh/IFCJR01MQzQbDtpEisbOeZUi43YVAAHKqI1EO9bRwg3frCjwAbml9MmI4utMW94gWFgvrMxIX+n42RBDIjf3Ot3jkT6gt3XeTTmO9bptgblZimhERdkFRUFpVtkocJeLoGuuzP93uH/Yp032wzRH+XmMgujfZv+vnfllJqxdowoQLx55FxLLeTeYfwi/xMSjZO2gNven3U/3KeSCd1kUOFS3AOrwZ0UNOXJeW5JQC6Vfd1BavFZ6FAta1fMLu3WFvNB+FqeHUaU3ya7rmtxJnzk29DeSqXgGNmVSywBS4NajI5jJIKAA6UhNJlsg8CHYwUOKf5ej8OoQCkbadUxXygAfxCfW2YBbujtI+PoyejRFxWUjYFWO5LeTI62UMyqfOEiqugoYjNxmQZla2s4YHVuqIC34R85FQlg9pKQBsDCCBxswggUDoAMCAQICEzMAAABCs21EHGjyqKYAAAAAAEIwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEnMCUGA1UEAxMeTWljcm9zb2Z0IE1hcmtldFBsYWNlIFBDQSAyMDExMB4XDTE4MDQyMDE2NDI0NFoXDTIxMDQyMDE2NDI0NFowgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIxJzAlBgNVBAMTHk1pY3Jvc29mdCBNYXJrZXRwbGFjZSBDQSBHIDAxMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOZ2KM9Pq1YCOiqWOivmHjUtkMgznTMP/Mr2YfzZeIIJySg1F4WxFZc4jagGHHNof9NRT+GGnktWsXkZuH1DzQEG4Ps1ln8+4vhbDglqu5ymDnd6RmsyoD+8xfc8bBIvE5o6R+ES4/GVD5TqNsOrWbwETaIZVbmTulJLoTS1WSsSjowmbc+sHqZiY8BNJNThUEmXSjuHqkQKKshuiFWYEqOTitp71mBLyH1wN7/jThRzGpolOeFusRNJdb8sEqvNzEN9Qh+Kp6ndzrnjE+t8ixXW3lShyyOOZqQMwsQn9q9T0v7Q69GuojBTFBOHKwigcCHr4xahuN+ZYMk0xGg+sm3Uj7I9mrWTSTiIRMZNIWq3sFg4+rFg48NYfRlXUpONmL7vXq6v1pIU99d2MXQ6uUrnUr1/n5ZiHGCeFcvWwqO8BYHdcTlrSOkayfFp7W9oCk9QO4Xy0h9cQRedRo2kvdTHxIuJS70Hdv6oePPF2ZFaLucUzzwsR4/XMAVKY8Vsm950omsSSOImsMtzavUdQM+wZFxvHTRqVDkF3quPdME0bCZOWB4hQJmd+o2clw+1mpwPu0/M92nA9FJg7MGPxkFaYW7g26jSqUJZ9AcX+Xa5TSIeqMZt3cRVjMTx0T/v73Sv8TpalqIQ5Fde1+hFK07sOAm3TwgzvlVJnbYgp0/rAgMBAAGjggGCMIIBfjASBgkrBgEEAYI3FQEEBQIDAgACMCMGCSsGAQQBgjcVAgQWBBSbJnDhuc3nQXuKuACsPflEbwjbozAdBgNVHQ4EFgQUSdgHVEWGlyUe1llxEsNym3Q4TegwEQYDVR0gBAowCDAGBgRVHSAAMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFA9Tyz8WYSX+YIkd07l86JCts5TRMFcGA1UdHwRQME4wTKBKoEiGRmh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY01hclBDQTIwMTFfMjAxMS0wMy0yOC5jcmwwWwYIKwYBBQUHAQEETzBNMEsGCCsGAQUFBzAChj9odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY01hclBDQTIwMTFfMjAxMS0wMy0yOC5jcnQwDQYJKoZIhvcNAQELBQADggIBAIa2oa6kvuIHCNfz7anlL0W9tOCt8gQNkxOGRK3yliQIelNQahDJojyEFlHQ2BcHL5oZit3WeSDoYddhojx6YzJIWwfGwtVqgc0JFDKJJ2ZXRYMRsuy01Hn25xob+zRMS6VmV1axQn6uwOSMcgYmzoroh6edjPKu7qXcpt6LmhF2qFvLySA7wBCwfI/rR5/PX6I7a07Av7PpbY6/+2ujd8m1H3hwMrb4Hq3z6gcq62zJ3nDXUbC0Bp6Jt2kV9f0rEFpDK9oxE2qrGBUf8c3O2XirHOgAjRyWjWWtVms+MP8qBIA1NSLrBmToEWVP3sEkQZWMkoZWo4rYEJZpX7UIgdDc9zYNakgTCJqPhqn8AE1sgSSnpqAdMkkP41rTlFCv2ig2QVzDerjGfEv+uPDnlAT0kucbBJxHHvUC4aqUxaTSa0sy2bZ6NWFx8/u0gW8JahzxYvvvZL8SfwaA9P4ETb8pH1jw+6N/LfM2zJrNKhf5hjKa0VDOXUpkYq60OqVVnWJ6oJaSIWNkZKfzPnl/UHA8Bh4qfVrhc9H5PExPhhB9WVTsjf4r+OOVuolJldThcWQqljiPjk5rultr63G5xLyFpxNi4BCrcNQBJFB5wKgOWOyjQTVWTmh2ESaeqZ2aWBjftFHlxJ/qYc7WOGJV0+cHGkB/dvFxmKnv6tuWexiMMYIVUTCCFU0CAQEwgaQwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIxJzAlBgNVBAMTHk1pY3Jvc29mdCBNYXJrZXRwbGFjZSBDQSBHIDAxMwITMwADLuPSoXzWpsoKVgACAAMu4zANBglghkgBZQMEAgEFAKCBlTAYBgkqhkiG9w0BCQMxCwYJKwYBBAGCNwoBMC8GCSqGSIb3DQEJBDEiBCAS0d3bw2YOODvKFr0S4e3BDnaDcZXUKeBO77yvkWzVojBIBgorBgEEAYI3AgEMMTowOKAegBwATQBpAGMAcgBvAHMAbwBmAHQAIABDAG8AcgBwoRaAFGh0dHA6Ly9NaWNyb3NvZnQuY29tMA0GCSqGSIb3DQEBAQUABIIBABoap3Y+2k+zFz2cCmkc8xxHnpIygLsUSRMXeXdjPVcYx3o5cPLIixnL6p8+LIrlIagPg23mzTEmnjZaO4aaexk+3XojlHj22w/bEigEDnKyWt5bHeS0UNHJbxEFYRfd84IP1+mSH4c4+GuU9p3LsAMh6wN03MYrGmczUOnlP6YlxHNQbQxnV0sl14yOE5ni9oT4y+l+SllvbV3/Jhwpov68aoP/2MazqxR4QyGfSxhCPJ4UuDHU7IrpnTxGBTL1/oUU8ED0FxyDoH/Sc5OhTLInFqbZaVzm5Mpr12wYUBL4nE5h0Kf6BCKdgM8a+Ti3wMUsBoC79ff3jE9U/xwSneOhghLlMIIS4QYKKwYBBAGCNwMDATGCEtEwghLNBgkqhkiG9w0BBwKgghK+MIISugIBAzEPMA0GCWCGSAFlAwQCAQUAMIIBUQYLKoZIhvcNAQkQAQSgggFABIIBPDCCATgCAQEGCisGAQQBhFkKAwEwMTANBglghkgBZQMEAgEFAAQghPy22lwuCYESw8jYhb4F9ZDPJ1LPgSSZgJDkyXYzVt4CBlv98KtAoBgTMjAxODExMzAwMTA1MTkuMTM4WjAEgAIB9KCB0KSBzTCByjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046RDA4Mi00QkZELUVFQkExJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIHNlcnZpY2Wggg48MIIE8TCCA9mgAwIBAgITMwAAAOIYOHtm6erB2AAAAAAA4jANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0xODA4MjMyMDI3MDNaFw0xOTExMjMyMDI3MDNaMIHKMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjpEMDgyLTRCRkQtRUVCQTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgc2VydmljZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKirA72FF3NCLW5mfLO/D0EZ5Ycs00oiMSissXLB6WF9GNdP78QzFwAypxW/+qZSczqaHbDH8hlbxkzf3DiYgAdpQjnGkLujwKtWSaP29/lVf7jFqHy9v6eH+LdOi0LvtrPRW34MyCvpxZyOW4H1h3PkxCBL5Ra21sDqgcVL1me0osw8QTURXmI4LyeLdTH3CcI2AgNDXTjsFBf3QsO+JYyAOYWrTcLnywVN6DrigmgrDJk5w+wR4VrHfl2T9PRZbZ+UDt13wwyB9d6IURuzV8lHsAVfF8t9S0aGVPmkQ3c2waOhHpsp6VEM+T5D2Ph8xJX1r82z67WRlmGcOP2NWC0CAwEAAaOCARswggEXMB0GA1UdDgQWBBSJPpD6BsP2p+crDJL232voEtLxezAfBgNVHSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNUaW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IBAQARQHu7ISeBuJSHKuDRI04704cH0B7BYzeEIrD15awviMRcYIfIOHpvGzZOWQgP2Hm0Rr7kvTUu1VrSSaQ7i1gPWdhqMmw5WBnSS5bxeMhhx9UsASeE84vUu82NeZapGSjH38YAb4WT+TtiTkcoI59rA+CTCq108ttIxVfZcr3id76OETIH0HvhlnxOOWjwGy4ul6Za5RoTLG/oo2rrGmVi3FwrNWGezYLBODuEsjzG36lCRtBKC2ZAHfbOz5wtkUHbqh79mUKocjP4r3qxf5TN87yf6g1uTx+J8pdnAi5iHt+ZtangWqnVTE8PoIREWhBVlGFfQdkELUx2Or90aAqWMIIGcTCCBFmgAwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcNMjUwNzAxMjE0NjU1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0VBDVpQoAgoX77XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEwWbEwRA/xYIiEVEMM1024OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQedGFnkV+BVLHPk0ySwcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJUGKxXf13Hz3wV3WsvYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw2k4GkbaICDXoeByw6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0CAwEAAaOCAeYwggHiMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7fEYbxTNoWoVtVTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0gAQH/BIGVMIGSMIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9naOhIW+z66bM9TG+zwXiqf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtRgkQS+7lTjMz0YBKKdsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzymXlKkVIArzgPF/UveYFl2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon/VWvL/625Y4zu2JfmttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3DnKOiPPp/fZZqkHimbdLhnPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/fmNZJQ96LjlXdqJxqgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110mCIIYdqwUB5vvfHhAN/nMQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0cs0d9LiFAR6A+xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7aKLixqduWsqdCosnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQcdeh0sVV42neV8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+NR4Iuto229Nfj950iEkSoYICzjCCAjcCAQEwgfihgdCkgc0wgcoxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJXQTEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOkQwODItNEJGRC1FRUJBMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBzZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQByQCUheEOevaI9Zc/3QGrkX42iC6CBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBBQUAAgUA36ppYDAiGA8yMDE4MTEyOTIxMzQyNFoYDzIwMTgxMTMwMjEzNDI0WjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDfqmlgAgEAMAoCAQACAitfAgH/MAcCAQACAhGtMAoCBQDfq7rgAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQEFBQADgYEAbAXXPR9wy4NA0892GGqetaZF+pNClpGcfEpSuHABaZ4Gzr1nY1nmrhexTtr/U6omHALRWzkQwthk0cy+mnEHXyOZGmoEEpgrLgK3AAP5NbK/XbtHQRyZJQyhZScFbOyQycoE8QQalSVOhWxk/bbBMQaQiYVMIexNd/T0KgaDDUMxggMNMIIDCQIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAOIYOHtm6erB2AAAAAAA4jANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCCr9IiSbx6s8MLdxldRG49+4h6CbicW8hWXAicI3jNmhDCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIN8BpJSmQCGubWwVa4tW+aMveoHMX/nDnVN8fiDOMsrLMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAADiGDh7ZunqwdgAAAAAAOIwIgQgTkOfRvGEZNbr5/hgWclsL4/Q7SOZihE/U0lz2wEMIGcwDQYJKoZIhvcNAQELBQAEggEATlxnCfTzFfTMDvK085zlYPVCroKYW6gKFYnbAhNmrNzcxqALKmIYXpFU7B6HH/vYzkUfCyXpf5tsyEWu0oTySOjyAZ9+2vdaG8nEgjOp0L737lcitgusIjpWtta3Ik0b+mzffnvyjrgTSuKDDni3mxGfvJU77k1Ctempma4H2FJso6Bur0PRH99vIYDu4lHigOSLbeyjR5CiDciBwEVUSA0FxhoFNX1yfpxz3sukOvkaoTduREIjH5LxUjNI1ZTMK/ZkeETI8IPRpWVzAc8q7CujErHKo4sdKej/O2cfUTUHplFLVCGGExpJUCg5FH5jVUUFt75ad8503sdGplggVQ==</Catalog></CustomCapabilityDescriptor>
+++ /dev/null
-The files in this folder are from the Microsoft.VisualStudio.Setup.Configuration.Native package on Nuget.
-
-They are licensed under the MIT license.
+++ /dev/null
-// The MIT License(MIT)
-// Copyright(C) Microsoft Corporation.All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files(the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions :
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-// IN THE SOFTWARE.
-//
-
-#pragma once
-
-// Constants
-//
-#ifndef E_NOTFOUND
-#define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
-#endif
-
-#ifndef E_FILENOTFOUND
-#define E_FILENOTFOUND HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
-#endif
-
-#ifndef E_NOTSUPPORTED
-#define E_NOTSUPPORTED HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)
-#endif
-
-// Enumerations
-//
-/// <summary>
-/// The state of an instance.
-/// </summary>
-enum InstanceState
-{
- /// <summary>
- /// The instance state has not been determined.
- /// </summary>
- eNone = 0,
-
- /// <summary>
- /// The instance installation path exists.
- /// </summary>
- eLocal = 1,
-
- /// <summary>
- /// A product is registered to the instance.
- /// </summary>
- eRegistered = 2,
-
- /// <summary>
- /// No reboot is required for the instance.
- /// </summary>
- eNoRebootRequired = 4,
-
- /// <summary>
- /// No errors were reported for the instance.
- /// </summary>
- eNoErrors = 8,
-
- /// <summary>
- /// The instance represents a complete install.
- /// </summary>
- eComplete = MAXUINT,
-};
-
-// Forward interface declarations
-//
-#ifndef __ISetupInstance_FWD_DEFINED__
-#define __ISetupInstance_FWD_DEFINED__
-typedef struct ISetupInstance ISetupInstance;
-#endif
-
-#ifndef __ISetupInstance2_FWD_DEFINED__
-#define __ISetupInstance2_FWD_DEFINED__
-typedef struct ISetupInstance2 ISetupInstance2;
-#endif
-
-#ifndef __ISetupLocalizedProperties_FWD_DEFINED__
-#define __ISetupLocalizedProperties_FWD_DEFINED__
-typedef struct ISetupLocalizedProperties ISetupLocalizedProperties;
-#endif
-
-#ifndef __IEnumSetupInstances_FWD_DEFINED__
-#define __IEnumSetupInstances_FWD_DEFINED__
-typedef struct IEnumSetupInstances IEnumSetupInstances;
-#endif
-
-#ifndef __ISetupConfiguration_FWD_DEFINED__
-#define __ISetupConfiguration_FWD_DEFINED__
-typedef struct ISetupConfiguration ISetupConfiguration;
-#endif
-
-#ifndef __ISetupConfiguration2_FWD_DEFINED__
-#define __ISetupConfiguration2_FWD_DEFINED__
-typedef struct ISetupConfiguration2 ISetupConfiguration2;
-#endif
-
-#ifndef __ISetupPackageReference_FWD_DEFINED__
-#define __ISetupPackageReference_FWD_DEFINED__
-typedef struct ISetupPackageReference ISetupPackageReference;
-#endif
-
-#ifndef __ISetupHelper_FWD_DEFINED__
-#define __ISetupHelper_FWD_DEFINED__
-typedef struct ISetupHelper ISetupHelper;
-#endif
-
-#ifndef __ISetupErrorState_FWD_DEFINED__
-#define __ISetupErrorState_FWD_DEFINED__
-typedef struct ISetupErrorState ISetupErrorState;
-#endif
-
-#ifndef __ISetupErrorState2_FWD_DEFINED__
-#define __ISetupErrorState2_FWD_DEFINED__
-typedef struct ISetupErrorState2 ISetupErrorState2;
-#endif
-
-#ifndef __ISetupFailedPackageReference_FWD_DEFINED__
-#define __ISetupFailedPackageReference_FWD_DEFINED__
-typedef struct ISetupFailedPackageReference ISetupFailedPackageReference;
-#endif
-
-#ifndef __ISetupFailedPackageReference2_FWD_DEFINED__
-#define __ISetupFailedPackageReference2_FWD_DEFINED__
-typedef struct ISetupFailedPackageReference2 ISetupFailedPackageReference2;
-#endif
-
-#ifndef __ISetupPropertyStore_FWD_DEFINED__
-#define __ISetupPropertyStore_FWD_DEFINED__
-typedef struct ISetupPropertyStore ISetupPropertyStore;
-#endif
-
-#ifndef __ISetupLocalizedPropertyStore_FWD_DEFINED__
-#define __ISetupLocalizedPropertyStore_FWD_DEFINED__
-typedef struct ISetupLocalizedPropertyStore ISetupLocalizedPropertyStore;
-#endif
-
-// Forward class declarations
-//
-#ifndef __SetupConfiguration_FWD_DEFINED__
-#define __SetupConfiguration_FWD_DEFINED__
-
-#ifdef __cplusplus
-typedef class SetupConfiguration SetupConfiguration;
-#endif
-
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Interface definitions
-//
-EXTERN_C const IID IID_ISetupInstance;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Information about an instance of a product.
-/// </summary>
-struct DECLSPEC_UUID("B41463C3-8866-43B5-BC33-2B0676F7F42E") DECLSPEC_NOVTABLE ISetupInstance : public IUnknown
-{
- /// <summary>
- /// Gets the instance identifier (should match the name of the parent instance directory).
- /// </summary>
- /// <param name="pbstrInstanceId">The instance identifier.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns>
- STDMETHOD(GetInstanceId)(
- _Out_ BSTR* pbstrInstanceId
- ) = 0;
-
- /// <summary>
- /// Gets the local date and time when the installation was originally installed.
- /// </summary>
- /// <param name="pInstallDate">The local date and time when the installation was originally installed.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
- STDMETHOD(GetInstallDate)(
- _Out_ LPFILETIME pInstallDate
- ) = 0;
-
- /// <summary>
- /// Gets the unique name of the installation, often indicating the branch and other information used for telemetry.
- /// </summary>
- /// <param name="pbstrInstallationName">The unique name of the installation, often indicating the branch and other information used for telemetry.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
- STDMETHOD(GetInstallationName)(
- _Out_ BSTR* pbstrInstallationName
- ) = 0;
-
- /// <summary>
- /// Gets the path to the installation root of the product.
- /// </summary>
- /// <param name="pbstrInstallationPath">The path to the installation root of the product.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
- STDMETHOD(GetInstallationPath)(
- _Out_ BSTR* pbstrInstallationPath
- ) = 0;
-
- /// <summary>
- /// Gets the version of the product installed in this instance.
- /// </summary>
- /// <param name="pbstrInstallationVersion">The version of the product installed in this instance.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
- STDMETHOD(GetInstallationVersion)(
- _Out_ BSTR* pbstrInstallationVersion
- ) = 0;
-
- /// <summary>
- /// Gets the display name (title) of the product installed in this instance.
- /// </summary>
- /// <param name="lcid">The LCID for the display name.</param>
- /// <param name="pbstrDisplayName">The display name (title) of the product installed in this instance.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
- STDMETHOD(GetDisplayName)(
- _In_ LCID lcid,
- _Out_ BSTR* pbstrDisplayName
- ) = 0;
-
- /// <summary>
- /// Gets the description of the product installed in this instance.
- /// </summary>
- /// <param name="lcid">The LCID for the description.</param>
- /// <param name="pbstrDescription">The description of the product installed in this instance.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
- STDMETHOD(GetDescription)(
- _In_ LCID lcid,
- _Out_ BSTR* pbstrDescription
- ) = 0;
-
- /// <summary>
- /// Resolves the optional relative path to the root path of the instance.
- /// </summary>
- /// <param name="pwszRelativePath">A relative path within the instance to resolve, or NULL to get the root path.</param>
- /// <param name="pbstrAbsolutePath">The full path to the optional relative path within the instance. If the relative path is NULL, the root path will always terminate in a backslash.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
- STDMETHOD(ResolvePath)(
- _In_opt_z_ LPCOLESTR pwszRelativePath,
- _Out_ BSTR* pbstrAbsolutePath
- ) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupInstance2;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Information about an instance of a product.
-/// </summary>
-struct DECLSPEC_UUID("89143C9A-05AF-49B0-B717-72E218A2185C") DECLSPEC_NOVTABLE ISetupInstance2 : public ISetupInstance
-{
- /// <summary>
- /// Gets the state of the instance.
- /// </summary>
- /// <param name="pState">The state of the instance.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns>
- STDMETHOD(GetState)(
- _Out_ InstanceState* pState
- ) = 0;
-
- /// <summary>
- /// Gets an array of package references registered to the instance.
- /// </summary>
- /// <param name="ppsaPackages">Pointer to an array of <see cref="ISetupPackageReference"/>.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the packages property is not defined.</returns>
- STDMETHOD(GetPackages)(
- _Out_ LPSAFEARRAY* ppsaPackages
- ) = 0;
-
- /// <summary>
- /// Gets a pointer to the <see cref="ISetupPackageReference"/> that represents the registered product.
- /// </summary>
- /// <param name="ppPackage">Pointer to an instance of <see cref="ISetupPackageReference"/>. This may be NULL if <see cref="GetState"/> does not return <see cref="eComplete"/>.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the packages property is not defined.</returns>
- STDMETHOD(GetProduct)(
- _Outptr_result_maybenull_ ISetupPackageReference** ppPackage
- ) = 0;
-
- /// <summary>
- /// Gets the relative path to the product application, if available.
- /// </summary>
- /// <param name="pbstrProductPath">The relative path to the product application, if available.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns>
- STDMETHOD(GetProductPath)(
- _Outptr_result_maybenull_ BSTR* pbstrProductPath
- ) = 0;
-
- /// <summary>
- /// Gets the error state of the instance, if available.
- /// </summary>
- /// <param name="pErrorState">The error state of the instance, if available.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns>
- STDMETHOD(GetErrors)(
- _Outptr_result_maybenull_ ISetupErrorState** ppErrorState
- ) = 0;
-
- /// <summary>
- /// Gets a value indicating whether the instance can be launched.
- /// </summary>
- /// <param name="pfIsLaunchable">Whether the instance can be launched.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- /// <remarks>
- /// An instance could have had errors during install but still be launched. Some features may not work correctly, but others will.
- /// </remarks>
- STDMETHOD(IsLaunchable)(
- _Out_ VARIANT_BOOL* pfIsLaunchable
- ) = 0;
-
- /// <summary>
- /// Gets a value indicating whether the instance is complete.
- /// </summary>
- /// <param name="pfIsLaunchable">Whether the instance is complete.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- /// <remarks>
- /// An instance is complete if it had no errors during install, resume, or repair.
- /// </remarks>
- STDMETHOD(IsComplete)(
- _Out_ VARIANT_BOOL* pfIsComplete
- ) = 0;
-
- /// <summary>
- /// Gets product-specific properties.
- /// </summary>
- /// <param name="ppPropeties">A pointer to an instance of <see cref="ISetupPropertyStore"/>. This may be NULL if no properties are defined.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns>
- STDMETHOD(GetProperties)(
- _Outptr_result_maybenull_ ISetupPropertyStore** ppProperties
- ) = 0;
-
- /// <summary>
- /// Gets the directory path to the setup engine that installed the instance.
- /// </summary>
- /// <param name="pbstrEnginePath">The directory path to the setup engine that installed the instance.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns>
- STDMETHOD(GetEnginePath)(
- _Outptr_result_maybenull_ BSTR* pbstrEnginePath
- ) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupLocalizedProperties;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Provides localized properties of an instance of a product.
-/// </summary>
-struct DECLSPEC_UUID("F4BD7382-FE27-4AB4-B974-9905B2A148B0") DECLSPEC_NOVTABLE ISetupLocalizedProperties : public IUnknown
-{
- /// <summary>
- /// Gets localized product-specific properties.
- /// </summary>
- /// <param name="ppLocalizedProperties">A pointer to an instance of <see cref="ISetupLocalizedPropertyStore"/>. This may be NULL if no properties are defined.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetLocalizedProperties)(
- _Outptr_result_maybenull_ ISetupLocalizedPropertyStore** ppLocalizedProperties
- ) = 0;
-
- /// <summary>
- /// Gets localized channel-specific properties.
- /// </summary>
- /// <param name="ppLocalizedChannelProperties">A pointer to an instance of <see cref="ISetupLocalizedPropertyStore"/>. This may be NULL if no channel properties are defined.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetLocalizedChannelProperties)(
- _Outptr_result_maybenull_ ISetupLocalizedPropertyStore** ppLocalizedChannelProperties
- ) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_IEnumSetupInstances;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// An enumerator of installed <see cref="ISetupInstance"/> objects.
-/// </summary>
-struct DECLSPEC_UUID("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848") DECLSPEC_NOVTABLE IEnumSetupInstances : public IUnknown
-{
- /// <summary>
- /// Retrieves the next set of product instances in the enumeration sequence.
- /// </summary>
- /// <param name="celt">The number of product instances to retrieve.</param>
- /// <param name="rgelt">A pointer to an array of <see cref="ISetupInstance"/>.</param>
- /// <param name="pceltFetched">A pointer to the number of product instances retrieved. If <paramref name="celt"/> is 1 this parameter may be NULL.</param>
- /// <returns>S_OK if the number of elements were fetched, S_FALSE if nothing was fetched (at end of enumeration), E_INVALIDARG if <paramref name="celt"/> is greater than 1 and pceltFetched is NULL, or E_OUTOFMEMORY if an <see cref="ISetupInstance"/> could not be allocated.</returns>
- STDMETHOD(Next)(
- _In_ ULONG celt,
- _Out_writes_to_(celt, *pceltFetched) ISetupInstance** rgelt,
- _Out_opt_ _Deref_out_range_(0, celt) ULONG* pceltFetched
- ) = 0;
-
- /// <summary>
- /// Skips the next set of product instances in the enumeration sequence.
- /// </summary>
- /// <param name="celt">The number of product instances to skip.</param>
- /// <returns>S_OK if the number of elements could be skipped; otherwise, S_FALSE;</returns>
- STDMETHOD(Skip)(
- _In_ ULONG celt
- ) = 0;
-
- /// <summary>
- /// Resets the enumeration sequence to the beginning.
- /// </summary>
- /// <returns>Always returns S_OK;</returns>
- STDMETHOD(Reset)(void) = 0;
-
- /// <summary>
- /// Creates a new enumeration object in the same state as the current enumeration object: the new object points to the same place in the enumeration sequence.
- /// </summary>
- /// <param name="ppenum">A pointer to a pointer to a new <see cref="IEnumSetupInstances"/> interface. If the method fails, this parameter is undefined.</param>
- /// <returns>S_OK if a clone was returned; otherwise, E_OUTOFMEMORY.</returns>
- STDMETHOD(Clone)(
- _Deref_out_opt_ IEnumSetupInstances** ppenum
- ) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupConfiguration;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Gets information about product instances installed on the machine.
-/// </summary>
-struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") DECLSPEC_NOVTABLE ISetupConfiguration : public IUnknown
-{
- /// <summary>
- /// Enumerates all launchable product instances installed.
- /// </summary>
- /// <param name="ppEnumInstances">An enumeration of completed, installed product instances.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(EnumInstances)(
- _Out_ IEnumSetupInstances** ppEnumInstances
- ) = 0;
-
- /// <summary>
- /// Gets the instance for the current process path.
- /// </summary>
- /// <param name="ppInstance">The instance for the current process path.</param>
- /// <returns>
- /// The instance for the current process path, or E_NOTFOUND if not found.
- /// The <see cref="ISetupInstance::GetState"/> may indicate the instance is invalid.
- /// </returns>
- /// <remarks>
- /// The returned instance may not be launchable.
- /// </remarks>
-STDMETHOD(GetInstanceForCurrentProcess)(
- _Out_ ISetupInstance** ppInstance
- ) = 0;
-
- /// <summary>
- /// Gets the instance for the given path.
- /// </summary>
- /// <param name="ppInstance">The instance for the given path.</param>
- /// <returns>
- /// The instance for the given path, or E_NOTFOUND if not found.
- /// The <see cref="ISetupInstance::GetState"/> may indicate the instance is invalid.
- /// </returns>
- /// <remarks>
- /// The returned instance may not be launchable.
- /// </remarks>
-STDMETHOD(GetInstanceForPath)(
- _In_z_ LPCWSTR wzPath,
- _Out_ ISetupInstance** ppInstance
- ) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupConfiguration2;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Gets information about product instances.
-/// </summary>
-struct DECLSPEC_UUID("26AAB78C-4A60-49D6-AF3B-3C35BC93365D") DECLSPEC_NOVTABLE ISetupConfiguration2 : public ISetupConfiguration
-{
- /// <summary>
- /// Enumerates all product instances.
- /// </summary>
- /// <param name="ppEnumInstances">An enumeration of all product instances.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(EnumAllInstances)(
- _Out_ IEnumSetupInstances** ppEnumInstances
- ) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupPackageReference;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// A reference to a package.
-/// </summary>
-struct DECLSPEC_UUID("da8d8a16-b2b6-4487-a2f1-594ccccd6bf5") DECLSPEC_NOVTABLE ISetupPackageReference : public IUnknown
-{
- /// <summary>
- /// Gets the general package identifier.
- /// </summary>
- /// <param name="pbstrId">The general package identifier.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetId)(
- _Out_ BSTR* pbstrId
- ) = 0;
-
- /// <summary>
- /// Gets the version of the package.
- /// </summary>
- /// <param name="pbstrVersion">The version of the package.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetVersion)(
- _Out_ BSTR* pbstrVersion
- ) = 0;
-
- /// <summary>
- /// Gets the target process architecture of the package.
- /// </summary>
- /// <param name="pbstrChip">The target process architecture of the package.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetChip)(
- _Out_ BSTR* pbstrChip
- ) = 0;
-
- /// <summary>
- /// Gets the language and optional region identifier.
- /// </summary>
- /// <param name="pbstrLanguage">The language and optional region identifier.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetLanguage)(
- _Out_ BSTR* pbstrLanguage
- ) = 0;
-
- /// <summary>
- /// Gets the build branch of the package.
- /// </summary>
- /// <param name="pbstrBranch">The build branch of the package.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetBranch)(
- _Out_ BSTR* pbstrBranch
- ) = 0;
-
- /// <summary>
- /// Gets the type of the package.
- /// </summary>
- /// <param name="pbstrType">The type of the package.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetType)(
- _Out_ BSTR* pbstrType
- ) = 0;
-
- /// <summary>
- /// Gets the unique identifier consisting of all defined tokens.
- /// </summary>
- /// <param name="pbstrUniqueId">The unique identifier consisting of all defined tokens.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_UNEXPECTED if no Id was defined (required).</returns>
- STDMETHOD(GetUniqueId)(
- _Out_ BSTR* pbstrUniqueId
- ) = 0;
-
- /// <summary>
- /// Gets a value indicating whether the package refers to an external extension.
- /// </summary>
- /// <param name="pfIsExtension">A value indicating whether the package refers to an external extension.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_UNEXPECTED if no Id was defined (required).</returns>
- STDMETHOD(GetIsExtension)(
- _Out_ VARIANT_BOOL* pfIsExtension
- ) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupHelper;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Helper functions.
-/// </summary>
-/// <remarks>
-/// You can query for this interface from the <see cref="SetupConfiguration"/> class.
-/// </remarks>
-struct DECLSPEC_UUID("42b21b78-6192-463e-87bf-d577838f1d5c") DECLSPEC_NOVTABLE ISetupHelper : public IUnknown
-{
- /// <summary>
- /// Parses a dotted quad version string into a 64-bit unsigned integer.
- /// </summary>
- /// <param name="pwszVersion">The dotted quad version string to parse, e.g. 1.2.3.4.</param>
- /// <param name="pullVersion">A 64-bit unsigned integer representing the version. You can compare this to other versions.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_INVALIDARG if the version is not valid.</returns>
- STDMETHOD(ParseVersion)(
- _In_ LPCOLESTR pwszVersion,
- _Out_ PULONGLONG pullVersion
- ) = 0;
-
- /// <summary>
- /// Parses a dotted quad version string into a 64-bit unsigned integer.
- /// </summary>
- /// <param name="pwszVersionRange">The string containing 1 or 2 dotted quad version strings to parse, e.g. [1.0,) that means 1.0.0.0 or newer.</param>
- /// <param name="pullMinVersion">A 64-bit unsigned integer representing the minimum version, which may be 0. You can compare this to other versions.</param>
- /// <param name="pullMaxVersion">A 64-bit unsigned integer representing the maximum version, which may be MAXULONGLONG. You can compare this to other versions.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_INVALIDARG if the version range is not valid.</returns>
- STDMETHOD(ParseVersionRange)(
- _In_ LPCOLESTR pwszVersionRange,
- _Out_ PULONGLONG pullMinVersion,
- _Out_ PULONGLONG pullMaxVersion
- ) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupErrorState;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Information about the error state of an instance.
-/// </summary>
-struct DECLSPEC_UUID("46DCCD94-A287-476A-851E-DFBC2FFDBC20") DECLSPEC_NOVTABLE ISetupErrorState : public IUnknown
-{
- /// <summary>
- /// Gets an array of failed package references.
- /// </summary>
- /// <param name="ppsaPackages">Pointer to an array of <see cref="ISetupFailedPackageReference"/>, if packages have failed.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetFailedPackages)(
- _Outptr_result_maybenull_ LPSAFEARRAY* ppsaFailedPackages
- ) = 0;
-
- /// <summary>
- /// Gets an array of skipped package references.
- /// </summary>
- /// <param name="ppsaPackages">Pointer to an array of <see cref="ISetupPackageReference"/>, if packages have been skipped.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetSkippedPackages)(
- _Outptr_result_maybenull_ LPSAFEARRAY* ppsaSkippedPackages
- ) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupErrorState2;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Information about the error state of an instance.
-/// </summary>
-struct DECLSPEC_UUID("9871385B-CA69-48F2-BC1F-7A37CBF0B1EF") DECLSPEC_NOVTABLE ISetupErrorState2 : public ISetupErrorState
-{
- /// <summary>
- /// Gets the path to the error log.
- /// </summary>
- /// <param name="pbstrChip">The path to the error log.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetErrorLogFilePath)(
- _Outptr_result_maybenull_ BSTR* pbstrErrorLogFilePath
- ) = 0;
-};
-#endif
-
-EXTERN_C const IID IID_ISetupFailedPackageReference;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// A reference to a failed package.
-/// </summary>
-struct DECLSPEC_UUID("E73559CD-7003-4022-B134-27DC650B280F") DECLSPEC_NOVTABLE ISetupFailedPackageReference : public ISetupPackageReference
-{
-};
-
-#endif
-
-EXTERN_C const IID IID_ISetupFailedPackageReference2;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// A reference to a failed package.
-/// </summary>
-struct DECLSPEC_UUID("0FAD873E-E874-42E3-B268-4FE2F096B9CA") DECLSPEC_NOVTABLE ISetupFailedPackageReference2 : public ISetupFailedPackageReference
-{
- /// <summary>
- /// Gets the path to the optional package log.
- /// </summary>
- /// <param name="pbstrId">The path to the optional package log.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetLogFilePath)(
- _Outptr_result_maybenull_ BSTR* pbstrLogFilePath
- ) = 0;
-
- /// <summary>
- /// Gets the description of the package failure.
- /// </summary>
- /// <param name="pbstrId">The description of the package failure.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetDescription)(
- _Outptr_result_maybenull_ BSTR* pbstrDescription
- ) = 0;
-
- /// <summary>
- /// Gets the signature to use for feedback reporting.
- /// </summary>
- /// <param name="pbstrId">The signature to use for feedback reporting.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetSignature)(
- _Outptr_result_maybenull_ BSTR* pbstrSignature
- ) = 0;
-
- /// <summary>
- /// Gets the array of details for this package failure.
- /// </summary>
- /// <param name="ppsaDetails">Pointer to an array of details as BSTRs.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetDetails)(
- _Out_ LPSAFEARRAY* ppsaDetails
- ) = 0;
-
- /// <summary>
- /// Gets an array of packages affected by this package failure.
- /// </summary>
- /// <param name="ppsaPackages">Pointer to an array of <see cref="ISetupPackageReference"/> for packages affected by this package failure. This may be NULL.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetAffectedPackages)(
- _Out_ LPSAFEARRAY* ppsaAffectedPackages
- ) = 0;
-};
-
-#endif
-
-EXTERN_C const IID IID_ISetupPropertyStore;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Provides named properties.
-/// </summary>
-/// <remarks>
-/// You can get this from an <see cref="ISetupInstance"/>, <see cref="ISetupPackageReference"/>, or derivative.
-/// </remarks>
-struct DECLSPEC_UUID("C601C175-A3BE-44BC-91F6-4568D230FC83") DECLSPEC_NOVTABLE ISetupPropertyStore : public IUnknown
-{
- /// <summary>
- /// Gets an array of property names in this property store.
- /// </summary>
- /// <param name="ppsaNames">Pointer to an array of property names as BSTRs.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetNames)(
- _Out_ LPSAFEARRAY* ppsaNames
- ) = 0;
-
- /// <summary>
- /// Gets the value of a named property in this property store.
- /// </summary>
- /// <param name="pwszName">The name of the property to get.</param>
- /// <param name="pvtValue">The value of the property.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_NOTFOUND if the property is not defined or E_NOTSUPPORTED if the property type is not supported.</returns>
- STDMETHOD(GetValue)(
- _In_ LPCOLESTR pwszName,
- _Out_ LPVARIANT pvtValue
- ) = 0;
-};
-
-#endif
-
-EXTERN_C const IID IID_ISetupLocalizedPropertyStore;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-/// <summary>
-/// Provides localized named properties.
-/// </summary>
-/// <remarks>
-/// You can get this from an <see cref="ISetupLocalizedProperties"/>.
-/// </remarks>
-struct DECLSPEC_UUID("5BB53126-E0D5-43DF-80F1-6B161E5C6F6C") DECLSPEC_NOVTABLE ISetupLocalizedPropertyStore : public IUnknown
-{
- /// <summary>
- /// Gets an array of property names in this property store.
- /// </summary>
- /// <param name="lcid">The LCID for the property names.</param>
- /// <param name="ppsaNames">Pointer to an array of property names as BSTRs.</param>
- /// <returns>Standard HRESULT indicating success or failure.</returns>
- STDMETHOD(GetNames)(
- _In_ LCID lcid,
- _Out_ LPSAFEARRAY* ppsaNames
- ) = 0;
-
- /// <summary>
- /// Gets the value of a named property in this property store.
- /// </summary>
- /// <param name="pwszName">The name of the property to get.</param>
- /// <param name="lcid">The LCID for the property.</param>
- /// <param name="pvtValue">The value of the property.</param>
- /// <returns>Standard HRESULT indicating success or failure, including E_NOTFOUND if the property is not defined or E_NOTSUPPORTED if the property type is not supported.</returns>
- STDMETHOD(GetValue)(
- _In_ LPCOLESTR pwszName,
- _In_ LCID lcid,
- _Out_ LPVARIANT pvtValue
- ) = 0;
-};
-
-#endif
-
-// Class declarations
-//
-EXTERN_C const CLSID CLSID_SetupConfiguration;
-
-#ifdef __cplusplus
-/// <summary>
-/// This class implements <see cref="ISetupConfiguration"/>, <see cref="ISetupConfiguration2"/>, and <see cref="ISetupHelper"/>.
-/// </summary>
-class DECLSPEC_UUID("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D") SetupConfiguration;
-#endif
-
-// Function declarations
-//
-/// <summary>
-/// Gets an <see cref="ISetupConfiguration"/> that provides information about product instances installed on the machine.
-/// </summary>
-/// <param name="ppConfiguration">The <see cref="ISetupConfiguration"/> that provides information about product instances installed on the machine.</param>
-/// <param name="pReserved">Reserved for future use.</param>
-/// <returns>Standard HRESULT indicating success or failure.</returns>
-STDMETHODIMP GetSetupConfiguration(
- _Out_ ISetupConfiguration** ppConfiguration,
- _Reserved_ LPVOID pReserved
-);
-
-#ifdef __cplusplus
-}
-#endif
get_program_full_path(const _PyCoreConfig *core_config,
PyCalculatePath *calculate, _PyPathConfig *config)
{
+ const wchar_t *pyvenv_launcher;
wchar_t program_full_path[MAXPATHLEN+1];
memset(program_full_path, 0, sizeof(program_full_path));
- if (!GetModuleFileNameW(NULL, program_full_path, MAXPATHLEN)) {
+ /* The launcher may need to force the executable path to a
+ * different environment, so override it here. */
+ pyvenv_launcher = _wgetenv(L"__PYVENV_LAUNCHER__");
+ if (pyvenv_launcher && pyvenv_launcher[0]) {
+ wcscpy_s(program_full_path, MAXPATHLEN+1, pyvenv_launcher);
+ } else if (!GetModuleFileNameW(NULL, program_full_path, MAXPATHLEN)) {
/* GetModuleFileName should never fail when passed NULL */
return _Py_INIT_ERR("Cannot determine program path");
}
size_t prefixlen = wcslen(prefix);
wchar_t *buf = (wchar_t*)PyMem_RawMalloc(bufsiz * sizeof(wchar_t));
+ if (buf == NULL) {
+ goto error;
+ }
buf[0] = '\0';
while (!feof(sp_file)) {
DWORD wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, NULL, 0);
wchar_t *wline = (wchar_t*)PyMem_RawMalloc((wn + 1) * sizeof(wchar_t));
+ if (wline == NULL) {
+ goto error;
+ }
wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1);
wline[wn] = '\0';
size_t usedsiz = wcslen(buf);
while (usedsiz + wn + prefixlen + 4 > bufsiz) {
bufsiz += MAXPATHLEN;
- buf = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) * sizeof(wchar_t));
- if (!buf) {
+ wchar_t *tmp = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) *
+ sizeof(wchar_t));
+ if (tmp == NULL) {
PyMem_RawFree(wline);
goto error;
}
+ buf = tmp;
}
if (usedsiz) {
#define RC_NO_PYTHON 103
#define RC_NO_MEMORY 104
/*
- * SCRIPT_WRAPPER is used to choose between two variants of an executable built
+ * SCRIPT_WRAPPER is used to choose one of the variants of an executable built
* from this source file. If not defined, the PEP 397 Python launcher is built;
* if defined, a script launcher of the type used by setuptools is built, which
* looks for a script name related to the executable name and runs that script
#if defined(SCRIPT_WRAPPER)
#define RC_NO_SCRIPT 105
#endif
+/*
+ * VENV_REDIRECT is used to choose the variant that looks for an adjacent or
+ * one-level-higher pyvenv.cfg, and uses its "home" property to locate and
+ * launch the original python.exe.
+ */
+#if defined(VENV_REDIRECT)
+#define RC_NO_VENV_CFG 106
+#define RC_BAD_VENV_CFG 107
+#endif
/* Just for now - static definition */
#if !defined(_WINDOWS)
fwprintf(stderr, L"%ls\n", message);
#else
- MessageBox(NULL, message, TEXT("Python Launcher is sorry to say ..."),
+ MessageBoxW(NULL, message, L"Python Launcher is sorry to say ...",
MB_OK);
#endif
exit(rc);
return buf;
}
+#if defined(_DEBUG)
+#if defined(_WINDOWS)
+
+#define PYTHON_EXECUTABLE L"pythonw_d.exe"
+
+#else
+
+#define PYTHON_EXECUTABLE L"python_d.exe"
+
+#endif
+#else
#if defined(_WINDOWS)
#define PYTHON_EXECUTABLE L"pythonw.exe"
#define PYTHON_EXECUTABLE L"python.exe"
#endif
+#endif
#define MAX_VERSION_SIZE 4
{ 3320, 3351, L"3.5" },
{ 3360, 3379, L"3.6" },
{ 3390, 3399, L"3.7" },
+ { 3400, 3409, L"3.8" },
{ 0 }
};
fwprintf(stderr, L"\n\nCan't find a Default Python.\n\n");
else
fwprintf(stderr, L"\n\n"); /* End with a blank line */
- return(FALSE); /* If this has been called we cannot continue */
+ return FALSE; /* If this has been called we cannot continue */
+}
+
+#if defined(VENV_REDIRECT)
+
+static int
+find_home_value(const char *buffer, const char **start, DWORD *length)
+{
+ for (const char *s = strstr(buffer, "home"); s; s = strstr(s + 1, "\nhome")) {
+ if (*s == '\n') {
+ ++s;
+ }
+ for (int i = 4; i > 0 && *s; --i, ++s);
+
+ while (*s && iswspace(*s)) {
+ ++s;
+ }
+ if (*s != L'=') {
+ continue;
+ }
+
+ do {
+ ++s;
+ } while (*s && iswspace(*s));
+
+ *start = s;
+ char *nl = strchr(s, '\n');
+ if (nl) {
+ *length = (DWORD)((ptrdiff_t)nl - (ptrdiff_t)s);
+ } else {
+ *length = (DWORD)strlen(s);
+ }
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+static wchar_t *
+wcsdup_pad(const wchar_t *s, int padding, int *newlen)
+{
+ size_t len = wcslen(s);
+ len += 1 + padding;
+ wchar_t *r = (wchar_t *)malloc(len * sizeof(wchar_t));
+ if (!r) {
+ return NULL;
+ }
+ if (wcscpy_s(r, len, s)) {
+ free(r);
+ return NULL;
+ }
+ *newlen = len < MAXINT ? (int)len : MAXINT;
+ return r;
+}
+
+static wchar_t *
+get_process_name()
+{
+ DWORD bufferLen = MAX_PATH;
+ DWORD len = bufferLen;
+ wchar_t *r = NULL;
+
+ while (!r) {
+ r = (wchar_t *)malloc(bufferLen * sizeof(wchar_t));
+ if (!r) {
+ error(RC_NO_MEMORY, L"out of memory");
+ return NULL;
+ }
+ len = GetModuleFileNameW(NULL, r, bufferLen);
+ if (len == 0) {
+ free(r);
+ error(0, L"Failed to get module name");
+ return NULL;
+ } else if (len == bufferLen &&
+ GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ free(r);
+ r = NULL;
+ bufferLen *= 2;
+ }
+ }
+
+ return r;
}
static int
wchar_t * command;
wchar_t * executable;
wchar_t * p;
+ wchar_t * argv0;
int rc = 0;
- size_t plen;
INSTALLED_PYTHON * ip;
BOOL valid;
DWORD size, attrs;
- HRESULT hr;
wchar_t message[MSGSIZE];
void * version_data;
VS_FIXEDFILEINFO * file_info;
UINT block_size;
- int index;
-#if defined(SCRIPT_WRAPPER)
+#if defined(VENV_REDIRECT)
+ wchar_t * venv_cfg_path;
int newlen;
+#elif defined(SCRIPT_WRAPPER)
wchar_t * newcommand;
wchar_t * av[2];
+ int newlen;
+ HRESULT hr;
+ int index;
+#else
+ HRESULT hr;
+ int index;
#endif
setvbuf(stderr, (char *)NULL, _IONBF, 0);
#else
debug(L"launcher executable: Console\n");
#endif
+#if !defined(VENV_REDIRECT)
/* Get the local appdata folder (non-roaming) */
hr = SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA,
NULL, 0, appdata_ini_path);
appdata_ini_path[0] = L'\0';
}
else {
- plen = wcslen(appdata_ini_path);
- p = &appdata_ini_path[plen];
- wcsncpy_s(p, MAX_PATH - plen, L"\\py.ini", _TRUNCATE);
+ wcsncat_s(appdata_ini_path, MAX_PATH, L"\\py.ini", _TRUNCATE);
attrs = GetFileAttributesW(appdata_ini_path);
if (attrs == INVALID_FILE_ATTRIBUTES) {
debug(L"File '%ls' non-existent\n", appdata_ini_path);
debug(L"Using local configuration file '%ls'\n", appdata_ini_path);
}
}
- plen = GetModuleFileNameW(NULL, launcher_ini_path, MAX_PATH);
- size = GetFileVersionInfoSizeW(launcher_ini_path, &size);
+#endif
+ argv0 = get_process_name();
+ size = GetFileVersionInfoSizeW(argv0, &size);
if (size == 0) {
winerror(GetLastError(), message, MSGSIZE);
debug(L"GetFileVersionInfoSize failed: %ls\n", message);
else {
version_data = malloc(size);
if (version_data) {
- valid = GetFileVersionInfoW(launcher_ini_path, 0, size,
+ valid = GetFileVersionInfoW(argv0, 0, size,
version_data);
if (!valid)
debug(L"GetFileVersionInfo failed: %X\n", GetLastError());
free(version_data);
}
}
+
+#if defined(VENV_REDIRECT)
+ /* Allocate some extra space for new filenames */
+ venv_cfg_path = wcsdup_pad(argv0, 32, &newlen);
+ if (!venv_cfg_path) {
+ error(RC_NO_MEMORY, L"Failed to copy module name");
+ }
+ p = wcsrchr(venv_cfg_path, L'\\');
+
+ if (p == NULL) {
+ error(RC_NO_VENV_CFG, L"No pyvenv.cfg file");
+ }
+ p[0] = L'\0';
+ wcscat_s(venv_cfg_path, newlen, L"\\pyvenv.cfg");
+ attrs = GetFileAttributesW(venv_cfg_path);
+ if (attrs == INVALID_FILE_ATTRIBUTES) {
+ debug(L"File '%ls' non-existent\n", venv_cfg_path);
+ p[0] = '\0';
+ p = wcsrchr(venv_cfg_path, L'\\');
+ if (p != NULL) {
+ p[0] = '\0';
+ wcscat_s(venv_cfg_path, newlen, L"\\pyvenv.cfg");
+ attrs = GetFileAttributesW(venv_cfg_path);
+ if (attrs == INVALID_FILE_ATTRIBUTES) {
+ debug(L"File '%ls' non-existent\n", venv_cfg_path);
+ error(RC_NO_VENV_CFG, L"No pyvenv.cfg file");
+ }
+ }
+ }
+ debug(L"Using venv configuration file '%ls'\n", venv_cfg_path);
+#else
+ /* Allocate some extra space for new filenames */
+ if (wcscpy_s(launcher_ini_path, MAX_PATH, argv0)) {
+ error(RC_NO_MEMORY, L"Failed to copy module name");
+ }
p = wcsrchr(launcher_ini_path, L'\\');
+
if (p == NULL) {
debug(L"GetModuleFileNameW returned value has no backslash: %ls\n",
launcher_ini_path);
launcher_ini_path[0] = L'\0';
}
else {
- wcsncpy_s(p, MAX_PATH - (p - launcher_ini_path), L"\\py.ini",
- _TRUNCATE);
+ p[0] = L'\0';
+ wcscat_s(launcher_ini_path, MAX_PATH, L"\\py.ini");
attrs = GetFileAttributesW(launcher_ini_path);
if (attrs == INVALID_FILE_ATTRIBUTES) {
debug(L"File '%ls' non-existent\n", launcher_ini_path);
debug(L"Using global configuration file '%ls'\n", launcher_ini_path);
}
}
+#endif
command = skip_me(GetCommandLineW());
debug(L"Called with command line: %ls\n", command);
command = newcommand;
valid = FALSE;
}
+#elif defined(VENV_REDIRECT)
+ {
+ FILE *f;
+ char buffer[4096]; /* 4KB should be enough for anybody */
+ char *start;
+ DWORD len, cch, cch_actual;
+ size_t cb;
+ if (_wfopen_s(&f, venv_cfg_path, L"r")) {
+ error(RC_BAD_VENV_CFG, L"Cannot read '%ls'", venv_cfg_path);
+ }
+ cb = fread_s(buffer, sizeof(buffer), sizeof(buffer[0]),
+ sizeof(buffer) / sizeof(buffer[0]), f);
+ fclose(f);
+
+ if (!find_home_value(buffer, &start, &len)) {
+ error(RC_BAD_VENV_CFG, L"Cannot find home in '%ls'",
+ venv_cfg_path);
+ }
+
+ cch = MultiByteToWideChar(CP_UTF8, 0, start, len, NULL, 0);
+ if (!cch) {
+ error(0, L"Cannot determine memory for home path");
+ }
+ cch += (DWORD)wcslen(PYTHON_EXECUTABLE) + 1 + 1; /* include sep and null */
+ executable = (wchar_t *)malloc(cch * sizeof(wchar_t));
+ if (executable == NULL) {
+ error(RC_NO_MEMORY, L"A memory allocation failed");
+ }
+ cch_actual = MultiByteToWideChar(CP_UTF8, 0, start, len, executable, cch);
+ if (!cch_actual) {
+ error(RC_BAD_VENV_CFG, L"Cannot decode home path in '%ls'",
+ venv_cfg_path);
+ }
+ if (executable[cch_actual - 1] != L'\\') {
+ executable[cch_actual++] = L'\\';
+ executable[cch_actual] = L'\0';
+ }
+ if (wcscat_s(executable, cch, PYTHON_EXECUTABLE)) {
+ error(RC_BAD_VENV_CFG, L"Cannot create executable path from '%ls'",
+ venv_cfg_path);
+ }
+ if (GetFileAttributesW(executable) == INVALID_FILE_ATTRIBUTES) {
+ error(RC_NO_PYTHON, L"No Python at '%ls'", executable);
+ }
+ if (!SetEnvironmentVariableW(L"__PYVENV_LAUNCHER__", argv0)) {
+ error(0, L"Failed to set launcher environment");
+ }
+ valid = 1;
+ }
#else
if (argc <= 1) {
valid = FALSE;
}
else {
p = argv[1];
- plen = wcslen(p);
- if ((argc == 2) &&
- (!wcsncmp(p, L"-0", wcslen(L"-0")) || /* Starts with -0 or --list */
+ if ((argc == 2) && // list version args
+ (!wcsncmp(p, L"-0", wcslen(L"-0")) ||
!wcsncmp(p, L"--list", wcslen(L"--list"))))
{
- valid = show_python_list(argv); /* Check for -0 or --list FIRST */
+ show_python_list(argv);
+ return rc;
}
valid = valid && (*p == L'-') && validate_version(&p[1]);
if (valid) {
--- /dev/null
+import sys
+
+try:
+ import layout
+except ImportError:
+ # Failed to import our package, which likely means we were started directly
+ # Add the additional search path needed to locate our module.
+ from pathlib import Path
+
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
+
+from layout.main import main
+
+sys.exit(int(main() or 0))
--- /dev/null
+"""
+Generates a layout of Python for Windows from a build.
+
+See python make_layout.py --help for usage.
+"""
+
+__author__ = "Steve Dower <steve.dower@python.org>"
+__version__ = "3.8"
+
+import argparse
+import functools
+import os
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+import zipfile
+
+from pathlib import Path
+
+if __name__ == "__main__":
+ # Started directly, so enable relative imports
+ __path__ = [str(Path(__file__).resolve().parent)]
+
+from .support.appxmanifest import *
+from .support.catalog import *
+from .support.constants import *
+from .support.filesets import *
+from .support.logging import *
+from .support.options import *
+from .support.pip import *
+from .support.props import *
+
+BDIST_WININST_FILES_ONLY = FileNameSet("wininst-*", "bdist_wininst.py")
+BDIST_WININST_STUB = "PC/layout/support/distutils.command.bdist_wininst.py"
+
+TEST_PYDS_ONLY = FileStemSet("xxlimited", "_ctypes_test", "_test*")
+TEST_DIRS_ONLY = FileNameSet("test", "tests")
+
+IDLE_DIRS_ONLY = FileNameSet("idlelib")
+
+TCLTK_PYDS_ONLY = FileStemSet("tcl*", "tk*", "_tkinter")
+TCLTK_DIRS_ONLY = FileNameSet("tkinter", "turtledemo")
+TCLTK_FILES_ONLY = FileNameSet("turtle.py")
+
+VENV_DIRS_ONLY = FileNameSet("venv", "ensurepip")
+
+EXCLUDE_FROM_PYDS = FileStemSet("python*", "pyshellext")
+EXCLUDE_FROM_LIB = FileNameSet("*.pyc", "__pycache__", "*.pickle")
+EXCLUDE_FROM_PACKAGED_LIB = FileNameSet("readme.txt")
+EXCLUDE_FROM_COMPILE = FileNameSet("badsyntax_*", "bad_*")
+EXCLUDE_FROM_CATALOG = FileSuffixSet(".exe", ".pyd", ".dll")
+
+REQUIRED_DLLS = FileStemSet("libcrypto*", "libssl*")
+
+LIB2TO3_GRAMMAR_FILES = FileNameSet("Grammar.txt", "PatternGrammar.txt")
+
+PY_FILES = FileSuffixSet(".py")
+PYC_FILES = FileSuffixSet(".pyc")
+CAT_FILES = FileSuffixSet(".cat")
+CDF_FILES = FileSuffixSet(".cdf")
+
+DATA_DIRS = FileNameSet("data")
+
+TOOLS_DIRS = FileNameSet("scripts", "i18n", "pynche", "demo", "parser")
+TOOLS_FILES = FileSuffixSet(".py", ".pyw", ".txt")
+
+
+def get_lib_layout(ns):
+ def _c(f):
+ if f in EXCLUDE_FROM_LIB:
+ return False
+ if f.is_dir():
+ if f in TEST_DIRS_ONLY:
+ return ns.include_tests
+ if f in TCLTK_DIRS_ONLY:
+ return ns.include_tcltk
+ if f in IDLE_DIRS_ONLY:
+ return ns.include_idle
+ if f in VENV_DIRS_ONLY:
+ return ns.include_venv
+ else:
+ if f in TCLTK_FILES_ONLY:
+ return ns.include_tcltk
+ if f in BDIST_WININST_FILES_ONLY:
+ return ns.include_bdist_wininst
+ return True
+
+ for dest, src in rglob(ns.source / "Lib", "**/*", _c):
+ yield dest, src
+
+ if not ns.include_bdist_wininst:
+ src = ns.source / BDIST_WININST_STUB
+ yield Path("distutils/command/bdist_wininst.py"), src
+
+
+def get_tcltk_lib(ns):
+ if not ns.include_tcltk:
+ return
+
+ tcl_lib = os.getenv("TCL_LIBRARY")
+ if not tcl_lib or not os.path.isdir(tcl_lib):
+ try:
+ with open(ns.build / "TCL_LIBRARY.env", "r", encoding="utf-8-sig") as f:
+ tcl_lib = f.read().strip()
+ except FileNotFoundError:
+ pass
+ if not tcl_lib or not os.path.isdir(tcl_lib):
+ warn("Failed to find TCL_LIBRARY")
+ return
+
+ for dest, src in rglob(Path(tcl_lib).parent, "**/*"):
+ yield "tcl/{}".format(dest), src
+
+
+def get_layout(ns):
+ def in_build(f, dest="", new_name=None):
+ n, _, x = f.rpartition(".")
+ n = new_name or n
+ src = ns.build / f
+ if ns.debug and src not in REQUIRED_DLLS:
+ if not src.stem.endswith("_d"):
+ src = src.parent / (src.stem + "_d" + src.suffix)
+ if not n.endswith("_d"):
+ n += "_d"
+ f = n + "." + x
+ yield dest + n + "." + x, src
+ if ns.include_symbols:
+ pdb = src.with_suffix(".pdb")
+ if pdb.is_file():
+ yield dest + n + ".pdb", pdb
+ if ns.include_dev:
+ lib = src.with_suffix(".lib")
+ if lib.is_file():
+ yield "libs/" + n + ".lib", lib
+
+ if ns.include_appxmanifest:
+ yield from in_build("python_uwp.exe", new_name="python")
+ yield from in_build("pythonw_uwp.exe", new_name="pythonw")
+ else:
+ yield from in_build("python.exe", new_name="python")
+ yield from in_build("pythonw.exe", new_name="pythonw")
+
+ yield from in_build(PYTHON_DLL_NAME)
+
+ if ns.include_launchers and ns.include_appxmanifest:
+ if ns.include_pip:
+ yield from in_build("python_uwp.exe", new_name="pip")
+ if ns.include_idle:
+ yield from in_build("pythonw_uwp.exe", new_name="idle")
+
+ if ns.include_stable:
+ yield from in_build(PYTHON_STABLE_DLL_NAME)
+
+ for dest, src in rglob(ns.build, "vcruntime*.dll"):
+ yield dest, src
+
+ for dest, src in rglob(ns.build, ("*.pyd", "*.dll")):
+ if src.stem.endswith("_d") != bool(ns.debug) and src not in REQUIRED_DLLS:
+ continue
+ if src in EXCLUDE_FROM_PYDS:
+ continue
+ if src in TEST_PYDS_ONLY and not ns.include_tests:
+ continue
+ if src in TCLTK_PYDS_ONLY and not ns.include_tcltk:
+ continue
+
+ yield from in_build(src.name, dest="" if ns.flat_dlls else "DLLs/")
+
+ if ns.zip_lib:
+ zip_name = PYTHON_ZIP_NAME
+ yield zip_name, ns.temp / zip_name
+ else:
+ for dest, src in get_lib_layout(ns):
+ yield "Lib/{}".format(dest), src
+
+ if ns.include_venv:
+ yield from in_build("venvlauncher.exe", "Lib/venv/scripts/nt/", "python")
+ yield from in_build("venvwlauncher.exe", "Lib/venv/scripts/nt/", "pythonw")
+
+ if ns.include_tools:
+
+ def _c(d):
+ if d.is_dir():
+ return d in TOOLS_DIRS
+ return d in TOOLS_FILES
+
+ for dest, src in rglob(ns.source / "Tools", "**/*", _c):
+ yield "Tools/{}".format(dest), src
+
+ if ns.include_underpth:
+ yield PYTHON_PTH_NAME, ns.temp / PYTHON_PTH_NAME
+
+ if ns.include_dev:
+
+ def _c(d):
+ if d.is_dir():
+ return d.name != "internal"
+ return True
+
+ for dest, src in rglob(ns.source / "Include", "**/*.h", _c):
+ yield "include/{}".format(dest), src
+ src = ns.source / "PC" / "pyconfig.h"
+ yield "include/pyconfig.h", src
+
+ for dest, src in get_tcltk_lib(ns):
+ yield dest, src
+
+ if ns.include_pip:
+ pip_dir = get_pip_dir(ns)
+ if not pip_dir.is_dir():
+ log_warning("Failed to find {} - pip will not be included", pip_dir)
+ else:
+ pkg_root = "packages/{}" if ns.zip_lib else "Lib/site-packages/{}"
+ for dest, src in rglob(pip_dir, "**/*"):
+ if src in EXCLUDE_FROM_LIB or src in EXCLUDE_FROM_PACKAGED_LIB:
+ continue
+ yield pkg_root.format(dest), src
+
+ if ns.include_chm:
+ for dest, src in rglob(ns.doc_build / "htmlhelp", PYTHON_CHM_NAME):
+ yield "Doc/{}".format(dest), src
+
+ if ns.include_html_doc:
+ for dest, src in rglob(ns.doc_build / "html", "**/*"):
+ yield "Doc/html/{}".format(dest), src
+
+ if ns.include_props:
+ for dest, src in get_props_layout(ns):
+ yield dest, src
+
+ for dest, src in get_appx_layout(ns):
+ yield dest, src
+
+ if ns.include_cat:
+ if ns.flat_dlls:
+ yield ns.include_cat.name, ns.include_cat
+ else:
+ yield "DLLs/{}".format(ns.include_cat.name), ns.include_cat
+
+
+def _compile_one_py(src, dest, name, optimize):
+ import py_compile
+
+ if dest is not None:
+ dest = str(dest)
+
+ try:
+ return Path(
+ py_compile.compile(
+ str(src),
+ dest,
+ str(name),
+ doraise=True,
+ optimize=optimize,
+ invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH,
+ )
+ )
+ except py_compile.PyCompileError:
+ log_warning("Failed to compile {}", src)
+ return None
+
+
+def _py_temp_compile(src, ns, dest_dir=None):
+ if not ns.precompile or src not in PY_FILES or src.parent in DATA_DIRS:
+ return None
+
+ dest = (dest_dir or ns.temp) / (src.stem + ".py")
+ return _compile_one_py(src, dest.with_suffix(".pyc"), dest, optimize=2)
+
+
+def _write_to_zip(zf, dest, src, ns):
+ pyc = _py_temp_compile(src, ns)
+ if pyc:
+ try:
+ zf.write(str(pyc), dest.with_suffix(".pyc"))
+ finally:
+ try:
+ pyc.unlink()
+ except:
+ log_exception("Failed to delete {}", pyc)
+ return
+
+ if src in LIB2TO3_GRAMMAR_FILES:
+ from lib2to3.pgen2.driver import load_grammar
+
+ tmp = ns.temp / src.name
+ try:
+ shutil.copy(src, tmp)
+ load_grammar(str(tmp))
+ for f in ns.temp.glob(src.stem + "*.pickle"):
+ zf.write(str(f), str(dest.parent / f.name))
+ try:
+ f.unlink()
+ except:
+ log_exception("Failed to delete {}", f)
+ except:
+ log_exception("Failed to compile {}", src)
+ finally:
+ try:
+ tmp.unlink()
+ except:
+ log_exception("Failed to delete {}", tmp)
+
+ zf.write(str(src), str(dest))
+
+
+def generate_source_files(ns):
+ if ns.zip_lib:
+ zip_name = PYTHON_ZIP_NAME
+ zip_path = ns.temp / zip_name
+ if zip_path.is_file():
+ zip_path.unlink()
+ elif zip_path.is_dir():
+ log_error(
+ "Cannot create zip file because a directory exists by the same name"
+ )
+ return
+ log_info("Generating {} in {}", zip_name, ns.temp)
+ ns.temp.mkdir(parents=True, exist_ok=True)
+ with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
+ for dest, src in get_lib_layout(ns):
+ _write_to_zip(zf, dest, src, ns)
+
+ if ns.include_underpth:
+ log_info("Generating {} in {}", PYTHON_PTH_NAME, ns.temp)
+ ns.temp.mkdir(parents=True, exist_ok=True)
+ with open(ns.temp / PYTHON_PTH_NAME, "w", encoding="utf-8") as f:
+ if ns.zip_lib:
+ print(PYTHON_ZIP_NAME, file=f)
+ if ns.include_pip:
+ print("packages", file=f)
+ else:
+ print("Lib", file=f)
+ print("Lib/site-packages", file=f)
+ if not ns.flat_dlls:
+ print("DLLs", file=f)
+ print(".", file=f)
+ print(file=f)
+ print("# Uncomment to run site.main() automatically", file=f)
+ print("#import site", file=f)
+
+ if ns.include_appxmanifest:
+ log_info("Generating AppxManifest.xml in {}", ns.temp)
+ ns.temp.mkdir(parents=True, exist_ok=True)
+
+ with open(ns.temp / "AppxManifest.xml", "wb") as f:
+ f.write(get_appxmanifest(ns))
+
+ with open(ns.temp / "_resources.xml", "wb") as f:
+ f.write(get_resources_xml(ns))
+
+ if ns.include_pip:
+ pip_dir = get_pip_dir(ns)
+ if not (pip_dir / "pip").is_dir():
+ log_info("Extracting pip to {}", pip_dir)
+ pip_dir.mkdir(parents=True, exist_ok=True)
+ extract_pip_files(ns)
+
+ if ns.include_props:
+ log_info("Generating {} in {}", PYTHON_PROPS_NAME, ns.temp)
+ ns.temp.mkdir(parents=True, exist_ok=True)
+ with open(ns.temp / PYTHON_PROPS_NAME, "wb") as f:
+ f.write(get_props(ns))
+
+
+def _create_zip_file(ns):
+ if not ns.zip:
+ return None
+
+ if ns.zip.is_file():
+ try:
+ ns.zip.unlink()
+ except OSError:
+ log_exception("Unable to remove {}", ns.zip)
+ sys.exit(8)
+ elif ns.zip.is_dir():
+ log_error("Cannot create ZIP file because {} is a directory", ns.zip)
+ sys.exit(8)
+
+ ns.zip.parent.mkdir(parents=True, exist_ok=True)
+ return zipfile.ZipFile(ns.zip, "w", zipfile.ZIP_DEFLATED)
+
+
+def copy_files(files, ns):
+ if ns.copy:
+ ns.copy.mkdir(parents=True, exist_ok=True)
+
+ try:
+ total = len(files)
+ except TypeError:
+ total = None
+ count = 0
+
+ zip_file = _create_zip_file(ns)
+ try:
+ need_compile = []
+ in_catalog = []
+
+ for dest, src in files:
+ count += 1
+ if count % 10 == 0:
+ if total:
+ log_info("Processed {:>4} of {} files", count, total)
+ else:
+ log_info("Processed {} files", count)
+ log_debug("Processing {!s}", src)
+
+ if (
+ ns.precompile
+ and src in PY_FILES
+ and src not in EXCLUDE_FROM_COMPILE
+ and src.parent not in DATA_DIRS
+ and os.path.normcase(str(dest)).startswith(os.path.normcase("Lib"))
+ ):
+ if ns.copy:
+ need_compile.append((dest, ns.copy / dest))
+ else:
+ (ns.temp / "Lib" / dest).parent.mkdir(parents=True, exist_ok=True)
+ shutil.copy2(src, ns.temp / "Lib" / dest)
+ need_compile.append((dest, ns.temp / "Lib" / dest))
+
+ if src not in EXCLUDE_FROM_CATALOG:
+ in_catalog.append((src.name, src))
+
+ if ns.copy:
+ log_debug("Copy {} -> {}", src, ns.copy / dest)
+ (ns.copy / dest).parent.mkdir(parents=True, exist_ok=True)
+ try:
+ shutil.copy2(src, ns.copy / dest)
+ except shutil.SameFileError:
+ pass
+
+ if ns.zip:
+ log_debug("Zip {} into {}", src, ns.zip)
+ zip_file.write(src, str(dest))
+
+ if need_compile:
+ for dest, src in need_compile:
+ compiled = [
+ _compile_one_py(src, None, dest, optimize=0),
+ _compile_one_py(src, None, dest, optimize=1),
+ _compile_one_py(src, None, dest, optimize=2),
+ ]
+ for c in compiled:
+ if not c:
+ continue
+ cdest = Path(dest).parent / Path(c).relative_to(src.parent)
+ if ns.zip:
+ log_debug("Zip {} into {}", c, ns.zip)
+ zip_file.write(c, str(cdest))
+ in_catalog.append((cdest.name, cdest))
+
+ if ns.catalog:
+ # Just write out the CDF now. Compilation and signing is
+ # an extra step
+ log_info("Generating {}", ns.catalog)
+ ns.catalog.parent.mkdir(parents=True, exist_ok=True)
+ write_catalog(ns.catalog, in_catalog)
+
+ finally:
+ if zip_file:
+ zip_file.close()
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-v", help="Increase verbosity", action="count")
+ parser.add_argument(
+ "-s",
+ "--source",
+ metavar="dir",
+ help="The directory containing the repository root",
+ type=Path,
+ default=None,
+ )
+ parser.add_argument(
+ "-b", "--build", metavar="dir", help="Specify the build directory", type=Path
+ )
+ parser.add_argument(
+ "--doc-build",
+ metavar="dir",
+ help="Specify the docs build directory",
+ type=Path,
+ default=None,
+ )
+ parser.add_argument(
+ "--copy",
+ metavar="directory",
+ help="The name of the directory to copy an extracted layout to",
+ type=Path,
+ default=None,
+ )
+ parser.add_argument(
+ "--zip",
+ metavar="file",
+ help="The ZIP file to write all files to",
+ type=Path,
+ default=None,
+ )
+ parser.add_argument(
+ "--catalog",
+ metavar="file",
+ help="The CDF file to write catalog entries to",
+ type=Path,
+ default=None,
+ )
+ parser.add_argument(
+ "--log",
+ metavar="file",
+ help="Write all operations to the specified file",
+ type=Path,
+ default=None,
+ )
+ parser.add_argument(
+ "-t",
+ "--temp",
+ metavar="file",
+ help="A temporary working directory",
+ type=Path,
+ default=None,
+ )
+ parser.add_argument(
+ "-d", "--debug", help="Include debug build", action="store_true"
+ )
+ parser.add_argument(
+ "-p",
+ "--precompile",
+ help="Include .pyc files instead of .py",
+ action="store_true",
+ )
+ parser.add_argument(
+ "-z", "--zip-lib", help="Include library in a ZIP file", action="store_true"
+ )
+ parser.add_argument(
+ "--flat-dlls", help="Does not create a DLLs directory", action="store_true"
+ )
+ parser.add_argument(
+ "-a",
+ "--include-all",
+ help="Include all optional components",
+ action="store_true",
+ )
+ parser.add_argument(
+ "--include-cat",
+ metavar="file",
+ help="Specify the catalog file to include",
+ type=Path,
+ default=None,
+ )
+ for opt, help in get_argparse_options():
+ parser.add_argument(opt, help=help, action="store_true")
+
+ ns = parser.parse_args()
+ update_presets(ns)
+
+ ns.source = ns.source or (Path(__file__).resolve().parent.parent.parent)
+ ns.build = ns.build or Path(sys.executable).parent
+ ns.temp = ns.temp or Path(tempfile.mkdtemp())
+ ns.doc_build = ns.doc_build or (ns.source / "Doc" / "build")
+ if not ns.source.is_absolute():
+ ns.source = (Path.cwd() / ns.source).resolve()
+ if not ns.build.is_absolute():
+ ns.build = (Path.cwd() / ns.build).resolve()
+ if not ns.temp.is_absolute():
+ ns.temp = (Path.cwd() / ns.temp).resolve()
+ if not ns.doc_build.is_absolute():
+ ns.doc_build = (Path.cwd() / ns.doc_build).resolve()
+ if ns.include_cat and not ns.include_cat.is_absolute():
+ ns.include_cat = (Path.cwd() / ns.include_cat).resolve()
+
+ if ns.copy and not ns.copy.is_absolute():
+ ns.copy = (Path.cwd() / ns.copy).resolve()
+ if ns.zip and not ns.zip.is_absolute():
+ ns.zip = (Path.cwd() / ns.zip).resolve()
+ if ns.catalog and not ns.catalog.is_absolute():
+ ns.catalog = (Path.cwd() / ns.catalog).resolve()
+
+ configure_logger(ns)
+
+ log_info(
+ """OPTIONS
+Source: {ns.source}
+Build: {ns.build}
+Temp: {ns.temp}
+
+Copy to: {ns.copy}
+Zip to: {ns.zip}
+Catalog: {ns.catalog}""",
+ ns=ns,
+ )
+
+ if ns.include_idle and not ns.include_tcltk:
+ log_warning("Assuming --include-tcltk to support --include-idle")
+ ns.include_tcltk = True
+
+ try:
+ generate_source_files(ns)
+ files = list(get_layout(ns))
+ copy_files(files, ns)
+ except KeyboardInterrupt:
+ log_info("Interrupted by Ctrl+C")
+ return 3
+ except SystemExit:
+ raise
+ except:
+ log_exception("Unhandled error")
+
+ if error_was_logged():
+ log_error("Errors occurred.")
+ return 1
+
+
+if __name__ == "__main__":
+ sys.exit(int(main() or 0))
--- /dev/null
+"""
+File generation for APPX/MSIX manifests.
+"""
+
+__author__ = "Steve Dower <steve.dower@python.org>"
+__version__ = "3.8"
+
+
+import collections
+import ctypes
+import io
+import os
+import sys
+
+from pathlib import Path, PureWindowsPath
+from xml.etree import ElementTree as ET
+
+from .constants import *
+
+__all__ = []
+
+
+def public(f):
+ __all__.append(f.__name__)
+ return f
+
+
+APPX_DATA = dict(
+ Name="PythonSoftwareFoundation.Python.{}".format(VER_DOT),
+ Version="{}.{}.{}.0".format(VER_MAJOR, VER_MINOR, VER_FIELD3),
+ Publisher=os.getenv(
+ "APPX_DATA_PUBLISHER", "CN=4975D53F-AA7E-49A5-8B49-EA4FDC1BB66B"
+ ),
+ DisplayName="Python {}".format(VER_DOT),
+ Description="The Python {} runtime and console.".format(VER_DOT),
+ ProcessorArchitecture="x64" if IS_X64 else "x86",
+)
+
+PYTHON_VE_DATA = dict(
+ DisplayName="Python {}".format(VER_DOT),
+ Description="Python interactive console",
+ Square150x150Logo="_resources/pythonx150.png",
+ Square44x44Logo="_resources/pythonx44.png",
+ BackgroundColor="transparent",
+)
+
+PYTHONW_VE_DATA = dict(
+ DisplayName="Python {} (Windowed)".format(VER_DOT),
+ Description="Python windowed app launcher",
+ Square150x150Logo="_resources/pythonwx150.png",
+ Square44x44Logo="_resources/pythonwx44.png",
+ BackgroundColor="transparent",
+ AppListEntry="none",
+)
+
+PIP_VE_DATA = dict(
+ DisplayName="pip (Python {})".format(VER_DOT),
+ Description="pip package manager for Python {}".format(VER_DOT),
+ Square150x150Logo="_resources/pythonx150.png",
+ Square44x44Logo="_resources/pythonx44.png",
+ BackgroundColor="transparent",
+ AppListEntry="none",
+)
+
+IDLE_VE_DATA = dict(
+ DisplayName="IDLE (Python {})".format(VER_DOT),
+ Description="IDLE editor for Python {}".format(VER_DOT),
+ Square150x150Logo="_resources/pythonwx150.png",
+ Square44x44Logo="_resources/pythonwx44.png",
+ BackgroundColor="transparent",
+)
+
+APPXMANIFEST_NS = {
+ "": "http://schemas.microsoft.com/appx/manifest/foundation/windows10",
+ "m": "http://schemas.microsoft.com/appx/manifest/foundation/windows10",
+ "uap": "http://schemas.microsoft.com/appx/manifest/uap/windows10",
+ "rescap": "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities",
+ "rescap4": "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities/4",
+ "desktop4": "http://schemas.microsoft.com/appx/manifest/desktop/windows10/4",
+ "desktop6": "http://schemas.microsoft.com/appx/manifest/desktop/windows10/6",
+ "uap3": "http://schemas.microsoft.com/appx/manifest/uap/windows10/3",
+ "uap4": "http://schemas.microsoft.com/appx/manifest/uap/windows10/4",
+ "uap5": "http://schemas.microsoft.com/appx/manifest/uap/windows10/5",
+}
+
+APPXMANIFEST_TEMPLATE = """<?xml version="1.0" encoding="utf-8"?>
+<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
+ xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
+ xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
+ xmlns:rescap4="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities/4"
+ xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
+ xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
+ xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5">
+ <Identity Name=""
+ Version=""
+ Publisher=""
+ ProcessorArchitecture="" />
+ <Properties>
+ <DisplayName></DisplayName>
+ <PublisherDisplayName>Python Software Foundation</PublisherDisplayName>
+ <Description></Description>
+ <Logo>_resources/pythonx50.png</Logo>
+ </Properties>
+ <Resources>
+ <Resource Language="en-US" />
+ </Resources>
+ <Dependencies>
+ <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="" />
+ </Dependencies>
+ <Capabilities>
+ <rescap:Capability Name="runFullTrust"/>
+ </Capabilities>
+ <Applications>
+ </Applications>
+ <Extensions>
+ </Extensions>
+</Package>"""
+
+
+RESOURCES_XML_TEMPLATE = r"""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--This file is input for makepri.exe. It should be excluded from the final package.-->
+<resources targetOsVersion="10.0.0" majorVersion="1">
+ <packaging>
+ <autoResourcePackage qualifier="Language"/>
+ <autoResourcePackage qualifier="Scale"/>
+ <autoResourcePackage qualifier="DXFeatureLevel"/>
+ </packaging>
+ <index root="\" startIndexAt="\">
+ <default>
+ <qualifier name="Language" value="en-US"/>
+ <qualifier name="Contrast" value="standard"/>
+ <qualifier name="Scale" value="100"/>
+ <qualifier name="HomeRegion" value="001"/>
+ <qualifier name="TargetSize" value="256"/>
+ <qualifier name="LayoutDirection" value="LTR"/>
+ <qualifier name="Theme" value="dark"/>
+ <qualifier name="AlternateForm" value=""/>
+ <qualifier name="DXFeatureLevel" value="DX9"/>
+ <qualifier name="Configuration" value=""/>
+ <qualifier name="DeviceFamily" value="Universal"/>
+ <qualifier name="Custom" value=""/>
+ </default>
+ <indexer-config type="folder" foldernameAsQualifier="true" filenameAsQualifier="true" qualifierDelimiter="$"/>
+ <indexer-config type="resw" convertDotsToSlashes="true" initialPath=""/>
+ <indexer-config type="resjson" initialPath=""/>
+ <indexer-config type="PRI"/>
+ </index>
+</resources>"""
+
+
+SCCD_FILENAME = "PC/classicAppCompat.sccd"
+
+REGISTRY = {
+ "HKCU\\Software\\Python\\PythonCore": {
+ VER_DOT: {
+ "DisplayName": APPX_DATA["DisplayName"],
+ "SupportUrl": "https://www.python.org/",
+ "SysArchitecture": "64bit" if IS_X64 else "32bit",
+ "SysVersion": VER_DOT,
+ "Version": "{}.{}.{}".format(VER_MAJOR, VER_MINOR, VER_MICRO),
+ "InstallPath": {
+ # I have no idea why the trailing spaces are needed, but they seem to be needed.
+ "": "[{AppVPackageRoot}][ ]",
+ "ExecutablePath": "[{AppVPackageRoot}]python.exe[ ]",
+ "WindowedExecutablePath": "[{AppVPackageRoot}]pythonw.exe[ ]",
+ },
+ "Help": {
+ "Main Python Documentation": {
+ "_condition": lambda ns: ns.include_chm,
+ "": "[{{AppVPackageRoot}}]Doc\\{}[ ]".format(
+ PYTHON_CHM_NAME
+ ),
+ },
+ "Local Python Documentation": {
+ "_condition": lambda ns: ns.include_html_doc,
+ "": "[{AppVPackageRoot}]Doc\\html\\index.html[ ]",
+ },
+ "Online Python Documentation": {
+ "": "https://docs.python.org/{}".format(VER_DOT)
+ },
+ },
+ "Idle": {
+ "_condition": lambda ns: ns.include_idle,
+ "": "[{AppVPackageRoot}]Lib\\idlelib\\idle.pyw[ ]",
+ },
+ }
+ }
+}
+
+
+def get_packagefamilyname(name, publisher_id):
+ class PACKAGE_ID(ctypes.Structure):
+ _fields_ = [
+ ("reserved", ctypes.c_uint32),
+ ("processorArchitecture", ctypes.c_uint32),
+ ("version", ctypes.c_uint64),
+ ("name", ctypes.c_wchar_p),
+ ("publisher", ctypes.c_wchar_p),
+ ("resourceId", ctypes.c_wchar_p),
+ ("publisherId", ctypes.c_wchar_p),
+ ]
+ _pack_ = 4
+
+ pid = PACKAGE_ID(0, 0, 0, name, publisher_id, None, None)
+ result = ctypes.create_unicode_buffer(256)
+ result_len = ctypes.c_uint32(256)
+ r = ctypes.windll.kernel32.PackageFamilyNameFromId(
+ pid, ctypes.byref(result_len), result
+ )
+ if r:
+ raise OSError(r, "failed to get package family name")
+ return result.value[: result_len.value]
+
+
+def _fixup_sccd(ns, sccd, new_hash=None):
+ if not new_hash:
+ return sccd
+
+ NS = dict(s="http://schemas.microsoft.com/appx/2016/sccd")
+ with open(sccd, "rb") as f:
+ xml = ET.parse(f)
+
+ pfn = get_packagefamilyname(APPX_DATA["Name"], APPX_DATA["Publisher"])
+
+ ae = xml.find("s:AuthorizedEntities", NS)
+ ae.clear()
+
+ e = ET.SubElement(ae, ET.QName(NS["s"], "AuthorizedEntity"))
+ e.set("AppPackageFamilyName", pfn)
+ e.set("CertificateSignatureHash", new_hash)
+
+ for e in xml.findall("s:Catalog", NS):
+ e.text = "FFFF"
+
+ sccd = ns.temp / sccd.name
+ sccd.parent.mkdir(parents=True, exist_ok=True)
+ with open(sccd, "wb") as f:
+ xml.write(f, encoding="utf-8")
+
+ return sccd
+
+
+@public
+def get_appx_layout(ns):
+ if not ns.include_appxmanifest:
+ return
+
+ yield "AppxManifest.xml", ns.temp / "AppxManifest.xml"
+ yield "_resources.xml", ns.temp / "_resources.xml"
+ icons = ns.source / "PC" / "icons"
+ yield "_resources/pythonx44.png", icons / "pythonx44.png"
+ yield "_resources/pythonx44$targetsize-44_altform-unplated.png", icons / "pythonx44.png"
+ yield "_resources/pythonx50.png", icons / "pythonx50.png"
+ yield "_resources/pythonx50$targetsize-50_altform-unplated.png", icons / "pythonx50.png"
+ yield "_resources/pythonx150.png", icons / "pythonx150.png"
+ yield "_resources/pythonx150$targetsize-150_altform-unplated.png", icons / "pythonx150.png"
+ yield "_resources/pythonwx44.png", icons / "pythonwx44.png"
+ yield "_resources/pythonwx44$targetsize-44_altform-unplated.png", icons / "pythonwx44.png"
+ yield "_resources/pythonwx150.png", icons / "pythonwx150.png"
+ yield "_resources/pythonwx150$targetsize-150_altform-unplated.png", icons / "pythonwx150.png"
+ sccd = ns.source / SCCD_FILENAME
+ if sccd.is_file():
+ # This should only be set for side-loading purposes.
+ sccd = _fixup_sccd(ns, sccd, os.getenv("APPX_DATA_SHA256"))
+ yield sccd.name, sccd
+
+
+def find_or_add(xml, element, attr=None, always_add=False):
+ if always_add:
+ e = None
+ else:
+ q = element
+ if attr:
+ q += "[@{}='{}']".format(*attr)
+ e = xml.find(q, APPXMANIFEST_NS)
+ if e is None:
+ prefix, _, name = element.partition(":")
+ name = ET.QName(APPXMANIFEST_NS[prefix or ""], name)
+ e = ET.SubElement(xml, name)
+ if attr:
+ e.set(*attr)
+ return e
+
+
+def _get_app(xml, appid):
+ if appid:
+ app = xml.find(
+ "m:Applications/m:Application[@Id='{}']".format(appid), APPXMANIFEST_NS
+ )
+ if app is None:
+ raise LookupError(appid)
+ else:
+ app = xml
+ return app
+
+
+def add_visual(xml, appid, data):
+ app = _get_app(xml, appid)
+ e = find_or_add(app, "uap:VisualElements")
+ for i in data.items():
+ e.set(*i)
+ return e
+
+
+def add_alias(xml, appid, alias, subsystem="windows"):
+ app = _get_app(xml, appid)
+ e = find_or_add(app, "m:Extensions")
+ e = find_or_add(e, "uap5:Extension", ("Category", "windows.appExecutionAlias"))
+ e = find_or_add(e, "uap5:AppExecutionAlias")
+ e.set(ET.QName(APPXMANIFEST_NS["desktop4"], "Subsystem"), subsystem)
+ e = find_or_add(e, "uap5:ExecutionAlias", ("Alias", alias))
+
+
+def add_file_type(xml, appid, name, suffix, parameters='"%1"'):
+ app = _get_app(xml, appid)
+ e = find_or_add(app, "m:Extensions")
+ e = find_or_add(e, "uap3:Extension", ("Category", "windows.fileTypeAssociation"))
+ e = find_or_add(e, "uap3:FileTypeAssociation", ("Name", name))
+ e.set("Parameters", parameters)
+ e = find_or_add(e, "uap:SupportedFileTypes")
+ if isinstance(suffix, str):
+ suffix = [suffix]
+ for s in suffix:
+ ET.SubElement(e, ET.QName(APPXMANIFEST_NS["uap"], "FileType")).text = s
+
+
+def add_application(
+ ns, xml, appid, executable, aliases, visual_element, subsystem, file_types
+):
+ node = xml.find("m:Applications", APPXMANIFEST_NS)
+ suffix = "_d.exe" if ns.debug else ".exe"
+ app = ET.SubElement(
+ node,
+ ET.QName(APPXMANIFEST_NS[""], "Application"),
+ {
+ "Id": appid,
+ "Executable": executable + suffix,
+ "EntryPoint": "Windows.FullTrustApplication",
+ ET.QName(APPXMANIFEST_NS["desktop4"], "SupportsMultipleInstances"): "true",
+ },
+ )
+ if visual_element:
+ add_visual(app, None, visual_element)
+ for alias in aliases:
+ add_alias(app, None, alias + suffix, subsystem)
+ if file_types:
+ add_file_type(app, None, *file_types)
+ return app
+
+
+def _get_registry_entries(ns, root="", d=None):
+ r = root if root else PureWindowsPath("")
+ if d is None:
+ d = REGISTRY
+ for key, value in d.items():
+ if key == "_condition":
+ continue
+ elif isinstance(value, dict):
+ cond = value.get("_condition")
+ if cond and not cond(ns):
+ continue
+ fullkey = r
+ for part in PureWindowsPath(key).parts:
+ fullkey /= part
+ if len(fullkey.parts) > 1:
+ yield str(fullkey), None, None
+ yield from _get_registry_entries(ns, fullkey, value)
+ elif len(r.parts) > 1:
+ yield str(r), key, value
+
+
+def add_registry_entries(ns, xml):
+ e = find_or_add(xml, "m:Extensions")
+ e = find_or_add(e, "rescap4:Extension")
+ e.set("Category", "windows.classicAppCompatKeys")
+ e.set("EntryPoint", "Windows.FullTrustApplication")
+ e = ET.SubElement(e, ET.QName(APPXMANIFEST_NS["rescap4"], "ClassicAppCompatKeys"))
+ for name, valuename, value in _get_registry_entries(ns):
+ k = ET.SubElement(
+ e, ET.QName(APPXMANIFEST_NS["rescap4"], "ClassicAppCompatKey")
+ )
+ k.set("Name", name)
+ if value:
+ k.set("ValueName", valuename)
+ k.set("Value", value)
+ k.set("ValueType", "REG_SZ")
+
+
+def disable_registry_virtualization(xml):
+ e = find_or_add(xml, "m:Properties")
+ e = find_or_add(e, "desktop6:RegistryWriteVirtualization")
+ e.text = "disabled"
+ e = find_or_add(xml, "m:Capabilities")
+ e = find_or_add(e, "rescap:Capability", ("Name", "unvirtualizedResources"))
+
+
+@public
+def get_appxmanifest(ns):
+ for k, v in APPXMANIFEST_NS.items():
+ ET.register_namespace(k, v)
+ ET.register_namespace("", APPXMANIFEST_NS["m"])
+
+ xml = ET.parse(io.StringIO(APPXMANIFEST_TEMPLATE))
+ NS = APPXMANIFEST_NS
+ QN = ET.QName
+
+ node = xml.find("m:Identity", NS)
+ for k in node.keys():
+ value = APPX_DATA.get(k)
+ if value:
+ node.set(k, value)
+
+ for node in xml.find("m:Properties", NS):
+ value = APPX_DATA.get(node.tag.rpartition("}")[2])
+ if value:
+ node.text = value
+
+ winver = sys.getwindowsversion()[:3]
+ if winver < (10, 0, 17763):
+ winver = 10, 0, 17763
+ find_or_add(xml, "m:Dependencies/m:TargetDeviceFamily").set(
+ "MaxVersionTested", "{}.{}.{}.0".format(*winver)
+ )
+
+ if winver > (10, 0, 17763):
+ disable_registry_virtualization(xml)
+
+ app = add_application(
+ ns,
+ xml,
+ "Python",
+ "python",
+ ["python", "python{}".format(VER_MAJOR), "python{}".format(VER_DOT)],
+ PYTHON_VE_DATA,
+ "console",
+ ("python.file", [".py"]),
+ )
+
+ add_application(
+ ns,
+ xml,
+ "PythonW",
+ "pythonw",
+ ["pythonw", "pythonw{}".format(VER_MAJOR), "pythonw{}".format(VER_DOT)],
+ PYTHONW_VE_DATA,
+ "windows",
+ ("python.windowedfile", [".pyw"]),
+ )
+
+ if ns.include_pip and ns.include_launchers:
+ add_application(
+ ns,
+ xml,
+ "Pip",
+ "pip",
+ ["pip", "pip{}".format(VER_MAJOR), "pip{}".format(VER_DOT)],
+ PIP_VE_DATA,
+ "console",
+ ("python.wheel", [".whl"], 'install "%1"'),
+ )
+
+ if ns.include_idle and ns.include_launchers:
+ add_application(
+ ns,
+ xml,
+ "Idle",
+ "idle",
+ ["idle", "idle{}".format(VER_MAJOR), "idle{}".format(VER_DOT)],
+ IDLE_VE_DATA,
+ "windows",
+ None,
+ )
+
+ if (ns.source / SCCD_FILENAME).is_file():
+ add_registry_entries(ns, xml)
+ node = xml.find("m:Capabilities", NS)
+ node = ET.SubElement(node, QN(NS["uap4"], "CustomCapability"))
+ node.set("Name", "Microsoft.classicAppCompat_8wekyb3d8bbwe")
+
+ buffer = io.BytesIO()
+ xml.write(buffer, encoding="utf-8", xml_declaration=True)
+ return buffer.getbuffer()
+
+
+@public
+def get_resources_xml(ns):
+ return RESOURCES_XML_TEMPLATE.encode("utf-8")
--- /dev/null
+"""
+File generation for catalog signing non-binary contents.
+"""
+
+__author__ = "Steve Dower <steve.dower@python.org>"
+__version__ = "3.8"
+
+
+import sys
+
+__all__ = ["PYTHON_CAT_NAME", "PYTHON_CDF_NAME"]
+
+
+def public(f):
+ __all__.append(f.__name__)
+ return f
+
+
+PYTHON_CAT_NAME = "python.cat"
+PYTHON_CDF_NAME = "python.cdf"
+
+
+CATALOG_TEMPLATE = r"""[CatalogHeader]
+Name={target.stem}.cat
+ResultDir={target.parent}
+PublicVersion=1
+CatalogVersion=2
+HashAlgorithms=SHA256
+PageHashes=false
+EncodingType=
+
+[CatalogFiles]
+"""
+
+
+def can_sign(file):
+ return file.is_file() and file.stat().st_size
+
+
+@public
+def write_catalog(target, files):
+ with target.open("w", encoding="utf-8") as cat:
+ cat.write(CATALOG_TEMPLATE.format(target=target))
+ cat.writelines("<HASH>{}={}\n".format(n, f) for n, f in files if can_sign(f))
--- /dev/null
+"""
+Constants for generating the layout.
+"""
+
+__author__ = "Steve Dower <steve.dower@python.org>"
+__version__ = "3.8"
+
+import struct
+import sys
+
+VER_MAJOR, VER_MINOR, VER_MICRO, VER_FIELD4 = struct.pack(">i", sys.hexversion)
+VER_FIELD3 = VER_MICRO << 8 | VER_FIELD4
+VER_NAME = {"alpha": "a", "beta": "b", "rc": "rc"}.get(
+ sys.version_info.releaselevel, ""
+)
+VER_SERIAL = sys.version_info.serial if VER_NAME else ""
+VER_DOT = "{}.{}".format(VER_MAJOR, VER_MINOR)
+
+PYTHON_DLL_NAME = "python{}{}.dll".format(VER_MAJOR, VER_MINOR)
+PYTHON_STABLE_DLL_NAME = "python{}.dll".format(VER_MAJOR)
+PYTHON_ZIP_NAME = "python{}{}.zip".format(VER_MAJOR, VER_MINOR)
+PYTHON_PTH_NAME = "python{}{}._pth".format(VER_MAJOR, VER_MINOR)
+
+PYTHON_CHM_NAME = "python{}{}{}{}{}.chm".format(
+ VER_MAJOR, VER_MINOR, VER_MICRO, VER_NAME, VER_SERIAL
+)
+
+IS_X64 = sys.maxsize > 2 ** 32
--- /dev/null
+"""distutils.command.bdist_wininst
+
+Suppress the 'bdist_wininst' command, while still allowing
+setuptools to import it without breaking."""
+
+from distutils.core import Command
+from distutils.errors import DistutilsPlatformError
+
+
+class bdist_wininst(Command):
+ description = "create an executable installer for MS Windows"
+
+ # Marker for tests that we have the unsupported bdist_wininst
+ _unsupported = True
+
+ def initialize_options(self):
+ pass
+
+ def finalize_options(self):
+ pass
+
+ def run(self):
+ raise DistutilsPlatformError(
+ "bdist_wininst is not supported in this Python distribution"
+ )
--- /dev/null
+"""
+File sets and globbing helper for make_layout.
+"""
+
+__author__ = "Steve Dower <steve.dower@python.org>"
+__version__ = "3.8"
+
+import os
+
+
+class FileStemSet:
+ def __init__(self, *patterns):
+ self._names = set()
+ self._prefixes = []
+ self._suffixes = []
+ for p in map(os.path.normcase, patterns):
+ if p.endswith("*"):
+ self._prefixes.append(p[:-1])
+ elif p.startswith("*"):
+ self._suffixes.append(p[1:])
+ else:
+ self._names.add(p)
+
+ def _make_name(self, f):
+ return os.path.normcase(f.stem)
+
+ def __contains__(self, f):
+ bn = self._make_name(f)
+ return (
+ bn in self._names
+ or any(map(bn.startswith, self._prefixes))
+ or any(map(bn.endswith, self._suffixes))
+ )
+
+
+class FileNameSet(FileStemSet):
+ def _make_name(self, f):
+ return os.path.normcase(f.name)
+
+
+class FileSuffixSet:
+ def __init__(self, *patterns):
+ self._names = set()
+ self._prefixes = []
+ self._suffixes = []
+ for p in map(os.path.normcase, patterns):
+ if p.startswith("*."):
+ self._names.add(p[1:])
+ elif p.startswith("*"):
+ self._suffixes.append(p[1:])
+ elif p.endswith("*"):
+ self._prefixes.append(p[:-1])
+ elif p.startswith("."):
+ self._names.add(p)
+ else:
+ self._names.add("." + p)
+
+ def _make_name(self, f):
+ return os.path.normcase(f.suffix)
+
+ def __contains__(self, f):
+ bn = self._make_name(f)
+ return (
+ bn in self._names
+ or any(map(bn.startswith, self._prefixes))
+ or any(map(bn.endswith, self._suffixes))
+ )
+
+
+def _rglob(root, pattern, condition):
+ dirs = [root]
+ recurse = pattern[:3] in {"**/", "**\\"}
+ if recurse:
+ pattern = pattern[3:]
+
+ while dirs:
+ d = dirs.pop(0)
+ if recurse:
+ dirs.extend(
+ filter(
+ condition, (type(root)(f2) for f2 in os.scandir(d) if f2.is_dir())
+ )
+ )
+ yield from (
+ (f.relative_to(root), f)
+ for f in d.glob(pattern)
+ if f.is_file() and condition(f)
+ )
+
+
+def _return_true(f):
+ return True
+
+
+def rglob(root, patterns, condition=None):
+ if isinstance(patterns, tuple):
+ for p in patterns:
+ yield from _rglob(root, p, condition or _return_true)
+ else:
+ yield from _rglob(root, patterns, condition or _return_true)
--- /dev/null
+"""
+Logging support for make_layout.
+"""
+
+__author__ = "Steve Dower <steve.dower@python.org>"
+__version__ = "3.8"
+
+import logging
+import sys
+
+__all__ = []
+
+LOG = None
+HAS_ERROR = False
+
+
+def public(f):
+ __all__.append(f.__name__)
+ return f
+
+
+@public
+def configure_logger(ns):
+ global LOG
+ if LOG:
+ return
+
+ LOG = logging.getLogger("make_layout")
+ LOG.level = logging.DEBUG
+
+ if ns.v:
+ s_level = max(logging.ERROR - ns.v * 10, logging.DEBUG)
+ f_level = max(logging.WARNING - ns.v * 10, logging.DEBUG)
+ else:
+ s_level = logging.ERROR
+ f_level = logging.INFO
+
+ handler = logging.StreamHandler(sys.stdout)
+ handler.setFormatter(logging.Formatter("{levelname:8s} {message}", style="{"))
+ handler.setLevel(s_level)
+ LOG.addHandler(handler)
+
+ if ns.log:
+ handler = logging.FileHandler(ns.log, encoding="utf-8", delay=True)
+ handler.setFormatter(
+ logging.Formatter("[{asctime}]{levelname:8s}: {message}", style="{")
+ )
+ handler.setLevel(f_level)
+ LOG.addHandler(handler)
+
+
+class BraceMessage:
+ def __init__(self, fmt, *args, **kwargs):
+ self.fmt = fmt
+ self.args = args
+ self.kwargs = kwargs
+
+ def __str__(self):
+ return self.fmt.format(*self.args, **self.kwargs)
+
+
+@public
+def log_debug(msg, *args, **kwargs):
+ return LOG.debug(BraceMessage(msg, *args, **kwargs))
+
+
+@public
+def log_info(msg, *args, **kwargs):
+ return LOG.info(BraceMessage(msg, *args, **kwargs))
+
+
+@public
+def log_warning(msg, *args, **kwargs):
+ return LOG.warning(BraceMessage(msg, *args, **kwargs))
+
+
+@public
+def log_error(msg, *args, **kwargs):
+ global HAS_ERROR
+ HAS_ERROR = True
+ return LOG.error(BraceMessage(msg, *args, **kwargs))
+
+
+@public
+def log_exception(msg, *args, **kwargs):
+ global HAS_ERROR
+ HAS_ERROR = True
+ return LOG.exception(BraceMessage(msg, *args, **kwargs))
+
+
+@public
+def error_was_logged():
+ return HAS_ERROR
--- /dev/null
+"""
+List of optional components.
+"""
+
+__author__ = "Steve Dower <steve.dower@python.org>"
+__version__ = "3.8"
+
+
+__all__ = []
+
+
+def public(f):
+ __all__.append(f.__name__)
+ return f
+
+
+OPTIONS = {
+ "stable": {"help": "stable ABI stub"},
+ "pip": {"help": "pip"},
+ "distutils": {"help": "distutils"},
+ "tcltk": {"help": "Tcl, Tk and tkinter"},
+ "idle": {"help": "Idle"},
+ "tests": {"help": "test suite"},
+ "tools": {"help": "tools"},
+ "venv": {"help": "venv"},
+ "dev": {"help": "headers and libs"},
+ "symbols": {"help": "symbols"},
+ "bdist-wininst": {"help": "bdist_wininst support"},
+ "underpth": {"help": "a python._pth file", "not-in-all": True},
+ "launchers": {"help": "specific launchers"},
+ "appxmanifest": {"help": "an appxmanifest"},
+ "props": {"help": "a python.props file"},
+ "chm": {"help": "the CHM documentation"},
+ "html-doc": {"help": "the HTML documentation"},
+}
+
+
+PRESETS = {
+ "appx": {
+ "help": "APPX package",
+ "options": [
+ "stable",
+ "pip",
+ "distutils",
+ "tcltk",
+ "idle",
+ "venv",
+ "dev",
+ "launchers",
+ "appxmanifest",
+ # XXX: Disabled for now "precompile",
+ ],
+ },
+ "nuget": {
+ "help": "nuget package",
+ "options": ["stable", "pip", "distutils", "dev", "props"],
+ },
+ "default": {
+ "help": "development kit package",
+ "options": [
+ "stable",
+ "pip",
+ "distutils",
+ "tcltk",
+ "idle",
+ "tests",
+ "tools",
+ "venv",
+ "dev",
+ "symbols",
+ "bdist-wininst",
+ "chm",
+ ],
+ },
+ "embed": {
+ "help": "embeddable package",
+ "options": ["stable", "zip-lib", "flat-dlls", "underpth", "precompile"],
+ },
+}
+
+
+@public
+def get_argparse_options():
+ for opt, info in OPTIONS.items():
+ help = "When specified, includes {}".format(info["help"])
+ if info.get("not-in-all"):
+ help = "{}. Not affected by --include-all".format(help)
+
+ yield "--include-{}".format(opt), help
+
+ for opt, info in PRESETS.items():
+ help = "When specified, includes default options for {}".format(info["help"])
+ yield "--preset-{}".format(opt), help
+
+
+def ns_get(ns, key, default=False):
+ return getattr(ns, key.replace("-", "_"), default)
+
+
+def ns_set(ns, key, value=True):
+ k1 = key.replace("-", "_")
+ k2 = "include_{}".format(k1)
+ if hasattr(ns, k2):
+ setattr(ns, k2, value)
+ elif hasattr(ns, k1):
+ setattr(ns, k1, value)
+ else:
+ raise AttributeError("no argument named '{}'".format(k1))
+
+
+@public
+def update_presets(ns):
+ for preset, info in PRESETS.items():
+ if ns_get(ns, "preset-{}".format(preset)):
+ for opt in info["options"]:
+ ns_set(ns, opt)
+
+ if ns.include_all:
+ for opt in OPTIONS:
+ if OPTIONS[opt].get("not-in-all"):
+ continue
+ ns_set(ns, opt)
--- /dev/null
+"""
+Extraction and file list generation for pip.
+"""
+
+__author__ = "Steve Dower <steve.dower@python.org>"
+__version__ = "3.8"
+
+
+import os
+import shutil
+import subprocess
+import sys
+
+__all__ = []
+
+
+def public(f):
+ __all__.append(f.__name__)
+ return f
+
+
+@public
+def get_pip_dir(ns):
+ if ns.copy:
+ if ns.zip_lib:
+ return ns.copy / "packages"
+ return ns.copy / "Lib" / "site-packages"
+ else:
+ return ns.temp / "packages"
+
+
+@public
+def extract_pip_files(ns):
+ dest = get_pip_dir(ns)
+ dest.mkdir(parents=True, exist_ok=True)
+
+ src = ns.source / "Lib" / "ensurepip" / "_bundled"
+
+ ns.temp.mkdir(parents=True, exist_ok=True)
+ wheels = [shutil.copy(whl, ns.temp) for whl in src.glob("*.whl")]
+ search_path = os.pathsep.join(wheels)
+ if os.environ.get("PYTHONPATH"):
+ search_path += ";" + os.environ["PYTHONPATH"]
+
+ env = os.environ.copy()
+ env["PYTHONPATH"] = search_path
+
+ output = subprocess.check_output(
+ [
+ sys.executable,
+ "-m",
+ "pip",
+ "--no-color",
+ "install",
+ "pip",
+ "setuptools",
+ "--upgrade",
+ "--target",
+ str(dest),
+ "--no-index",
+ "--no-cache-dir",
+ "-f",
+ str(src),
+ "--only-binary",
+ ":all:",
+ ],
+ env=env,
+ )
+
+ try:
+ shutil.rmtree(dest / "bin")
+ except OSError:
+ pass
+
+ for file in wheels:
+ try:
+ os.remove(file)
+ except OSError:
+ pass
--- /dev/null
+"""
+Provides .props file.
+"""
+
+import os
+
+from .constants import *
+
+__all__ = ["PYTHON_PROPS_NAME"]
+
+
+def public(f):
+ __all__.append(f.__name__)
+ return f
+
+
+PYTHON_PROPS_NAME = "python.props"
+
+PROPS_DATA = {
+ "PYTHON_TAG": VER_DOT,
+ "PYTHON_VERSION": os.getenv("PYTHON_NUSPEC_VERSION"),
+ "PYTHON_PLATFORM": os.getenv("PYTHON_PROPS_PLATFORM"),
+ "PYTHON_TARGET": "",
+}
+
+if not PROPS_DATA["PYTHON_VERSION"]:
+ if VER_NAME:
+ PROPS_DATA["PYTHON_VERSION"] = "{}.{}-{}{}".format(
+ VER_DOT, VER_MICRO, VER_NAME, VER_SERIAL
+ )
+ else:
+ PROPS_DATA["PYTHON_VERSION"] = "{}.{}".format(VER_DOT, VER_MICRO)
+
+if not PROPS_DATA["PYTHON_PLATFORM"]:
+ PROPS_DATA["PYTHON_PLATFORM"] = "x64" if IS_X64 else "Win32"
+
+PROPS_DATA["PYTHON_TARGET"] = "_GetPythonRuntimeFilesDependsOn{}{}_{}".format(
+ VER_MAJOR, VER_MINOR, PROPS_DATA["PYTHON_PLATFORM"]
+)
+
+PROPS_TEMPLATE = r"""<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Condition="$(Platform) == '{PYTHON_PLATFORM}'">
+ <PythonHome Condition="$(Configuration) == 'Debug'">$([msbuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), "python_d.exe")</PythonHome>
+ <PythonHome Condition="$(PythonHome) == ''">$([msbuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), "python.exe")</PythonHome>
+ <PythonInclude>$(PythonHome)\include</PythonInclude>
+ <PythonLibs>$(PythonHome)\libs</PythonLibs>
+ <PythonTag>{PYTHON_TAG}</PythonTag>
+ <PythonVersion>{PYTHON_VERSION}</PythonVersion>
+
+ <IncludePythonExe Condition="$(IncludePythonExe) == ''">true</IncludePythonExe>
+ <IncludeDistutils Condition="$(IncludeDistutils) == ''">false</IncludeDistutils>
+ <IncludeLib2To3 Condition="$(IncludeLib2To3) == ''">false</IncludeLib2To3>
+ <IncludeVEnv Condition="$(IncludeVEnv) == ''">false</IncludeVEnv>
+
+ <GetPythonRuntimeFilesDependsOn>{PYTHON_TARGET};$(GetPythonRuntimeFilesDependsOn)</GetPythonRuntimeFilesDependsOn>
+ </PropertyGroup>
+
+ <ItemDefinitionGroup Condition="$(Platform) == '{PYTHON_PLATFORM}'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>$(PythonInclude);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>$(PythonLibs);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <Target Name="GetPythonRuntimeFiles" Returns="@(PythonRuntime)" DependsOnTargets="$(GetPythonRuntimeFilesDependsOn)" />
+
+ <Target Name="{PYTHON_TARGET}" Returns="@(PythonRuntime)">
+ <ItemGroup>
+ <_PythonRuntimeExe Include="$(PythonHome)\python*.dll" />
+ <_PythonRuntimeExe Include="$(PythonHome)\python*.exe" Condition="$(IncludePythonExe) == 'true'" />
+ <_PythonRuntimeExe>
+ <Link>%(Filename)%(Extension)</Link>
+ </_PythonRuntimeExe>
+ <_PythonRuntimeDlls Include="$(PythonHome)\DLLs\*.pyd" />
+ <_PythonRuntimeDlls Include="$(PythonHome)\DLLs\*.dll" />
+ <_PythonRuntimeDlls>
+ <Link>DLLs\%(Filename)%(Extension)</Link>
+ </_PythonRuntimeDlls>
+ <_PythonRuntimeLib Include="$(PythonHome)\Lib\**\*" Exclude="$(PythonHome)\Lib\**\*.pyc;$(PythonHome)\Lib\site-packages\**\*" />
+ <_PythonRuntimeLib Remove="$(PythonHome)\Lib\distutils\**\*" Condition="$(IncludeDistutils) != 'true'" />
+ <_PythonRuntimeLib Remove="$(PythonHome)\Lib\lib2to3\**\*" Condition="$(IncludeLib2To3) != 'true'" />
+ <_PythonRuntimeLib Remove="$(PythonHome)\Lib\ensurepip\**\*" Condition="$(IncludeVEnv) != 'true'" />
+ <_PythonRuntimeLib Remove="$(PythonHome)\Lib\venv\**\*" Condition="$(IncludeVEnv) != 'true'" />
+ <_PythonRuntimeLib>
+ <Link>Lib\%(RecursiveDir)%(Filename)%(Extension)</Link>
+ </_PythonRuntimeLib>
+ <PythonRuntime Include="@(_PythonRuntimeExe);@(_PythonRuntimeDlls);@(_PythonRuntimeLib)" />
+ </ItemGroup>
+
+ <Message Importance="low" Text="Collected Python runtime from $(PythonHome):%0D%0A@(PythonRuntime->' %(Link)','%0D%0A')" />
+ </Target>
+</Project>
+"""
+
+
+@public
+def get_props_layout(ns):
+ if ns.include_all or ns.include_props:
+ yield "python.props", ns.temp / "python.props"
+
+
+@public
+def get_props(ns):
+ # TODO: Filter contents of props file according to included/excluded items
+ props = PROPS_TEMPLATE.format_map(PROPS_DATA)
+ return props.encode("utf-8")
#include <winuser.h>
1 RT_MANIFEST "python.manifest"
+#if defined(PY_ICON)
+1 ICON DISCARDABLE "icons\python.ico"
+#elif defined(PYW_ICON)
+1 ICON DISCARDABLE "icons\pythonw.ico"
+#else
1 ICON DISCARDABLE "icons\launcher.ico"
2 ICON DISCARDABLE "icons\py.ico"
3 ICON DISCARDABLE "icons\pyc.ico"
5 ICON DISCARDABLE "icons\python.ico"
6 ICON DISCARDABLE "icons\pythonw.ico"
7 ICON DISCARDABLE "icons\setup.ico"
+#endif
/////////////////////////////////////////////////////////////////////////////
//
--- /dev/null
+/* Main program when embedded in a UWP application on Windows */
+
+#include "Python.h"
+#include <string.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <shellapi.h>
+
+#include <winrt\Windows.ApplicationModel.h>
+#include <winrt\Windows.Storage.h>
+
+#ifdef PYTHONW
+#ifdef _DEBUG
+const wchar_t *PROGNAME = L"pythonw_d.exe";
+#else
+const wchar_t *PROGNAME = L"pythonw.exe";
+#endif
+#else
+#ifdef _DEBUG
+const wchar_t *PROGNAME = L"python_d.exe";
+#else
+const wchar_t *PROGNAME = L"python.exe";
+#endif
+#endif
+
+static void
+set_user_base()
+{
+ wchar_t envBuffer[2048];
+ try {
+ const auto appData = winrt::Windows::Storage::ApplicationData::Current();
+ if (appData) {
+ const auto localCache = appData.LocalCacheFolder();
+ if (localCache) {
+ auto path = localCache.Path();
+ if (!path.empty() &&
+ !wcscpy_s(envBuffer, path.c_str()) &&
+ !wcscat_s(envBuffer, L"\\local-packages")
+ ) {
+ _wputenv_s(L"PYTHONUSERBASE", envBuffer);
+ }
+ }
+ }
+ } catch (...) {
+ }
+}
+
+static const wchar_t *
+get_argv0(const wchar_t *argv0)
+{
+ winrt::hstring installPath;
+ const wchar_t *launcherPath;
+ wchar_t *buffer;
+ size_t len;
+
+ launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__");
+ if (launcherPath && launcherPath[0]) {
+ len = wcslen(launcherPath) + 1;
+ buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
+ if (!buffer) {
+ Py_FatalError("out of memory");
+ return NULL;
+ }
+ if (wcscpy_s(buffer, len, launcherPath)) {
+ Py_FatalError("failed to copy to buffer");
+ return NULL;
+ }
+ return buffer;
+ }
+
+ try {
+ const auto package = winrt::Windows::ApplicationModel::Package::Current();
+ if (package) {
+ const auto install = package.InstalledLocation();
+ if (install) {
+ installPath = install.Path();
+ }
+ }
+ }
+ catch (...) {
+ }
+
+ if (!installPath.empty()) {
+ len = installPath.size() + wcslen(PROGNAME) + 2;
+ } else {
+ len = wcslen(argv0) + wcslen(PROGNAME) + 1;
+ }
+
+ buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
+ if (!buffer) {
+ Py_FatalError("out of memory");
+ return NULL;
+ }
+
+ if (!installPath.empty()) {
+ if (wcscpy_s(buffer, len, installPath.c_str())) {
+ Py_FatalError("failed to copy to buffer");
+ return NULL;
+ }
+ if (wcscat_s(buffer, len, L"\\")) {
+ Py_FatalError("failed to concatenate backslash");
+ return NULL;
+ }
+ } else {
+ if (wcscpy_s(buffer, len, argv0)) {
+ Py_FatalError("failed to copy argv[0]");
+ return NULL;
+ }
+
+ wchar_t *name = wcsrchr(buffer, L'\\');
+ if (name) {
+ name[1] = L'\0';
+ } else {
+ buffer[0] = L'\0';
+ }
+ }
+
+ if (wcscat_s(buffer, len, PROGNAME)) {
+ Py_FatalError("failed to concatenate program name");
+ return NULL;
+ }
+
+ return buffer;
+}
+
+static wchar_t *
+get_process_name()
+{
+ DWORD bufferLen = MAX_PATH;
+ DWORD len = bufferLen;
+ wchar_t *r = NULL;
+
+ while (!r) {
+ r = (wchar_t *)malloc(bufferLen * sizeof(wchar_t));
+ if (!r) {
+ Py_FatalError("out of memory");
+ return NULL;
+ }
+ len = GetModuleFileNameW(NULL, r, bufferLen);
+ if (len == 0) {
+ free((void *)r);
+ return NULL;
+ } else if (len == bufferLen &&
+ GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ free(r);
+ r = NULL;
+ bufferLen *= 2;
+ }
+ }
+
+ return r;
+}
+
+int
+wmain(int argc, wchar_t **argv)
+{
+ const wchar_t **new_argv;
+ int new_argc;
+ const wchar_t *exeName;
+
+ new_argc = argc;
+ new_argv = (const wchar_t**)malloc(sizeof(wchar_t *) * (argc + 2));
+ if (new_argv == NULL) {
+ Py_FatalError("out of memory");
+ return -1;
+ }
+
+ exeName = get_process_name();
+
+ new_argv[0] = get_argv0(exeName ? exeName : argv[0]);
+ for (int i = 1; i < argc; ++i) {
+ new_argv[i] = argv[i];
+ }
+
+ set_user_base();
+
+ if (exeName) {
+ const wchar_t *p = wcsrchr(exeName, L'\\');
+ if (p) {
+ const wchar_t *moduleName = NULL;
+ if (*p++ == L'\\') {
+ if (wcsnicmp(p, L"pip", 3) == 0) {
+ moduleName = L"pip";
+ _wputenv_s(L"PIP_USER", L"true");
+ }
+ else if (wcsnicmp(p, L"idle", 4) == 0) {
+ moduleName = L"idlelib";
+ }
+ }
+
+ if (moduleName) {
+ new_argc += 2;
+ for (int i = argc; i >= 1; --i) {
+ new_argv[i + 2] = new_argv[i];
+ }
+ new_argv[1] = L"-m";
+ new_argv[2] = moduleName;
+ }
+ }
+ }
+
+ /* Override program_full_path from here so that
+ sys.executable is set correctly. */
+ _Py_SetProgramFullPath(new_argv[0]);
+
+ int result = Py_Main(new_argc, (wchar_t **)new_argv);
+
+ free((void *)exeName);
+ free((void *)new_argv);
+
+ return result;
+}
+
+#ifdef PYTHONW
+
+int WINAPI wWinMain(
+ HINSTANCE hInstance, /* handle to current instance */
+ HINSTANCE hPrevInstance, /* handle to previous instance */
+ LPWSTR lpCmdLine, /* pointer to command line */
+ int nCmdShow /* show state of window */
+)
+{
+ return wmain(__argc, __wargv);
+}
+
+#endif
--- /dev/null
+# Overview
+
+NOTE: This file requires more content.
+
+Since Python 3.7.2, releases have been made through the Microsoft Store
+to allow easy installation on Windows 10.0.17763.0 and later.
+
+# Building
+
+To build the store package, the PC/layout script should be used.
+Execute the directory with the build of Python to package, and pass
+"-h" for full command-line options.
+
+To sideload test builds, you will need a local certificate.
+Instructions are available at
+https://docs.microsoft.com/windows/uwp/packaging/create-certificate-package-signing.
+
+After exporting your certificate, you will need the subject name and
+SHA256 hash. The `certutil -dump <cert file>` command will display this
+information.
+
+To build for sideloading, use these commands in PowerShell:
+
+```
+$env:APPX_DATA_PUBLISHER=<your certificate subject name>
+$env:APPX_DATA_SHA256=<your certificate SHA256>
+$env:SigningCertificateFile=<your certificate file>
+
+python PC/layout --copy <layout directory> --include-appxmanifest
+Tools/msi/make_appx.ps1 <layout directory> python.msix -sign
+
+Add-AppxPackage python.msix
+```
+
+(Note that only the last command requires PowerShell, and the others
+can be used from Command Prompt. You can also double-click to install
+the final package.)
+
+To build for publishing to the Store, use these commands:
+
+```
+$env:APPX_DATA_PUBLISHER = $null
+$env:APPX_DATA_SHA256 = $null
+
+python PC/layout --copy <layout directory> --preset-appxmanifest --precompile
+Tools/msi/make_appx.ps1 <layout directory> python.msix
+```
+
+Note that this package cannot be installed locally. It may only be
+added to a submission for the store.
+
+
+# Submission Metadata
+
+This file contains the text that we use to fill out the store listing
+for the Microsoft Store. It needs to be entered manually when creating
+a new submission via the dashboard at
+https://partner.microsoft.com/dashboard.
+
+We keep it here for convenience and to allow it to be updated via pull
+requests.
+
+## Title
+
+Python 3.7
+
+## Short Title
+
+Python
+
+## Description
+
+Python is an easy to learn, powerful programming language. It has efficient high-level data structures and a simple but effective approach to object-oriented programming. Python’s elegant syntax and dynamic typing, together with its interpreted nature, make it an ideal language for scripting and rapid application development in many areas on most platforms.
+
+The Python interpreter and the extensive standard library are freely available in source or binary form for all major platforms from the Python Web site, https://www.python.org/, and may be freely distributed. The same site also contains distributions of and pointers to many free third party Python modules, programs and tools, and additional documentation.
+
+The Python interpreter is easily extended with new functions and data types implemented in C or C++ (or other languages callable from C). Python is also suitable as an extension language for customizable applications.
+
+## ShortDescription
+
+The Python 3.7 interpreter and runtime.
+
+## Copyright Trademark Information
+
+(c) Python Software Foundation
+
+## Additional License Terms
+
+Visit https://docs.python.org/3.7/license.html for latest license terms.
+
+PSF LICENSE AGREEMENT FOR PYTHON 3.7
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
+ the Individual or Organization ("Licensee") accessing and otherwise using Python
+ 3.7 software in source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+ analyze, test, perform and/or display publicly, prepare derivative works,
+ distribute, and otherwise use Python 3.7 alone or in any derivative
+ version, provided, however, that PSF's License Agreement and PSF's notice of
+ copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights
+ Reserved" are retained in Python 3.7 alone or in any derivative version
+ prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+ incorporates Python 3.7 or any part thereof, and wants to make the
+ derivative work available to others as provided herein, then Licensee hereby
+ agrees to include in any such work a brief summary of the changes made to Python
+ 3.7.
+
+4. PSF is making Python 3.7 available to Licensee on an "AS IS" basis.
+ PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
+ EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
+ USE OF PYTHON 3.7 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
+ MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7, OR ANY DERIVATIVE
+ THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material breach of
+ its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any relationship
+ of agency, partnership, or joint venture between PSF and Licensee. This License
+ Agreement does not grant permission to use PSF trademarks or trade name in a
+ trademark sense to endorse or promote products or services of Licensee, or any
+ third party.
+
+8. By copying, installing or otherwise using Python 3.7, Licensee agrees
+ to be bound by the terms and conditions of this License Agreement.
+
+## Features
+
+* Easy to install Python runtime
+* Supported by core CPython team
+* Find Python, Pip and Idle on PATH
+
+## Search Terms
+
+* Python
+* Scripting
+* Interpreter
+
PyMem_Free(str);
return NULL;
}
- PyList_SetItem(obData,
- index,
- PyUnicode_FromWideChar(str[index], len));
+ PyObject *uni = PyUnicode_FromWideChar(str[index], len);
+ if (uni == NULL) {
+ Py_DECREF(obData);
+ PyMem_Free(str);
+ return NULL;
+ }
+ PyList_SET_ITEM(obData, index, uni);
}
PyMem_Free(str);
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup>\r
- <ResourceCompile Include="..\PC\python_nt.rc" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <Filter Include="Source Files">\r
- <UniqueIdentifier>{c56a5dd3-7838-48e9-a781-855d8be7370f}</UniqueIdentifier>\r
- </Filter>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClCompile Include="..\PC\_findvs.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- </ItemGroup>\r
-</Project>
\ No newline at end of file
<Target Name="_CleanTclTkDLL" BeforeTargets="Clean">\r
<Delete Files="@(_TclTkDLL->'$(OutDir)%(Filename)%(Extension)')" />\r
</Target>\r
+ <Target Name="_WriteTCL_LIBRARY" Outputs="$(OutDir)TCL_LIBRARY.env" AfterTargets="Build">\r
+ <WriteLinesToFile File="$(OutDir)TCL_LIBRARY.env" Lines="$(tcltkdir)\lib\tcl$(TclMajorVersion).$(TclMinorVersion)" Encoding="utf-8" Overwrite="true" />\r
+ </Target>\r
+ <Target Name="_CleanTCL_LIBRARY" BeforeTargets="Clean">\r
+ <Delete Files="$(OutDir)TCL_LIBRARY.env" />\r
+ </Target>\r
</Project>
\ No newline at end of file
\r
:Version\r
rem Display the current build version information\r
-%MSBUILD% "%dir%python.props" /t:ShowVersionInfo /v:m /nologo %1 %2 %3 %4 %5 %6 %7 %8 %9\r
+call "%dir%find_msbuild.bat" %MSBUILD%\r
+if not ERRORLEVEL 1 %MSBUILD% "%dir%pythoncore.vcxproj" /t:ShowVersionInfo /v:m /nologo %1 %2 %3 %4 %5 %6 %7 %8 %9\r
@where msbuild > "%TEMP%\msbuild.loc" 2> nul && set /P MSBUILD= < "%TEMP%\msbuild.loc" & del "%TEMP%\msbuild.loc"\r
@if exist "%MSBUILD%" set MSBUILD="%MSBUILD%" & (set _Py_MSBuild_Source=PATH) & goto :found\r
\r
+@rem VS 2017 and later provide vswhere.exe, which can be used\r
+@if not exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" goto :skip_vswhere\r
+@set _Py_MSBuild_Root=\r
+@for /F "tokens=*" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -property installationPath -latest') DO @(set _Py_MSBuild_Root=%%i\MSBuild)\r
+@if not defined _Py_MSBuild_Root goto :skip_vswhere\r
+@for %%j in (Current 15.0) DO @if exist "%_Py_MSBuild_Root%\%%j\Bin\msbuild.exe" (set MSBUILD="%_Py_MSBuild_Root%\%%j\Bin\msbuild.exe")\r
+@set _Py_MSBuild_Root=\r
+@if defined MSBUILD @if exist %MSBUILD% (set _Py_MSBuild_Source=Visual Studio installation) & goto :found\r
+:skip_vswhere\r
+\r
@rem VS 2017 sets exactly one install as the "main" install, so we may find MSBuild in there.\r
@reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v 15.0 /reg:32 >nul 2>nul\r
@if NOT ERRORLEVEL 1 @for /F "tokens=1,2*" %%i in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v 15.0 /reg:32') DO @(\r
\r
set libraries=\r
set libraries=%libraries% bzip2-1.0.6\r
-if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.0i\r
+if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.0j\r
set libraries=%libraries% sqlite-3.21.0.0\r
if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.8.0\r
if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.8.0\r
echo.Fetching external binaries...\r
\r
set binaries=\r
-if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.0i\r
+if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.0j\r
if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.8.0\r
if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06\r
\r
<IncludeTests Condition="'$(IncludeTest)' == ''">true</IncludeTests>\r
<IncludeSSL Condition="'$(IncludeSSL)' == ''">true</IncludeSSL>\r
<IncludeTkinter Condition="'$(IncludeTkinter)' == ''">true</IncludeTkinter>\r
+ <IncludeUwp Condition="'$(IncludeUwp)' == ''">false</IncludeUwp>\r
</PropertyGroup>\r
\r
<ItemDefinitionGroup>\r
<!-- pyshellext.dll -->\r
<Projects Include="pyshellext.vcxproj" />\r
<!-- Extension modules -->\r
- <ExtensionModules Include="_asyncio;_contextvars;_ctypes;_decimal;_distutils_findvs;_elementtree;_msi;_multiprocessing;_overlapped;pyexpat;_queue;select;unicodedata;winsound" />\r
+ <ExtensionModules Include="_asyncio;_contextvars;_ctypes;_decimal;_elementtree;_msi;_multiprocessing;_overlapped;pyexpat;_queue;select;unicodedata;winsound" />\r
<!-- Extension modules that require external sources -->\r
<ExternalModules Include="_bz2;_lzma;_sqlite3" />\r
+ <!-- venv launchers -->\r
+ <Projects Include="venvlauncher.vcxproj;venvwlauncher.vcxproj" />\r
<!-- _ssl will build _socket as well, which may cause conflicts in parallel builds -->\r
<ExtensionModules Include="_socket" Condition="!$(IncludeSSL) or !$(IncludeExternals)" />\r
<ExternalModules Include="_ssl;_hashlib" Condition="$(IncludeSSL)" />\r
<Projects2 Include="_freeze_importlib.vcxproj" />\r
<!-- python[w].exe -->\r
<Projects2 Include="python.vcxproj;pythonw.vcxproj" />\r
+ <Projects2 Include="python_uwp.vcxproj;pythonw_uwp.vcxproj" Condition="$(IncludeUwp)" />\r
+ <!-- venv[w]launcher.exe -->\r
+ <Projects2 Include="venvlauncher.vcxproj;venvwlauncher.vcxproj" />\r
</ItemGroup>\r
\r
<Target Name="Build">\r
EndProject\r
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblzma", "liblzma.vcxproj", "{12728250-16EC-4DC6-94D7-E21DD88947F8}"\r
EndProject\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_distutils_findvs", "_distutils_findvs.vcxproj", "{41ADEDF9-11D8-474E-B4D7-BB82332C878E}"\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "python_uwp", "python_uwp.vcxproj", "{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "venvlauncher", "venvlauncher.vcxproj", "{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "venvwlauncher", "venvwlauncher.vcxproj", "{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pythonw_uwp", "pythonw_uwp.vcxproj", "{AB603547-1E2A-45B3-9E09-B04596006393}"\r
EndProject\r
Global\r
GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|Win32.Build.0 = Release|Win32\r
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|x64.ActiveCfg = Release|x64\r
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|x64.Build.0 = Release|x64\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.Debug|Win32.ActiveCfg = Debug|Win32\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.Debug|Win32.Build.0 = Debug|Win32\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.Debug|x64.ActiveCfg = Debug|x64\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.Debug|x64.Build.0 = Debug|x64\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.PGInstrument|Win32.Build.0 = PGInstrument|Win32\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.PGInstrument|x64.ActiveCfg = PGInstrument|x64\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.PGInstrument|x64.Build.0 = PGInstrument|x64\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.PGUpdate|Win32.Build.0 = PGUpdate|Win32\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.PGUpdate|x64.ActiveCfg = PGUpdate|x64\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.PGUpdate|x64.Build.0 = PGUpdate|x64\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.Release|Win32.ActiveCfg = Release|Win32\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.Release|Win32.Build.0 = Release|Win32\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.Release|x64.ActiveCfg = Release|x64\r
- {41ADEDF9-11D8-474E-B4D7-BB82332C878E}.Release|x64.Build.0 = Release|x64\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|Win32.Build.0 = Debug|Win32\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|x64.ActiveCfg = Debug|x64\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|x64.Build.0 = Debug|x64\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|Win32.Build.0 = PGInstrument|Win32\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|x64.ActiveCfg = PGInstrument|x64\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|x64.Build.0 = PGInstrument|x64\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|Win32.Build.0 = PGUpdate|Win32\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|x64.ActiveCfg = PGUpdate|x64\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|x64.Build.0 = PGUpdate|x64\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|Win32.ActiveCfg = Release|Win32\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|Win32.Build.0 = Release|Win32\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|x64.ActiveCfg = Release|x64\r
+ {9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|x64.Build.0 = Release|x64\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|Win32.Build.0 = Debug|Win32\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|x64.ActiveCfg = Debug|x64\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|x64.Build.0 = Debug|x64\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|Win32.Build.0 = PGInstrument|Win32\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|x64.ActiveCfg = PGInstrument|x64\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|x64.Build.0 = PGInstrument|x64\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|Win32.Build.0 = PGUpdate|Win32\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|x64.ActiveCfg = PGUpdate|x64\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|x64.Build.0 = PGUpdate|x64\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|Win32.ActiveCfg = Release|Win32\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|Win32.Build.0 = Release|Win32\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|x64.ActiveCfg = Release|x64\r
+ {494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|x64.Build.0 = Release|x64\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|Win32.Build.0 = Debug|Win32\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|x64.ActiveCfg = Debug|x64\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|x64.Build.0 = Debug|x64\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|Win32.Build.0 = PGInstrument|Win32\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|x64.ActiveCfg = PGInstrument|x64\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|x64.Build.0 = PGInstrument|x64\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|Win32.Build.0 = PGUpdate|Win32\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|x64.ActiveCfg = PGUpdate|x64\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|x64.Build.0 = PGUpdate|x64\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|Win32.ActiveCfg = Release|Win32\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|Win32.Build.0 = Release|Win32\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|x64.ActiveCfg = Release|x64\r
+ {FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|x64.Build.0 = Release|x64\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.Debug|Win32.Build.0 = Debug|Win32\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.Debug|x64.ActiveCfg = Debug|x64\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.Debug|x64.Build.0 = Debug|x64\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|Win32.Build.0 = PGInstrument|Win32\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|x64.ActiveCfg = PGInstrument|x64\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|x64.Build.0 = PGInstrument|x64\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|Win32.Build.0 = PGUpdate|Win32\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|x64.ActiveCfg = PGUpdate|x64\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|x64.Build.0 = PGUpdate|x64\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.Release|Win32.ActiveCfg = Release|Win32\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.Release|Win32.Build.0 = Release|Win32\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.Release|x64.ActiveCfg = Release|x64\r
+ {AB603547-1E2A-45B3-9E09-B04596006393}.Release|x64.Build.0 = Release|x64\r
EndGlobalSection\r
GlobalSection(SolutionProperties) = preSolution\r
HideSolutionNode = FALSE\r
if "%PCBUILD%"=="" (set PCBUILD=%~dp0)\r
if "%EXTERNALS_DIR%"=="" (set EXTERNALS_DIR=%PCBUILD%\..\externals)\r
\r
-set OUT=\r
-set SRC=\r
set ORG_SETTING=\r
\r
:CheckOpts\r
if "%~1"=="--certificate" (set SigningCertificate=%~2) && shift && shift & goto CheckOpts\r
if "%~1"=="-c" (set SigningCertificate=%~2) && shift && shift & goto CheckOpts\r
if "%~1"=="--organization" (set ORG_SETTING=--organization "%~2") && shift && shift && goto CheckOpts\r
-if "%~1"=="-i" (SET SRC=$~2) && shift && shift && goto CheckOpts\r
-if "%~1"=="--in" (SET SRC=$~2) && shift && shift && goto CheckOpts\r
-if "%~1"=="-o" (set OUT=$~2) && shift && shift && goto CheckOpts\r
-if "%~1"=="--out" (set OUT=$~2) && shift && shift && goto CheckOpts\r
\r
if "%~1"=="" goto Build\r
echo Unrecognized option: %1\r
goto Usage\r
\r
:Build\r
-if not defined SRC (echo --in directory is required & exit /b 1)\r
-if not defined OUT (echo --out directory is required & exit /b 1)\r
-\r
call "%PCBUILD%\find_msbuild.bat" %MSBUILD%\r
if ERRORLEVEL 1 (echo Cannot locate MSBuild.exe on PATH or as MSBUILD variable & exit /b 2)\r
\r
<FileName Required="true" />\r
</ParameterGroup>\r
<Task>\r
- <Code Type="Fragment" Language="cs">\r
+ <Using Namespace="System.Diagnostics"/>\r
+ <Using Namespace="System.IO"/>\r
+ <Using Namespace="System.Runtime.InteropServices"/>\r
+ <Using Namespace="System.Text"/>\r
+ <Code Type="Method" Language="cs">\r
<![CDATA[\r
-string fullPath = System.IO.Path.GetFullPath(FileName);\r
-Log.LogMessage("Looking for " + fullPath, MessageImportance.Normal);\r
-foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses()) {\r
- try {\r
- Log.LogMessage("Found running process: " + p.MainModule.FileName, MessageImportance.Low);\r
- if (fullPath.Equals(System.IO.Path.GetFullPath(p.MainModule.FileName), StringComparison.OrdinalIgnoreCase)) {\r
- Log.LogMessage("Terminating " + p.MainModule.FileName, MessageImportance.High);\r
- p.Kill();\r
+[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]\r
+public static extern bool QueryFullProcessImageName([In]IntPtr hProcess, [In]int dwFlags,\r
+ [Out]StringBuilder lpExeName, ref int lpdwSize);\r
+public override bool Execute() {\r
+ string fullPath = Path.GetFullPath(FileName);\r
+ Log.LogMessage("Looking for " + fullPath, MessageImportance.Normal);\r
+ foreach (Process p in Process.GetProcesses()) {\r
+ try {\r
+ int pathLength = 32768;\r
+ StringBuilder pathBuilder = new StringBuilder(pathLength);\r
+ if (QueryFullProcessImageName(p.Handle, 0, pathBuilder, ref pathLength)) {\r
+ string exeName = Path.GetFullPath(pathBuilder.ToString());\r
+ Log.LogMessage("Found running process: " + exeName, MessageImportance.Low);\r
+ if (fullPath.Equals(exeName, StringComparison.OrdinalIgnoreCase)) {\r
+ Log.LogMessage("Terminating " + exeName, MessageImportance.High);\r
+ p.Kill();\r
+ }\r
+ }\r
+ } catch {\r
}\r
- } catch {\r
}\r
+ return true;\r
}\r
]]>\r
</Code>\r
<sqlite3Dir>$(ExternalsDir)sqlite-3.21.0.0\</sqlite3Dir>\r
<bz2Dir>$(ExternalsDir)bzip2-1.0.6\</bz2Dir>\r
<lzmaDir>$(ExternalsDir)xz-5.2.2\</lzmaDir>\r
- <opensslDir>$(ExternalsDir)openssl-1.1.0i\</opensslDir>\r
- <opensslOutDir>$(ExternalsDir)openssl-bin-1.1.0i\$(ArchName)\</opensslOutDir>\r
+ <opensslDir>$(ExternalsDir)openssl-1.1.0j\</opensslDir>\r
+ <opensslOutDir>$(ExternalsDir)openssl-bin-1.1.0j\$(ArchName)\</opensslOutDir>\r
<opensslIncludeDir>$(opensslOutDir)include</opensslIncludeDir>\r
<nasmDir>$(ExternalsDir)\nasm-2.11.06\</nasmDir>\r
<zlibDir>$(ExternalsDir)\zlib-1.2.11\</zlibDir>\r
-->\r
<_RegistryVersion>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion)</_RegistryVersion>\r
<_RegistryVersion Condition="$(_RegistryVersion) == ''">$(Registry:HKEY_LOCAL_MACHINE\WOW6432Node\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion)</_RegistryVersion>\r
- <DefaultWindowsSDKVersion>10.0.17134.0</DefaultWindowsSDKVersion>\r
- <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == '10.0.16299'">10.0.16299.0</DefaultWindowsSDKVersion>\r
- <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == '10.0.15063'">10.0.15063.0</DefaultWindowsSDKVersion>\r
- <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == '10.0.14393'">10.0.14393.0</DefaultWindowsSDKVersion>\r
- <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == '10.0.10586'">10.0.10586.0</DefaultWindowsSDKVersion>\r
- <DefaultWindowsSDKVersion Condition="$(_RegistryVersion) == '10.0.10240'">10.0.10240.0</DefaultWindowsSDKVersion>\r
+ <!-- Sometimes the version in the registry has to .0 suffix, and sometimes it doesn't. Check and add it -->\r
+ <_RegistryVersion Condition="$(_RegistryVersion) != '' and !$(_RegistryVersion.EndsWith('.0'))">$(_RegistryVersion).0</_RegistryVersion>\r
+\r
+ <!-- The minimum allowed SDK version to use for building -->\r
+ <DefaultWindowsSDKVersion>10.0.10586.0</DefaultWindowsSDKVersion>\r
+ <DefaultWindowsSDKVersion Condition="$([System.Version]::Parse($(_RegistryVersion))) > $([System.Version]::Parse($(DefaultWindowsSDKVersion)))">$(_RegistryVersion)</DefaultWindowsSDKVersion>\r
</PropertyGroup>\r
\r
+ <PropertyGroup Condition="$(WindowsTargetPlatformVersion) == ''">\r
+ <WindowsTargetPlatformVersion>$(DefaultWindowsSDKVersion)</WindowsTargetPlatformVersion>\r
+ </PropertyGroup>\r
+\r
<PropertyGroup Condition="'$(OverrideVersion)' == ''">\r
<!--\r
Read version information from Include\patchlevel.h. The following properties are set:\r
<Message Importance="high" Text="Field3Value: $(Field3Value)" />\r
<Message Importance="high" Text="SysWinVer: $(SysWinVer)" />\r
<Message Importance="high" Text="PyDllName: $(PyDllName)" />\r
+ <Message Importance="high" Text="WindowsSdkVersion: $(TargetPlatformVersion)" />\r
</Target>\r
</Project>\r
</ProjectConfiguration>\r
</ItemGroup>\r
<PropertyGroup Label="Globals">\r
- <ProjectGuid>{41ADEDF9-11D8-474E-B4D7-BB82332C878E}</ProjectGuid>\r
- <RootNamespace>_distutils_findvs</RootNamespace>\r
- <Keyword>Win32Proj</Keyword>\r
+ <ProjectGuid>{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}</ProjectGuid>\r
</PropertyGroup>\r
<Import Project="python.props" />\r
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
<PropertyGroup Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <CharacterSet>NotSet</CharacterSet>\r
+ <ConfigurationType>Application</ConfigurationType>\r
+ <UseOfMfc>false</UseOfMfc>\r
+ <CharacterSet>Unicode</CharacterSet>\r
</PropertyGroup>\r
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
- <PropertyGroup>\r
- <TargetExt>.pyd</TargetExt>\r
- </PropertyGroup>\r
<ImportGroup Label="ExtensionSettings">\r
</ImportGroup>\r
<ImportGroup Label="PropertySheets">\r
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
</PropertyGroup>\r
<ItemDefinitionGroup>\r
+ <ClCompile>\r
+ <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <AdditionalOptions>/EHsc /std:c++17 %(AdditionalOptions)</AdditionalOptions>\r
+ </ClCompile>\r
<Link>\r
- <AdditionalDependencies>version.lib;ole32.lib;oleaut32.lib;Microsoft.VisualStudio.Setup.Configuration.Native.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories);$(PySourcePath)PC\external\$(PlatformToolset)\$(ArchName)</AdditionalLibraryDirectories>\r
+ <AdditionalDependencies>windowsapp.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+ <SubSystem>Console</SubSystem>\r
</Link>\r
</ItemDefinitionGroup>\r
<ItemGroup>\r
- <ClCompile Include="..\PC\_findvs.cpp" />\r
+ <None Include="..\PC\pycon.ico" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ResourceCompile Include="..\PC\python_exe.rc" />\r
</ItemGroup>\r
<ItemGroup>\r
- <ResourceCompile Include="..\PC\python_nt.rc" />\r
+ <ClCompile Include="..\PC\python_uwp.cpp" />\r
</ItemGroup>\r
<ItemGroup>\r
<ProjectReference Include="pythoncore.vcxproj">\r
<Target Name="_WarnAboutZlib" BeforeTargets="PrepareForBuild" Condition="!$(IncludeExternals)">\r
<Warning Text="Not including zlib is not a supported configuration." />\r
</Target>\r
+\r
+ <PropertyGroup>\r
+ <VCRedistDir>$(VCInstallDir)\Redist\MSVC\$(VCToolsRedistVersion)\</VCRedistDir>\r
+ <VCRedistDir Condition="$(Platform) == 'Win32'">$(VCRedistDir)x86\</VCRedistDir>\r
+ <VCRedistDir Condition="$(Platform) != 'Win32'">$(VCRedistDir)$(Platform)\</VCRedistDir>\r
+ </PropertyGroup>\r
+ <ItemGroup Condition="$(VCInstallDir) != ''">\r
+ <VCRuntimeDLL Include="$(VCRedistDir)\**\vcruntime*.dll" />\r
+ </ItemGroup>\r
+ <Target Name="_CopyVCRuntime" AfterTargets="Build" Inputs="@(VCRuntimeDLL)" Outputs="$(OutDir)%(Filename)%(Extension)">\r
+ <Copy SourceFiles="%(VCRuntimeDLL.FullPath)" DestinationFolder="$(OutDir)" />\r
+ </Target>\r
+ <Target Name="_CleanVCRuntime" AfterTargets="Clean">\r
+ <Delete Files="@(VCRuntimeDLL->'$(OutDir)%(Filename)%(Extension)')" />\r
+ </Target>\r
</Project>\r
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+ <ItemGroup Label="ProjectConfigurations">\r
+ <ProjectConfiguration Include="Debug|Win32">\r
+ <Configuration>Debug</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="Debug|x64">\r
+ <Configuration>Debug</Configuration>\r
+ <Platform>x64</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="PGInstrument|Win32">\r
+ <Configuration>PGInstrument</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="PGInstrument|x64">\r
+ <Configuration>PGInstrument</Configuration>\r
+ <Platform>x64</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="PGUpdate|Win32">\r
+ <Configuration>PGUpdate</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="PGUpdate|x64">\r
+ <Configuration>PGUpdate</Configuration>\r
+ <Platform>x64</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="Release|Win32">\r
+ <Configuration>Release</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="Release|x64">\r
+ <Configuration>Release</Configuration>\r
+ <Platform>x64</Platform>\r
+ </ProjectConfiguration>\r
+ </ItemGroup>\r
+ <PropertyGroup Label="Globals">\r
+ <ProjectGuid>{AB603547-1E2A-45B3-9E09-B04596006393}</ProjectGuid>\r
+ </PropertyGroup>\r
+ <Import Project="python.props" />\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+ <PropertyGroup Label="Configuration">\r
+ <ConfigurationType>Application</ConfigurationType>\r
+ <UseOfMfc>false</UseOfMfc>\r
+ <CharacterSet>Unicode</CharacterSet>\r
+ </PropertyGroup>\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+ <ImportGroup Label="ExtensionSettings">\r
+ </ImportGroup>\r
+ <ImportGroup Label="PropertySheets">\r
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+ <Import Project="pyproject.props" />\r
+ </ImportGroup>\r
+ <PropertyGroup Label="UserMacros" />\r
+ <PropertyGroup>\r
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
+ </PropertyGroup>\r
+ <ItemDefinitionGroup>\r
+ <ClCompile>\r
+ <PreprocessorDefinitions>PYTHONW;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <AdditionalOptions>/EHsc /std:c++17 %(AdditionalOptions)</AdditionalOptions>\r
+ </ClCompile>\r
+ <Link>\r
+ <AdditionalDependencies>windowsapp.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+ <SubSystem>Windows</SubSystem>\r
+ </Link>\r
+ </ItemDefinitionGroup>\r
+ <ItemGroup>\r
+ <None Include="..\PC\pyconw.ico" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ResourceCompile Include="..\PC\pythonw_exe.rc" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ClCompile Include="..\PC\python_uwp.cpp" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ProjectReference Include="pythoncore.vcxproj">\r
+ <Project>{cf7ac3d1-e2df-41d2-bea6-1e2556cdea26}</Project>\r
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
+ </ProjectReference>\r
+ </ItemGroup>\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+ <ImportGroup Label="ExtensionTargets">\r
+ </ImportGroup>\r
+</Project>\r
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+ <ItemGroup Label="ProjectConfigurations">\r
+ <ProjectConfiguration Include="Debug|Win32">\r
+ <Configuration>Debug</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="Debug|x64">\r
+ <Configuration>Debug</Configuration>\r
+ <Platform>x64</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="PGInstrument|Win32">\r
+ <Configuration>PGInstrument</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="PGInstrument|x64">\r
+ <Configuration>PGInstrument</Configuration>\r
+ <Platform>x64</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="PGUpdate|Win32">\r
+ <Configuration>PGUpdate</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="PGUpdate|x64">\r
+ <Configuration>PGUpdate</Configuration>\r
+ <Platform>x64</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="Release|Win32">\r
+ <Configuration>Release</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="Release|x64">\r
+ <Configuration>Release</Configuration>\r
+ <Platform>x64</Platform>\r
+ </ProjectConfiguration>\r
+ </ItemGroup>\r
+ <PropertyGroup Label="Globals">\r
+ <ProjectGuid>{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}</ProjectGuid>\r
+ <RootNamespace>venvlauncher</RootNamespace>\r
+ <TargetName>venvlauncher</TargetName>\r
+ <SupportPGO>false</SupportPGO>\r
+ </PropertyGroup>\r
+ <Import Project="python.props" />\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+ <PropertyGroup Label="Configuration">\r
+ <ConfigurationType>Application</ConfigurationType>\r
+ <CharacterSet>MultiByte</CharacterSet>\r
+ </PropertyGroup>\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+ <ImportGroup Label="ExtensionSettings">\r
+ </ImportGroup>\r
+ <PropertyGroup>\r
+ <MakeVersionInfoBeforeTarget>ClCompile</MakeVersionInfoBeforeTarget>\r
+ </PropertyGroup>\r
+ <ImportGroup Label="PropertySheets">\r
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+ <Import Project="pyproject.props" />\r
+ </ImportGroup>\r
+ <PropertyGroup Label="UserMacros" />\r
+ <ItemDefinitionGroup>\r
+ <ClCompile>\r
+ <PreprocessorDefinitions>_CONSOLE;VENV_REDIRECT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
+ </ClCompile>\r
+ <ResourceCompile>\r
+ <PreprocessorDefinitions>PY_ICON;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ </ResourceCompile>\r
+ <Link>\r
+ <AdditionalDependencies>version.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+ <SubSystem>Console</SubSystem>\r
+ </Link>\r
+ </ItemDefinitionGroup>\r
+ <ItemGroup>\r
+ <ClCompile Include="..\PC\launcher.c" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <None Include="..\PC\launcher.ico" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ResourceCompile Include="..\PC\pylauncher.rc" />\r
+ </ItemGroup>\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+ <ImportGroup Label="ExtensionTargets">\r
+ </ImportGroup>\r
+</Project>\r
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+ <ItemGroup Label="ProjectConfigurations">\r
+ <ProjectConfiguration Include="Debug|Win32">\r
+ <Configuration>Debug</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="Debug|x64">\r
+ <Configuration>Debug</Configuration>\r
+ <Platform>x64</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="PGInstrument|Win32">\r
+ <Configuration>PGInstrument</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="PGInstrument|x64">\r
+ <Configuration>PGInstrument</Configuration>\r
+ <Platform>x64</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="PGUpdate|Win32">\r
+ <Configuration>PGUpdate</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="PGUpdate|x64">\r
+ <Configuration>PGUpdate</Configuration>\r
+ <Platform>x64</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="Release|Win32">\r
+ <Configuration>Release</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="Release|x64">\r
+ <Configuration>Release</Configuration>\r
+ <Platform>x64</Platform>\r
+ </ProjectConfiguration>\r
+ </ItemGroup>\r
+ <PropertyGroup Label="Globals">\r
+ <ProjectGuid>{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}</ProjectGuid>\r
+ <RootNamespace>venvwlauncher</RootNamespace>\r
+ <TargetName>venvwlauncher</TargetName>\r
+ <SupportPGO>false</SupportPGO>\r
+ </PropertyGroup>\r
+ <Import Project="python.props" />\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+ <PropertyGroup Label="Configuration">\r
+ <ConfigurationType>Application</ConfigurationType>\r
+ <CharacterSet>MultiByte</CharacterSet>\r
+ </PropertyGroup>\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+ <ImportGroup Label="ExtensionSettings">\r
+ </ImportGroup>\r
+ <PropertyGroup>\r
+ <MakeVersionInfoBeforeTarget>ClCompile</MakeVersionInfoBeforeTarget>\r
+ </PropertyGroup>\r
+ <ImportGroup Label="PropertySheets">\r
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+ <Import Project="pyproject.props" />\r
+ </ImportGroup>\r
+ <PropertyGroup Label="UserMacros" />\r
+ <ItemDefinitionGroup>\r
+ <ClCompile>\r
+ <PreprocessorDefinitions>_WINDOWS;VENV_REDIRECT;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
+ </ClCompile>\r
+ <ResourceCompile>\r
+ <PreprocessorDefinitions>PYW_ICON;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ </ResourceCompile>\r
+ <Link>\r
+ <AdditionalDependencies>version.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+ <SubSystem>Windows</SubSystem>\r
+ </Link>\r
+ </ItemDefinitionGroup>\r
+ <ItemGroup>\r
+ <ClCompile Include="..\PC\launcher.c" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <None Include="..\PC\launcher.ico" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ResourceCompile Include="..\PC\pylauncher.rc" />\r
+ </ItemGroup>\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+ <ImportGroup Label="ExtensionTargets">\r
+ </ImportGroup>\r
+</Project>\r
wbuf = (wchar_t*)PyMem_RawMalloc(wbuflen * sizeof(wchar_t));
if (wbuf)
wcscpy_s(wbuf, wbuflen, wbuf_local);
+ else {
+ PyErr_NoMemory();
+ goto exit;
+ }
+ }
+ else {
+ wchar_t *tmp = PyMem_RawRealloc(wbuf, wbuflen * sizeof(wchar_t));
+ if (tmp == NULL) {
+ PyErr_NoMemory();
+ goto exit;
+ }
+ wbuf = tmp;
}
- else
- wbuf = (wchar_t*)PyMem_RawRealloc(wbuf, wbuflen * sizeof(wchar_t));
}
if (wbuf[0] == '\x1a') {
buf = PyMem_RawMalloc(1);
if (buf)
buf[0] = '\0';
+ else {
+ PyErr_NoMemory();
+ }
goto exit;
}
u8len = WideCharToMultiByte(CP_UTF8, 0, wbuf, total_read, NULL, 0, NULL, NULL);
buf = PyMem_RawMalloc(u8len + 1);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ goto exit;
+ }
u8len = WideCharToMultiByte(CP_UTF8, 0, wbuf, total_read, buf, u8len, NULL, NULL);
buf[u8len] = '\0';
int wlen;
wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1,
NULL, 0);
- if (wlen &&
- (wbuf = PyMem_RawMalloc(wlen * sizeof(wchar_t)))) {
+ if (wlen) {
+ wbuf = PyMem_RawMalloc(wlen * sizeof(wchar_t));
+ if (wbuf == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
wlen = MultiByteToWideChar(CP_UTF8, 0, prompt, -1,
wbuf, wlen);
if (wlen) {
n = 100;
p = (char *)PyMem_RawMalloc(n);
- if (p == NULL)
+ if (p == NULL) {
+ PyErr_NoMemory();
return NULL;
+ }
fflush(sys_stdout);
if (prompt)
if (_PyOS_ReadlineLock == NULL) {
_PyOS_ReadlineLock = PyThread_allocate_lock();
+ if (_PyOS_ReadlineLock == NULL) {
+ PyErr_SetString(PyExc_MemoryError, "can't allocate lock");
+ return NULL;
+ }
}
_PyOS_ReadlineTState = PyThreadState_GET();
len = strlen(rv) + 1;
res = PyMem_Malloc(len);
- if (res != NULL)
+ if (res != NULL) {
memcpy(res, rv, len);
+ }
+ else {
+ PyErr_NoMemory();
+ }
PyMem_RawFree(rv);
return res;
buflen = PyBytes_GET_SIZE(u);
buf = PyBytes_AS_STRING(u);
newtok = PyMem_MALLOC(buflen+1);
+ if (newtok == NULL) {
+ Py_DECREF(u);
+ tok->done = E_NOMEM;
+ return EOF;
+ }
strcpy(newtok, buf);
Py_DECREF(u);
}
}
-static void
-dump_config(void)
+static int
+dump_config_impl(void)
{
-#define ASSERT_EQUAL(a, b) \
- if ((a) != (b)) { \
- printf("ERROR: %s != %s (%i != %i)\n", #a, #b, (a), (b)); \
- exit(1); \
+ PyObject *config = NULL;
+ PyObject *dict = NULL;
+
+ config = PyDict_New();
+ if (config == NULL) {
+ goto error;
}
-#define ASSERT_STR_EQUAL(a, b) \
- if ((a) == NULL || (b == NULL) || wcscmp((a), (b)) != 0) { \
- printf("ERROR: %s != %s ('%ls' != '%ls')\n", #a, #b, (a), (b)); \
- exit(1); \
+
+ /* global config */
+ dict = _Py_GetGlobalVariablesAsDict();
+ if (dict == NULL) {
+ goto error;
}
+ if (PyDict_SetItemString(config, "global_config", dict) < 0) {
+ goto error;
+ }
+ Py_CLEAR(dict);
+ /* core config */
PyInterpreterState *interp = PyThreadState_Get()->interp;
- _PyCoreConfig *config = &interp->core_config;
-
- printf("install_signal_handlers = %i\n", config->install_signal_handlers);
-
- printf("Py_IgnoreEnvironmentFlag = %i\n", Py_IgnoreEnvironmentFlag);
+ const _PyCoreConfig *core_config = &interp->core_config;
+ dict = _PyCoreConfig_AsDict(core_config);
+ if (dict == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(config, "core_config", dict) < 0) {
+ goto error;
+ }
+ Py_CLEAR(dict);
- printf("use_hash_seed = %i\n", config->use_hash_seed);
- printf("hash_seed = %lu\n", config->hash_seed);
+ /* main config */
+ const _PyMainInterpreterConfig *main_config = &interp->config;
+ dict = _PyMainInterpreterConfig_AsDict(main_config);
+ if (dict == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(config, "main_config", dict) < 0) {
+ goto error;
+ }
+ Py_CLEAR(dict);
+
+ PyObject *json = PyImport_ImportModule("json");
+ PyObject *res = PyObject_CallMethod(json, "dumps", "O", config);
+ Py_DECREF(json);
+ Py_CLEAR(config);
+ if (res == NULL) {
+ goto error;
+ }
- printf("allocator = %s\n", config->allocator);
+ PySys_FormatStdout("%S\n", res);
+ Py_DECREF(res);
- printf("dev_mode = %i\n", config->dev_mode);
- printf("faulthandler = %i\n", config->faulthandler);
- printf("tracemalloc = %i\n", config->tracemalloc);
- printf("import_time = %i\n", config->import_time);
- printf("show_ref_count = %i\n", config->show_ref_count);
- printf("show_alloc_count = %i\n", config->show_alloc_count);
- printf("dump_refs = %i\n", config->dump_refs);
- printf("malloc_stats = %i\n", config->malloc_stats);
+ return 0;
- printf("coerce_c_locale = %i\n", config->coerce_c_locale);
- printf("coerce_c_locale_warn = %i\n", config->coerce_c_locale_warn);
- printf("utf8_mode = %i\n", config->utf8_mode);
+error:
+ Py_XDECREF(config);
+ Py_XDECREF(dict);
+ return -1;
+}
- printf("program_name = %ls\n", config->program_name);
- ASSERT_STR_EQUAL(config->program_name, Py_GetProgramName());
- printf("argc = %i\n", config->argc);
- printf("argv = [");
- for (int i=0; i < config->argc; i++) {
- if (i) {
- printf(", ");
- }
- printf("\"%ls\"", config->argv[i]);
+static void
+dump_config(void)
+{
+ if (dump_config_impl() < 0) {
+ fprintf(stderr, "failed to dump the configuration:\n");
+ PyErr_Print();
}
- printf("]\n");
-
- printf("program = %ls\n", config->program);
- /* FIXME: test xoptions */
- /* FIXME: test warnoptions */
- /* FIXME: test module_search_path_env */
- /* FIXME: test home */
- /* FIXME: test module_search_paths */
- /* FIXME: test executable */
- /* FIXME: test prefix */
- /* FIXME: test base_prefix */
- /* FIXME: test exec_prefix */
- /* FIXME: test base_exec_prefix */
- /* FIXME: test dll_path */
-
- printf("Py_IsolatedFlag = %i\n", Py_IsolatedFlag);
- printf("Py_NoSiteFlag = %i\n", Py_NoSiteFlag);
- printf("Py_BytesWarningFlag = %i\n", Py_BytesWarningFlag);
- printf("Py_InspectFlag = %i\n", Py_InspectFlag);
- printf("Py_InteractiveFlag = %i\n", Py_InteractiveFlag);
- printf("Py_OptimizeFlag = %i\n", Py_OptimizeFlag);
- printf("Py_DebugFlag = %i\n", Py_DebugFlag);
- printf("Py_DontWriteBytecodeFlag = %i\n", Py_DontWriteBytecodeFlag);
- printf("Py_VerboseFlag = %i\n", Py_VerboseFlag);
- printf("Py_QuietFlag = %i\n", Py_QuietFlag);
- printf("Py_NoUserSiteDirectory = %i\n", Py_NoUserSiteDirectory);
- printf("Py_UnbufferedStdioFlag = %i\n", Py_UnbufferedStdioFlag);
- /* FIXME: test legacy_windows_fs_encoding */
- /* FIXME: test legacy_windows_stdio */
-
- printf("_disable_importlib = %i\n", config->_disable_importlib);
- /* cannot test _Py_CheckHashBasedPycsMode: the symbol is not exported */
- printf("Py_FrozenFlag = %i\n", Py_FrozenFlag);
-
-#undef ASSERT_EQUAL
-#undef ASSERT_STR_EQUAL
}
Py_SetProgramName(L"./globalvar");
config.program_name = L"./conf_program_name";
- /* FIXME: test argc/argv */
+ static wchar_t* argv[2] = {
+ L"-c",
+ L"pass",
+ };
+ config.argc = Py_ARRAY_LENGTH(argv);
+ config.argv = argv;
+
config.program = L"conf_program";
- /* FIXME: test xoptions */
- /* FIXME: test warnoptions */
+
+ static wchar_t* xoptions[3] = {
+ L"core_xoption1=3",
+ L"core_xoption2=",
+ L"core_xoption3",
+ };
+ config.nxoption = Py_ARRAY_LENGTH(xoptions);
+ config.xoptions = xoptions;
+
+ static wchar_t* warnoptions[2] = {
+ L"default",
+ L"error::ResourceWarning",
+ };
+ config.nwarnoption = Py_ARRAY_LENGTH(warnoptions);
+ config.warnoptions = warnoptions;
+
/* FIXME: test module_search_path_env */
/* FIXME: test home */
/* FIXME: test path config: module_search_path .. dll_path */
version_obj = _PyDict_GetItemId(registry, &PyId_version);
if (version_obj == NULL
|| !PyLong_CheckExact(version_obj)
- || PyLong_AsLong(version_obj) != _PyRuntime.warnings.filters_version) {
+ || PyLong_AsLong(version_obj) != _PyRuntime.warnings.filters_version)
+ {
+ if (PyErr_Occurred()) {
+ return -1;
+ }
PyDict_Clear(registry);
version_obj = PyLong_FromLong(_PyRuntime.warnings.filters_version);
if (version_obj == NULL)
}
/* Create a duplicate without underscores. */
dup = PyMem_Malloc(strlen(s) + 1);
+ if (dup == NULL) {
+ return PyErr_NoMemory();
+ }
end = dup;
for (; *s; s++) {
if (*s != '_') {
len = expr_end - expr_start;
/* Allocate 3 extra bytes: open paren, close paren, null byte. */
str = PyMem_RawMalloc(len + 3);
- if (str == NULL)
+ if (str == NULL) {
+ PyErr_NoMemory();
return NULL;
+ }
str[0] = '(';
memcpy(str+1, expr_start, len);
# endif
#endif
+#ifdef _Py_MEMORY_SANITIZER
+# include <sanitizer/msan_interface.h>
+#endif
+
#ifdef Py_DEBUG
int _Py_HashSecret_Initialized = 0;
#else
else {
n = syscall(SYS_getrandom, dest, n, flags);
}
+# ifdef _Py_MEMORY_SANITIZER
+ if (n > 0) {
+ __msan_unpoison(dest, n);
+ }
+# endif
#endif
if (n < 0) {
return current_frame->f_builtins;
}
+/* Convenience function to get a builtin from its name */
+PyObject *
+_PyEval_GetBuiltinId(_Py_Identifier *name)
+{
+ PyObject *attr = _PyDict_GetItemIdWithError(PyEval_GetBuiltins(), name);
+ if (attr) {
+ Py_INCREF(attr);
+ }
+ else if (!PyErr_Occurred()) {
+ PyErr_SetObject(PyExc_AttributeError, _PyUnicode_FromId(name));
+ }
+ return attr;
+}
+
PyObject *
PyEval_GetLocals(void)
{
PyObject *names = f->f_code->co_names;
PyObject *name = GETITEM(names, oparg);
PyObject *locals = f->f_locals;
- if (PyDict_CheckExact(locals) &&
+ if (locals && PyDict_CheckExact(locals) &&
PyDict_GetItem(locals, name) == v) {
if (PyDict_DelItem(locals, name) != 0) {
PyErr_Clear();
Py_DECREF(l);
return NULL;
}
- PyList_SetItem(l, i, x);
+ PyList_SET_ITEM(l, i, x);
}
for (i = 0; i < 256; i++)
a[i] = 0;
Py_DECREF(l);
return NULL;
}
- PyList_SetItem(l, i, x);
+ PyList_SET_ITEM(l, i, x);
}
return l;
#endif
/* Next, scan the search functions in order of registration */
args = PyTuple_New(1);
- if (args == NULL)
- goto onError;
+ if (args == NULL) {
+ Py_DECREF(v);
+ return NULL;
+ }
PyTuple_SET_ITEM(args,0,v);
len = PyList_Size(interp->codec_search_path);
}
static PyObject *
-token_get_var(PyContextToken *self)
+token_get_var(PyContextToken *self, void *Py_UNUSED(ignored))
{
Py_INCREF(self->tok_var);
return (PyObject *)self->tok_var;
}
static PyObject *
-token_get_old_value(PyContextToken *self)
+token_get_old_value(PyContextToken *self, void *Py_UNUSED(ignored))
{
if (self->tok_oldval == NULL) {
return get_token_missing();
return 1;
}
+
+int
+_Py_GetForceASCII(void)
+{
+ if (force_ascii == -1) {
+ force_ascii = check_force_ascii();
+ }
+ return force_ascii;
+}
+
+
+void
+_Py_ResetForceASCII(void)
+{
+ force_ascii = -1;
+}
+
+
static int
encode_ascii(const wchar_t *text, char **str,
size_t *error_pos, const char **reason,
*str = result;
return 0;
}
+#else
+int
+_Py_GetForceASCII(void)
+{
+ return 0;
+}
+
+void
+_Py_ResetForceASCII(void)
+{
+ /* nothing to do */
+}
#endif /* !defined(__APPLE__) && !defined(__ANDROID__) && !defined(MS_WINDOWS) */
* handler raised an exception. */
assert(!PyErr_Occurred());
-#ifdef MS_WINDOWS
- if (count > INT_MAX) {
- /* On Windows, the count parameter of read() is an int */
- count = INT_MAX;
- }
-#else
- if (count > PY_SSIZE_T_MAX) {
- /* if count is greater than PY_SSIZE_T_MAX,
- * read() result is undefined */
- count = PY_SSIZE_T_MAX;
+ if (count > _PY_READ_MAX) {
+ count = _PY_READ_MAX;
}
-#endif
_Py_BEGIN_SUPPRESS_IPH
do {
depending on heap usage). */
count = 32767;
}
- else if (count > INT_MAX)
- count = INT_MAX;
-#else
- if (count > PY_SSIZE_T_MAX) {
- /* write() should truncate count to PY_SSIZE_T_MAX, but it's safer
- * to do it ourself to have a portable behaviour. */
- count = PY_SSIZE_T_MAX;
- }
#endif
+ if (count > _PY_WRITE_MAX) {
+ count = _PY_WRITE_MAX;
+ }
if (gil_held) {
do {
if (change_locale) {
oldloc = setlocale(LC_CTYPE, NULL);
if (!oldloc) {
- PyErr_SetString(PyExc_RuntimeWarning, "faild to get LC_CTYPE locale");
+ PyErr_SetString(PyExc_RuntimeWarning, "failed to get LC_CTYPE locale");
return -1;
}
}
if (loc != NULL) {
- /* Only set the locale temporarilty the LC_CTYPE locale
+ /* Only set the locale temporarily the LC_CTYPE locale
if LC_NUMERIC locale is different than LC_CTYPE locale and
decimal_point and/or thousands_sep are non-ASCII or longer than
1 byte */
PyObject *decimal_point;
PyObject *thousands_sep;
const char *grouping;
+ char *grouping_buffer;
} LocaleInfo;
-#define STATIC_LOCALE_INFO_INIT {0, 0, 0}
+#define STATIC_LOCALE_INFO_INIT {0, 0, 0, 0}
/* describes the layout for an integer, see the comment in
calc_number_widths() for details */
/* not all fields of format are used. for example, precision is
unused. should this take discrete params in order to be more clear
about what it does? or is passing a single format parameter easier
- and more efficient enough to justify a little obfuscation? */
+ and more efficient enough to justify a little obfuscation?
+ Return -1 on error. */
static Py_ssize_t
calc_number_widths(NumberFieldWidths *spec, Py_ssize_t n_prefix,
Py_UCS4 sign_char, PyObject *number, Py_ssize_t n_start,
Py_UCS4 grouping_maxchar;
spec->n_grouped_digits = _PyUnicode_InsertThousandsGrouping(
NULL, 0,
- 0, NULL,
- spec->n_digits, spec->n_min_width,
+ NULL, 0, spec->n_digits,
+ spec->n_min_width,
locale->grouping, locale->thousands_sep, &grouping_maxchar);
+ if (spec->n_grouped_digits == -1) {
+ return -1;
+ }
*maxchar = Py_MAX(*maxchar, grouping_maxchar);
}
/* Only for type 'c' special case, it has no digits. */
if (spec->n_digits != 0) {
/* Fill the digits with InsertThousandsGrouping. */
- char *pdigits;
- if (PyUnicode_READY(digits))
- return -1;
- pdigits = PyUnicode_DATA(digits);
- if (PyUnicode_KIND(digits) < kind) {
- pdigits = _PyUnicode_AsKind(digits, kind);
- if (pdigits == NULL)
- return -1;
- }
r = _PyUnicode_InsertThousandsGrouping(
- writer->buffer, writer->pos,
- spec->n_grouped_digits,
- pdigits + kind * d_pos,
- spec->n_digits, spec->n_min_width,
+ writer, spec->n_grouped_digits,
+ digits, d_pos, spec->n_digits,
+ spec->n_min_width,
locale->grouping, locale->thousands_sep, NULL);
if (r == -1)
return -1;
assert(r == spec->n_grouped_digits);
- if (PyUnicode_KIND(digits) < kind)
- PyMem_Free(pdigits);
d_pos += spec->n_digits;
}
if (toupper) {
{
switch (type) {
case LT_CURRENT_LOCALE: {
+ const char *grouping;
if (_Py_GetLocaleconvNumeric(&locale_info->decimal_point,
&locale_info->thousands_sep,
- &locale_info->grouping) < 0) {
+ &grouping) < 0) {
+ return -1;
+ }
+
+ /* localeconv() grouping can become a dangling pointer or point
+ to a different string if another thread calls localeconv() during
+ the string formatting. Copy the string to avoid this risk. */
+ locale_info->grouping_buffer = _PyMem_Strdup(grouping);
+ if (locale_info->grouping_buffer == NULL) {
+ PyErr_NoMemory();
return -1;
}
+ locale_info->grouping = locale_info->grouping_buffer;
break;
}
case LT_DEFAULT_LOCALE:
{
Py_XDECREF(locale_info->decimal_point);
Py_XDECREF(locale_info->thousands_sep);
+ PyMem_Free(locale_info->grouping_buffer);
}
/************************************************************************/
n_total = calc_number_widths(&spec, n_prefix, sign_char, tmp, inumeric_chars,
inumeric_chars + n_digits, n_remainder, 0,
&locale, format, &maxchar);
+ if (n_total == -1) {
+ goto done;
+ }
/* Allocate the memory. */
if (_PyUnicodeWriter_Prepare(writer, n_total, maxchar) == -1)
n_total = calc_number_widths(&spec, 0, sign_char, unicode_tmp, index,
index + n_digits, n_remainder, has_decimal,
&locale, format, &maxchar);
+ if (n_total == -1) {
+ goto done;
+ }
/* Allocate the memory. */
if (_PyUnicodeWriter_Prepare(writer, n_total, maxchar) == -1)
i_re, i_re + n_re_digits, n_re_remainder,
re_has_decimal, &locale, &tmp_format,
&maxchar);
+ if (n_re_total == -1) {
+ goto done;
+ }
/* Same formatting, but always include a sign, unless the real part is
* going to be omitted, in which case we use whatever sign convention was
i_im, i_im + n_im_digits, n_im_remainder,
im_has_decimal, &locale, &tmp_format,
&maxchar);
+ if (n_im_total == -1) {
+ goto done;
+ }
if (skip_re)
n_re_total = 0;
if (!PyMapping_HasKey(modules, name)) {
return;
}
- Py_FatalError("import: deleting existing key in"
+ Py_FatalError("import: deleting existing key in "
"sys.modules failed");
}
}
}
mod = _PyImport_FindExtensionObject(name, path);
- if (mod != NULL) {
+ if (mod != NULL || PyErr_Occurred()) {
Py_DECREF(name);
Py_DECREF(path);
- Py_INCREF(mod);
+ Py_XINCREF(mod);
return mod;
}
p->buf_size = n;
}
else if (p->buf_size < n) {
- p->buf = PyMem_REALLOC(p->buf, n);
- if (p->buf == NULL) {
+ char *tmp = PyMem_REALLOC(p->buf, n);
+ if (tmp == NULL) {
PyErr_NoMemory();
return NULL;
}
+ p->buf = tmp;
p->buf_size = n;
}
}
+void
+_Py_SetProgramFullPath(const wchar_t *program_full_path)
+{
+ if (program_full_path == NULL || program_full_path[0] == L'\0') {
+ return;
+ }
+
+ PyMemAllocatorEx old_alloc;
+ _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+
+ PyMem_RawFree(_Py_path_config.program_full_path);
+ _Py_path_config.program_full_path = _PyMem_RawWcsdup(program_full_path);
+
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+
+ if (_Py_path_config.program_full_path == NULL) {
+ Py_FatalError("Py_SetProgramFullPath() failed: out of memory");
+ }
+}
+
+
wchar_t *
Py_GetPath(void)
{
/* Scans through EXTENDED ARGs, seeking the index of the effective opcode */
static Py_ssize_t
-find_op(const _Py_CODEUNIT *codestr, Py_ssize_t i)
+find_op(const _Py_CODEUNIT *codestr, Py_ssize_t codelen, Py_ssize_t i)
{
- while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
+ while (i < codelen && _Py_OPCODE(codestr[i]) == EXTENDED_ARG) {
i++;
}
return i;
Called with codestr pointing to the first LOAD_CONST.
*/
static Py_ssize_t
-fold_tuple_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t c_start,
- Py_ssize_t opcode_end, PyObject *consts, int n)
+fold_tuple_on_constants(_Py_CODEUNIT *codestr, Py_ssize_t codelen,
+ Py_ssize_t c_start, Py_ssize_t opcode_end,
+ PyObject *consts, int n)
{
/* Pre-conditions */
assert(PyList_CheckExact(consts));
for (Py_ssize_t i = 0, pos = c_start; i < n; i++, pos++) {
assert(pos < opcode_end);
- pos = find_op(codestr, pos);
+ pos = find_op(codestr, codelen, pos);
assert(_Py_OPCODE(codestr[pos]) == LOAD_CONST);
unsigned int arg = get_arg(codestr, pos);
goto exitError;
assert(PyList_Check(consts));
- for (i=find_op(codestr, 0) ; i<codelen ; i=nexti) {
+ for (i=find_op(codestr, codelen, 0) ; i<codelen ; i=nexti) {
opcode = _Py_OPCODE(codestr[i]);
op_start = i;
while (op_start >= 1 && _Py_OPCODE(codestr[op_start-1]) == EXTENDED_ARG) {
if (j > 0 && lastlc >= j) {
h = lastn_const_start(codestr, op_start, j);
if (ISBASICBLOCK(blocks, h, op_start)) {
- h = fold_tuple_on_constants(codestr, h, i+1, consts, j);
+ h = fold_tuple_on_constants(codestr, codelen,
+ h, i+1, consts, j);
break;
}
}
case JUMP_IF_FALSE_OR_POP:
case JUMP_IF_TRUE_OR_POP:
h = get_arg(codestr, i) / sizeof(_Py_CODEUNIT);
- tgt = find_op(codestr, h);
+ tgt = find_op(codestr, codelen, h);
j = _Py_OPCODE(codestr[tgt]);
if (CONDITIONAL_JUMP(j)) {
case SETUP_WITH:
case SETUP_ASYNC_WITH:
h = GETJUMPTGT(codestr, i);
- tgt = find_op(codestr, h);
+ tgt = find_op(codestr, codelen, h);
/* Replace JUMP_* to a RETURN into just a RETURN */
if (UNCONDITIONAL_JUMP(opcode) &&
_Py_OPCODE(codestr[tgt]) == RETURN_VALUE) {
}
if (h > i + 1) {
fill_nops(codestr, i + 1, h);
- nexti = find_op(codestr, h);
+ nexti = find_op(codestr, codelen, h);
}
break;
}
char *
_Py_SetLocaleFromEnv(int category)
{
+ char *res;
#ifdef __ANDROID__
const char *locale;
const char **pvar;
}
}
#endif
- return setlocale(category, utf8_locale);
-#else /* __ANDROID__ */
- return setlocale(category, "");
-#endif /* __ANDROID__ */
+ res = setlocale(category, utf8_locale);
+#else /* !defined(__ANDROID__) */
+ res = setlocale(category, "");
+#endif
+ _Py_ResetForceASCII();
+ return res;
}
PyDict_SetItemString(interp->sysdict, "modules", modules);
_PySys_EndInit(interp->sysdict, &interp->config);
}
+ else if (PyErr_Occurred()) {
+ goto handle_error;
+ }
bimod = _PyImport_FindBuiltin("builtins", modules);
if (bimod != NULL) {
goto handle_error;
Py_INCREF(interp->builtins);
}
+ else if (PyErr_Occurred()) {
+ goto handle_error;
+ }
/* initialize builtin exceptions */
_PyExc_Init(bimod);
Py_FileSystemDefaultEncoding = "utf-8";
Py_HasFileSystemDefaultEncoding = 1;
}
+ else if (_Py_GetForceASCII()) {
+ Py_FileSystemDefaultEncoding = "ascii";
+ Py_HasFileSystemDefaultEncoding = 1;
+ }
else if (Py_FileSystemDefaultEncoding == NULL) {
Py_FileSystemDefaultEncoding = get_locale_encoding();
if (Py_FileSystemDefaultEncoding == NULL) {
PyObject *exception, *v, *tb;
int has_tb;
- if (PyThreadState_GET() == NULL) {
- /* The GIL is released: trying to acquire it is likely to deadlock,
- just give up. */
- return 0;
- }
-
PyErr_Fetch(&exception, &v, &tb);
if (exception == NULL) {
/* No current exception */
fputs("\n", stderr);
fflush(stderr); /* it helps in Windows debug build */
- /* Print the exception (if an exception is set) with its traceback,
- * or display the current Python stack. */
- if (!_Py_FatalError_PrintExc(fd)) {
+ /* Check if the current thread has a Python thread state
+ and holds the GIL */
+ PyThreadState *tss_tstate = PyGILState_GetThisThreadState();
+ if (tss_tstate != NULL) {
+ PyThreadState *tstate = PyThreadState_GET();
+ if (tss_tstate != tstate) {
+ /* The Python thread does not hold the GIL */
+ tss_tstate = NULL;
+ }
+ }
+ else {
+ /* Py_FatalError() has been called from a C thread
+ which has no Python thread state. */
+ }
+ int has_tstate_and_gil = (tss_tstate != NULL);
+
+ if (has_tstate_and_gil) {
+ /* If an exception is set, print the exception with its traceback */
+ if (!_Py_FatalError_PrintExc(fd)) {
+ /* No exception is set, or an exception is set without traceback */
+ _Py_FatalError_DumpTracebacks(fd);
+ }
+ }
+ else {
_Py_FatalError_DumpTracebacks(fd);
}
_PyFaulthandler_Fini();
/* Check if the current Python thread hold the GIL */
- if (PyThreadState_GET() != NULL) {
+ if (has_tstate_and_gil) {
/* Flush sys.stdout and sys.stderr */
flush_std_files();
}
/* inline assembly for getting and setting the 387 FPU control word on
gcc/x86 */
-
+#ifdef _Py_MEMORY_SANITIZER
+__attribute__((no_sanitize_memory))
+#endif
unsigned short _Py_get_387controlword(void) {
unsigned short cw;
__asm__ __volatile__ ("fnstcw %0" : "=m" (cw));
Py_FatalError("PyState_RemoveModule: Module index out of bounds.");
return -1;
}
+ Py_INCREF(Py_None);
return PyList_SetItem(state->modules_by_index, index, Py_None);
}
}
dup = PyMem_Malloc(orig_len + 1);
+ if (dup == NULL) {
+ return PyErr_NoMemory();
+ }
end = dup;
prev = '\0';
last = s + orig_len;
struct symtable *st;
st = (struct symtable *)PyMem_Malloc(sizeof(struct symtable));
- if (st == NULL)
+ if (st == NULL) {
+ PyErr_NoMemory();
return NULL;
+ }
st->st_filename = NULL;
st->st_blocks = NULL;
* call optional for embedding applications, thus making this
* reachable again.
*/
- Py_XDECREF(warnoptions);
warnoptions = PyList_New(0);
if (warnoptions == NULL)
return NULL;
PySys_HasWarnOptions(void)
{
PyObject *warnoptions = _PySys_GetObjectId(&PyId_warnoptions);
- return (warnoptions != NULL && (PyList_Size(warnoptions) > 0)) ? 1 : 0;
+ return (warnoptions != NULL && PyList_Check(warnoptions)
+ && PyList_GET_SIZE(warnoptions) > 0);
}
static PyObject *
* call optional for embedding applications, thus making this
* reachable again.
*/
- Py_XDECREF(xoptions);
xoptions = PyDict_New();
if (xoptions == NULL)
return NULL;
Py_DECREF(v);
return NULL;
}
- PyList_SetItem(v, i, w);
+ PyList_SET_ITEM(v, i, w);
if (*p == '\0')
break;
path = p+1;
* Thread support.
*/
+/* bpo-33015: pythread_callback struct and pythread_wrapper() cast
+ "void func(void *)" to "void* func(void *)": always return NULL.
+
+ PyThread_start_new_thread() uses "void func(void *)" type, whereas
+ pthread_create() requires a void* return value. */
+typedef struct {
+ void (*func) (void *);
+ void *arg;
+} pythread_callback;
+
+static void *
+pythread_wrapper(void *arg)
+{
+ /* copy func and func_arg and free the temporary structure */
+ pythread_callback *callback = arg;
+ void (*func)(void *) = callback->func;
+ void *func_arg = callback->arg;
+ PyMem_RawFree(arg);
+
+ func(func_arg);
+ return NULL;
+}
unsigned long
PyThread_start_new_thread(void (*func)(void *), void *arg)
pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM);
#endif
+ pythread_callback *callback = PyMem_RawMalloc(sizeof(pythread_callback));
+
+ if (callback == NULL) {
+ return PYTHREAD_INVALID_THREAD_ID;
+ }
+
+ callback->func = func;
+ callback->arg = arg;
+
status = pthread_create(&th,
#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
&attrs,
#else
(pthread_attr_t*)NULL,
#endif
- (void* (*)(void *))func,
- (void *)arg
- );
+ pythread_wrapper, callback);
#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
pthread_attr_destroy(&attrs);
#endif
- if (status != 0)
+
+ if (status != 0) {
+ PyMem_RawFree(callback);
return PYTHREAD_INVALID_THREAD_ID;
+ }
pthread_detach(th);
return 0;
}
-static void
+static int
tb_clear(PyTracebackObject *tb)
{
Py_CLEAR(tb->tb_next);
Py_CLEAR(tb->tb_frame);
+ return 0;
}
PyTypeObject PyTraceBack_Type = {
-This is Python version 3.7.1
+This is Python version 3.7.2
============================
.. image:: https://travis-ci.org/python/cpython.svg?branch=master
if long(f_trace) != 0:
# we have a non-NULL f_trace:
return self.f_lineno
- else:
- #try:
+
+ try:
return self.co.addr2line(self.f_lasti)
- #except ValueError:
- # return self.f_lineno
+ except Exception:
+ # bpo-34989: addr2line() is a complex function, it can fail in many
+ # ways. For example, it fails with a TypeError on "FakeRepr" if
+ # gdb fails to load debug symbols. Use a catch-all "except
+ # Exception" to make the whole function safe. The caller has to
+ # handle None anyway for optimized Python.
+ return None
def current_line(self):
'''Get the text of the current source line as a string, with a trailing
newline character'''
if self.is_optimized_out():
return '(frame information optimized out)'
+
+ lineno = self.current_line_num()
+ if lineno is None:
+ return '(failed to get frame line number)'
+
filename = self.filename()
try:
- f = open(os_fsencode(filename), 'r')
+ with open(os_fsencode(filename), 'r') as fp:
+ lines = fp.readlines()
except IOError:
return None
- with f:
- all_lines = f.readlines()
- # Convert from 1-based current_line_num to 0-based list offset:
- return all_lines[self.current_line_num()-1]
+
+ try:
+ # Convert from 1-based current_line_num to 0-based list offset
+ return lines[lineno - 1]
+ except IndexError:
+ return None
def write_repr(self, out, visited):
if self.is_optimized_out():
out.write('(frame information optimized out)')
return
- out.write('Frame 0x%x, for file %s, line %i, in %s ('
+ lineno = self.current_line_num()
+ lineno = str(lineno) if lineno is not None else "?"
+ out.write('Frame 0x%x, for file %s, line %s, in %s ('
% (self.as_address(),
self.co_filename.proxyval(visited),
- self.current_line_num(),
+ lineno,
self.co_name.proxyval(visited)))
first = True
for pyop_name, pyop_value in self.iter_locals():
sys.stdout.write(' (frame information optimized out)\n')
return
visited = set()
- sys.stdout.write(' File "%s", line %i, in %s\n'
+ lineno = self.current_line_num()
+ lineno = str(lineno) if lineno is not None else "?"
+ sys.stdout.write(' File "%s", line %s, in %s\n'
% (self.co_filename.proxyval(visited),
- self.current_line_num(),
+ lineno,
self.co_name.proxyval(visited)))
class PySetObjectPtr(PyObjectPtr):
filename = pyop.filename()
lineno = pyop.current_line_num()
+ if lineno is None:
+ print('Unable to read python frame line number')
+ return
if start is None:
start = lineno - 5
set TARGET=Rebuild\r
set TESTTARGETDIR=\r
set PGO=-m test -q --pgo\r
+set BUILDMSI=1\r
set BUILDNUGET=1\r
set BUILDZIP=1\r
\r
if "%1" EQU "--skip-pgo" (set PGO=) && shift && goto CheckOpts\r
if "%1" EQU "--skip-nuget" (set BUILDNUGET=) && shift && goto CheckOpts\r
if "%1" EQU "--skip-zip" (set BUILDZIP=) && shift && goto CheckOpts\r
+if "%1" EQU "--skip-msi" (set BUILDMSI=) && shift && goto CheckOpts\r
\r
if "%1" NEQ "" echo Invalid option: "%1" && exit /B 1\r
\r
)\r
\r
set BUILDOPTS=/p:Platform=%1 /p:BuildForRelease=true /p:DownloadUrl=%DOWNLOAD_URL% /p:DownloadUrlBase=%DOWNLOAD_URL_BASE% /p:ReleaseUri=%RELEASE_URI%\r
-%MSBUILD% "%D%bundle\releaselocal.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=true\r
-if errorlevel 1 exit /B\r
-%MSBUILD% "%D%bundle\releaseweb.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false\r
-if errorlevel 1 exit /B\r
+if defined BUILDMSI (\r
+ %MSBUILD% "%D%bundle\releaselocal.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=true\r
+ if errorlevel 1 exit /B\r
+ %MSBUILD% "%D%bundle\releaseweb.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false\r
+ if errorlevel 1 exit /B\r
+)\r
\r
if defined BUILDZIP (\r
%MSBUILD% "%D%make_zip.proj" /t:Build %BUILDOPTS% %CERTOPTS% /p:OutputPath="%BUILD%en-us"\r
echo --skip-doc (-D) Do not build documentation\r
echo --pgo Specify PGO command for x64 installers\r
echo --skip-pgo Build x64 installers without using PGO\r
+echo --skip-msi Do not build executable/MSI packages\r
echo --skip-nuget Do not build Nuget packages\r
echo --skip-zip Do not build embeddable package\r
echo --download Specify the full download URL for MSIs\r
<EmbeddedResource Include="*.wxl" />
</ItemGroup>
<ItemGroup>
- <InstallFiles Include="$(PySourcePath)include\*.h">
+ <InstallFiles Include="$(PySourcePath)include\**\*.h">
<SourceBase>$(PySourcePath)</SourceBase>
<Source>!(bindpath.src)</Source>
<TargetBase>$(PySourcePath)</TargetBase>
<Group>dev_include</Group>
</InstallFiles>
</ItemGroup>
-
+
<Target Name="BuildMinGWLib"
Inputs="$(BuildPath)$(PyDllName).dll"
Outputs="$(BuildPath)lib$(PyDllName).a"
</Target>
<Import Project="..\msi.targets" />
-</Project>
\ No newline at end of file
+</Project>
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
- <?define exts=pyexpat;select;unicodedata;winsound;_bz2;_elementtree;_socket;_ssl;_msi;_ctypes;_hashlib;_multiprocessing;_lzma;_decimal;_overlapped;_sqlite3;_asyncio;_queue;_distutils_findvs;_contextvars ?>
+ <?define exts=pyexpat;select;unicodedata;winsound;_bz2;_elementtree;_socket;_ssl;_msi;_ctypes;_hashlib;_multiprocessing;_lzma;_decimal;_overlapped;_sqlite3;_asyncio;_queue;_contextvars ?>
<Fragment>
+ <DirectoryRef Id="Lib_venv_scripts_nt" />
+
<ComponentGroup Id="lib_extensions">
<?foreach ext in $(var.exts)?>
<Component Id="libssl.dll" Directory="DLLs" Guid="*">
<File Name="libssl$(var.ssltag).dll" KeyPath="yes" />
</Component>
+ <Component Id="venvlauncher.exe" Directory="Lib_venv_scripts_nt" Guid="*">
+ <File Name="python.exe" Source="venvlauncher.exe" KeyPath="yes" />
+ </Component>
+ <Component Id="venvwlauncher.exe" Directory="Lib_venv_scripts_nt" Guid="*">
+ <File Name="pythonw.exe" Source="venvwlauncher.exe" KeyPath="yes" />
+ </Component>
</ComponentGroup>
</Fragment>
<Fragment>
+ <!-- The auto-generated directory is not available when building symbols -->
+ <DirectoryRef Id="Lib">
+ <Directory Id="Lib_venv__pdbs" Name="venv">
+ <Directory Id="Lib_venv_scripts__pdbs" Name="scripts">
+ <Directory Id="Lib_venv_scripts_nt__pdbs" Name="nt" />
+ </Directory>
+ </Directory>
+ </DirectoryRef>
+
<ComponentGroup Id="lib_extensions_symbols">
<?foreach ext in $(var.exts)?>
<Component Id="libssl.pdb" Directory="DLLs" Guid="*">
<File Name="libssl$(var.ssltag).pdb" KeyPath="yes" />
</Component>
+ <Component Id="venvlauncher.pdb" Directory="Lib_venv_scripts_nt__pdbs" Guid="*">
+ <File Name="python.pdb" Source="venvlauncher.pdb" KeyPath="yes" />
+ </Component>
+ <Component Id="venvwlauncher.pdb" Directory="Lib_venv_scripts_nt__pdbs" Guid="*">
+ <File Name="pythonw.pdb" Source="venvwlauncher.pdb" KeyPath="yes" />
+ </Component>
</ComponentGroup>
</Fragment>
--- /dev/null
+<#\r
+.Synopsis\r
+ Compiles and signs an APPX package\r
+.Description\r
+ Given the file listing, ensures all the contents are signed\r
+ and builds and signs the final package.\r
+.Parameter mapfile\r
+ The location on disk of the text mapping file.\r
+.Parameter msix\r
+ The path and name to store the APPX/MSIX.\r
+.Parameter sign\r
+ When set, signs the APPX/MSIX. Packages to be published to\r
+ the store should not be signed.\r
+.Parameter description\r
+ Description to embed in the signature (optional).\r
+.Parameter certname\r
+ The name of the certificate to sign with (optional).\r
+.Parameter certsha1\r
+ The SHA1 hash of the certificate to sign with (optional).\r
+#>\r
+param(\r
+ [Parameter(Mandatory=$true)][string]$layout,\r
+ [Parameter(Mandatory=$true)][string]$msix,\r
+ [switch]$sign,\r
+ [string]$description,\r
+ [string]$certname,\r
+ [string]$certsha1,\r
+ [string]$certfile\r
+)\r
+\r
+$tools = $script:MyInvocation.MyCommand.Path | Split-Path -parent;\r
+Import-Module $tools\sdktools.psm1 -WarningAction SilentlyContinue -Force\r
+\r
+Set-Alias makeappx (Find-Tool "makeappx.exe") -Scope Script\r
+Set-Alias makepri (Find-Tool "makepri.exe") -Scope Script\r
+\r
+$msixdir = Split-Path $msix -Parent\r
+if ($msixdir) {\r
+ $msixdir = (mkdir -Force $msixdir).FullName\r
+} else {\r
+ $msixdir = Get-Location\r
+}\r
+$msix = Join-Path $msixdir (Split-Path $msix -Leaf)\r
+\r
+pushd $layout\r
+try {\r
+ if (Test-Path resources.pri) {\r
+ del resources.pri\r
+ }\r
+ $name = ([xml](gc AppxManifest.xml)).Package.Identity.Name\r
+ makepri new /pr . /mn AppxManifest.xml /in $name /cf _resources.xml /of _resources.pri /mf appx /o\r
+ if (-not $? -or -not (Test-Path _resources.map.txt)) {\r
+ throw "makepri step failed"\r
+ }\r
+ $lines = gc _resources.map.txt\r
+ $lines | ?{ -not ($_ -match '"_resources[\w\.]+?"') } | Out-File _resources.map.txt -Encoding utf8\r
+ makeappx pack /f _resources.map.txt /m AppxManifest.xml /o /p $msix\r
+ if (-not $?) {\r
+ throw "makeappx step failed"\r
+ }\r
+} finally {\r
+ popd\r
+}\r
+\r
+if ($sign) {\r
+ Sign-File -certname $certname -certsha1 $certsha1 -certfile $certfile -description $description -files $msix\r
+\r
+ if (-not $?) {\r
+ throw "Package signing failed"\r
+ }\r
+}\r
--- /dev/null
+<#\r
+.Synopsis\r
+ Compiles and signs a catalog file.\r
+.Description\r
+ Given the CDF definition file, builds and signs a catalog.\r
+.Parameter catalog\r
+ The path to the catalog definition file to compile and\r
+ sign. It is assumed that the .cat file will be the same\r
+ name with a new extension.\r
+.Parameter description\r
+ The description to add to the signature (optional).\r
+.Parameter certname\r
+ The name of the certificate to sign with (optional).\r
+.Parameter certsha1\r
+ The SHA1 hash of the certificate to sign with (optional).\r
+#>\r
+param(\r
+ [Parameter(Mandatory=$true)][string]$catalog,\r
+ [string]$description,\r
+ [string]$certname,\r
+ [string]$certsha1,\r
+ [string]$certfile\r
+)\r
+\r
+$tools = $script:MyInvocation.MyCommand.Path | Split-Path -parent;\r
+Import-Module $tools\sdktools.psm1 -WarningAction SilentlyContinue -Force\r
+\r
+Set-Alias MakeCat (Find-Tool "makecat.exe") -Scope Script\r
+\r
+MakeCat $catalog\r
+if (-not $?) {\r
+ throw "Catalog compilation failed"\r
+}\r
+Sign-File -certname $certname -certsha1 $certsha1 -certfile $certfile -description $description -files @($catalog -replace 'cdf$', 'cat')\r
<TargetExt>.zip</TargetExt>\r
<TargetPath>$(OutputPath)\$(TargetName)$(TargetExt)</TargetPath>\r
<CleanCommand>rmdir /q/s "$(IntermediateOutputPath)\zip_$(ArchName)"</CleanCommand>\r
- <Arguments>"$(PythonExe)" "$(MSBuildThisFileDirectory)\make_zip.py"</Arguments>\r
- <Arguments>$(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -b "$(BuildPath.TrimEnd(`\`))"</Arguments>\r
- <Environment>set DOC_FILENAME=python$(PythonVersion).chm</Environment>\r
+ <Arguments>"$(PythonExe)" "$(PySourcePath)PC\layout"</Arguments>\r
+ <Arguments>$(Arguments) -b "$(BuildPath.TrimEnd(`\`))" -s "$(PySourcePath.TrimEnd(`\`))"</Arguments>\r
+ <Arguments>$(Arguments) -t "$(IntermediateOutputPath)\zip_$(ArchName)"</Arguments>\r
+ <Arguments>$(Arguments) --zip "$(TargetPath)"</Arguments>\r
+ <Arguments>$(Arguments) --precompile --zip-lib --include-underpth --include-stable --flat-dlls</Arguments>\r
<Environment>$(Environment)%0D%0Aset PYTHONPATH=$(PySourcePath)Lib</Environment>\r
- <Environment Condition="Exists($(CRTRedist))">$(Environment)%0D%0Aset VCREDIST_PATH=$(CRTRedist)\$(Platform)</Environment>\r
</PropertyGroup>\r
\r
<Target Name="_Build">\r
+++ /dev/null
-import argparse
-import py_compile
-import re
-import sys
-import shutil
-import stat
-import os
-import tempfile
-
-from itertools import chain
-from pathlib import Path
-from zipfile import ZipFile, ZIP_DEFLATED
-
-
-TKTCL_RE = re.compile(r'^(_?tk|tcl).+\.(pyd|dll)', re.IGNORECASE)
-DEBUG_RE = re.compile(r'_d\.(pyd|dll|exe|pdb|lib)$', re.IGNORECASE)
-PYTHON_DLL_RE = re.compile(r'python\d\d?\.dll$', re.IGNORECASE)
-
-DEBUG_FILES = {
- '_ctypes_test',
- '_testbuffer',
- '_testcapi',
- '_testconsole',
- '_testimportmultiple',
- '_testmultiphase',
- 'xxlimited',
- 'python3_dstub',
-}
-
-EXCLUDE_FROM_LIBRARY = {
- '__pycache__',
- 'idlelib',
- 'pydoc_data',
- 'site-packages',
- 'tkinter',
- 'turtledemo',
-}
-
-EXCLUDE_FROM_EMBEDDABLE_LIBRARY = {
- 'ensurepip',
- 'venv',
-}
-
-EXCLUDE_FILE_FROM_LIBRARY = {
- 'bdist_wininst.py',
-}
-
-EXCLUDE_FILE_FROM_LIBS = {
- 'liblzma',
- 'python3stub',
-}
-
-EXCLUDED_FILES = {
- 'pyshellext',
-}
-
-def is_not_debug(p):
- if DEBUG_RE.search(p.name):
- return False
-
- if TKTCL_RE.search(p.name):
- return False
-
- return p.stem.lower() not in DEBUG_FILES and p.stem.lower() not in EXCLUDED_FILES
-
-def is_not_debug_or_python(p):
- return is_not_debug(p) and not PYTHON_DLL_RE.search(p.name)
-
-def include_in_lib(p):
- name = p.name.lower()
- if p.is_dir():
- if name in EXCLUDE_FROM_LIBRARY:
- return False
- if name == 'test' and p.parts[-2].lower() == 'lib':
- return False
- if name in {'test', 'tests'} and p.parts[-3].lower() == 'lib':
- return False
- return True
-
- if name in EXCLUDE_FILE_FROM_LIBRARY:
- return False
-
- suffix = p.suffix.lower()
- return suffix not in {'.pyc', '.pyo', '.exe'}
-
-def include_in_embeddable_lib(p):
- if p.is_dir() and p.name.lower() in EXCLUDE_FROM_EMBEDDABLE_LIBRARY:
- return False
-
- return include_in_lib(p)
-
-def include_in_libs(p):
- if not is_not_debug(p):
- return False
-
- return p.stem.lower() not in EXCLUDE_FILE_FROM_LIBS
-
-def include_in_tools(p):
- if p.is_dir() and p.name.lower() in {'scripts', 'i18n', 'pynche', 'demo', 'parser'}:
- return True
-
- return p.suffix.lower() in {'.py', '.pyw', '.txt'}
-
-BASE_NAME = 'python{0.major}{0.minor}'.format(sys.version_info)
-
-FULL_LAYOUT = [
- ('/', '$build', 'python.exe', is_not_debug),
- ('/', '$build', 'pythonw.exe', is_not_debug),
- ('/', '$build', 'python{}.dll'.format(sys.version_info.major), is_not_debug),
- ('/', '$build', '{}.dll'.format(BASE_NAME), is_not_debug),
- ('DLLs/', '$build', '*.pyd', is_not_debug),
- ('DLLs/', '$build', '*.dll', is_not_debug_or_python),
- ('include/', 'include', '*.h', None),
- ('include/', 'PC', 'pyconfig.h', None),
- ('Lib/', 'Lib', '**/*', include_in_lib),
- ('libs/', '$build', '*.lib', include_in_libs),
- ('Tools/', 'Tools', '**/*', include_in_tools),
-]
-
-EMBED_LAYOUT = [
- ('/', '$build', 'python*.exe', is_not_debug),
- ('/', '$build', '*.pyd', is_not_debug),
- ('/', '$build', '*.dll', is_not_debug),
- ('{}.zip'.format(BASE_NAME), 'Lib', '**/*', include_in_embeddable_lib),
-]
-
-if os.getenv('DOC_FILENAME'):
- FULL_LAYOUT.append(('Doc/', 'Doc/build/htmlhelp', os.getenv('DOC_FILENAME'), None))
-if os.getenv('VCREDIST_PATH'):
- FULL_LAYOUT.append(('/', os.getenv('VCREDIST_PATH'), 'vcruntime*.dll', None))
- EMBED_LAYOUT.append(('/', os.getenv('VCREDIST_PATH'), 'vcruntime*.dll', None))
-
-def copy_to_layout(target, rel_sources):
- count = 0
-
- if target.suffix.lower() == '.zip':
- if target.exists():
- target.unlink()
-
- with ZipFile(str(target), 'w', ZIP_DEFLATED) as f:
- with tempfile.TemporaryDirectory() as tmpdir:
- for s, rel in rel_sources:
- if rel.suffix.lower() == '.py':
- pyc = Path(tmpdir) / rel.with_suffix('.pyc').name
- try:
- py_compile.compile(str(s), str(pyc), str(rel), doraise=True, optimize=2)
- except py_compile.PyCompileError:
- f.write(str(s), str(rel))
- else:
- f.write(str(pyc), str(rel.with_suffix('.pyc')))
- else:
- f.write(str(s), str(rel))
- count += 1
-
- else:
- for s, rel in rel_sources:
- dest = target / rel
- try:
- dest.parent.mkdir(parents=True)
- except FileExistsError:
- pass
- if dest.is_file():
- dest.chmod(stat.S_IWRITE)
- shutil.copy(str(s), str(dest))
- if dest.is_file():
- dest.chmod(stat.S_IWRITE)
- count += 1
-
- return count
-
-def rglob(root, pattern, condition):
- dirs = [root]
- recurse = pattern[:3] in {'**/', '**\\'}
- while dirs:
- d = dirs.pop(0)
- for f in d.glob(pattern[3:] if recurse else pattern):
- if recurse and f.is_dir() and (not condition or condition(f)):
- dirs.append(f)
- elif f.is_file() and (not condition or condition(f)):
- yield f, f.relative_to(root)
-
-def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('-s', '--source', metavar='dir', help='The directory containing the repository root', type=Path)
- parser.add_argument('-o', '--out', metavar='file', help='The name of the output archive', type=Path, default=None)
- parser.add_argument('-t', '--temp', metavar='dir', help='A directory to temporarily extract files into', type=Path, default=None)
- parser.add_argument('-e', '--embed', help='Create an embedding layout', action='store_true', default=False)
- parser.add_argument('-b', '--build', help='Specify the build directory', type=Path, default=None)
- ns = parser.parse_args()
-
- source = ns.source or (Path(__file__).resolve().parent.parent.parent)
- out = ns.out
- build = ns.build or Path(sys.exec_prefix)
- assert isinstance(source, Path)
- assert not out or isinstance(out, Path)
- assert isinstance(build, Path)
-
- if ns.temp:
- temp = ns.temp
- delete_temp = False
- else:
- temp = Path(tempfile.mkdtemp())
- delete_temp = True
-
- if out:
- try:
- out.parent.mkdir(parents=True)
- except FileExistsError:
- pass
- try:
- temp.mkdir(parents=True)
- except FileExistsError:
- pass
-
- layout = EMBED_LAYOUT if ns.embed else FULL_LAYOUT
-
- try:
- for t, s, p, c in layout:
- if s == '$build':
- fs = build
- else:
- fs = source / s
- files = rglob(fs, p, c)
- extra_files = []
- if s == 'Lib' and p == '**/*':
- extra_files.append((
- source / 'tools' / 'msi' / 'distutils.command.bdist_wininst.py',
- Path('distutils') / 'command' / 'bdist_wininst.py'
- ))
- copied = copy_to_layout(temp / t.rstrip('/'), chain(files, extra_files))
- print('Copied {} files'.format(copied))
-
- if ns.embed:
- with open(str(temp / (BASE_NAME + '._pth')), 'w') as f:
- print(BASE_NAME + '.zip', file=f)
- print('.', file=f)
- print('', file=f)
- print('# Uncomment to run site.main() automatically', file=f)
- print('#import site', file=f)
-
- if out:
- total = copy_to_layout(out, rglob(temp, '**/*', None))
- print('Wrote {} files to {}'.format(total, out))
- finally:
- if delete_temp:
- shutil.rmtree(temp, True)
-
-
-if __name__ == "__main__":
- sys.exit(int(main() or 0))
--- /dev/null
+function Find-Tool {
+ param([string]$toolname)
+
+ $kitroot = (gp 'HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots\').KitsRoot10
+ $tool = (gci -r "$kitroot\Bin\*\x64\$toolname" | sort FullName -Desc | select -First 1)
+ if (-not $tool) {
+ throw "$toolname is not available"
+ }
+ Write-Host "Found $toolname at $($tool.FullName)"
+ return $tool.FullName
+}
+
+Set-Alias SignTool (Find-Tool "signtool.exe") -Scope Script
+
+function Sign-File {
+ param([string]$certname, [string]$certsha1, [string]$certfile, [string]$description, [string[]]$files)
+
+ if (-not $description) {
+ $description = $env:SigningDescription;
+ if (-not $description) {
+ $description = "Python";
+ }
+ }
+ if (-not $certname) {
+ $certname = $env:SigningCertificate;
+ }
+ if (-not $certfile) {
+ $certfile = $env:SigningCertificateFile;
+ }
+
+ foreach ($a in $files) {
+ if ($certsha1) {
+ SignTool sign /sha1 $certsha1 /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d $description $a
+ } elseif ($certname) {
+ SignTool sign /n $certname /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d $description $a
+ } elseif ($certfile) {
+ SignTool sign /f $certfile /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d $description $a
+ } else {
+ SignTool sign /a /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d $description $a
+ }
+ }
+}
+
--- /dev/null
+<#\r
+.Synopsis\r
+ Recursively signs the contents of a directory.\r
+.Description\r
+ Given the file patterns, code signs the contents.\r
+.Parameter root\r
+ The root directory to sign.\r
+.Parameter patterns\r
+ The file patterns to sign\r
+.Parameter description\r
+ The description to add to the signature (optional).\r
+.Parameter certname\r
+ The name of the certificate to sign with (optional).\r
+.Parameter certsha1\r
+ The SHA1 hash of the certificate to sign with (optional).\r
+#>\r
+param(\r
+ [Parameter(Mandatory=$true)][string]$root,\r
+ [string[]]$patterns=@("*.exe", "*.dll", "*.pyd"),\r
+ [string]$description,\r
+ [string]$certname,\r
+ [string]$certsha1,\r
+ [string]$certfile\r
+)\r
+\r
+$tools = $script:MyInvocation.MyCommand.Path | Split-Path -parent;\r
+Import-Module $tools\sdktools.psm1 -WarningAction SilentlyContinue -Force\r
+\r
+pushd $root\r
+try {\r
+ Sign-File -certname $certname -certsha1 $certsha1 -certfile $certfile -description $description -files (gci -r $patterns)\r
+} finally {\r
+ popd\r
+}
\ No newline at end of file
<SignOutput>false</SignOutput>\r
<TargetName>$(OutputName).$(NuspecVersion)</TargetName>\r
<TargetExt>.nupkg</TargetExt>\r
- <IntermediateOutputPath>$(IntermediateOutputPath)\nuget_$(ArchName)</IntermediateOutputPath>\r
+ <IntermediateOutputPath>$(IntermediateOutputPath)\nuget_$(ArchName)\</IntermediateOutputPath>\r
\r
- <CleanCommand>rmdir /q/s "$(IntermediateOutputPath)"</CleanCommand>\r
+ <CleanCommand>rmdir /q/s "$(IntermediateOutputPath.TrimEnd(`\`))"</CleanCommand>\r
\r
- <PythonArguments>"$(PythonExe)" "$(MSBuildThisFileDirectory)\..\msi\make_zip.py"</PythonArguments>\r
- <PythonArguments>$(PythonArguments) -t "$(IntermediateOutputPath)" -b "$(BuildPath.TrimEnd(`\`))"</PythonArguments>\r
+ <PythonArguments>"$(PythonExe)" "$(PySourcePath)PC\layout"</PythonArguments>\r
+ <PythonArguments>$(PythonArguments) -b "$(BuildPath.TrimEnd(`\`))" -s "$(PySourcePath.TrimEnd(`\`))"</PythonArguments>\r
+ <PythonArguments>$(PythonArguments) -t "$(IntermediateOutputPath)obj"</PythonArguments>\r
+ <PythonArguments>$(PythonArguments) --copy "$(IntermediateOutputPath)pkg"</PythonArguments>\r
+ <PythonArguments>$(PythonArguments) --include-dev --include-tools --include-pip --include-stable --include-launcher --include-props</PythonArguments>\r
\r
- <PipArguments>"$(IntermediateOutputPath)\python.exe" -B -c "import sys; sys.path.append(r'$(PySourcePath)\Lib'); import ensurepip; ensurepip._main()"</PipArguments>\r
- <PackageArguments Condition="$(Packages) != ''">"$(IntermediateOutputPath)\python.exe" -B -m pip install -U $(Packages)</PackageArguments>\r
+ <PackageArguments Condition="$(Packages) != ''">"$(IntermediateOutputPath)pkg\pip.exe" -B -m pip install -U $(Packages)</PackageArguments>\r
\r
- <NugetPackCommand>"$(Nuget)" pack "$(MSBuildThisFileDirectory)\$(OutputName).nuspec" -BasePath "$(IntermediateOutputPath)"</NugetPackCommand>\r
+ <NugetPackCommand>"$(Nuget)" pack "$(MSBuildThisFileDirectory)\$(OutputName).nuspec" -BasePath "$(IntermediateOutputPath)pkg"</NugetPackCommand>\r
<NugetPackSymbolsCommand Condition="Exists('$(MSBuildThisFileDirectory)\$(OutputName).symbols.nuspec')">"$(Nuget)" pack "$(MSBuildThisFileDirectory)\$(OutputName).symbols.nuspec" -BasePath "$(BuildPath.TrimEnd(`\`))"</NugetPackSymbolsCommand>\r
<NugetArguments>$(NugetArguments) -OutputDirectory "$(OutputPath.Trim(`\`))"</NugetArguments>\r
<NugetArguments>$(NugetArguments) -Version "$(NuspecVersion)"</NugetArguments>\r
<NugetArguments>$(NugetArguments) -NoPackageAnalysis -NonInteractive</NugetArguments>\r
\r
- <Environment>set DOC_FILENAME=python$(PythonVersion).chm</Environment>\r
<Environment>$(Environment)%0D%0Aset PYTHONPATH=$(PySourcePath)Lib</Environment>\r
- <Environment Condition="Exists($(CRTRedist))">$(Environment)%0D%0Aset VCREDIST_PATH=$(CRTRedist)\$(Platform)</Environment>\r
+ <Environment>$(Environment)%0D%0Aset PYTHON_NUSPEC_VERSION=$(NuspecVersion)</Environment>\r
+ <Environment Condition="$(Platform) != 'x86'">$(Environment)%0D%0Aset PYTHON_PROPS_PLATFORM=$(Platform)</Environment>\r
+ <Environment Condition="$(Platform) == 'x86'">$(Environment)%0D%0Aset PYTHON_PROPS_PLATFORM=Win32</Environment>\r
<Environment>$(Environment)%0D%0Amkdir "$(OutputPath.Trim(`\`))" >nul 2>nul</Environment>\r
</PropertyGroup>\r
\r
\r
<Target Name="_Build">\r
<Exec Command="$(CleanCommand)" />\r
- <Exec Command="setlocal%0D%0A$(Environment)%0D%0A$(PythonArguments)" />\r
- <Exec Command="$(PipArguments)" />\r
- <Exec Command="$(PackageArguments)" Condition="$(PackageArguments) != ''" />\r
-\r
- <PropertyGroup>\r
- <_PropsContents>$([System.IO.File]::ReadAllText('python.props'))</_PropsContents>\r
- <_PropsContents>$(_PropsContents.Replace('$$PYTHON_TAG$$', '$(MajorVersionNumber).$(MinorVersionNumber)'))</_PropsContents>\r
- <_PropsContents>$(_PropsContents.Replace('$$PYTHON_VERSION$$', '$(NuspecVersion)'))</_PropsContents>\r
- <_PropsContents Condition="$(Platform) == 'x86'">$(_PropsContents.Replace('$$PYTHON_PLATFORM$$', 'Win32'))</_PropsContents>\r
- <_PropsContents Condition="$(Platform) != 'x86'">$(_PropsContents.Replace('$$PYTHON_PLATFORM$$', '$(Platform)'))</_PropsContents>\r
- <_PropsContents>$(_PropsContents.Replace('$$PYTHON_TARGET$$', '_GetPythonRuntimeFilesDependsOn$(MajorVersionNumber)$(MinorVersionNumber)_$(Platform)'))</_PropsContents>\r
- <_ExistingContents Condition="Exists('$(IntermediateOutputPath)\python.props')">$([System.IO.File]::ReadAllText('$(IntermediateOutputPath)\python.props'))</_ExistingContents>\r
- </PropertyGroup>\r
- <WriteLinesToFile File="$(IntermediateOutputPath)\python.props"\r
- Lines="$(_PropsContents)"\r
- Condition="$(_PropsContents) != $(_ExistingContents)" />\r
+ <Exec Command="setlocal%0D%0A$(Environment)%0D%0A$(PythonArguments)%0D%0A$(PackageArguments)" />\r
\r
<Exec Command="$(NugetPackCommand) $(NugetArguments)" />\r
<Exec Command="$(NugetPackSymbolsCommand) $(NugetArguments)" Condition="$(NugetPackSymbolsCommand) != ''" />\r
"""Get the symbolic name for the current git branch"""
cmd = "git rev-parse --abbrev-ref HEAD".split()
try:
- return subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
+ return subprocess.check_output(cmd,
+ stderr=subprocess.DEVNULL,
+ cwd=SRCDIR)
except subprocess.CalledProcessError:
return None
"""
cmd = "git remote get-url upstream".split()
try:
- subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
+ subprocess.check_output(cmd,
+ stderr=subprocess.DEVNULL,
+ cwd=SRCDIR)
except subprocess.CalledProcessError:
return "origin"
return "upstream"
else:
cmd = 'git status --porcelain'
filenames = []
- with subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) as st:
+ with subprocess.Popen(cmd.split(),
+ stdout=subprocess.PIPE,
+ cwd=SRCDIR) as st:
for line in st.stdout:
line = line.decode().rstrip()
status_text, filename = line.split(maxsplit=1)
print('<!-- This file defines the table of contents -->', file=fp)
print('<HTML>', file=fp)
print('<HEAD>', file=fp)
- print('<meta name="GENERATOR"'
+ print('<meta name="GENERATOR" '
'content="Microsoft® HTML Help Workshop 4.1">', file=fp)
print('<!-- Sitemap 1.0 -->', file=fp)
print('</HEAD>', file=fp)
print('<!-- This file defines the index -->', file=fp)
print('<HTML>', file=fp)
print('<HEAD>', file=fp)
- print('<meta name="GENERATOR"'
+ print('<meta name="GENERATOR" '
'content="Microsoft® HTML Help Workshop 4.1">', file=fp)
print('<!-- Sitemap 1.0 -->', file=fp)
print('</HEAD>', file=fp)
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
-dnl serial 11 (pkg-config-0.29.1)
+dnl serial 11 (pkg-config-0.29)
dnl
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require.
m4_defun([PKG_PREREQ],
-[m4_define([PKG_MACROS_VERSION], [0.29.1])
+[m4_define([PKG_MACROS_VERSION], [0.29])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ
LIBTOOL_CRUFT
OTHER_LIBTOOL_OPT
UNIVERSAL_ARCH_FLAGS
+LDFLAGS_NODIST
CFLAGS_NODIST
BASECFLAGS
CFLAGS_ALIASING
OPT
LLVM_PROF_FOUND
-target_os
-target_vendor
-target_cpu
-target
LLVM_PROFDATA
LLVM_PROF_ERR
LLVM_PROF_FILE
LLVM_PROF_MERGER
PGO_PROF_USE_FLAG
PGO_PROF_GEN_FLAG
+LLVM_AR_FOUND
+target_os
+target_vendor
+target_cpu
+target
+LLVM_AR
DEF_MAKE_RULE
DEF_MAKE_ALL_RULE
ABIFLAGS
with_lto
with_hash_algorithm
with_address_sanitizer
+with_memory_sanitizer
+with_undefined_behavior_sanitizer
with_libs
with_system_expat
with_system_ffi
--with-hash-algorithm=[fnv|siphash24]
select hash algorithm
--with-address-sanitizer
- enable AddressSanitizer
+ enable AddressSanitizer (asan)
+ --with-memory-sanitizer enable MemorySanitizer (msan)
+ --with-undefined-behavior-sanitizer
+ enable UndefinedBehaviorSanitizer (ubsan)
--with-libs='lib1 ...' link against additional libs
--with-system-expat build pyexpat module using an installed expat
library
DEF_MAKE_RULE="all"
fi
+# Make llvm-relatec checks work on systems where llvm tools are not installed with their
+# normal names in the default $PATH (ie: Ubuntu). They exist under the
+# non-suffixed name in their versioned llvm directory.
+
+llvm_bin_dir=''
+llvm_path="${PATH}"
+if test "${CC}" = "clang"
+then
+ clang_bin=`which clang`
+ # Some systems install clang elsewhere as a symlink to the real path
+ # which is where the related llvm tools are located.
+ if test -L "${clang_bin}"
+ then
+ clang_dir=`dirname "${clang_bin}"`
+ clang_bin=`readlink "${clang_bin}"`
+ llvm_bin_dir="${clang_dir}/"`dirname "${clang_bin}"`
+ llvm_path="${llvm_path}${PATH_SEPARATOR}${llvm_bin_dir}"
+ fi
+fi
+
# Enable LTO flags
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-lto" >&5
$as_echo_n "checking for --with-lto... " >&6; }
if test "$Py_LTO" = 'true' ; then
case $CC in
*clang*)
- case $ac_sys_system in
- Darwin*)
- # Any changes made here should be reflected in the GCC+Darwin case below
- LTOFLAGS="-flto -Wl,-export_dynamic"
- ;;
- *)
- LTOFLAGS="-flto"
- ;;
- esac
- ;;
- *gcc*)
- case $ac_sys_system in
- Darwin*)
- LTOFLAGS="-flto -Wl,-export_dynamic"
- ;;
- *)
- LTOFLAGS="-flto -fuse-linker-plugin -ffat-lto-objects -flto-partition=none"
- ;;
- esac
- ;;
- esac
-
- if test "$ac_cv_prog_cc_g" = "yes"
- then
- # bpo-30345: Add -g to LDFLAGS when compiling with LTO
- # to get debug symbols.
- LTOFLAGS="$LTOFLAGS -g"
- fi
-
- CFLAGS="$CFLAGS $LTOFLAGS"
- LDFLAGS="$LDFLAGS $LTOFLAGS"
-fi
-
-# Enable PGO flags.
-
-
-
-
-
-# Make this work on systems where llvm tools are not installed with their
-# normal names in the default $PATH (ie: Ubuntu). They exist under the
-# non-suffixed name in their versioned llvm directory.
-llvm_bin_dir=''
-llvm_path="${PATH}"
-if test "${CC}" = "clang"
-then
- clang_bin=`which clang`
- # Some systems install clang elsewhere as a symlink to the real path
- # which is where the related llvm tools are located.
- if test -L "${clang_bin}"
- then
- clang_dir=`dirname "${clang_bin}"`
- clang_bin=`readlink "${clang_bin}"`
- llvm_bin_dir="${clang_dir}/"`dirname "${clang_bin}"`
- llvm_path="${llvm_path}${PATH_SEPARATOR}${llvm_bin_dir}"
- fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
$as_echo_n "checking target system type... " >&6; }
if ${ac_cv_target+:} false; then :
$as_echo_n "(cached) " >&6
test "$program_prefix$program_suffix$program_transform_name" = \
NONENONEs,x,x, &&
program_prefix=${target_alias}-
+# Extract the first word of "$target_alias-llvm-ar", so it can be a program name with args.
+set dummy $target_alias-llvm-ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_LLVM_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $LLVM_AR in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_LLVM_AR="$LLVM_AR" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in ${llvm_path}
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_LLVM_AR="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+LLVM_AR=$ac_cv_path_LLVM_AR
+if test -n "$LLVM_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LLVM_AR" >&5
+$as_echo "$LLVM_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+if test -z "$ac_cv_path_LLVM_AR"; then
+ if test "$build" = "$target"; then
+ ac_pt_LLVM_AR=$LLVM_AR
+ # Extract the first word of "llvm-ar", so it can be a program name with args.
+set dummy llvm-ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_LLVM_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $ac_pt_LLVM_AR in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_LLVM_AR="$ac_pt_LLVM_AR" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in ${llvm_path}
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_LLVM_AR="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_ac_pt_LLVM_AR" && ac_cv_path_ac_pt_LLVM_AR="''"
+ ;;
+esac
+fi
+ac_pt_LLVM_AR=$ac_cv_path_ac_pt_LLVM_AR
+if test -n "$ac_pt_LLVM_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LLVM_AR" >&5
+$as_echo "$ac_pt_LLVM_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ LLVM_AR=$ac_pt_LLVM_AR
+ else
+ LLVM_AR="''"
+ fi
+else
+ LLVM_AR="$ac_cv_path_LLVM_AR"
+fi
+
+
+ if test -n "${LLVM_AR}" -a -x "${LLVM_AR}"
+ then
+ LLVM_AR_FOUND="found"
+ else
+ LLVM_AR_FOUND="not-found"
+ fi
+ if test "$ac_sys_system" = "Darwin" -a "${LLVM_AR_FOUND}" = "not-found"
+ then
+ found_llvm_ar=`/usr/bin/xcrun -find llvm-ar 2>/dev/null`
+ if test -n "${found_llvm_ar}"
+ then
+ LLVM_AR='/usr/bin/xcrun llvm-ar'
+ LLVM_AR_FOUND=found
+ { $as_echo "$as_me:${as_lineno-$LINENO}: llvm-ar found via xcrun: ${LLVM_AR}" >&5
+$as_echo "$as_me: llvm-ar found via xcrun: ${LLVM_AR}" >&6;}
+ fi
+ fi
+ if test $LLVM_AR_FOUND = not-found
+ then
+ LLVM_PROFR_ERR=yes
+ as_fn_error $? "llvm-ar is required for a --with-lto build with clang but could not be found." "$LINENO" 5
+ else
+ LLVM_AR_ERR=no
+ fi
+ AR="${LLVM_AR}"
+ case $ac_sys_system in
+ Darwin*)
+ # Any changes made here should be reflected in the GCC+Darwin case below
+ LTOFLAGS="-flto -Wl,-export_dynamic"
+ ;;
+ *)
+ LTOFLAGS="-flto"
+ ;;
+ esac
+ ;;
+ *gcc*)
+ case $ac_sys_system in
+ Darwin*)
+ LTOFLAGS="-flto -Wl,-export_dynamic"
+ ;;
+ *)
+ LTOFLAGS="-flto -fuse-linker-plugin -ffat-lto-objects -flto-partition=none"
+ ;;
+ esac
+ ;;
+ esac
+
+ if test "$ac_cv_prog_cc_g" = "yes"
+ then
+ # bpo-30345: Add -g to LDFLAGS when compiling with LTO
+ # to get debug symbols.
+ LTOFLAGS="$LTOFLAGS -g"
+ fi
+
+ CFLAGS_NODIST="$CFLAGS_NODIST $LTOFLAGS"
+ LDFLAGS_NODIST="$LDFLAGS_NODIST $LTOFLAGS"
+fi
+
+# Enable PGO flags.
+
+
+
+
+
+
# Extract the first word of "$target_alias-llvm-profdata", so it can be a program name with args.
set dummy $target_alias-llvm-profdata; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+
# The -arch flags for universal builds on OSX
UNIVERSAL_ARCH_FLAGS=
$as_echo "$withval" >&6; }
BASECFLAGS="-fsanitize=address -fno-omit-frame-pointer $BASECFLAGS"
LDFLAGS="-fsanitize=address $LDFLAGS"
+# ASan works by controlling memory allocation, our own malloc interferes.
+with_pymalloc="no"
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-memory-sanitizer" >&5
+$as_echo_n "checking for --with-memory-sanitizer... " >&6; }
+
+# Check whether --with-memory_sanitizer was given.
+if test "${with_memory_sanitizer+set}" = set; then :
+ withval=$with_memory_sanitizer;
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5
+$as_echo "$withval" >&6; }
+BASECFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer $BASECFLAGS"
+LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 $LDFLAGS"
+# MSan works by controlling memory allocation, our own malloc interferes.
+with_pymalloc="no"
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-undefined-behavior-sanitizer" >&5
+$as_echo_n "checking for --with-undefined-behavior-sanitizer... " >&6; }
+
+# Check whether --with-undefined_behavior_sanitizer was given.
+if test "${with_undefined_behavior_sanitizer+set}" = set; then :
+ withval=$with_undefined_behavior_sanitizer;
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5
+$as_echo "$withval" >&6; }
+BASECFLAGS="-fsanitize=undefined $BASECFLAGS"
+LDFLAGS="-fsanitize=undefined $LDFLAGS"
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
DEF_MAKE_RULE="all"
fi
+# Make llvm-relatec checks work on systems where llvm tools are not installed with their
+# normal names in the default $PATH (ie: Ubuntu). They exist under the
+# non-suffixed name in their versioned llvm directory.
+
+llvm_bin_dir=''
+llvm_path="${PATH}"
+if test "${CC}" = "clang"
+then
+ clang_bin=`which clang`
+ # Some systems install clang elsewhere as a symlink to the real path
+ # which is where the related llvm tools are located.
+ if test -L "${clang_bin}"
+ then
+ clang_dir=`dirname "${clang_bin}"`
+ clang_bin=`readlink "${clang_bin}"`
+ llvm_bin_dir="${clang_dir}/"`dirname "${clang_bin}"`
+ llvm_path="${llvm_path}${PATH_SEPARATOR}${llvm_bin_dir}"
+ fi
+fi
+
# Enable LTO flags
AC_MSG_CHECKING(for --with-lto)
AC_ARG_WITH(lto, AS_HELP_STRING([--with-lto], [Enable Link Time Optimization in any build. Disabled by default.]),
if test "$Py_LTO" = 'true' ; then
case $CC in
*clang*)
+ AC_SUBST(LLVM_AR)
+ AC_PATH_TARGET_TOOL(LLVM_AR, llvm-ar, '', ${llvm_path})
+ AC_SUBST(LLVM_AR_FOUND)
+ if test -n "${LLVM_AR}" -a -x "${LLVM_AR}"
+ then
+ LLVM_AR_FOUND="found"
+ else
+ LLVM_AR_FOUND="not-found"
+ fi
+ if test "$ac_sys_system" = "Darwin" -a "${LLVM_AR_FOUND}" = "not-found"
+ then
+ found_llvm_ar=`/usr/bin/xcrun -find llvm-ar 2>/dev/null`
+ if test -n "${found_llvm_ar}"
+ then
+ LLVM_AR='/usr/bin/xcrun llvm-ar'
+ LLVM_AR_FOUND=found
+ AC_MSG_NOTICE([llvm-ar found via xcrun: ${LLVM_AR}])
+ fi
+ fi
+ if test $LLVM_AR_FOUND = not-found
+ then
+ LLVM_PROFR_ERR=yes
+ AC_MSG_ERROR([llvm-ar is required for a --with-lto build with clang but could not be found.])
+ else
+ LLVM_AR_ERR=no
+ fi
+ AR="${LLVM_AR}"
case $ac_sys_system in
Darwin*)
# Any changes made here should be reflected in the GCC+Darwin case below
LTOFLAGS="$LTOFLAGS -g"
fi
- CFLAGS="$CFLAGS $LTOFLAGS"
- LDFLAGS="$LDFLAGS $LTOFLAGS"
+ CFLAGS_NODIST="$CFLAGS_NODIST $LTOFLAGS"
+ LDFLAGS_NODIST="$LDFLAGS_NODIST $LTOFLAGS"
fi
# Enable PGO flags.
AC_SUBST(LLVM_PROF_MERGER)
AC_SUBST(LLVM_PROF_FILE)
AC_SUBST(LLVM_PROF_ERR)
-# Make this work on systems where llvm tools are not installed with their
-# normal names in the default $PATH (ie: Ubuntu). They exist under the
-# non-suffixed name in their versioned llvm directory.
-llvm_bin_dir=''
-llvm_path="${PATH}"
-if test "${CC}" = "clang"
-then
- clang_bin=`which clang`
- # Some systems install clang elsewhere as a symlink to the real path
- # which is where the related llvm tools are located.
- if test -L "${clang_bin}"
- then
- clang_dir=`dirname "${clang_bin}"`
- clang_bin=`readlink "${clang_bin}"`
- llvm_bin_dir="${clang_dir}/"`dirname "${clang_bin}"`
- llvm_path="${llvm_path}${PATH_SEPARATOR}${llvm_bin_dir}"
- fi
-fi
AC_SUBST(LLVM_PROFDATA)
AC_PATH_TARGET_TOOL(LLVM_PROFDATA, llvm-profdata, '', ${llvm_path})
AC_SUBST(LLVM_PROF_FOUND)
AC_SUBST(BASECFLAGS)
AC_SUBST(CFLAGS_NODIST)
+AC_SUBST(LDFLAGS_NODIST)
# The -arch flags for universal builds on OSX
UNIVERSAL_ARCH_FLAGS=
AC_MSG_CHECKING(for --with-address-sanitizer)
AC_ARG_WITH(address_sanitizer,
AS_HELP_STRING([--with-address-sanitizer],
- [enable AddressSanitizer]),
+ [enable AddressSanitizer (asan)]),
[
AC_MSG_RESULT($withval)
BASECFLAGS="-fsanitize=address -fno-omit-frame-pointer $BASECFLAGS"
LDFLAGS="-fsanitize=address $LDFLAGS"
+# ASan works by controlling memory allocation, our own malloc interferes.
+with_pymalloc="no"
+],
+[AC_MSG_RESULT(no)])
+
+AC_MSG_CHECKING(for --with-memory-sanitizer)
+AC_ARG_WITH(memory_sanitizer,
+ AS_HELP_STRING([--with-memory-sanitizer],
+ [enable MemorySanitizer (msan)]),
+[
+AC_MSG_RESULT($withval)
+BASECFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer $BASECFLAGS"
+LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 $LDFLAGS"
+# MSan works by controlling memory allocation, our own malloc interferes.
+with_pymalloc="no"
+],
+[AC_MSG_RESULT(no)])
+
+AC_MSG_CHECKING(for --with-undefined-behavior-sanitizer)
+AC_ARG_WITH(undefined_behavior_sanitizer,
+ AS_HELP_STRING([--with-undefined-behavior-sanitizer],
+ [enable UndefinedBehaviorSanitizer (ubsan)]),
+[
+AC_MSG_RESULT($withval)
+BASECFLAGS="-fsanitize=undefined $BASECFLAGS"
+LDFLAGS="-fsanitize=undefined $LDFLAGS"
],
[AC_MSG_RESULT(no)])
cross_compiling = "_PYTHON_HOST_PLATFORM" in os.environ
-# Add special CFLAGS reserved for building the interpreter and the stdlib
-# modules (Issue #21121).
-cflags = sysconfig.get_config_var('CFLAGS')
-py_cflags_nodist = sysconfig.get_config_var('PY_CFLAGS_NODIST')
-sysconfig.get_config_vars()['CFLAGS'] = cflags + ' ' + py_cflags_nodist
+# Set common compiler and linker flags derived from the Makefile,
+# reserved for building the interpreter and the stdlib modules.
+# See bpo-21121 and bpo-35257
+def set_compiler_flags(compiler_flags, compiler_py_flags_nodist):
+ flags = sysconfig.get_config_var(compiler_flags)
+ py_flags_nodist = sysconfig.get_config_var(compiler_py_flags_nodist)
+ sysconfig.get_config_vars()[compiler_flags] = flags + ' ' + py_flags_nodist
+
+set_compiler_flags('CFLAGS', 'PY_CFLAGS_NODIST')
+set_compiler_flags('LDFLAGS', 'PY_LDFLAGS_NODIST')
class Dummy:
"""Hack for parallel build"""