Merge branch 'main' into unicode-passwords-smtplib

This commit is contained in:
Oleg Iarygin 2023-04-25 14:55:53 +04:00 committed by GitHub
commit 5d870db7ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
272 changed files with 15699 additions and 9070 deletions

View file

@ -9,8 +9,8 @@ ENV WASMTIME_HOME=/opt/wasmtime
ENV WASMTIME_VERSION=7.0.0
ENV WASMTIME_CPU_ARCH=x86_64
RUN dnf -y --nodocs install git clang xz python3-blurb dnf-plugins-core && \
dnf -y --nodocs builddep python3 && \
RUN dnf -y --nodocs --setopt=install_weak_deps=False install /usr/bin/{blurb,clang,curl,git,ln,tar,xz} 'dnf-command(builddep)' && \
dnf -y --nodocs --setopt=install_weak_deps=False builddep python3 && \
dnf -y clean all
RUN mkdir ${WASI_SDK_PATH} && \

View file

@ -6,7 +6,7 @@ on:
jobs:
label:
name: DO-NOT-MERGE
name: DO-NOT-MERGE / unresolved review
runs-on: ubuntu-latest
timeout-minutes: 10
@ -15,4 +15,4 @@ jobs:
with:
mode: exactly
count: 0
labels: "DO-NOT-MERGE"
labels: "DO-NOT-MERGE, awaiting changes, awaiting change review"

View file

@ -232,6 +232,15 @@ Type Objects
.. versionadded:: 3.11
.. c:function:: int PyUnstable_Type_AssignVersionTag(PyTypeObject *type)
Attempt to assign a version tag to the given type.
Returns 1 if the type already had a valid version tag or a new one was
assigned, or 0 if a new tag could not be assigned.
.. versionadded:: 3.12
Creating Heap-Allocated Types
.............................

View file

@ -76,6 +76,13 @@ venvdir = os.getenv('VENVDIR')
if venvdir is not None:
exclude_patterns.append(venvdir + '/*')
nitpick_ignore = [
# Do not error nit-picky mode builds when _SubParsersAction.add_parser cannot
# be resolved, as the method is currently undocumented. For context, see
# https://github.com/python/cpython/pull/103289.
('py:meth', '_SubParsersAction.add_parser'),
]
# Disable Docutils smartquotes for several translations
smartquotes_excludes = {
'languages': ['ja', 'fr', 'zh_TW', 'zh_CN'], 'builders': ['man', 'text'],
@ -263,6 +270,24 @@ linkcheck_allowed_redirects = {
r'https://github.com/python/cpython/tree/.*': 'https://github.com/python/cpython/blob/.*'
}
linkcheck_anchors_ignore = [
# ignore anchors that start with a '/', e.g. Wikipedia media files:
# https://en.wikipedia.org/wiki/Walrus#/media/File:Pacific_Walrus_-_Bull_(8247646168).jpg
r'\/.*',
]
linkcheck_ignore = [
# The crawler gets "Anchor not found"
r'https://developer.apple.com/documentation/.+?#.*',
r'https://devguide.python.org.+?/#.*',
r'https://github.com.+?#.*',
# Robot crawlers not allowed: "403 Client Error: Forbidden"
r'https://support.enthought.com/hc/.*',
# SSLError CertificateError, even though it is valid
r'https://unix.org/version2/whatsnew/lp64_wp.html',
]
# Options for extensions
# ----------------------

View file

@ -129,14 +129,10 @@ involved in creating and publishing a project:
* `Uploading the project to the Python Package Index`_
* `The .pypirc file`_
.. _Project structure: \
https://packaging.python.org/tutorials/packaging-projects/#packaging-python-projects
.. _Building and packaging the project: \
https://packaging.python.org/tutorials/packaging-projects/#creating-the-package-files
.. _Uploading the project to the Python Package Index: \
https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives
.. _The .pypirc file: \
https://packaging.python.org/specifications/pypirc/
.. _Project structure: https://packaging.python.org/tutorials/packaging-projects/#packaging-python-projects
.. _Building and packaging the project: https://packaging.python.org/tutorials/packaging-projects/#creating-the-package-files
.. _Uploading the project to the Python Package Index: https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives
.. _The .pypirc file: https://packaging.python.org/specifications/pypirc/
How do I...?

View file

@ -337,7 +337,7 @@ Here is an example::
}
PyErr_Format(PyExc_AttributeError,
"'%.50s' object has no attribute '%.400s'",
"'%.100s' object has no attribute '%.400s'",
tp->tp_name, name);
return NULL;
}

View file

@ -780,7 +780,7 @@ socket to :meth:`select.select` to check if it's writable.
The :mod:`asyncio` module provides a general purpose single-threaded and
concurrent asynchronous library, which can be used for writing non-blocking
network code.
The third-party `Twisted <https://twistedmatrix.com/trac/>`_ library is
The third-party `Twisted <https://twisted.org/>`_ library is
a popular and feature-rich alternative.

View file

@ -1,10 +1,12 @@
.. _argparse-tutorial:
*****************
Argparse Tutorial
*****************
:author: Tshepang Mbambo
.. _argparse-tutorial:
.. currentmodule:: argparse
This tutorial is intended to be a gentle introduction to :mod:`argparse`, the
recommended command-line parsing module in the Python standard library.
@ -12,7 +14,7 @@ recommended command-line parsing module in the Python standard library.
.. note::
There are two other modules that fulfill the same task, namely
:mod:`getopt` (an equivalent for :c:func:`getopt` from the C
:mod:`getopt` (an equivalent for ``getopt()`` from the C
language) and the deprecated :mod:`optparse`.
Note also that :mod:`argparse` is based on :mod:`optparse`,
and therefore very similar in terms of usage.
@ -137,13 +139,13 @@ And running the code:
Here is what's happening:
* We've added the :meth:`add_argument` method, which is what we use to specify
* We've added the :meth:`~ArgumentParser.add_argument` method, which is what we use to specify
which command-line options the program is willing to accept. In this case,
I've named it ``echo`` so that it's in line with its function.
* Calling our program now requires us to specify an option.
* The :meth:`parse_args` method actually returns some data from the
* The :meth:`~ArgumentParser.parse_args` method actually returns some data from the
options specified, in this case, ``echo``.
* The variable is some form of 'magic' that :mod:`argparse` performs for free
@ -256,7 +258,7 @@ Here is what is happening:
* To show that the option is actually optional, there is no error when running
the program without it. Note that by default, if an optional argument isn't
used, the relevant variable, in this case :attr:`args.verbosity`, is
used, the relevant variable, in this case ``args.verbosity``, is
given ``None`` as a value, which is the reason it fails the truth
test of the :keyword:`if` statement.
@ -299,7 +301,7 @@ Here is what is happening:
We even changed the name of the option to match that idea.
Note that we now specify a new keyword, ``action``, and give it the value
``"store_true"``. This means that, if the option is specified,
assign the value ``True`` to :data:`args.verbose`.
assign the value ``True`` to ``args.verbose``.
Not specifying it implies ``False``.
* It complains when you specify a value, in true spirit of what flags
@ -698,7 +700,7 @@ Conflicting options
So far, we have been working with two methods of an
:class:`argparse.ArgumentParser` instance. Let's introduce a third one,
:meth:`add_mutually_exclusive_group`. It allows for us to specify options that
:meth:`~ArgumentParser.add_mutually_exclusive_group`. It allows for us to specify options that
conflict with each other. Let's also change the rest of the program so that
the new functionality makes more sense:
we'll introduce the ``--quiet`` option,

View file

@ -1273,11 +1273,14 @@ Using the non-data descriptor protocol, a pure Python version of
.. testcode::
import functools
class StaticMethod:
"Emulate PyStaticMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
functools.update_wrapper(self, f)
def __get__(self, obj, objtype=None):
return self.f
@ -1285,13 +1288,19 @@ Using the non-data descriptor protocol, a pure Python version of
def __call__(self, *args, **kwds):
return self.f(*args, **kwds)
The :func:`functools.update_wrapper` call adds a ``__wrapped__`` attribute
that refers to the underlying function. Also it carries forward
the attributes necessary to make the wrapper look like the wrapped
function: ``__name__``, ``__qualname__``, ``__doc__``, and ``__annotations__``.
.. testcode::
:hide:
class E_sim:
@StaticMethod
def f(x):
return x * 10
def f(x: int) -> str:
"Simple function example"
return "!" * x
wrapped_ord = StaticMethod(ord)
@ -1299,11 +1308,51 @@ Using the non-data descriptor protocol, a pure Python version of
:hide:
>>> E_sim.f(3)
30
'!!!'
>>> E_sim().f(3)
30
'!!!'
>>> sm = vars(E_sim)['f']
>>> type(sm).__name__
'StaticMethod'
>>> f = E_sim.f
>>> type(f).__name__
'function'
>>> sm.__name__
'f'
>>> f.__name__
'f'
>>> sm.__qualname__
'E_sim.f'
>>> f.__qualname__
'E_sim.f'
>>> sm.__doc__
'Simple function example'
>>> f.__doc__
'Simple function example'
>>> sm.__annotations__
{'x': <class 'int'>, 'return': <class 'str'>}
>>> f.__annotations__
{'x': <class 'int'>, 'return': <class 'str'>}
>>> sm.__module__ == f.__module__
True
>>> sm(3)
'!!!'
>>> f(3)
'!!!'
>>> wrapped_ord('A')
65
>>> wrapped_ord.__module__ == ord.__module__
True
>>> wrapped_ord.__wrapped__ == ord
True
>>> wrapped_ord.__name__ == ord.__name__
True
>>> wrapped_ord.__qualname__ == ord.__qualname__
True
>>> wrapped_ord.__doc__ == ord.__doc__
True
Class methods
@ -1359,11 +1408,14 @@ Using the non-data descriptor protocol, a pure Python version of
.. testcode::
import functools
class ClassMethod:
"Emulate PyClassMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
functools.update_wrapper(self, f)
def __get__(self, obj, cls=None):
if cls is None:
@ -1380,8 +1432,9 @@ Using the non-data descriptor protocol, a pure Python version of
# Verify the emulation works
class T:
@ClassMethod
def cm(cls, x, y):
return (cls, x, y)
def cm(cls, x: int, y: str) -> tuple[str, int, str]:
"Class method that returns a tuple"
return (cls.__name__, x, y)
@ClassMethod
@property
@ -1393,17 +1446,40 @@ Using the non-data descriptor protocol, a pure Python version of
:hide:
>>> T.cm(11, 22)
(<class 'T'>, 11, 22)
('T', 11, 22)
# Also call it from an instance
>>> t = T()
>>> t.cm(11, 22)
(<class 'T'>, 11, 22)
('T', 11, 22)
# Check the alternate path for chained descriptors
>>> T.__doc__
"A doc for 'T'"
# Verify that T uses our emulation
>>> type(vars(T)['cm']).__name__
'ClassMethod'
# Verify that update_wrapper() correctly copied attributes
>>> T.cm.__name__
'cm'
>>> T.cm.__qualname__
'T.cm'
>>> T.cm.__doc__
'Class method that returns a tuple'
>>> T.cm.__annotations__
{'x': <class 'int'>, 'y': <class 'str'>, 'return': tuple[str, int, str]}
# Verify that __wrapped__ was added and works correctly
>>> f = vars(T)['cm'].__wrapped__
>>> type(f).__name__
'function'
>>> f.__name__
'cm'
>>> f(T, 11, 22)
('T', 11, 22)
The code path for ``hasattr(type(self.f), '__get__')`` was added in
Python 3.9 and makes it possible for :func:`classmethod` to support
@ -1423,6 +1499,12 @@ chained together. In Python 3.11, this functionality was deprecated.
>>> G.__doc__
"A doc for 'G'"
The :func:`functools.update_wrapper` call in ``ClassMethod`` adds a
``__wrapped__`` attribute that refers to the underlying function. Also
it carries forward the attributes necessary to make the wrapper look
like the wrapped function: ``__name__``, ``__qualname__``, ``__doc__``,
and ``__annotations__``.
Member objects and __slots__
----------------------------

View file

@ -36,8 +36,10 @@ inherits from :class:`Enum` itself.
.. note:: Case of Enum Members
Because Enums are used to represent constants we recommend using
UPPER_CASE names for members, and will be using that style in our examples.
Because Enums are used to represent constants, and to help avoid issues
with name clashes between mixin-class methods/attributes and enum names,
we strongly recommend using UPPER_CASE names for members, and will be using
that style in our examples.
Depending on the nature of the enum a member's value may or may not be
important, but either way that value can be used to get the corresponding
@ -490,6 +492,10 @@ the :meth:`~Enum.__repr__` omits the inherited class' name. For example::
Use the :func:`!dataclass` argument ``repr=False``
to use the standard :func:`repr`.
.. versionchanged:: 3.12
Only the dataclass fields are shown in the value area, not the dataclass'
name.
Pickling
--------
@ -992,7 +998,9 @@ but remain normal attributes.
Enum members are instances of their enum class, and are normally accessed as
``EnumClass.member``. In certain situations, such as writing custom enum
behavior, being able to access one member directly from another is useful,
and is supported.
and is supported; however, in order to avoid name clashes between member names
and attributes/methods from mixed-in classes, upper-case names are strongly
recommended.
.. versionchanged:: 3.5

View file

@ -1208,8 +1208,8 @@ General
-------
**Structure and Interpretation of Computer Programs**, by Harold Abelson and
Gerald Jay Sussman with Julie Sussman. Full text at
https://mitpress.mit.edu/sicp/. In this classic textbook of computer science,
Gerald Jay Sussman with Julie Sussman. The book can be found at
https://mitpress.mit.edu/sicp. In this classic textbook of computer science,
chapters 2 and 3 discuss the use of sequences and streams to organize the data
flow inside a program. The book uses Scheme for its examples, but many of the
design approaches described in these chapters are applicable to functional-style

View file

@ -86,7 +86,7 @@ response::
import urllib.request
req = urllib.request.Request('http://www.voidspace.org.uk')
req = urllib.request.Request('http://python.org/')
with urllib.request.urlopen(req) as response:
the_page = response.read()
@ -458,7 +458,7 @@ To illustrate creating and installing a handler we will use the
``HTTPBasicAuthHandler``. For a more detailed discussion of this subject --
including an explanation of how Basic Authentication works - see the `Basic
Authentication Tutorial
<http://www.voidspace.org.uk/python/articles/authentication.shtml>`_.
<https://web.archive.org/web/20201215133350/http://www.voidspace.org.uk/python/articles/authentication.shtml>`__.
When authentication is required, the server sends a header (as well as the 401
error code) requesting authentication. This specifies the authentication scheme

View file

@ -67,7 +67,7 @@ default_ Default value used when an argument is not provided
dest_ Specify the attribute name used in the result namespace
help_ Help message for an argument
metavar_ Alternate display name for the argument as shown in help
nargs_ Number of times the argument can be used :class:`int`, ``'?'``, ``'*'``, ``'+'``, or ``argparse.REMAINDER``
nargs_ Number of times the argument can be used :class:`int`, ``'?'``, ``'*'``, or ``'+'``
required_ Indicate whether an argument is required or optional ``True`` or ``False``
type_ Automatically convert an argument to the given type :class:`int`, :class:`float`, ``argparse.FileType('w')``, or callable function
====================== =========================================================== ==========================================================================================================================
@ -585,7 +585,7 @@ arguments will never be treated as file references.
.. versionchanged:: 3.12
:class:`ArgumentParser` changed encoding and errors to read arguments files
from default (e.g. :func:`locale.getpreferredencoding(False)` and
from default (e.g. :func:`locale.getpreferredencoding(False) <locale.getpreferredencoding>` and
``"strict"``) to :term:`filesystem encoding and error handler`.
Arguments file should be encoded in UTF-8 instead of ANSI Codepage on Windows.
@ -1191,7 +1191,7 @@ done downstream after the arguments are parsed.
For example, JSON or YAML conversions have complex error cases that require
better reporting than can be given by the ``type`` keyword. A
:exc:`~json.JSONDecodeError` would not be well formatted and a
:exc:`FileNotFound` exception would not be handled at all.
:exc:`FileNotFoundError` exception would not be handled at all.
Even :class:`~argparse.FileType` has its limitations for use with the ``type``
keyword. If one argument uses *FileType* and then a subsequent argument fails,
@ -1445,7 +1445,7 @@ Action classes
Action classes implement the Action API, a callable which returns a callable
which processes arguments from the command-line. Any object which follows
this API may be passed as the ``action`` parameter to
:meth:`add_argument`.
:meth:`~ArgumentParser.add_argument`.
.. class:: Action(option_strings, dest, nargs=None, const=None, default=None, \
type=None, choices=None, required=False, help=None, \
@ -1723,7 +1723,7 @@ Sub-commands
:class:`ArgumentParser` supports the creation of such sub-commands with the
:meth:`add_subparsers` method. The :meth:`add_subparsers` method is normally
called with no arguments and returns a special action object. This object
has a single method, :meth:`~ArgumentParser.add_parser`, which takes a
has a single method, :meth:`~_SubParsersAction.add_parser`, which takes a
command name and any :class:`ArgumentParser` constructor arguments, and
returns an :class:`ArgumentParser` object that can be modified as usual.
@ -1789,7 +1789,7 @@ Sub-commands
for that particular parser will be printed. The help message will not
include parent parser or sibling parser messages. (A help message for each
subparser command, however, can be given by supplying the ``help=`` argument
to :meth:`add_parser` as above.)
to :meth:`~_SubParsersAction.add_parser` as above.)
::
@ -2157,7 +2157,7 @@ the populated namespace and the list of remaining argument strings.
.. warning::
:ref:`Prefix matching <prefix-matching>` rules apply to
:meth:`parse_known_args`. The parser may consume an option even if it's just
:meth:`~ArgumentParser.parse_known_args`. The parser may consume an option even if it's just
a prefix of one of its known options, instead of leaving it in the remaining
arguments list.
@ -2218,7 +2218,7 @@ support this parsing style.
These parsers do not support all the argparse features, and will raise
exceptions if unsupported features are used. In particular, subparsers,
``argparse.REMAINDER``, and mutually exclusive groups that include both
and mutually exclusive groups that include both
optionals and positionals are not supported.
The following example shows the difference between
@ -2295,3 +2295,17 @@ A partial upgrade path from :mod:`optparse` to :mod:`argparse`:
* Replace the OptionParser constructor ``version`` argument with a call to
``parser.add_argument('--version', action='version', version='<the version>')``.
Exceptions
----------
.. exception:: ArgumentError
An error from creating or using an argument (optional or positional).
The string value of this exception is the message, augmented with
information about the argument that caused it.
.. exception:: ArgumentTypeError
Raised when something goes wrong converting a command line string to a type.

View file

@ -256,8 +256,9 @@ Creating Tasks
.. note::
:meth:`asyncio.TaskGroup.create_task` is a newer alternative
that allows for convenient waiting for a group of related tasks.
:meth:`asyncio.TaskGroup.create_task` is a new alternative
leveraging structural concurrency; it allows for waiting
for a group of related tasks with strong safety guarantees.
.. important::
@ -340,7 +341,7 @@ Example::
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(some_coro(...))
task2 = tg.create_task(another_coro(...))
print("Both tasks have completed now.")
print(f"Both tasks have completed now: {task1.result()}, {task2.result()}")
The ``async with`` statement will wait for all tasks in the group to finish.
While waiting, new tasks may still be added to the group
@ -459,8 +460,12 @@ Running Tasks Concurrently
Tasks/Futures to be cancelled.
.. note::
A more modern way to create and run tasks concurrently and
wait for their completion is :class:`asyncio.TaskGroup`.
A new alternative to create and run tasks concurrently and
wait for their completion is :class:`asyncio.TaskGroup`. *TaskGroup*
provides stronger safety guarantees than *gather* for scheduling a nesting of subtasks:
if a task (or a subtask, a task scheduled by a task)
raises an exception, *TaskGroup* will, while *gather* will not,
cancel the remaining scheduled tasks).
.. _asyncio_example_gather:
@ -829,6 +834,9 @@ Waiting Primitives
Deprecation warning is emitted if not all awaitable objects in the *aws*
iterable are Future-like objects and there is no running event loop.
.. versionchanged:: 3.12
Added support for generators yielding tasks.
Running in Threads
==================

View file

@ -304,8 +304,15 @@ Functions and classes provided:
This context manager is :ref:`reentrant <reentrant-cms>`.
If the code within the :keyword:`!with` block raises an
:exc:`ExceptionGroup`, suppressed exceptions are removed from the
group. If any exceptions in the group are not suppressed, a group containing them is re-raised.
.. versionadded:: 3.4
.. versionchanged:: 3.12
``suppress`` now supports suppressing exceptions raised as
part of an :exc:`ExceptionGroup`.
.. function:: redirect_stdout(new_target)

View file

@ -28,8 +28,8 @@ Such constructors may be factory functions or class instances.
.. function:: pickle(type, function, constructor_ob=None)
Declares that *function* should be used as a "reduction" function for objects
of type *type*. *function* should return either a string or a tuple
containing two or three elements. See the :attr:`~pickle.Pickler.dispatch_table`
of type *type*. *function* must return either a string or a tuple
containing two or five elements. See the :attr:`~pickle.Pickler.dispatch_table`
for more details on the interface of *function*.
The *constructor_ob* parameter is a legacy feature and is now ignored, but if

View file

@ -12,8 +12,8 @@
--------------
This module provides a decorator and functions for automatically
adding generated :term:`special method`\s such as :meth:`__init__` and
:meth:`__repr__` to user-defined classes. It was originally described
adding generated :term:`special method`\s such as :meth:`~object.__init__` and
:meth:`~object.__repr__` to user-defined classes. It was originally described
in :pep:`557`.
The member variables to use in these generated methods are defined
@ -31,7 +31,7 @@ using :pep:`526` type annotations. For example, this code::
def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand
will add, among other things, a :meth:`__init__` that looks like::
will add, among other things, a :meth:`~object.__init__` that looks like::
def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0):
self.name = name
@ -86,86 +86,86 @@ Module contents
The parameters to :func:`dataclass` are:
- ``init``: If true (the default), a :meth:`__init__` method will be
- ``init``: If true (the default), a :meth:`~object.__init__` method will be
generated.
If the class already defines :meth:`__init__`, this parameter is
If the class already defines :meth:`~object.__init__`, this parameter is
ignored.
- ``repr``: If true (the default), a :meth:`__repr__` method will be
- ``repr``: If true (the default), a :meth:`~object.__repr__` method will be
generated. The generated repr string will have the class name and
the name and repr of each field, in the order they are defined in
the class. Fields that are marked as being excluded from the repr
are not included. For example:
``InventoryItem(name='widget', unit_price=3.0, quantity_on_hand=10)``.
If the class already defines :meth:`__repr__`, this parameter is
If the class already defines :meth:`~object.__repr__`, this parameter is
ignored.
- ``eq``: If true (the default), an :meth:`__eq__` method will be
- ``eq``: If true (the default), an :meth:`~object.__eq__` method will be
generated. This method compares the class as if it were a tuple
of its fields, in order. Both instances in the comparison must
be of the identical type.
If the class already defines :meth:`__eq__`, this parameter is
If the class already defines :meth:`~object.__eq__`, this parameter is
ignored.
- ``order``: If true (the default is ``False``), :meth:`__lt__`,
:meth:`__le__`, :meth:`__gt__`, and :meth:`__ge__` methods will be
- ``order``: If true (the default is ``False``), :meth:`~object.__lt__`,
:meth:`~object.__le__`, :meth:`~object.__gt__`, and :meth:`~object.__ge__` methods will be
generated. These compare the class as if it were a tuple of its
fields, in order. Both instances in the comparison must be of the
identical type. If ``order`` is true and ``eq`` is false, a
:exc:`ValueError` is raised.
If the class already defines any of :meth:`__lt__`,
:meth:`__le__`, :meth:`__gt__`, or :meth:`__ge__`, then
If the class already defines any of :meth:`~object.__lt__`,
:meth:`~object.__le__`, :meth:`~object.__gt__`, or :meth:`~object.__ge__`, then
:exc:`TypeError` is raised.
- ``unsafe_hash``: If ``False`` (the default), a :meth:`__hash__` method
- ``unsafe_hash``: If ``False`` (the default), a :meth:`~object.__hash__` method
is generated according to how ``eq`` and ``frozen`` are set.
:meth:`__hash__` is used by built-in :meth:`hash()`, and when objects are
:meth:`~object.__hash__` is used by built-in :meth:`hash()`, and when objects are
added to hashed collections such as dictionaries and sets. Having a
:meth:`__hash__` implies that instances of the class are immutable.
:meth:`~object.__hash__` implies that instances of the class are immutable.
Mutability is a complicated property that depends on the programmer's
intent, the existence and behavior of :meth:`__eq__`, and the values of
intent, the existence and behavior of :meth:`~object.__eq__`, and the values of
the ``eq`` and ``frozen`` flags in the :func:`dataclass` decorator.
By default, :func:`dataclass` will not implicitly add a :meth:`__hash__`
By default, :func:`dataclass` will not implicitly add a :meth:`~object.__hash__`
method unless it is safe to do so. Neither will it add or change an
existing explicitly defined :meth:`__hash__` method. Setting the class
existing explicitly defined :meth:`~object.__hash__` method. Setting the class
attribute ``__hash__ = None`` has a specific meaning to Python, as
described in the :meth:`__hash__` documentation.
described in the :meth:`~object.__hash__` documentation.
If :meth:`__hash__` is not explicitly defined, or if it is set to ``None``,
then :func:`dataclass` *may* add an implicit :meth:`__hash__` method.
If :meth:`~object.__hash__` is not explicitly defined, or if it is set to ``None``,
then :func:`dataclass` *may* add an implicit :meth:`~object.__hash__` method.
Although not recommended, you can force :func:`dataclass` to create a
:meth:`__hash__` method with ``unsafe_hash=True``. This might be the case
:meth:`~object.__hash__` method with ``unsafe_hash=True``. This might be the case
if your class is logically immutable but can nonetheless be mutated.
This is a specialized use case and should be considered carefully.
Here are the rules governing implicit creation of a :meth:`__hash__`
method. Note that you cannot both have an explicit :meth:`__hash__`
Here are the rules governing implicit creation of a :meth:`~object.__hash__`
method. Note that you cannot both have an explicit :meth:`~object.__hash__`
method in your dataclass and set ``unsafe_hash=True``; this will result
in a :exc:`TypeError`.
If ``eq`` and ``frozen`` are both true, by default :func:`dataclass` will
generate a :meth:`__hash__` method for you. If ``eq`` is true and
``frozen`` is false, :meth:`__hash__` will be set to ``None``, marking it
generate a :meth:`~object.__hash__` method for you. If ``eq`` is true and
``frozen`` is false, :meth:`~object.__hash__` will be set to ``None``, marking it
unhashable (which it is, since it is mutable). If ``eq`` is false,
:meth:`__hash__` will be left untouched meaning the :meth:`__hash__`
:meth:`~object.__hash__` will be left untouched meaning the :meth:`~object.__hash__`
method of the superclass will be used (if the superclass is
:class:`object`, this means it will fall back to id-based hashing).
- ``frozen``: If true (the default is ``False``), assigning to fields will
generate an exception. This emulates read-only frozen instances. If
:meth:`__setattr__` or :meth:`__delattr__` is defined in the class, then
:meth:`~object.__setattr__` or :meth:`~object.__delattr__` is defined in the class, then
:exc:`TypeError` is raised. See the discussion below.
- ``match_args``: If true (the default is ``True``), the
``__match_args__`` tuple will be created from the list of
parameters to the generated :meth:`__init__` method (even if
:meth:`__init__` is not generated, see above). If false, or if
parameters to the generated :meth:`~object.__init__` method (even if
:meth:`~object.__init__` is not generated, see above). If false, or if
``__match_args__`` is already defined in the class, then
``__match_args__`` will not be generated.
@ -173,18 +173,18 @@ Module contents
- ``kw_only``: If true (the default value is ``False``), then all
fields will be marked as keyword-only. If a field is marked as
keyword-only, then the only effect is that the :meth:`__init__`
keyword-only, then the only effect is that the :meth:`~object.__init__`
parameter generated from a keyword-only field must be specified
with a keyword when :meth:`__init__` is called. There is no
with a keyword when :meth:`~object.__init__` is called. There is no
effect on any other aspect of dataclasses. See the
:term:`parameter` glossary entry for details. Also see the
:const:`KW_ONLY` section.
.. versionadded:: 3.10
- ``slots``: If true (the default is ``False``), :attr:`__slots__` attribute
- ``slots``: If true (the default is ``False``), :attr:`~object.__slots__` attribute
will be generated and new class will be returned instead of the original one.
If :attr:`__slots__` is already defined in the class, then :exc:`TypeError`
If :attr:`~object.__slots__` is already defined in the class, then :exc:`TypeError`
is raised.
.. versionadded:: 3.10
@ -215,7 +215,7 @@ Module contents
b: int = 0 # assign a default value for 'b'
In this example, both ``a`` and ``b`` will be included in the added
:meth:`__init__` method, which will be defined as::
:meth:`~object.__init__` method, which will be defined as::
def __init__(self, a: int, b: int = 0):
@ -256,13 +256,13 @@ Module contents
error to specify both ``default`` and ``default_factory``.
- ``init``: If true (the default), this field is included as a
parameter to the generated :meth:`__init__` method.
parameter to the generated :meth:`~object.__init__` method.
- ``repr``: If true (the default), this field is included in the
string returned by the generated :meth:`__repr__` method.
string returned by the generated :meth:`~object.__repr__` method.
- ``hash``: This can be a bool or ``None``. If true, this field is
included in the generated :meth:`__hash__` method. If ``None`` (the
included in the generated :meth:`~object.__hash__` method. If ``None`` (the
default), use the value of ``compare``: this would normally be
the expected behavior. A field should be considered in the hash
if it's used for comparisons. Setting this value to anything
@ -275,8 +275,8 @@ Module contents
is excluded from the hash, it will still be used for comparisons.
- ``compare``: If true (the default), this field is included in the
generated equality and comparison methods (:meth:`__eq__`,
:meth:`__gt__`, et al.).
generated equality and comparison methods (:meth:`~object.__eq__`,
:meth:`~object.__gt__`, et al.).
- ``metadata``: This can be a mapping or None. None is treated as
an empty dict. This value is wrapped in
@ -287,7 +287,7 @@ Module contents
namespace in the metadata.
- ``kw_only``: If true, this field will be marked as keyword-only.
This is used when the generated :meth:`__init__` method's
This is used when the generated :meth:`~object.__init__` method's
parameters are computed.
.. versionadded:: 3.10
@ -435,13 +435,13 @@ Module contents
Class, raises :exc:`TypeError`. If values in ``changes`` do not
specify fields, raises :exc:`TypeError`.
The newly returned object is created by calling the :meth:`__init__`
The newly returned object is created by calling the :meth:`~object.__init__`
method of the dataclass. This ensures that
:meth:`__post_init__`, if present, is also called.
:ref:`__post_init__ <post-init-processing>`, if present, is also called.
Init-only variables without default values, if any exist, must be
specified on the call to :func:`replace` so that they can be passed to
:meth:`__init__` and :meth:`__post_init__`.
:meth:`~object.__init__` and :ref:`__post_init__ <post-init-processing>`.
It is an error for ``changes`` to contain any fields that are
defined as having ``init=False``. A :exc:`ValueError` will be raised
@ -449,7 +449,7 @@ Module contents
Be forewarned about how ``init=False`` fields work during a call to
:func:`replace`. They are not copied from the source object, but
rather are initialized in :meth:`__post_init__`, if they're
rather are initialized in :ref:`__post_init__ <post-init-processing>`, if they're
initialized at all. It is expected that ``init=False`` fields will
be rarely and judiciously used. If they are used, it might be wise
to have alternate class constructors, or perhaps a custom
@ -480,7 +480,7 @@ Module contents
:const:`KW_ONLY` is otherwise completely ignored. This includes the
name of such a field. By convention, a name of ``_`` is used for a
:const:`KW_ONLY` field. Keyword-only fields signify
:meth:`__init__` parameters that must be specified as keywords when
:meth:`~object.__init__` parameters that must be specified as keywords when
the class is instantiated.
In this example, the fields ``y`` and ``z`` will be marked as keyword-only fields::
@ -501,20 +501,22 @@ Module contents
.. exception:: FrozenInstanceError
Raised when an implicitly defined :meth:`__setattr__` or
:meth:`__delattr__` is called on a dataclass which was defined with
Raised when an implicitly defined :meth:`~object.__setattr__` or
:meth:`~object.__delattr__` is called on a dataclass which was defined with
``frozen=True``. It is a subclass of :exc:`AttributeError`.
.. _post-init-processing:
Post-init processing
--------------------
The generated :meth:`__init__` code will call a method named
:meth:`__post_init__`, if :meth:`__post_init__` is defined on the
The generated :meth:`~object.__init__` code will call a method named
:meth:`!__post_init__`, if :meth:`!__post_init__` is defined on the
class. It will normally be called as ``self.__post_init__()``.
However, if any ``InitVar`` fields are defined, they will also be
passed to :meth:`__post_init__` in the order they were defined in the
class. If no :meth:`__init__` method is generated, then
:meth:`__post_init__` will not automatically be called.
passed to :meth:`!__post_init__` in the order they were defined in the
class. If no :meth:`~object.__init__` method is generated, then
:meth:`!__post_init__` will not automatically be called.
Among other uses, this allows for initializing field values that
depend on one or more other fields. For example::
@ -528,10 +530,10 @@ depend on one or more other fields. For example::
def __post_init__(self):
self.c = self.a + self.b
The :meth:`__init__` method generated by :func:`dataclass` does not call base
class :meth:`__init__` methods. If the base class has an :meth:`__init__` method
The :meth:`~object.__init__` method generated by :func:`dataclass` does not call base
class :meth:`~object.__init__` methods. If the base class has an :meth:`~object.__init__` method
that has to be called, it is common to call this method in a
:meth:`__post_init__` method::
:meth:`!__post_init__` method::
@dataclass
class Rectangle:
@ -545,12 +547,12 @@ that has to be called, it is common to call this method in a
def __post_init__(self):
super().__init__(self.side, self.side)
Note, however, that in general the dataclass-generated :meth:`__init__` methods
Note, however, that in general the dataclass-generated :meth:`~object.__init__` methods
don't need to be called, since the derived dataclass will take care of
initializing all fields of any base class that is a dataclass itself.
See the section below on init-only variables for ways to pass
parameters to :meth:`__post_init__`. Also see the warning about how
parameters to :meth:`!__post_init__`. Also see the warning about how
:func:`replace` handles ``init=False`` fields.
Class variables
@ -573,8 +575,8 @@ if the type of a field is of type ``dataclasses.InitVar``. If a field
is an ``InitVar``, it is considered a pseudo-field called an init-only
field. As it is not a true field, it is not returned by the
module-level :func:`fields` function. Init-only fields are added as
parameters to the generated :meth:`__init__` method, and are passed to
the optional :meth:`__post_init__` method. They are not otherwise used
parameters to the generated :meth:`~object.__init__` method, and are passed to
the optional :ref:`__post_init__ <post-init-processing>` method. They are not otherwise used
by dataclasses.
For example, suppose a field will be initialized from a database, if a
@ -601,12 +603,12 @@ Frozen instances
It is not possible to create truly immutable Python objects. However,
by passing ``frozen=True`` to the :meth:`dataclass` decorator you can
emulate immutability. In that case, dataclasses will add
:meth:`__setattr__` and :meth:`__delattr__` methods to the class. These
:meth:`~object.__setattr__` and :meth:`~object.__delattr__` methods to the class. These
methods will raise a :exc:`FrozenInstanceError` when invoked.
There is a tiny performance penalty when using ``frozen=True``:
:meth:`__init__` cannot use simple assignment to initialize fields, and
must use :meth:`object.__setattr__`.
:meth:`~object.__init__` cannot use simple assignment to initialize fields, and
must use :meth:`~object.__setattr__`.
Inheritance
-----------
@ -634,14 +636,14 @@ example::
The final list of fields is, in order, ``x``, ``y``, ``z``. The final
type of ``x`` is ``int``, as specified in class ``C``.
The generated :meth:`__init__` method for ``C`` will look like::
The generated :meth:`~object.__init__` method for ``C`` will look like::
def __init__(self, x: int = 15, y: int = 0, z: int = 10):
Re-ordering of keyword-only parameters in :meth:`__init__`
----------------------------------------------------------
Re-ordering of keyword-only parameters in :meth:`~object.__init__`
------------------------------------------------------------------
After the parameters needed for :meth:`__init__` are computed, any
After the parameters needed for :meth:`~object.__init__` are computed, any
keyword-only parameters are moved to come after all regular
(non-keyword-only) parameters. This is a requirement of how
keyword-only parameters are implemented in Python: they must come
@ -662,7 +664,7 @@ fields, and ``Base.x`` and ``D.z`` are regular fields::
z: int = 10
t: int = field(kw_only=True, default=0)
The generated :meth:`__init__` method for ``D`` will look like::
The generated :meth:`~object.__init__` method for ``D`` will look like::
def __init__(self, x: Any = 15.0, z: int = 10, *, y: int = 0, w: int = 1, t: int = 0):
@ -671,7 +673,7 @@ the list of fields: parameters derived from regular fields are
followed by parameters derived from keyword-only fields.
The relative ordering of keyword-only parameters is maintained in the
re-ordered :meth:`__init__` parameter list.
re-ordered :meth:`~object.__init__` parameter list.
Default factory functions
@ -683,10 +685,10 @@ example, to create a new instance of a list, use::
mylist: list = field(default_factory=list)
If a field is excluded from :meth:`__init__` (using ``init=False``)
If a field is excluded from :meth:`~object.__init__` (using ``init=False``)
and the field also specifies ``default_factory``, then the default
factory function will always be called from the generated
:meth:`__init__` function. This happens because there is no other
:meth:`~object.__init__` function. This happens because there is no other
way to give the field an initial value.
Mutable default values
@ -714,7 +716,7 @@ Using dataclasses, *if* this code was valid::
@dataclass
class D:
x: List = []
x: list = [] # This code raises ValueError
def add(self, element):
self.x += element

View file

@ -1043,7 +1043,7 @@ Other constructors, all class methods:
Return a :class:`.datetime` corresponding to *date_string*, parsed according to
*format*.
This is equivalent to::
If *format* does not contain microseconds or timezone information, this is equivalent to::
datetime(*(time.strptime(date_string, format)[0:6]))
@ -2510,10 +2510,7 @@ Notes:
Because the format depends on the current locale, care should be taken when
making assumptions about the output value. Field orderings will vary (for
example, "month/day/year" versus "day/month/year"), and the output may
contain Unicode characters encoded using the locale's default encoding (for
example, if the current locale is ``ja_JP``, the default encoding could be
any one of ``eucJP``, ``SJIS``, or ``utf-8``; use :meth:`locale.getlocale`
to determine the current locale's encoding).
contain non-ASCII characters.
(2)
The :meth:`strptime` method can parse years in the full [1, 9999] range, but

View file

@ -926,7 +926,7 @@ Each thread has its own current context which is accessed or changed using the
You can also use the :keyword:`with` statement and the :func:`localcontext`
function to temporarily change the active context.
.. function:: localcontext(ctx=None, \*\*kwargs)
.. function:: localcontext(ctx=None, **kwargs)
Return a context manager that will set the current context for the active thread
to a copy of *ctx* on entry to the with-statement and restore the previous context

View file

@ -1036,6 +1036,24 @@ iterations of the loop.
pushed to the stack before the attribute or unbound method respectively.
.. opcode:: LOAD_SUPER_ATTR (namei)
This opcode implements :func:`super` (e.g. ``super().method()`` and
``super().attr``). It works the same as :opcode:`LOAD_ATTR`, except that
``namei`` is shifted left by 2 bits instead of 1, and instead of expecting a
single receiver on the stack, it expects three objects (from top of stack
down): ``self`` (the first argument to the current method), ``cls`` (the
class within which the current method was defined), and the global ``super``.
The low bit of ``namei`` signals to attempt a method load, as with
:opcode:`LOAD_ATTR`.
The second-low bit of ``namei``, if set, means that this was a two-argument
call to :func:`super` (unset means zero-argument).
.. versionadded:: 3.12
.. opcode:: COMPARE_OP (opname)
Performs a Boolean operation. The operation name can be found in

View file

@ -119,7 +119,8 @@ Module Contents
:func:`~enum.property`
Allows :class:`Enum` members to have attributes without conflicting with
member names.
member names. The ``value`` and ``name`` attributes are implemented this
way.
:func:`unique`
@ -169,7 +170,7 @@ Data Types
final *enum*, as well as creating the enum members, properly handling
duplicates, providing iteration over the enum class, etc.
.. method:: EnumType.__call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
.. method:: EnumType.__call__(cls, value, names=None, \*, module=None, qualname=None, type=None, start=1, boundary=None)
This method is called in two different ways:
@ -317,7 +318,7 @@ Data Types
>>> PowersOfThree.SECOND.value
9
.. method:: Enum.__init_subclass__(cls, **kwds)
.. method:: Enum.__init_subclass__(cls, \**kwds)
A *classmethod* that is used to further configure subsequent subclasses.
By default, does nothing.

View file

@ -49,8 +49,13 @@ The :mod:`functools` module defines the following functions:
>>> factorial(12) # makes two new recursive calls, the other 10 are cached
479001600
The cache is threadsafe so the wrapped function can be used in multiple
threads.
The cache is threadsafe so that the wrapped function can be used in
multiple threads. This means that the underlying data structure will
remain coherent during concurrent updates.
It is possible for the wrapped function to be called more than once if
another thread makes an additional call before the initial call has been
completed and cached.
.. versionadded:: 3.9
@ -118,6 +123,7 @@ The :mod:`functools` module defines the following functions:
def stdev(self):
return statistics.stdev(self._data)
.. versionadded:: 3.8
.. versionchanged:: 3.12
Prior to Python 3.12, ``cached_property`` included an undocumented lock to
@ -126,8 +132,6 @@ The :mod:`functools` module defines the following functions:
per-instance, which could result in unacceptably high lock contention. In
Python 3.12+ this locking is removed.
.. versionadded:: 3.8
.. function:: cmp_to_key(func)
@ -159,8 +163,13 @@ The :mod:`functools` module defines the following functions:
*maxsize* most recent calls. It can save time when an expensive or I/O bound
function is periodically called with the same arguments.
The cache is threadsafe so the wrapped function can be used in multiple
threads.
The cache is threadsafe so that the wrapped function can be used in
multiple threads. This means that the underlying data structure will
remain coherent during concurrent updates.
It is possible for the wrapped function to be called more than once if
another thread makes an additional call before the initial call has been
completed and cached.
Since a dictionary is used to cache results, the positional and keyword
arguments to the function must be :term:`hashable`.
@ -233,7 +242,7 @@ The :mod:`functools` module defines the following functions:
@lru_cache(maxsize=32)
def get_pep(num):
'Retrieve text of a Python Enhancement Proposal'
resource = 'https://peps.python.org/pep-%04d/' % num
resource = f'https://peps.python.org/pep-{num:04d}'
try:
with urllib.request.urlopen(resource) as s:
return s.read()

View file

@ -308,6 +308,10 @@ Python module or `Import Package <https://packaging.python.org/en/latest/glossar
>>> packages_distributions()
{'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...}
Some editable installs, `do not supply top-level names
<https://github.com/pypa/packaging-problems/issues/609>`_, and thus this
function is not reliable with such installs.
.. versionadded:: 3.10
.. _distributions:

View file

@ -452,9 +452,7 @@ process which created it.
importable by the children. This is covered in :ref:`multiprocessing-programming`
however it is worth pointing out here. This means that some examples, such
as the :class:`multiprocessing.pool.Pool` examples will not work in the
interactive interpreter. For example:
.. code-block:: text
interactive interpreter. For example::
>>> from multiprocessing import Pool
>>> p = Pool(5)

View file

@ -954,7 +954,16 @@ The canonical way to create an :class:`Option` instance is with the
As you can see, most actions involve storing or updating a value somewhere.
:mod:`optparse` always creates a special object for this, conventionally called
``options`` (it happens to be an instance of :class:`optparse.Values`). Option
``options``, which is an instance of :class:`optparse.Values`.
.. class:: Values
An object holding parsed argument names and values as attributes.
Normally created by calling when calling :meth:`OptionParser.parse_args`,
and can be overridden by a custom subclass passed to the *values* argument of
:meth:`OptionParser.parse_args` (as described in :ref:`optparse-parsing-arguments`).
Option
arguments (and various other values) are stored as attributes of this object,
according to the :attr:`~Option.dest` (destination) option attribute.
@ -991,6 +1000,14 @@ one that makes sense for *all* options.
Option attributes
^^^^^^^^^^^^^^^^^
.. class:: Option
A single command line argument,
with various attributes passed by keyword to the constructor.
Normally created with :meth:`OptionParser.add_option` rather than directly,
and can be overridden by a custom class via the *option_class* argument
to :class:`OptionParser`.
The following option attributes may be passed as keyword arguments to
:meth:`OptionParser.add_option`. If you pass an option attribute that is not
relevant to a particular option, or fail to pass a required option attribute,
@ -2035,3 +2052,27 @@ Features of note:
about setting a default value for the option destinations in question; they
can just leave the default as ``None`` and :meth:`ensure_value` will take care of
getting it right when it's needed.
Exceptions
----------
.. exception:: OptionError
Raised if an :class:`Option` instance is created with invalid or
inconsistent arguments.
.. exception:: OptionConflictError
Raised if conflicting options are added to an :class:`OptionParser`.
.. exception:: OptionValueError
Raised if an invalid option value is encountered on the command line.
.. exception:: BadOptionError
Raised if an invalid option is passed on the command line.
.. exception:: AmbiguousOptionError
Raised if an ambiguous option is passed on the command line.

View file

@ -3919,7 +3919,8 @@ to be ignored.
the :envvar:`PATH` variable. The other variants, :func:`execl`, :func:`execle`,
:func:`execv`, and :func:`execve`, will not use the :envvar:`PATH` variable to
locate the executable; *path* must contain an appropriate absolute or relative
path.
path. Relative paths must include at least one slash, even on Windows, as
plain names will not be resolved.
For :func:`execle`, :func:`execlpe`, :func:`execve`, and :func:`execvpe` (note
that these all end in "e"), the *env* parameter must be a mapping which is

View file

@ -25,9 +25,9 @@ support.
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
This will add to the package's ``__path__`` all subdirectories of directories
on :data:`sys.path` named after the package. This is useful if one wants to
distribute different parts of a single logical package as multiple
For each directory on :data:`sys.path` that has a subdirectory that matches the
package name, add the subdirectory to the package's :attr:`__path__`. This is useful
if one wants to distribute different parts of a single logical package as multiple
directories.
It also looks for :file:`\*.pkg` files beginning where ``*`` matches the
@ -82,7 +82,7 @@ support.
This is a backwards compatibility wrapper around
:func:`importlib.util.find_spec` that converts most failures to
:exc:`ImportError` and only returns the loader rather than the full
:class:`ModuleSpec`.
:class:`importlib.machinery.ModuleSpec`.
.. versionchanged:: 3.3
Updated to be based directly on :mod:`importlib` rather than relying

View file

@ -19,7 +19,7 @@ function.
Readline keybindings may be configured via an initialization file, typically
``.inputrc`` in your home directory. See `Readline Init File
<https://tiswww.cwru.edu/php/chet/readline/rluserman.html#SEC9>`_
<https://tiswww.cwru.edu/php/chet/readline/rluserman.html#Readline-Init-File>`_
in the GNU Readline manual for information about the format and
allowable constructs of that file, and the capabilities of the
Readline library in general.

View file

@ -662,7 +662,7 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
Remove the archive format *name* from the list of supported formats.
.. function:: unpack_archive(filename[, extract_dir[, format]])
.. function:: unpack_archive(filename[, extract_dir[, format[, filter]]])
Unpack an archive. *filename* is the full path of the archive.
@ -676,6 +676,14 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
registered for that extension. In case none is found,
a :exc:`ValueError` is raised.
The keyword-only *filter* argument is passed to the underlying unpacking
function. For zip files, *filter* is not accepted.
For tar files, it is recommended to set it to ``'data'``,
unless using features specific to tar and UNIX-like filesystems.
(See :ref:`tarfile-extraction-filter` for details.)
The ``'data'`` filter will become the default for tar files
in Python 3.14.
.. audit-event:: shutil.unpack_archive filename,extract_dir,format shutil.unpack_archive
.. warning::
@ -688,6 +696,9 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
.. versionchanged:: 3.7
Accepts a :term:`path-like object` for *filename* and *extract_dir*.
.. versionchanged:: 3.12
Added the *filter* argument.
.. function:: register_unpack_format(name, extensions, function[, extra_args[, description]])
Registers an unpack format. *name* is the name of the format and
@ -695,11 +706,14 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
``.zip`` for Zip files.
*function* is the callable that will be used to unpack archives. The
callable will receive the path of the archive, followed by the directory
the archive must be extracted to.
callable will receive:
When provided, *extra_args* is a sequence of ``(name, value)`` tuples that
will be passed as keywords arguments to the callable.
- the path of the archive, as a positional argument;
- the directory the archive must be extracted to, as a positional argument;
- possibly a *filter* keyword argument, if it was given to
:func:`unpack_archive`;
- additional keyword arguments, specified by *extra_args* as a sequence
of ``(name, value)`` tuples.
*description* can be provided to describe the format, and will be returned
by the :func:`get_unpack_formats` function.

View file

@ -140,9 +140,16 @@ server is the address family.
ForkingUDPServer
ThreadingTCPServer
ThreadingUDPServer
ForkingUnixStreamServer
ForkingUnixDatagramServer
ThreadingUnixStreamServer
ThreadingUnixDatagramServer
These classes are pre-defined using the mix-in classes.
.. versionadded:: 3.12
The ``ForkingUnixStreamServer`` and ``ForkingUnixDatagramServer`` classes
were added.
To implement a service, you must derive a class from :class:`BaseRequestHandler`
and redefine its :meth:`~BaseRequestHandler.handle` method.

View file

@ -1605,8 +1605,8 @@ expression support in the :mod:`re` module).
converts it to ``"ss"``.
The casefolding algorithm is
`described in section 3.13 of the Unicode Standard
<http://www.unicode.org/versions/Unicode15.0.0/ch03.pdf#G53253>`__.
`described in section 3.13 'Default Case Folding' of the Unicode Standard
<https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf>`__.
.. versionadded:: 3.3
@ -1768,8 +1768,9 @@ expression support in the :mod:`re` module).
one character, ``False`` otherwise. Alphabetic characters are those characters defined
in the Unicode character database as "Letter", i.e., those with general category
property being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is different
from the `Alphabetic property defined in the Unicode Standard
<https://www.unicode.org/versions/Unicode15.0.0/ch04.pdf#G91002>`_.
from the `Alphabetic property defined in the section 4.10 'Letters, Alphabetic, and
Ideographic' of the Unicode Standard
<https://www.unicode.org/versions/Unicode15.0.0/ch04.pdf>`_.
.. method:: str.isascii()
@ -1904,8 +1905,8 @@ expression support in the :mod:`re` module).
lowercase.
The lowercasing algorithm used is
`described in section 3.13 of the Unicode Standard
<https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf#G34078>`__.
`described in section 3.13 'Default Case Folding' of the Unicode Standard
<https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf>`__.
.. method:: str.lstrip([chars])
@ -2250,8 +2251,8 @@ expression support in the :mod:`re` module).
titlecase).
The uppercasing algorithm used is
`described in section 3.13 of the Unicode Standard
<https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf#G34078>`__.
`described in section 3.13 'Default Case Folding' of the Unicode Standard
<https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf>`__.
.. method:: str.zfill(width)
@ -3714,12 +3715,15 @@ copying.
types such as :class:`bytes` and :class:`bytearray`, an element is a single
byte, but other types such as :class:`array.array` may have bigger elements.
``len(view)`` is equal to the length of :class:`~memoryview.tolist`.
If ``view.ndim = 0``, the length is 1. If ``view.ndim = 1``, the length
is equal to the number of elements in the view. For higher dimensions,
the length is equal to the length of the nested list representation of
the view. The :class:`~memoryview.itemsize` attribute will give you the
number of bytes in a single element.
``len(view)`` is equal to the length of :class:`~memoryview.tolist`, which
is the nested list representation of the view. If ``view.ndim = 1``,
this is equal to the number of elements in the view.
.. versionchanged:: 3.12
If ``view.ndim == 0``, ``len(view)`` now raises :exc:`TypeError` instead of returning 1.
The :class:`~memoryview.itemsize` attribute will give you the number of
bytes in a single element.
A :class:`memoryview` supports slicing and indexing to expose its data.
One-dimensional slicing will result in a subview::

View file

@ -919,9 +919,12 @@ Reassigning them to new values is unsupported:
.. attribute:: Popen.returncode
The child return code, set by :meth:`poll` and :meth:`wait` (and indirectly
by :meth:`communicate`). A ``None`` value indicates that the process
hasn't terminated yet.
The child return code. Initially ``None``, :attr:`returncode` is set by
a call to the :meth:`poll`, :meth:`wait`, or :meth:`communicate` methods
if they detect that the process has terminated.
A ``None`` value indicates that the process hadn't yet terminated at the
time of the last method call.
A negative value ``-N`` indicates that the child was terminated by signal
``N`` (POSIX only).

View file

@ -670,6 +670,13 @@ always available.
.. versionadded:: 3.4
.. function:: getunicodeinternedsize()
Return the number of unicode objects that have been interned.
.. versionadded:: 3.12
.. function:: getandroidapilevel()
Return the build time API version of Android as an integer.

View file

@ -36,6 +36,13 @@ Some facts and figures:
.. versionchanged:: 3.3
Added support for :mod:`lzma` compression.
.. versionchanged:: 3.12
Archives are extracted using a :ref:`filter <tarfile-extraction-filter>`,
which makes it possible to either limit surprising/dangerous features,
or to acknowledge that they are expected and the archive is fully trusted.
By default, archives are fully trusted, but this default is deprecated
and slated to change in Python 3.14.
.. function:: open(name=None, mode='r', fileobj=None, bufsize=10240, **kwargs)
@ -209,6 +216,38 @@ The :mod:`tarfile` module defines the following exceptions:
Is raised by :meth:`TarInfo.frombuf` if the buffer it gets is invalid.
.. exception:: FilterError
Base class for members :ref:`refused <tarfile-extraction-refuse>` by
filters.
.. attribute:: tarinfo
Information about the member that the filter refused to extract,
as :ref:`TarInfo <tarinfo-objects>`.
.. exception:: AbsolutePathError
Raised to refuse extracting a member with an absolute path.
.. exception:: OutsideDestinationError
Raised to refuse extracting a member outside the destination directory.
.. exception:: SpecialFileError
Raised to refuse extracting a special file (e.g. a device or pipe).
.. exception:: AbsoluteLinkError
Raised to refuse extracting a symbolic link with an absolute path.
.. exception:: LinkOutsideDestinationError
Raised to refuse extracting a symbolic link pointing outside the destination
directory.
The following constants are available at the module level:
.. data:: ENCODING
@ -319,11 +358,8 @@ be finalized; only the internally used file object will be closed. See the
*debug* can be set from ``0`` (no debug messages) up to ``3`` (all debug
messages). The messages are written to ``sys.stderr``.
If *errorlevel* is ``0``, all errors are ignored when using :meth:`TarFile.extract`.
Nevertheless, they appear as error messages in the debug output, when debugging
is enabled. If ``1``, all *fatal* errors are raised as :exc:`OSError`
exceptions. If ``2``, all *non-fatal* errors are raised as :exc:`TarError`
exceptions as well.
*errorlevel* controls how extraction errors are handled,
see :attr:`the corresponding attribute <~TarFile.errorlevel>`.
The *encoding* and *errors* arguments define the character encoding to be
used for reading or writing the archive and how conversion errors are going
@ -390,7 +426,7 @@ be finalized; only the internally used file object will be closed. See the
available.
.. method:: TarFile.extractall(path=".", members=None, *, numeric_owner=False)
.. method:: TarFile.extractall(path=".", members=None, *, numeric_owner=False, filter=None)
Extract all members from the archive to the current working directory or
directory *path*. If optional *members* is given, it must be a subset of the
@ -404,6 +440,12 @@ be finalized; only the internally used file object will be closed. See the
are used to set the owner/group for the extracted files. Otherwise, the named
values from the tarfile are used.
The *filter* argument specifies how ``members`` are modified or rejected
before extraction.
See :ref:`tarfile-extraction-filter` for details.
It is recommended to set this explicitly depending on which *tar* features
you need to support.
.. warning::
Never extract archives from untrusted sources without prior inspection.
@ -411,14 +453,20 @@ be finalized; only the internally used file object will be closed. See the
that have absolute filenames starting with ``"/"`` or filenames with two
dots ``".."``.
Set ``filter='data'`` to prevent the most dangerous security issues,
and read the :ref:`tarfile-extraction-filter` section for details.
.. versionchanged:: 3.5
Added the *numeric_owner* parameter.
.. versionchanged:: 3.6
The *path* parameter accepts a :term:`path-like object`.
.. versionchanged:: 3.12
Added the *filter* parameter.
.. method:: TarFile.extract(member, path="", set_attrs=True, *, numeric_owner=False)
.. method:: TarFile.extract(member, path="", set_attrs=True, *, numeric_owner=False, filter=None)
Extract a member from the archive to the current working directory, using its
full name. Its file information is extracted as accurately as possible. *member*
@ -426,9 +474,8 @@ be finalized; only the internally used file object will be closed. See the
directory using *path*. *path* may be a :term:`path-like object`.
File attributes (owner, mtime, mode) are set unless *set_attrs* is false.
If *numeric_owner* is :const:`True`, the uid and gid numbers from the tarfile
are used to set the owner/group for the extracted files. Otherwise, the named
values from the tarfile are used.
The *numeric_owner* and *filter* arguments are the same as
for :meth:`extractall`.
.. note::
@ -439,6 +486,9 @@ be finalized; only the internally used file object will be closed. See the
See the warning for :meth:`extractall`.
Set ``filter='data'`` to prevent the most dangerous security issues,
and read the :ref:`tarfile-extraction-filter` section for details.
.. versionchanged:: 3.2
Added the *set_attrs* parameter.
@ -448,6 +498,9 @@ be finalized; only the internally used file object will be closed. See the
.. versionchanged:: 3.6
The *path* parameter accepts a :term:`path-like object`.
.. versionchanged:: 3.12
Added the *filter* parameter.
.. method:: TarFile.extractfile(member)
@ -460,6 +513,55 @@ be finalized; only the internally used file object will be closed. See the
.. versionchanged:: 3.3
Return an :class:`io.BufferedReader` object.
.. attribute:: TarFile.errorlevel
:type: int
If *errorlevel* is ``0``, errors are ignored when using :meth:`TarFile.extract`
and :meth:`TarFile.extractall`.
Nevertheless, they appear as error messages in the debug output when
*debug* is greater than 0.
If ``1`` (the default), all *fatal* errors are raised as :exc:`OSError` or
:exc:`FilterError` exceptions. If ``2``, all *non-fatal* errors are raised
as :exc:`TarError` exceptions as well.
Some exceptions, e.g. ones caused by wrong argument types or data
corruption, are always raised.
Custom :ref:`extraction filters <tarfile-extraction-filter>`
should raise :exc:`FilterError` for *fatal* errors
and :exc:`ExtractError` for *non-fatal* ones.
Note that when an exception is raised, the archive may be partially
extracted. It is the users responsibility to clean up.
.. attribute:: TarFile.extraction_filter
.. versionadded:: 3.12
The :ref:`extraction filter <tarfile-extraction-filter>` used
as a default for the *filter* argument of :meth:`~TarFile.extract`
and :meth:`~TarFile.extractall`.
The attribute may be ``None`` or a callable.
String names are not allowed for this attribute, unlike the *filter*
argument to :meth:`~TarFile.extract`.
If ``extraction_filter`` is ``None`` (the default),
calling an extraction method without a *filter* argument will raise a
``DeprecationWarning``,
and fall back to the :func:`fully_trusted <fully_trusted_filter>` filter,
whose dangerous behavior matches previous versions of Python.
In Python 3.14+, leaving ``extraction_filter=None`` will cause
extraction methods to use the :func:`data <data_filter>` filter by default.
The attribute may be set on instances or overridden in subclasses.
It also is possible to set it on the ``TarFile`` class itself to set a
global default, although, since it affects all uses of *tarfile*,
it is best practice to only do so in top-level applications or
:mod:`site configuration <site>`.
To set a global default this way, a filter function needs to be wrapped in
:func:`staticmethod()` to prevent injection of a ``self`` argument.
.. method:: TarFile.add(name, arcname=None, recursive=True, *, filter=None)
@ -535,8 +637,23 @@ permissions, owner etc.), it provides some useful methods to determine its type.
It does *not* contain the file's data itself.
:class:`TarInfo` objects are returned by :class:`TarFile`'s methods
:meth:`getmember`, :meth:`getmembers` and :meth:`gettarinfo`.
:meth:`~TarFile.getmember`, :meth:`~TarFile.getmembers` and
:meth:`~TarFile.gettarinfo`.
Modifying the objects returned by :meth:`~!TarFile.getmember` or
:meth:`~!TarFile.getmembers` will affect all subsequent
operations on the archive.
For cases where this is unwanted, you can use :mod:`copy.copy() <copy>` or
call the :meth:`~TarInfo.replace` method to create a modified copy in one step.
Several attributes can be set to ``None`` to indicate that a piece of metadata
is unused or unknown.
Different :class:`TarInfo` methods handle ``None`` differently:
- The :meth:`~TarFile.extract` or :meth:`~TarFile.extractall` methods will
ignore the corresponding metadata, leaving it set to a default.
- :meth:`~TarFile.addfile` will fail.
- :meth:`~TarFile.list` will print a placeholder string.
.. class:: TarInfo(name="")
@ -569,24 +686,39 @@ A ``TarInfo`` object has the following public data attributes:
.. attribute:: TarInfo.name
:type: str
Name of the archive member.
.. attribute:: TarInfo.size
:type: int
Size in bytes.
.. attribute:: TarInfo.mtime
:type: int | float
Time of last modification.
Time of last modification in seconds since the :ref:`epoch <epoch>`,
as in :attr:`os.stat_result.st_mtime`.
.. versionchanged:: 3.12
Can be set to ``None`` for :meth:`~TarFile.extract` and
:meth:`~TarFile.extractall`, causing extraction to skip applying this
attribute.
.. attribute:: TarInfo.mode
:type: int
Permission bits.
Permission bits, as for :func:`os.chmod`.
.. versionchanged:: 3.12
Can be set to ``None`` for :meth:`~TarFile.extract` and
:meth:`~TarFile.extractall`, causing extraction to skip applying this
attribute.
.. attribute:: TarInfo.type
@ -598,35 +730,76 @@ A ``TarInfo`` object has the following public data attributes:
.. attribute:: TarInfo.linkname
:type: str
Name of the target file name, which is only present in :class:`TarInfo` objects
of type :const:`LNKTYPE` and :const:`SYMTYPE`.
.. attribute:: TarInfo.uid
:type: int
User ID of the user who originally stored this member.
.. versionchanged:: 3.12
Can be set to ``None`` for :meth:`~TarFile.extract` and
:meth:`~TarFile.extractall`, causing extraction to skip applying this
attribute.
.. attribute:: TarInfo.gid
:type: int
Group ID of the user who originally stored this member.
.. versionchanged:: 3.12
Can be set to ``None`` for :meth:`~TarFile.extract` and
:meth:`~TarFile.extractall`, causing extraction to skip applying this
attribute.
.. attribute:: TarInfo.uname
:type: str
User name.
.. versionchanged:: 3.12
Can be set to ``None`` for :meth:`~TarFile.extract` and
:meth:`~TarFile.extractall`, causing extraction to skip applying this
attribute.
.. attribute:: TarInfo.gname
:type: str
Group name.
.. versionchanged:: 3.12
Can be set to ``None`` for :meth:`~TarFile.extract` and
:meth:`~TarFile.extractall`, causing extraction to skip applying this
attribute.
.. attribute:: TarInfo.pax_headers
:type: dict
A dictionary containing key-value pairs of an associated pax extended header.
.. method:: TarInfo.replace(name=..., mtime=..., mode=..., linkname=...,
uid=..., gid=..., uname=..., gname=...,
deep=True)
.. versionadded:: 3.12
Return a *new* copy of the :class:`!TarInfo` object with the given attributes
changed. For example, to return a ``TarInfo`` with the group name set to
``'staff'``, use::
new_tarinfo = old_tarinfo.replace(gname='staff')
By default, a deep copy is made.
If *deep* is false, the copy is shallow, i.e. ``pax_headers``
and any custom attributes are shared with the original ``TarInfo`` object.
A :class:`TarInfo` object also provides some convenient query methods:
@ -676,9 +849,258 @@ A :class:`TarInfo` object also provides some convenient query methods:
Return :const:`True` if it is one of character device, block device or FIFO.
.. _tarfile-extraction-filter:
Extraction filters
------------------
.. versionadded:: 3.12
The *tar* format is designed to capture all details of a UNIX-like filesystem,
which makes it very powerful.
Unfortunately, the features make it easy to create tar files that have
unintended -- and possibly malicious -- effects when extracted.
For example, extracting a tar file can overwrite arbitrary files in various
ways (e.g. by using absolute paths, ``..`` path components, or symlinks that
affect later members).
In most cases, the full functionality is not needed.
Therefore, *tarfile* supports extraction filters: a mechanism to limit
functionality, and thus mitigate some of the security issues.
.. seealso::
:pep:`706`
Contains further motivation and rationale behind the design.
The *filter* argument to :meth:`TarFile.extract` or :meth:`~TarFile.extractall`
can be:
* the string ``'fully_trusted'``: Honor all metadata as specified in the
archive.
Should be used if the user trusts the archive completely, or implements
their own complex verification.
* the string ``'tar'``: Honor most *tar*-specific features (i.e. features of
UNIX-like filesystems), but block features that are very likely to be
surprising or malicious. See :func:`tar_filter` for details.
* the string ``'data'``: Ignore or block most features specific to UNIX-like
filesystems. Intended for extracting cross-platform data archives.
See :func:`data_filter` for details.
* ``None`` (default): Use :attr:`TarFile.extraction_filter`.
If that is also ``None`` (the default), raise a ``DeprecationWarning``,
and fall back to the ``'fully_trusted'`` filter, whose dangerous behavior
matches previous versions of Python.
In Python 3.14, the ``'data'`` filter will become the default instead.
It's possible to switch earlier; see :attr:`TarFile.extraction_filter`.
* A callable which will be called for each extracted member with a
:ref:`TarInfo <tarinfo-objects>` describing the member and the destination
path to where the archive is extracted (i.e. the same path is used for all
members)::
filter(/, member: TarInfo, path: str) -> TarInfo | None
The callable is called just before each member is extracted, so it can
take the current state of the disk into account.
It can:
- return a :class:`TarInfo` object which will be used instead of the metadata
in the archive, or
- return ``None``, in which case the member will be skipped, or
- raise an exception to abort the operation or skip the member,
depending on :attr:`~TarFile.errorlevel`.
Note that when extraction is aborted, :meth:`~TarFile.extractall` may leave
the archive partially extracted. It does not attempt to clean up.
Default named filters
~~~~~~~~~~~~~~~~~~~~~
The pre-defined, named filters are available as functions, so they can be
reused in custom filters:
.. function:: fully_trusted_filter(/, member, path)
Return *member* unchanged.
This implements the ``'fully_trusted'`` filter.
.. function:: tar_filter(/, member, path)
Implements the ``'tar'`` filter.
- Strip leading slashes (``/`` and :attr:`os.sep`) from filenames.
- :ref:`Refuse <tarfile-extraction-refuse>` to extract files with absolute
paths (in case the name is absolute
even after stripping slashes, e.g. ``C:/foo`` on Windows).
This raises :class:`~tarfile.AbsolutePathError`.
- :ref:`Refuse <tarfile-extraction-refuse>` to extract files whose absolute
path (after following symlinks) would end up outside the destination.
This raises :class:`~tarfile.OutsideDestinationError`.
- Clear high mode bits (setuid, setgid, sticky) and group/other write bits
(:attr:`~stat.S_IWGRP`|:attr:`~stat.S_IWOTH`).
Return the modified ``TarInfo`` member.
.. function:: data_filter(/, member, path)
Implements the ``'data'`` filter.
In addition to what ``tar_filter`` does:
- :ref:`Refuse <tarfile-extraction-refuse>` to extract links (hard or soft)
that link to absolute paths, or ones that link outside the destination.
This raises :class:`~tarfile.AbsoluteLinkError` or
:class:`~tarfile.LinkOutsideDestinationError`.
Note that such files are refused even on platforms that do not support
symbolic links.
- :ref:`Refuse <tarfile-extraction-refuse>` to extract device files
(including pipes).
This raises :class:`~tarfile.SpecialFileError`.
- For regular files, including hard links:
- Set the owner read and write permissions
(:attr:`~stat.S_IRUSR`|:attr:`~stat.S_IWUSR`).
- Remove the group & other executable permission
(:attr:`~stat.S_IXGRP`|:attr:`~stat.S_IXOTH`)
if the owner doesnt have it (:attr:`~stat.S_IXUSR`).
- For other files (directories), set ``mode`` to ``None``, so
that extraction methods skip applying permission bits.
- Set user and group info (``uid``, ``gid``, ``uname``, ``gname``)
to ``None``, so that extraction methods skip setting it.
Return the modified ``TarInfo`` member.
.. _tarfile-extraction-refuse:
Filter errors
~~~~~~~~~~~~~
When a filter refuses to extract a file, it will raise an appropriate exception,
a subclass of :class:`~tarfile.FilterError`.
This will abort the extraction if :attr:`TarFile.errorlevel` is 1 or more.
With ``errorlevel=0`` the error will be logged and the member will be skipped,
but extraction will continue.
Hints for further verification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Even with ``filter='data'``, *tarfile* is not suited for extracting untrusted
files without prior inspection.
Among other issues, the pre-defined filters do not prevent denial-of-service
attacks. Users should do additional checks.
Here is an incomplete list of things to consider:
* Extract to a :func:`new temporary directory <tempfile.mkdtemp>`
to prevent e.g. exploiting pre-existing links, and to make it easier to
clean up after a failed extraction.
* When working with untrusted data, use external (e.g. OS-level) limits on
disk, memory and CPU usage.
* Check filenames against an allow-list of characters
(to filter out control characters, confusables, foreign path separators,
etc.).
* Check that filenames have expected extensions (discouraging files that
execute when you “click on them”, or extension-less files like Windows special device names).
* Limit the number of extracted files, total size of extracted data,
filename length (including symlink length), and size of individual files.
* Check for files that would be shadowed on case-insensitive filesystems.
Also note that:
* Tar files may contain multiple versions of the same file.
Later ones are expected to overwrite any earlier ones.
This feature is crucial to allow updating tape archives, but can be abused
maliciously.
* *tarfile* does not protect against issues with “live” data,
e.g. an attacker tinkering with the destination (or source) directory while
extraction (or archiving) is in progress.
Supporting older Python versions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Extraction filters were added to Python 3.12, but may be backported to older
versions as security updates.
To check whether the feature is available, use e.g.
``hasattr(tarfile, 'data_filter')`` rather than checking the Python version.
The following examples show how to support Python versions with and without
the feature.
Note that setting ``extraction_filter`` will affect any subsequent operations.
* Fully trusted archive::
my_tarfile.extraction_filter = (lambda member, path: member)
my_tarfile.extractall()
* Use the ``'data'`` filter if available, but revert to Python 3.11 behavior
(``'fully_trusted'``) if this feature is not available::
my_tarfile.extraction_filter = getattr(tarfile, 'data_filter',
(lambda member, path: member))
my_tarfile.extractall()
* Use the ``'data'`` filter; *fail* if it is not available::
my_tarfile.extractall(filter=tarfile.data_filter)
or::
my_tarfile.extraction_filter = tarfile.data_filter
my_tarfile.extractall()
* Use the ``'data'`` filter; *warn* if it is not available::
if hasattr(tarfile, 'data_filter'):
my_tarfile.extractall(filter='data')
else:
# remove this when no longer needed
warn_the_user('Extracting may be unsafe; consider updating Python')
my_tarfile.extractall()
Stateful extraction filter example
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
While *tarfile*'s extraction methods take a simple *filter* callable,
custom filters may be more complex objects with an internal state.
It may be useful to write these as context managers, to be used like this::
with StatefulFilter() as filter_func:
tar.extractall(path, filter=filter_func)
Such a filter can be written as, for example::
class StatefulFilter:
def __init__(self):
self.file_count = 0
def __enter__(self):
return self
def __call__(self, member, path):
self.file_count += 1
return member
def __exit__(self, *exc_info):
print(f'{self.file_count} files extracted')
.. _tarfile-commandline:
.. program:: tarfile
Command-Line Interface
----------------------
@ -748,6 +1170,13 @@ Command-line options
Verbose output.
.. cmdoption:: --filter <filtername>
Specifies the *filter* for ``--extract``.
See :ref:`tarfile-extraction-filter` for details.
Only string names are accepted (that is, ``fully_trusted``, ``tar``,
and ``data``).
.. _tar-examples:
Examples
@ -757,7 +1186,7 @@ How to extract an entire tar archive to the current working directory::
import tarfile
tar = tarfile.open("sample.tar.gz")
tar.extractall()
tar.extractall(filter='data')
tar.close()
How to extract a subset of a tar archive with :meth:`TarFile.extractall` using

View file

@ -201,6 +201,10 @@
Token value for ``":="``.
.. data:: EXCLAMATION
Token value for ``"!"``.
.. data:: OP
.. data:: AWAIT
@ -213,6 +217,12 @@
.. data:: SOFT_KEYWORD
.. data:: FSTRING_START
.. data:: FSTRING_MIDDLE
.. data:: FSTRING_END
.. data:: ERRORTOKEN
.. data:: N_TOKENS

View file

@ -82,6 +82,46 @@ Dynamic Type Creation
.. versionadded:: 3.7
.. function:: get_original_bases(cls, /)
Return the tuple of objects originally given as the bases of *cls* before
the :meth:`~object.__mro_entries__` method has been called on any bases
(following the mechanisms laid out in :pep:`560`). This is useful for
introspecting :ref:`Generics <user-defined-generics>`.
For classes that have an ``__orig_bases__`` attribute, this
function returns the value of ``cls.__orig_bases__``.
For classes without the ``__orig_bases__`` attribute, ``cls.__bases__`` is
returned.
Examples::
from typing import TypeVar, Generic, NamedTuple, TypedDict
T = TypeVar("T")
class Foo(Generic[T]): ...
class Bar(Foo[int], float): ...
class Baz(list[str]): ...
Eggs = NamedTuple("Eggs", [("a", int), ("b", str)])
Spam = TypedDict("Spam", {"a": int, "b": str})
assert Bar.__bases__ == (Foo, float)
assert get_original_bases(Bar) == (Foo[int], float)
assert Baz.__bases__ == (list,)
assert get_original_bases(Baz) == (list[str],)
assert Eggs.__bases__ == (tuple,)
assert get_original_bases(Eggs) == (NamedTuple,)
assert Spam.__bases__ == (dict,)
assert get_original_bases(Spam) == (TypedDict,)
assert int.__bases__ == (object,)
assert get_original_bases(int) == (object,)
.. versionadded:: 3.12
.. seealso::
:pep:`560` - Core support for typing module and generic types

View file

@ -7,7 +7,7 @@
.. moduleauthor:: James C. Ahlstrom <jim@interet.com>
.. sectionauthor:: James C. Ahlstrom <jim@interet.com>
**Source code:** :source:`Lib/zipfile.py`
**Source code:** :source:`Lib/zipfile/`
--------------

View file

@ -2102,6 +2102,10 @@ Resolving MRO entries
:func:`types.resolve_bases`
Dynamically resolve bases that are not instances of :class:`type`.
:func:`types.get_original_bases`
Retrieve a class's "original bases" prior to modifications by
:meth:`~object.__mro_entries__`.
:pep:`560`
Core support for typing module and generic types.

View file

@ -59,7 +59,6 @@ Doc/faq/gui.rst
Doc/faq/library.rst
Doc/faq/programming.rst
Doc/glossary.rst
Doc/howto/argparse.rst
Doc/howto/curses.rst
Doc/howto/descriptor.rst
Doc/howto/enum.rst
@ -78,7 +77,6 @@ Doc/library/__future__.rst
Doc/library/_thread.rst
Doc/library/abc.rst
Doc/library/aifc.rst
Doc/library/argparse.rst
Doc/library/ast.rst
Doc/library/asyncio-dev.rst
Doc/library/asyncio-eventloop.rst
@ -113,7 +111,6 @@ Doc/library/csv.rst
Doc/library/ctypes.rst
Doc/library/curses.ascii.rst
Doc/library/curses.rst
Doc/library/dataclasses.rst
Doc/library/datetime.rst
Doc/library/dbm.rst
Doc/library/decimal.rst
@ -180,7 +177,6 @@ Doc/library/os.rst
Doc/library/ossaudiodev.rst
Doc/library/pickle.rst
Doc/library/pickletools.rst
Doc/library/pkgutil.rst
Doc/library/platform.rst
Doc/library/plistlib.rst
Doc/library/poplib.rst

View file

@ -54,13 +54,6 @@ On FreeBSD and OpenBSD
pkg_add ftp://ftp.openbsd.org/pub/OpenBSD/4.2/packages/i386/python-2.5.1p2.tgz
On OpenSolaris
--------------
You can get Python from `OpenCSW <https://www.opencsw.org/>`_. Various versions
of Python are available and can be installed with e.g. ``pkgutil -i python27``.
.. _building-python-on-unix:
Building Python

View file

@ -470,7 +470,7 @@ 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.
dependents, such as Idle), pip and the Python documentation are not included.
.. note::

View file

@ -172,7 +172,7 @@ this edition of "What's New in Python" links to the bug/patch
item for each change.
Hosting of the Python bug tracker is kindly provided by
`Upfront Systems <http://www.upfrontsoftware.co.za>`__
`Upfront Systems <https://upfrontsoftware.co.za>`__
of Stellenbosch, South Africa. Martin von Löwis put a
lot of effort into importing existing bugs and patches from
SourceForge; his scripts for this import operation are at

View file

@ -2104,7 +2104,7 @@ Changes to Python's build process and to the C API include:
* The latest release of the GNU Debugger, GDB 7, can be `scripted
using Python
<https://sourceware.org/gdb/current/onlinedocs/gdb/Python.html>`__.
<https://web.archive.org/web/20110715084810/http://sourceware.org/gdb/current/onlinedocs/gdb/Python.html>`__.
When you begin debugging an executable program P, GDB will look for
a file named ``P-gdb.py`` and automatically read it. Dave Malcolm
contributed a :file:`python-gdb.py` that adds a number of

View file

@ -137,6 +137,13 @@ New Features
(Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes
with contributions from Gregory P. Smith [Google] and Mark Shannon
in :gh:`96123`.)
* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`,
have a new a *filter* argument that allows limiting tar features than may be
surprising or dangerous, such as creating files outside the destination
directory.
See :ref:`tarfile-extraction-filter` for details.
In Python 3.14, the default will switch to ``'data'``.
(Contributed by Petr Viktorin in :pep:`706`.)
Other Language Changes
@ -250,7 +257,8 @@ asyncio
:mod:`asyncio` does not support legacy generator-based coroutines.
(Contributed by Kumar Aditya in :gh:`102748`.)
* :func:`asyncio.wait` now accepts generators yielding tasks.
* :func:`asyncio.wait` and :func:`asyncio.as_completed` now accepts generators
yielding tasks.
(Contributed by Kumar Aditya in :gh:`78530`.)
csv
@ -308,6 +316,13 @@ fractions
* Objects of type :class:`fractions.Fraction` now support float-style
formatting. (Contributed by Mark Dickinson in :gh:`100161`.)
itertools
---------
* Added :class:`itertools.batched()` for collecting into even-sized
tuples where the last batch may be shorter than the rest.
(Contributed by Raymond Hettinger in :gh:`98363`.)
math
----
@ -399,6 +414,13 @@ threading
profiling functions in all running threads in addition to the calling one.
(Contributed by Pablo Galindo in :gh:`93503`.)
types
-----
* Add :func:`types.get_original_bases` to allow for further introspection of
:ref:`user-defined-generics` when subclassed. (Contributed by
James Hilton-Balfe and Alex Waygood in :gh:`101827`.)
unicodedata
-----------
@ -615,6 +637,10 @@ Deprecated
* The *onerror* argument of :func:`shutil.rmtree` is deprecated as will be removed
in Python 3.14. Use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.)
* Extracting tar archives without specifying *filter* is deprecated until
Python 3.14, when ``'data'`` filter will become the default.
See :ref:`tarfile-extraction-filter` for details.
Pending Removal in Python 3.13
------------------------------
@ -977,6 +1003,10 @@ Changes in the Python API
exception instance, rather than to a ``(typ, exc, tb)`` tuple.
(Contributed by Irit Katriel in :gh:`103176`.)
* When extracting tar files using :mod:`tarfile` or
:func:`shutil.unpack_archive`, pass the *filter* argument to limit features
that may be surprising or dangerous.
See :ref:`tarfile-extraction-filter` for details.
Build Changes
=============
@ -1121,6 +1151,24 @@ New Features
to replace the legacy-api :c:func:`!PyErr_Display`. (Contributed by
Irit Katriel in :gh:`102755`).
* :pep:`683`: Introduced Immortal Objects to Python which allows objects
to bypass reference counts and introduced changes to the C-API:
- ``_Py_IMMORTAL_REFCNT``: The reference count that defines an object
as immortal.
- ``_Py_IsImmortal`` Checks if an object has the immortal reference count.
- ``PyObject_HEAD_INIT`` This will now initialize reference count to
``_Py_IMMORTAL_REFCNT`` when used with ``Py_BUILD_CORE``.
- ``SSTATE_INTERNED_IMMORTAL`` An identifier for interned unicode objects
that are immortal.
- ``SSTATE_INTERNED_IMMORTAL_STATIC`` An identifier for interned unicode
objects that are immortal and static
- ``sys.getunicodeinternedsize`` This returns the total number of unicode
objects that have been interned. This is now needed for refleak.py to
correctly track reference counts and allocated blocks
(Contributed by Eddie Elizondo in :gh:`84436`.)
Porting to Python 3.12
----------------------
@ -1285,8 +1333,7 @@ Removed
* :c:func:`!PyUnicode_GetSize`
* :c:func:`!PyUnicode_GET_DATA_SIZE`
* Remove the ``PyUnicode_InternImmortal()`` function and the
``SSTATE_INTERNED_IMMORTAL`` macro.
* Remove the ``PyUnicode_InternImmortal()`` function macro.
(Contributed by Victor Stinner in :gh:`85858`.)
* Remove ``Jython`` compatibility hacks from several stdlib modules and tests.

View file

@ -53,6 +53,7 @@ ATEQUAL '@='
RARROW '->'
ELLIPSIS '...'
COLONEQUAL ':='
EXCLAMATION '!'
OP
AWAIT
@ -60,6 +61,9 @@ ASYNC
TYPE_IGNORE
TYPE_COMMENT
SOFT_KEYWORD
FSTRING_START
FSTRING_MIDDLE
FSTRING_END
ERRORTOKEN
# These aren't used by the C tokenizer but are needed for tokenize.py

View file

@ -194,7 +194,7 @@ yield_stmt[stmt_ty]: y=yield_expr { _PyAST_Expr(y, EXTRA) }
assert_stmt[stmt_ty]: 'assert' a=expression b=[',' z=expression { z }] { _PyAST_Assert(a, b, EXTRA) }
import_stmt[stmt_ty]:
import_stmt[stmt_ty]:
| invalid_import
| import_name
| import_from
@ -415,8 +415,8 @@ try_stmt[stmt_ty]:
| invalid_try_stmt
| 'try' &&':' b=block f=finally_block { _PyAST_Try(b, NULL, NULL, f, EXTRA) }
| 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_block+ el=[else_block] f=[finally_block] { _PyAST_Try(b, ex, el, f, EXTRA) }
| 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_star_block+ el=[else_block] f=[finally_block] {
CHECK_VERSION(stmt_ty, 11, "Exception groups are",
| 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_star_block+ el=[else_block] f=[finally_block] {
CHECK_VERSION(stmt_ty, 11, "Exception groups are",
_PyAST_TryStar(b, ex, el, f, EXTRA)) }
@ -807,7 +807,7 @@ atom[expr_ty]:
| 'True' { _PyAST_Constant(Py_True, NULL, EXTRA) }
| 'False' { _PyAST_Constant(Py_False, NULL, EXTRA) }
| 'None' { _PyAST_Constant(Py_None, NULL, EXTRA) }
| &STRING strings
| &(STRING|FSTRING_START) strings
| NUMBER
| &'(' (tuple | group | genexp)
| &'[' (list | listcomp)
@ -877,7 +877,26 @@ lambda_param[arg_ty]: a=NAME { _PyAST_arg(a->v.Name.id, NULL, NULL, EXTRA) }
# LITERALS
# ========
strings[expr_ty] (memo): a=STRING+ { _PyPegen_concatenate_strings(p, a) }
fstring_middle[expr_ty]:
| fstring_replacement_field
| t=FSTRING_MIDDLE { _PyPegen_constant_from_token(p, t) }
fstring_replacement_field[expr_ty]:
| '{' a=(yield_expr | star_expressions) debug_expr="="? conversion=[fstring_conversion] format=[fstring_full_format_spec] '}' {
_PyPegen_formatted_value(p, a, debug_expr, conversion, format, EXTRA)
}
| invalid_replacement_field
fstring_conversion[expr_ty]:
| conv_token="!" conv=NAME { _PyPegen_check_fstring_conversion(p, conv_token, conv) }
fstring_full_format_spec[expr_ty]:
| ':' spec=fstring_format_spec* { spec ? _PyAST_JoinedStr((asdl_expr_seq*)spec, EXTRA) : NULL }
fstring_format_spec[expr_ty]:
| t=FSTRING_MIDDLE { _PyPegen_constant_from_token(p, t) }
| fstring_replacement_field
fstring[expr_ty]:
| a=FSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) }
string[expr_ty]: s[Token*]=STRING { _PyPegen_constant_from_string(p, s) }
strings[expr_ty] (memo): a[asdl_expr_seq*]=(fstring|string)+ { _PyPegen_concatenate_strings(p, a, EXTRA) }
list[expr_ty]:
| '[' a=[star_named_expressions] ']' { _PyAST_List(a, Load, EXTRA) }
@ -1118,6 +1137,8 @@ invalid_expression:
_PyPegen_check_legacy_stmt(p, a) ? NULL : p->tokens[p->mark-1]->level == 0 ? NULL :
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Perhaps you forgot a comma?") }
| a=disjunction 'if' b=disjunction !('else'|':') { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "expected 'else' after 'if' expression") }
| a='lambda' [lambda_params] b=':' &(FSTRING_MIDDLE | fstring_replacement_field) {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "f-string: lambda expressions are not allowed without parentheses") }
invalid_named_expression(memo):
| a=expression ':=' expression {
@ -1241,7 +1262,7 @@ invalid_group:
invalid_import:
| a='import' dotted_name 'from' dotted_name {
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "Did you mean to use 'from ... import ...' instead?") }
invalid_import_from_targets:
| import_from_as_names ',' NEWLINE {
RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") }
@ -1335,3 +1356,24 @@ invalid_kvpair:
| expression a=':' &('}'|',') {RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expression expected after dictionary key and ':'") }
invalid_starred_expression:
| a='*' expression '=' b=expression { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot assign to iterable argument unpacking") }
invalid_replacement_field:
| '{' a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '='") }
| '{' a='!' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '!'") }
| '{' a=':' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before ':'") }
| '{' a='}' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '}'") }
| '{' !(yield_expr | star_expressions) { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting a valid expression after '{'")}
| '{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}') {
PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '=', or '!', or ':', or '}'") }
| '{' (yield_expr | star_expressions) '=' !('!' | ':' | '}') {
PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '!', or ':', or '}'") }
| '{' (yield_expr | star_expressions) '='? invalid_conversion_character
| '{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}') {
PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting ':' or '}'") }
| '{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}' {
PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '}', or format specs") }
| '{' (yield_expr | star_expressions) '='? ['!' NAME] !'}' {
PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '}'") }
invalid_conversion_character:
| '!' &(':' | '}') { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: missing conversion character") }
| '!' !NAME { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: invalid conversion character") }

View file

@ -11,8 +11,7 @@ PyAPI_DATA(PyTypeObject) PyBool_Type;
#define PyBool_Check(x) Py_IS_TYPE((x), &PyBool_Type)
/* Py_False and Py_True are the only two bools in existence.
Don't forget to apply Py_INCREF() when returning either!!! */
/* Py_False and Py_True are the only two bools in existence. */
/* Don't use these directly */
PyAPI_DATA(PyLongObject) _Py_FalseStruct;
@ -31,8 +30,8 @@ PyAPI_FUNC(int) Py_IsFalse(PyObject *x);
#define Py_IsFalse(x) Py_Is((x), Py_False)
/* Macros for returning Py_True or Py_False, respectively */
#define Py_RETURN_TRUE return Py_NewRef(Py_True)
#define Py_RETURN_FALSE return Py_NewRef(Py_False)
#define Py_RETURN_TRUE return Py_True
#define Py_RETURN_FALSE return Py_False
/* Function to return a bool from a C long */
PyAPI_FUNC(PyObject *) PyBool_FromLong(long);

View file

@ -245,6 +245,8 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config,
/* --- PyInterpreterConfig ------------------------------------ */
typedef struct {
// XXX "allow_object_sharing"? "own_objects"?
int use_main_obmalloc;
int allow_fork;
int allow_exec;
int allow_threads;
@ -254,6 +256,7 @@ typedef struct {
#define _PyInterpreterConfig_INIT \
{ \
.use_main_obmalloc = 0, \
.allow_fork = 0, \
.allow_exec = 0, \
.allow_threads = 1, \
@ -263,6 +266,7 @@ typedef struct {
#define _PyInterpreterConfig_LEGACY_INIT \
{ \
.use_main_obmalloc = 1, \
.allow_fork = 1, \
.allow_exec = 1, \
.allow_threads = 1, \

View file

@ -564,3 +564,10 @@ PyAPI_FUNC(int) PyType_AddWatcher(PyType_WatchCallback callback);
PyAPI_FUNC(int) PyType_ClearWatcher(int watcher_id);
PyAPI_FUNC(int) PyType_Watch(int watcher_id, PyObject *type);
PyAPI_FUNC(int) PyType_Unwatch(int watcher_id, PyObject *type);
/* Attempt to assign a version tag to the given type.
*
* Returns 1 if the type already had a valid version tag or a new one was
* assigned, or 0 if a new tag could not be assigned.
*/
PyAPI_FUNC(int) PyUnstable_Type_AssignVersionTag(PyTypeObject *type);

View file

@ -11,6 +11,10 @@ is available in a given context. For example, forking the process
might not be allowed in the current interpreter (i.e. os.fork() would fail).
*/
/* Set if the interpreter share obmalloc runtime state
with the main interpreter. */
#define Py_RTFLAGS_USE_MAIN_OBMALLOC (1UL << 5)
/* Set if import should check a module for subinterpreter support. */
#define Py_RTFLAGS_MULTI_INTERP_EXTENSIONS (1UL << 8)

View file

@ -98,9 +98,16 @@ typedef struct {
Py_ssize_t length; /* Number of code points in the string */
Py_hash_t hash; /* Hash value; -1 if not set */
struct {
/* If interned is set, the two references from the
dictionary to this object are *not* counted in ob_refcnt. */
unsigned int interned:1;
/* If interned is non-zero, the two references from the
dictionary to this object are *not* counted in ob_refcnt.
The possible values here are:
0: Not Interned
1: Interned
2: Interned and Immortal
3: Interned, Immortal, and Static
This categorization allows the runtime to determine the right
cleanup mechanism at runtime shutdown. */
unsigned int interned:2;
/* Character size:
- PyUnicode_1BYTE_KIND (1):
@ -135,7 +142,7 @@ typedef struct {
unsigned int ascii:1;
/* Padding to ensure that PyUnicode_DATA() is always aligned to
4 bytes (see issue #19537 on m68k). */
unsigned int :26;
unsigned int :25;
} state;
} PyASCIIObject;
@ -183,6 +190,8 @@ PyAPI_FUNC(int) _PyUnicode_CheckConsistency(
/* Interning state. */
#define SSTATE_NOT_INTERNED 0
#define SSTATE_INTERNED_MORTAL 1
#define SSTATE_INTERNED_IMMORTAL 2
#define SSTATE_INTERNED_IMMORTAL_STATIC 3
/* Use only if you know it's a string */
static inline unsigned int PyUnicode_CHECK_INTERNED(PyObject *op) {

View file

@ -8,15 +8,13 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define"
#endif
#include "pycore_object.h" // _PyObject_IMMORTAL_REFCNT
#ifdef Py_DEBUG
static inline void
_PyStaticObject_CheckRefcnt(PyObject *obj) {
if (Py_REFCNT(obj) < _PyObject_IMMORTAL_REFCNT) {
if (Py_REFCNT(obj) < _Py_IMMORTAL_REFCNT) {
_PyObject_ASSERT_FAILED_MSG(obj,
"immortal object has less refcnt than expected "
"_PyObject_IMMORTAL_REFCNT");
"_Py_IMMORTAL_REFCNT");
}
}
#endif

View file

@ -19,6 +19,8 @@ struct _import_runtime_state {
used exclusively for when the extensions dict is access/modified
from an arbitrary thread. */
PyThreadState main_tstate;
/* A lock to guard the dict. */
PyThread_type_lock mutex;
/* A dict mapping (filename, name) to PyModuleDef for modules.
Only legacy (single-phase init) extension modules are added
and only if they support multiple initialization (m_size >- 0)

View file

@ -23,11 +23,12 @@ extern "C" {
#include "pycore_function.h" // FUNC_MAX_WATCHERS
#include "pycore_genobject.h" // struct _Py_async_gen_state
#include "pycore_gc.h" // struct _gc_runtime_state
#include "pycore_global_objects.h" // struct _Py_interp_static_objects
#include "pycore_import.h" // struct _import_state
#include "pycore_instruments.h" // PY_MONITORING_EVENTS
#include "pycore_list.h" // struct _Py_list_state
#include "pycore_global_objects.h" // struct _Py_interp_static_objects
#include "pycore_object_state.h" // struct _py_object_state
#include "pycore_obmalloc.h" // struct obmalloc_state
#include "pycore_tuple.h" // struct _Py_tuple_state
#include "pycore_typeobject.h" // struct type_cache
#include "pycore_unicodeobject.h" // struct _Py_unicode_state
@ -82,6 +83,8 @@ struct _is {
int _initialized;
int finalizing;
struct _obmalloc_state obmalloc;
struct _ceval_state ceval;
struct _gc_runtime_state gc;

View file

@ -245,7 +245,7 @@ _PyLong_FlipSign(PyLongObject *op) {
#define _PyLong_DIGIT_INIT(val) \
{ \
.ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \
.ob_base = _PyObject_HEAD_INIT(&PyLong_Type) \
.long_value = { \
.lv_tag = TAG_FROM_SIGN_AND_SIZE( \
(val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \

View file

@ -14,21 +14,25 @@ extern "C" {
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_runtime.h" // _PyRuntime
/* This value provides *effective* immortality, meaning the object should never
be deallocated (until runtime finalization). See PEP 683 for more details about
immortality, as well as a proposed mechanism for proper immortality. */
#define _PyObject_IMMORTAL_REFCNT 999999999
#define _PyObject_IMMORTAL_INIT(type) \
{ \
.ob_refcnt = _PyObject_IMMORTAL_REFCNT, \
.ob_type = (type), \
}
#define _PyVarObject_IMMORTAL_INIT(type, size) \
{ \
.ob_base = _PyObject_IMMORTAL_INIT(type), \
.ob_size = size, \
}
/* We need to maintain an internal copy of Py{Var}Object_HEAD_INIT to avoid
designated initializer conflicts in C++20. If we use the deinition in
object.h, we will be mixing designated and non-designated initializers in
pycore objects which is forbiddent in C++20. However, if we then use
designated initializers in object.h then Extensions without designated break.
Furthermore, we can't use designated initializers in Extensions since these
are not supported pre-C++20. Thus, keeping an internal copy here is the most
backwards compatible solution */
#define _PyObject_HEAD_INIT(type) \
{ \
_PyObject_EXTRA_INIT \
.ob_refcnt = _Py_IMMORTAL_REFCNT, \
.ob_type = (type) \
},
#define _PyVarObject_HEAD_INIT(type, size) \
{ \
.ob_base = _PyObject_HEAD_INIT(type) \
.ob_size = size \
},
PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc(
const char *func,
@ -61,9 +65,20 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
}
#define _Py_RefcntAdd(op, n) _Py_RefcntAdd(_PyObject_CAST(op), n)
static inline void _Py_SetImmortal(PyObject *op)
{
if (op) {
op->ob_refcnt = _Py_IMMORTAL_REFCNT;
}
}
#define _Py_SetImmortal(op) _Py_SetImmortal(_PyObject_CAST(op))
static inline void
_Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
{
if (_Py_IsImmortal(op)) {
return;
}
_Py_DECREF_STAT_INC();
#ifdef Py_REF_DEBUG
_Py_DEC_REFTOTAL(_PyInterpreterState_GET());
@ -82,6 +97,9 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
static inline void
_Py_DECREF_NO_DEALLOC(PyObject *op)
{
if (_Py_IsImmortal(op)) {
return;
}
_Py_DECREF_STAT_INC();
#ifdef Py_REF_DEBUG
_Py_DEC_REFTOTAL(_PyInterpreterState_GET());

View file

@ -657,8 +657,12 @@ struct _obmalloc_usage {
#endif /* WITH_PYMALLOC_RADIX_TREE */
struct _obmalloc_state {
struct _obmalloc_global_state {
int dump_debug_stats;
Py_ssize_t interpreter_leaks;
};
struct _obmalloc_state {
struct _obmalloc_pools pools;
struct _obmalloc_mgmt mgmt;
struct _obmalloc_usage usage;
@ -675,7 +679,11 @@ void _PyObject_VirtualFree(void *, size_t size);
/* This function returns the number of allocated memory blocks, regardless of size */
PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void);
extern Py_ssize_t _Py_GetGlobalAllocatedBlocks(void);
#define _Py_GetAllocatedBlocks() \
_Py_GetGlobalAllocatedBlocks()
extern Py_ssize_t _PyInterpreterState_GetAllocatedBlocks(PyInterpreterState *);
extern void _PyInterpreterState_FinalizeAllocatedBlocks(PyInterpreterState *);
#ifdef WITH_PYMALLOC

View file

@ -54,9 +54,13 @@ extern "C" {
# error "NB_SMALL_SIZE_CLASSES should be less than 64"
#endif
#define _obmalloc_state_INIT(obmalloc) \
#define _obmalloc_global_state_INIT \
{ \
.dump_debug_stats = -1, \
}
#define _obmalloc_state_INIT(obmalloc) \
{ \
.pools = { \
.used = _obmalloc_pools_INIT(obmalloc.pools), \
}, \

View file

@ -179,6 +179,7 @@ const uint8_t _PyOpcode_Deopt[256] = {
[LOAD_GLOBAL_BUILTIN] = LOAD_GLOBAL,
[LOAD_GLOBAL_MODULE] = LOAD_GLOBAL,
[LOAD_NAME] = LOAD_NAME,
[LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR,
[MAKE_CELL] = MAKE_CELL,
[MAKE_FUNCTION] = MAKE_FUNCTION,
[MAP_ADD] = MAP_ADD,
@ -236,7 +237,7 @@ const uint8_t _PyOpcode_Deopt[256] = {
#endif // NEED_OPCODE_TABLES
#ifdef Py_DEBUG
static const char *const _PyOpcode_OpName[263] = {
static const char *const _PyOpcode_OpName[266] = {
[CACHE] = "CACHE",
[POP_TOP] = "POP_TOP",
[PUSH_NULL] = "PUSH_NULL",
@ -378,9 +379,9 @@ static const char *const _PyOpcode_OpName[263] = {
[STORE_DEREF] = "STORE_DEREF",
[DELETE_DEREF] = "DELETE_DEREF",
[JUMP_BACKWARD] = "JUMP_BACKWARD",
[STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST",
[LOAD_SUPER_ATTR] = "LOAD_SUPER_ATTR",
[CALL_FUNCTION_EX] = "CALL_FUNCTION_EX",
[STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT",
[STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST",
[EXTENDED_ARG] = "EXTENDED_ARG",
[LIST_APPEND] = "LIST_APPEND",
[SET_ADD] = "SET_ADD",
@ -390,15 +391,15 @@ static const char *const _PyOpcode_OpName[263] = {
[YIELD_VALUE] = "YIELD_VALUE",
[RESUME] = "RESUME",
[MATCH_CLASS] = "MATCH_CLASS",
[STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT",
[STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT",
[UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST",
[FORMAT_VALUE] = "FORMAT_VALUE",
[BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP",
[BUILD_STRING] = "BUILD_STRING",
[UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST",
[UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE",
[UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE",
[SEND_GEN] = "SEND_GEN",
[161] = "<161>",
[LIST_EXTEND] = "LIST_EXTEND",
[SET_UPDATE] = "SET_UPDATE",
[DICT_MERGE] = "DICT_MERGE",
@ -500,11 +501,13 @@ static const char *const _PyOpcode_OpName[263] = {
[JUMP] = "JUMP",
[JUMP_NO_INTERRUPT] = "JUMP_NO_INTERRUPT",
[LOAD_METHOD] = "LOAD_METHOD",
[LOAD_SUPER_METHOD] = "LOAD_SUPER_METHOD",
[LOAD_ZERO_SUPER_METHOD] = "LOAD_ZERO_SUPER_METHOD",
[LOAD_ZERO_SUPER_ATTR] = "LOAD_ZERO_SUPER_ATTR",
};
#endif
#define EXTRA_CASES \
case 161: \
case 166: \
case 167: \
case 168: \

View file

@ -64,6 +64,7 @@ extern void _PyAtExit_Fini(PyInterpreterState *interp);
extern void _PyThread_FiniType(PyInterpreterState *interp);
extern void _Py_Deepfreeze_Fini(void);
extern void _PyArg_Fini(void);
extern void _Py_FinalizeAllocatedBlocks(_PyRuntimeState *);
extern PyStatus _PyGILState_Init(PyInterpreterState *interp);
extern PyStatus _PyGILState_SetTstate(PyThreadState *tstate);

View file

@ -33,6 +33,13 @@ _Py_IsMainInterpreter(PyInterpreterState *interp)
return (interp == _PyInterpreterState_Main());
}
static inline int
_Py_IsMainInterpreterFinalizing(PyInterpreterState *interp)
{
return (_PyRuntimeState_GetFinalizing(interp->runtime) != NULL &&
interp == &interp->runtime->_main_interpreter);
}
static inline const PyConfig *
_Py_GetMainConfig(void)
@ -64,17 +71,14 @@ _Py_ThreadCanHandlePendingCalls(void)
/* Variable and macro for in-line access to current thread
and interpreter state */
static inline PyThreadState*
_PyRuntimeState_GetThreadState(_PyRuntimeState *runtime)
{
return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->tstate_current);
}
#if defined(HAVE_THREAD_LOCAL) && !defined(Py_BUILD_CORE_MODULE)
extern _Py_thread_local PyThreadState *_Py_tss_tstate;
#endif
PyAPI_DATA(PyThreadState *) _PyThreadState_GetCurrent(void);
/* Get the current Python thread state.
Efficient macro reading directly the 'tstate_current' atomic
variable. The macro is unsafe: it does not check for error and it can
return NULL.
This function is unsafe: it does not check for error and it can return NULL.
The caller must hold the GIL.
@ -82,9 +86,20 @@ _PyRuntimeState_GetThreadState(_PyRuntimeState *runtime)
static inline PyThreadState*
_PyThreadState_GET(void)
{
return _PyRuntimeState_GetThreadState(&_PyRuntime);
#if defined(HAVE_THREAD_LOCAL) && !defined(Py_BUILD_CORE_MODULE)
return _Py_tss_tstate;
#else
return _PyThreadState_GetCurrent();
#endif
}
static inline PyThreadState*
_PyRuntimeState_GetThreadState(_PyRuntimeState *Py_UNUSED(runtime))
{
return _PyThreadState_GET();
}
static inline void
_Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate)
{

View file

@ -21,10 +21,10 @@ extern "C" {
#include "pycore_pymem.h" // struct _pymem_allocators
#include "pycore_pyhash.h" // struct pyhash_runtime_state
#include "pycore_pythread.h" // struct _pythread_runtime_state
#include "pycore_obmalloc.h" // struct obmalloc_state
#include "pycore_signal.h" // struct _signals_runtime_state
#include "pycore_time.h" // struct _time_runtime_state
#include "pycore_tracemalloc.h" // struct _tracemalloc_runtime_state
#include "pycore_typeobject.h" // struct types_runtime_state
#include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_ids
struct _getargs_runtime_state {
@ -87,7 +87,7 @@ typedef struct pyruntimestate {
_Py_atomic_address _finalizing;
struct _pymem_allocators allocators;
struct _obmalloc_state obmalloc;
struct _obmalloc_global_state obmalloc;
struct pyhash_runtime_state pyhash_state;
struct _time_runtime_state time;
struct _pythread_runtime_state threads;
@ -119,9 +119,6 @@ typedef struct pyruntimestate {
unsigned long main_thread;
/* Assuming the current thread holds the GIL, this is the
PyThreadState for the current thread. */
_Py_atomic_address tstate_current;
/* Used for the thread state bound to the current thread. */
Py_tss_t autoTSSkey;
@ -153,13 +150,7 @@ typedef struct pyruntimestate {
struct _py_object_runtime_state object_state;
struct _Py_float_runtime_state float_state;
struct _Py_unicode_runtime_state unicode_state;
struct {
/* Used to set PyTypeObject.tp_version_tag */
// bpo-42745: next_version_tag remains shared by all interpreters
// because of static types.
unsigned int next_version_tag;
} types;
struct _types_runtime_state types;
/* All the objects that are shared by the runtime's interpreters. */
struct _Py_static_objects static_objects;

View file

@ -29,7 +29,7 @@ extern PyTypeObject _PyExc_MemoryError;
_pymem_allocators_debug_INIT, \
_pymem_allocators_obj_arena_INIT, \
}, \
.obmalloc = _obmalloc_state_INIT(runtime.obmalloc), \
.obmalloc = _obmalloc_global_state_INIT, \
.pyhash_state = pyhash_state_INIT, \
.signals = _signals_RUNTIME_INIT, \
.interpreters = { \
@ -76,13 +76,13 @@ extern PyTypeObject _PyExc_MemoryError;
.latin1 = _Py_str_latin1_INIT, \
}, \
.tuple_empty = { \
.ob_base = _PyVarObject_IMMORTAL_INIT(&PyTuple_Type, 0) \
.ob_base = _PyVarObject_HEAD_INIT(&PyTuple_Type, 0) \
}, \
.hamt_bitmap_node_empty = { \
.ob_base = _PyVarObject_IMMORTAL_INIT(&_PyHamt_BitmapNode_Type, 0) \
.ob_base = _PyVarObject_HEAD_INIT(&_PyHamt_BitmapNode_Type, 0) \
}, \
.context_token_missing = { \
.ob_base = _PyObject_IMMORTAL_INIT(&_PyContextTokenMissing_Type), \
.ob_base = _PyObject_HEAD_INIT(&_PyContextTokenMissing_Type) \
}, \
}, \
}, \
@ -93,6 +93,7 @@ extern PyTypeObject _PyExc_MemoryError;
{ \
.id_refcount = -1, \
.imports = IMPORTS_INIT, \
.obmalloc = _obmalloc_state_INIT(INTERP.obmalloc), \
.ceval = { \
.recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \
}, \
@ -112,15 +113,18 @@ extern PyTypeObject _PyExc_MemoryError;
.func_state = { \
.next_version = 1, \
}, \
.types = { \
.next_version_tag = _Py_TYPE_BASE_VERSION_TAG, \
}, \
.static_objects = { \
.singletons = { \
._not_used = 1, \
.hamt_empty = { \
.ob_base = _PyObject_IMMORTAL_INIT(&_PyHamt_Type), \
.ob_base = _PyObject_HEAD_INIT(&_PyHamt_Type) \
.h_root = (PyHamtNode*)&_Py_SINGLETON(hamt_bitmap_node_empty), \
}, \
.last_resort_memory_error = { \
_PyObject_IMMORTAL_INIT(&_PyExc_MemoryError), \
_PyObject_HEAD_INIT(&_PyExc_MemoryError) \
}, \
}, \
}, \
@ -138,7 +142,7 @@ extern PyTypeObject _PyExc_MemoryError;
#define _PyBytes_SIMPLE_INIT(CH, LEN) \
{ \
_PyVarObject_IMMORTAL_INIT(&PyBytes_Type, (LEN)), \
_PyVarObject_HEAD_INIT(&PyBytes_Type, (LEN)) \
.ob_shash = -1, \
.ob_sval = { (CH) }, \
}
@ -149,7 +153,7 @@ extern PyTypeObject _PyExc_MemoryError;
#define _PyUnicode_ASCII_BASE_INIT(LITERAL, ASCII) \
{ \
.ob_base = _PyObject_IMMORTAL_INIT(&PyUnicode_Type), \
.ob_base = _PyObject_HEAD_INIT(&PyUnicode_Type) \
.length = sizeof(LITERAL) - 1, \
.hash = -1, \
.state = { \

View file

@ -67,14 +67,18 @@ extern "C" {
#define RARROW 51
#define ELLIPSIS 52
#define COLONEQUAL 53
#define OP 54
#define AWAIT 55
#define ASYNC 56
#define TYPE_IGNORE 57
#define TYPE_COMMENT 58
#define SOFT_KEYWORD 59
#define ERRORTOKEN 60
#define N_TOKENS 64
#define EXCLAMATION 54
#define OP 55
#define AWAIT 56
#define ASYNC 57
#define TYPE_IGNORE 58
#define TYPE_COMMENT 59
#define SOFT_KEYWORD 60
#define FSTRING_START 61
#define FSTRING_MIDDLE 62
#define FSTRING_END 63
#define ERRORTOKEN 64
#define N_TOKENS 68
#define NT_OFFSET 256
/* Special definitions for cooperation with parser */
@ -86,6 +90,8 @@ extern "C" {
(x) == NEWLINE || \
(x) == INDENT || \
(x) == DEDENT)
#define ISSTRINGLIT(x) ((x) == STRING || \
(x) == FSTRING_MIDDLE)
// Symbols exported for test_peg_generator

View file

@ -11,22 +11,17 @@ extern "C" {
#endif
/* runtime lifecycle */
/* state */
extern PyStatus _PyTypes_InitTypes(PyInterpreterState *);
extern void _PyTypes_FiniTypes(PyInterpreterState *);
extern void _PyTypes_Fini(PyInterpreterState *);
#define _Py_TYPE_BASE_VERSION_TAG (2<<16)
#define _Py_MAX_GLOBAL_TYPE_VERSION_TAG (_Py_TYPE_BASE_VERSION_TAG - 1)
/* other API */
/* Length of array of slotdef pointers used to store slots with the
same __name__. There should be at most MAX_EQUIV-1 slotdef entries with
the same __name__, for any __name__. Since that's a static property, it is
appropriate to declare fixed-size arrays for this. */
#define MAX_EQUIV 10
typedef struct wrapperbase pytype_slotdef;
struct _types_runtime_state {
/* Used to set PyTypeObject.tp_version_tag for core static types. */
// bpo-42745: next_version_tag remains shared by all interpreters
// because of static types.
unsigned int next_version_tag;
};
// Type attribute lookup cache: speed up attribute and method lookups,
@ -57,6 +52,36 @@ typedef struct {
PyObject *tp_weaklist;
} static_builtin_state;
struct types_state {
/* Used to set PyTypeObject.tp_version_tag.
It starts at _Py_MAX_GLOBAL_TYPE_VERSION_TAG + 1,
where all those lower numbers are used for core static types. */
unsigned int next_version_tag;
struct type_cache type_cache;
size_t num_builtins_initialized;
static_builtin_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES];
};
/* runtime lifecycle */
extern PyStatus _PyTypes_InitTypes(PyInterpreterState *);
extern void _PyTypes_FiniTypes(PyInterpreterState *);
extern void _PyTypes_Fini(PyInterpreterState *);
/* other API */
/* Length of array of slotdef pointers used to store slots with the
same __name__. There should be at most MAX_EQUIV-1 slotdef entries with
the same __name__, for any __name__. Since that's a static property, it is
appropriate to declare fixed-size arrays for this. */
#define MAX_EQUIV 10
typedef struct wrapperbase pytype_slotdef;
static inline PyObject **
_PyStaticType_GET_WEAKREFS_LISTPTR(static_builtin_state *state)
{
@ -78,12 +103,6 @@ _PyType_GetModuleState(PyTypeObject *type)
return mod->md_state;
}
struct types_state {
struct type_cache type_cache;
size_t num_builtins_initialized;
static_builtin_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES];
};
extern int _PyStaticType_InitBuiltin(PyTypeObject *type);
extern static_builtin_state * _PyStaticType_GetState(PyTypeObject *);
@ -98,6 +117,9 @@ _Py_type_getattro(PyTypeObject *type, PyObject *name);
PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name);
PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name);
PyObject *
_PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *meth_found);
#ifdef __cplusplus
}
#endif

View file

@ -12,6 +12,7 @@ extern "C" {
#include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI
void _PyUnicode_ExactDealloc(PyObject *op);
Py_ssize_t _PyUnicode_InternedSize(void);
/* runtime lifecycle */

View file

@ -78,12 +78,76 @@ whose size is determined when the object is allocated.
/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD PyObject ob_base;
#define PyObject_HEAD_INIT(type) \
{ _PyObject_EXTRA_INIT \
1, (type) },
/*
Immortalization:
#define PyVarObject_HEAD_INIT(type, size) \
{ PyObject_HEAD_INIT(type) (size) },
The following indicates the immortalization strategy depending on the amount
of available bits in the reference count field. All strategies are backwards
compatible but the specific reference count value or immortalization check
might change depending on the specializations for the underlying system.
Proper deallocation of immortal instances requires distinguishing between
statically allocated immortal instances vs those promoted by the runtime to be
immortal. The latter should be the only instances that require
cleanup during runtime finalization.
*/
#if SIZEOF_VOID_P > 4
/*
In 64+ bit systems, an object will be marked as immortal by setting all of the
lower 32 bits of the reference count field, which is equal to: 0xFFFFFFFF
Using the lower 32 bits makes the value backwards compatible by allowing
C-Extensions without the updated checks in Py_INCREF and Py_DECREF to safely
increase and decrease the objects reference count. The object would lose its
immortality, but the execution would still be correct.
Reference count increases will use saturated arithmetic, taking advantage of
having all the lower 32 bits set, which will avoid the reference count to go
beyond the refcount limit. Immortality checks for reference count decreases will
be done by checking the bit sign flag in the lower 32 bits.
*/
#define _Py_IMMORTAL_REFCNT UINT_MAX
#else
/*
In 32 bit systems, an object will be marked as immortal by setting all of the
lower 30 bits of the reference count field, which is equal to: 0x3FFFFFFF
Using the lower 30 bits makes the value backwards compatible by allowing
C-Extensions without the updated checks in Py_INCREF and Py_DECREF to safely
increase and decrease the objects reference count. The object would lose its
immortality, but the execution would still be correct.
Reference count increases and decreases will first go through an immortality
check by comparing the reference count field to the immortality reference count.
*/
#define _Py_IMMORTAL_REFCNT (UINT_MAX >> 2)
#endif
// Make all internal uses of PyObject_HEAD_INIT immortal while preserving the
// C-API expectation that the refcnt will be set to 1.
#ifdef Py_BUILD_CORE
#define PyObject_HEAD_INIT(type) \
{ \
_PyObject_EXTRA_INIT \
{ _Py_IMMORTAL_REFCNT }, \
(type) \
},
#else
#define PyObject_HEAD_INIT(type) \
{ \
_PyObject_EXTRA_INIT \
{ 1 }, \
(type) \
},
#endif /* Py_BUILD_CORE */
#define PyVarObject_HEAD_INIT(type, size) \
{ \
PyObject_HEAD_INIT(type) \
(size) \
},
/* PyObject_VAR_HEAD defines the initial segment of all variable-size
* container objects. These end with a declaration of an array with 1
@ -101,7 +165,12 @@ whose size is determined when the object is allocated.
*/
struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
union {
Py_ssize_t ob_refcnt;
#if SIZEOF_VOID_P > 4
PY_UINT32_T ob_refcnt_split[2];
#endif
};
PyTypeObject *ob_type;
};
@ -152,6 +221,15 @@ static inline Py_ssize_t Py_SIZE(PyObject *ob) {
# define Py_SIZE(ob) Py_SIZE(_PyObject_CAST(ob))
#endif
static inline Py_ALWAYS_INLINE int _Py_IsImmortal(PyObject *op)
{
#if SIZEOF_VOID_P > 4
return _Py_CAST(PY_INT32_T, op->ob_refcnt) < 0;
#else
return op->ob_refcnt == _Py_IMMORTAL_REFCNT;
#endif
}
#define _Py_IsImmortal(op) _Py_IsImmortal(_PyObject_CAST(op))
static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
return Py_TYPE(ob) == type;
@ -162,6 +240,13 @@ static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) {
// This immortal check is for code that is unaware of immortal objects.
// The runtime tracks these objects and we should avoid as much
// as possible having extensions inadvertently change the refcnt
// of an immortalized object.
if (_Py_IsImmortal(ob)) {
return;
}
ob->ob_refcnt = refcnt;
}
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
@ -524,19 +609,33 @@ PyAPI_FUNC(void) Py_DecRef(PyObject *);
PyAPI_FUNC(void) _Py_IncRef(PyObject *);
PyAPI_FUNC(void) _Py_DecRef(PyObject *);
static inline void Py_INCREF(PyObject *op)
static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op)
{
#if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030A0000
// Stable ABI for Python 3.10 built in debug mode.
_Py_IncRef(op);
#else
_Py_INCREF_STAT_INC();
// Non-limited C API and limited C API for Python 3.9 and older access
// directly PyObject.ob_refcnt.
#if SIZEOF_VOID_P > 4
// Portable saturated add, branching on the carry flag and set low bits
PY_UINT32_T cur_refcnt = op->ob_refcnt_split[PY_BIG_ENDIAN];
PY_UINT32_T new_refcnt = cur_refcnt + 1;
if (new_refcnt == 0) {
return;
}
op->ob_refcnt_split[PY_BIG_ENDIAN] = new_refcnt;
#else
// Explicitly check immortality against the immortal value
if (_Py_IsImmortal(op)) {
return;
}
op->ob_refcnt++;
#endif
_Py_INCREF_STAT_INC();
#ifdef Py_REF_DEBUG
_Py_INC_REFTOTAL();
#endif // Py_REF_DEBUG
op->ob_refcnt++;
#endif
#endif
}
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
@ -553,6 +652,9 @@ static inline void Py_DECREF(PyObject *op) {
#elif defined(Py_REF_DEBUG)
static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
{
if (_Py_IsImmortal(op)) {
return;
}
_Py_DECREF_STAT_INC();
_Py_DEC_REFTOTAL();
if (--op->ob_refcnt != 0) {
@ -567,11 +669,14 @@ static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
#define Py_DECREF(op) Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op))
#else
static inline void Py_DECREF(PyObject *op)
static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op)
{
_Py_DECREF_STAT_INC();
// Non-limited C API and limited C API for Python 3.9 and older access
// directly PyObject.ob_refcnt.
if (_Py_IsImmortal(op)) {
return;
}
_Py_DECREF_STAT_INC();
if (--op->ob_refcnt == 0) {
_Py_Dealloc(op);
}
@ -721,7 +826,7 @@ PyAPI_FUNC(int) Py_IsNone(PyObject *x);
#define Py_IsNone(x) Py_Is((x), Py_None)
/* Macro for returning Py_None from a function */
#define Py_RETURN_NONE return Py_NewRef(Py_None)
#define Py_RETURN_NONE return Py_None
/*
Py_NotImplemented is a singleton used to signal that an operation is
@ -731,7 +836,7 @@ PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */
#define Py_NotImplemented (&_Py_NotImplementedStruct)
/* Macro for returning Py_NotImplemented from a function */
#define Py_RETURN_NOTIMPLEMENTED return Py_NewRef(Py_NotImplemented)
#define Py_RETURN_NOTIMPLEMENTED return Py_NotImplemented
/* Rich comparison opcodes */
#define Py_LT 0

23
Include/opcode.h generated
View file

@ -95,6 +95,7 @@ extern "C" {
#define STORE_DEREF 138
#define DELETE_DEREF 139
#define JUMP_BACKWARD 140
#define LOAD_SUPER_ATTR 141
#define CALL_FUNCTION_EX 142
#define EXTENDED_ARG 144
#define LIST_APPEND 145
@ -142,7 +143,10 @@ extern "C" {
#define JUMP 260
#define JUMP_NO_INTERRUPT 261
#define LOAD_METHOD 262
#define MAX_PSEUDO_OPCODE 262
#define LOAD_SUPER_METHOD 263
#define LOAD_ZERO_SUPER_METHOD 264
#define LOAD_ZERO_SUPER_ATTR 265
#define MAX_PSEUDO_OPCODE 265
#define BINARY_OP_ADD_FLOAT 6
#define BINARY_OP_ADD_INT 7
#define BINARY_OP_ADD_UNICODE 8
@ -198,18 +202,21 @@ extern "C" {
#define STORE_ATTR_SLOT 111
#define STORE_ATTR_WITH_HINT 112
#define STORE_FAST__LOAD_FAST 113
#define STORE_FAST__STORE_FAST 141
#define STORE_SUBSCR_DICT 143
#define STORE_SUBSCR_LIST_INT 153
#define UNPACK_SEQUENCE_LIST 154
#define UNPACK_SEQUENCE_TUPLE 158
#define UNPACK_SEQUENCE_TWO_TUPLE 159
#define SEND_GEN 160
#define STORE_FAST__STORE_FAST 143
#define STORE_SUBSCR_DICT 153
#define STORE_SUBSCR_LIST_INT 154
#define UNPACK_SEQUENCE_LIST 158
#define UNPACK_SEQUENCE_TUPLE 159
#define UNPACK_SEQUENCE_TWO_TUPLE 160
#define SEND_GEN 161
#define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\
|| ((op) == JUMP) \
|| ((op) == JUMP_NO_INTERRUPT) \
|| ((op) == LOAD_METHOD) \
|| ((op) == LOAD_SUPER_METHOD) \
|| ((op) == LOAD_ZERO_SUPER_METHOD) \
|| ((op) == LOAD_ZERO_SUPER_ATTR) \
)
#define HAS_CONST(op) (false\

View file

@ -184,7 +184,6 @@ typedef Py_ssize_t Py_ssize_clean_t;
# define Py_LOCAL_INLINE(type) static inline type
#endif
// bpo-28126: Py_MEMCPY is kept for backwards compatibility,
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
# define Py_MEMCPY memcpy
#endif
@ -663,6 +662,27 @@ extern char * _getpty(int *, int, mode_t, int);
# define WITH_THREAD
#endif
#ifdef WITH_THREAD
# ifdef Py_BUILD_CORE
# ifdef HAVE_THREAD_LOCAL
# error "HAVE_THREAD_LOCAL is already defined"
# endif
# define HAVE_THREAD_LOCAL 1
# ifdef thread_local
# define _Py_thread_local thread_local
# elif __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
# define _Py_thread_local _Thread_local
# elif defined(_MSC_VER) /* AKA NT_THREADS */
# define _Py_thread_local __declspec(thread)
# elif defined(__GNUC__) /* includes clang */
# define _Py_thread_local __thread
# else
// fall back to the PyThread_tss_*() API, or ignore.
# undef HAVE_THREAD_LOCAL
# endif
# endif
#endif
/* Check that ALT_SOABI is consistent with Py_TRACE_REFS:
./configure --with-trace-refs should must be used to define Py_TRACE_REFS */
#if defined(ALT_SOABI) && defined(Py_TRACE_REFS)

View file

@ -25,6 +25,7 @@
:license: Python License.
"""
import sys
import re
from _ast import *
from contextlib import contextmanager, nullcontext
from enum import IntEnum, auto, _simple_enum
@ -305,28 +306,17 @@ def get_docstring(node, clean=True):
return text
def _splitlines_no_ff(source):
_line_pattern = re.compile(r"(.*?(?:\r\n|\n|\r|$))")
def _splitlines_no_ff(source, maxlines=None):
"""Split a string into lines ignoring form feed and other chars.
This mimics how the Python parser splits source code.
"""
idx = 0
lines = []
next_line = ''
while idx < len(source):
c = source[idx]
next_line += c
idx += 1
# Keep \r\n together
if c == '\r' and idx < len(source) and source[idx] == '\n':
next_line += '\n'
idx += 1
if c in '\r\n':
lines.append(next_line)
next_line = ''
if next_line:
lines.append(next_line)
for lineno, match in enumerate(_line_pattern.finditer(source), 1):
if maxlines is not None and lineno > maxlines:
break
lines.append(match[0])
return lines
@ -360,7 +350,7 @@ def get_source_segment(source, node, *, padded=False):
except AttributeError:
return None
lines = _splitlines_no_ff(source)
lines = _splitlines_no_ff(source, maxlines=end_lineno+1)
if end_lineno == lineno:
return lines[lineno].encode()[col_offset:end_col_offset].decode()

View file

@ -574,6 +574,8 @@ class Bdb:
line = linecache.getline(filename, lineno, frame.f_globals)
if line:
s += lprefix + line.strip()
else:
s += f'{lprefix}Warning: lineno is None'
return s
# The following methods can be called by clients to use

View file

@ -7,6 +7,7 @@ set the first day of the week (0=Monday, 6=Sunday)."""
import sys
import datetime
from enum import IntEnum, global_enum
import locale as _locale
from itertools import repeat
@ -16,6 +17,9 @@ __all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday",
"timegm", "month_name", "month_abbr", "day_name", "day_abbr",
"Calendar", "TextCalendar", "HTMLCalendar", "LocaleTextCalendar",
"LocaleHTMLCalendar", "weekheader",
"Day", "Month", "JANUARY", "FEBRUARY", "MARCH",
"APRIL", "MAY", "JUNE", "JULY",
"AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
"MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY",
"SATURDAY", "SUNDAY"]
@ -37,9 +41,35 @@ class IllegalWeekdayError(ValueError):
return "bad weekday number %r; must be 0 (Monday) to 6 (Sunday)" % self.weekday
# Constants for months referenced later
January = 1
February = 2
# Constants for months
@global_enum
class Month(IntEnum):
JANUARY = 1
FEBRUARY = 2
MARCH = 3
APRIL = 4
MAY = 5
JUNE = 6
JULY = 7
AUGUST = 8
SEPTEMBER = 9
OCTOBER = 10
NOVEMBER = 11
DECEMBER = 12
# Constants for days
@global_enum
class Day(IntEnum):
MONDAY = 0
TUESDAY = 1
WEDNESDAY = 2
THURSDAY = 3
FRIDAY = 4
SATURDAY = 5
SUNDAY = 6
# Number of days per month (except for February in leap years)
mdays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
@ -95,9 +125,6 @@ day_abbr = _localized_day('%a')
month_name = _localized_month('%B')
month_abbr = _localized_month('%b')
# Constants for weekdays
(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)
def isleap(year):
"""Return True for leap years, False for non-leap years."""
@ -125,12 +152,12 @@ def monthrange(year, month):
if not 1 <= month <= 12:
raise IllegalMonthError(month)
day1 = weekday(year, month, 1)
ndays = mdays[month] + (month == February and isleap(year))
ndays = mdays[month] + (month == FEBRUARY and isleap(year))
return day1, ndays
def _monthlen(year, month):
return mdays[month] + (month == February and isleap(year))
return mdays[month] + (month == FEBRUARY and isleap(year))
def _prevmonth(year, month):
@ -260,10 +287,7 @@ class Calendar(object):
Each month contains between 4 and 6 weeks and each week contains 1-7
days. Days are datetime.date objects.
"""
months = [
self.monthdatescalendar(year, i)
for i in range(January, January+12)
]
months = [self.monthdatescalendar(year, m) for m in Month]
return [months[i:i+width] for i in range(0, len(months), width) ]
def yeardays2calendar(self, year, width=3):
@ -273,10 +297,7 @@ class Calendar(object):
(day number, weekday number) tuples. Day numbers outside this month are
zero.
"""
months = [
self.monthdays2calendar(year, i)
for i in range(January, January+12)
]
months = [self.monthdays2calendar(year, m) for m in Month]
return [months[i:i+width] for i in range(0, len(months), width) ]
def yeardayscalendar(self, year, width=3):
@ -285,10 +306,7 @@ class Calendar(object):
yeardatescalendar()). Entries in the week lists are day numbers.
Day numbers outside this month are zero.
"""
months = [
self.monthdayscalendar(year, i)
for i in range(January, January+12)
]
months = [self.monthdayscalendar(year, m) for m in Month]
return [months[i:i+width] for i in range(0, len(months), width) ]
@ -509,7 +527,7 @@ class HTMLCalendar(Calendar):
a('\n')
a('<tr><th colspan="%d" class="%s">%s</th></tr>' % (
width, self.cssclass_year_head, theyear))
for i in range(January, January+12, width):
for i in range(JANUARY, JANUARY+12, width):
# months in this row
months = range(i, min(i+width, 13))
a('<tr>')

View file

@ -441,7 +441,16 @@ class suppress(AbstractContextManager):
# exactly reproduce the limitations of the CPython interpreter.
#
# See http://bugs.python.org/issue12029 for more details
return exctype is not None and issubclass(exctype, self._exceptions)
if exctype is None:
return
if issubclass(exctype, self._exceptions):
return True
if issubclass(exctype, ExceptionGroup):
match, rest = excinst.split(self._exceptions)
if rest is None:
return True
raise rest
return False
class _BaseExitStack:

View file

@ -1965,6 +1965,11 @@ class datetime(date):
def _local_timezone(self):
if self.tzinfo is None:
ts = self._mktime()
# Detect gap
ts2 = self.replace(fold=1-self.fold)._mktime()
if ts2 != ts: # This happens in a gap or a fold
if (ts2 > ts) == self.fold:
ts = ts2
else:
ts = (self - _EPOCH) // timedelta(seconds=1)
localtm = _time.localtime(ts)

View file

@ -41,6 +41,7 @@ JUMP_BACKWARD = opmap['JUMP_BACKWARD']
FOR_ITER = opmap['FOR_ITER']
SEND = opmap['SEND']
LOAD_ATTR = opmap['LOAD_ATTR']
LOAD_SUPER_ATTR = opmap['LOAD_SUPER_ATTR']
CACHE = opmap["CACHE"]
@ -475,6 +476,10 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
argval, argrepr = _get_name_info(arg//2, get_name)
if (arg & 1) and argrepr:
argrepr = "NULL|self + " + argrepr
elif deop == LOAD_SUPER_ATTR:
argval, argrepr = _get_name_info(arg//4, get_name)
if (arg & 1) and argrepr:
argrepr = "NULL|self + " + argrepr
else:
argval, argrepr = _get_name_info(arg, get_name)
elif deop in hasjabs:

View file

@ -1987,7 +1987,7 @@ def get_address_list(value):
try:
token, value = get_address(value)
address_list.append(token)
except errors.HeaderParseError as err:
except errors.HeaderParseError:
leader = None
if value[0] in CFWS_LEADER:
leader, value = get_cfws(value)
@ -2096,7 +2096,7 @@ def get_msg_id(value):
except errors.HeaderParseError:
try:
token, value = get_no_fold_literal(value)
except errors.HeaderParseError as e:
except errors.HeaderParseError:
try:
token, value = get_domain(value)
msg_id.defects.append(errors.ObsoleteHeaderDefect(
@ -2443,7 +2443,6 @@ def get_parameter(value):
raise errors.HeaderParseError("Parameter not followed by '='")
param.append(ValueTerminal('=', 'parameter-separator'))
value = value[1:]
leader = None
if value and value[0] in CFWS_LEADER:
token, value = get_cfws(value)
param.append(token)
@ -2568,7 +2567,7 @@ def parse_mime_parameters(value):
try:
token, value = get_parameter(value)
mime_parameters.append(token)
except errors.HeaderParseError as err:
except errors.HeaderParseError:
leader = None
if value[0] in CFWS_LEADER:
leader, value = get_cfws(value)
@ -2626,7 +2625,6 @@ def parse_content_type_header(value):
don't do that.
"""
ctype = ContentType()
recover = False
if not value:
ctype.defects.append(errors.HeaderMissingRequiredValue(
"Missing content type specification"))

View file

@ -341,7 +341,6 @@ class Charset:
if not lines and not current_line:
lines.append(None)
else:
separator = (' ' if lines else '')
joined_line = EMPTYSTRING.join(current_line)
header_bytes = _encode(joined_line, codec)
lines.append(encoder(header_bytes))

View file

@ -264,7 +264,7 @@ class FeedParser:
yield NeedMoreData
continue
break
msg = self._pop_message()
self._pop_message()
# We need to pop the EOF matcher in order to tell if we're at
# the end of the current file, not the end of the last block
# of message headers.

View file

@ -14,7 +14,7 @@ from io import BytesIO, StringIO
# Intrapackage imports
from email import utils
from email import errors
from email._policybase import Policy, compat32
from email._policybase import compat32
from email import charset as _charset
from email._encoded_words import decode_b
Charset = _charset.Charset

View file

@ -6,7 +6,6 @@
__all__ = ['MIMEText']
from email.charset import Charset
from email.mime.nonmultipart import MIMENonMultipart
@ -36,6 +35,6 @@ class MIMEText(MIMENonMultipart):
_charset = 'utf-8'
MIMENonMultipart.__init__(self, 'text', _subtype, policy=policy,
**{'charset': str(_charset)})
charset=str(_charset))
self.set_payload(_text, _charset)

View file

@ -10,7 +10,7 @@ from importlib import resources
__all__ = ["version", "bootstrap"]
_PACKAGE_NAMES = ('pip',)
_PIP_VERSION = "23.0.1"
_PIP_VERSION = "23.1.1"
_PROJECTS = [
("pip", _PIP_VERSION, "py3"),
]

View file

@ -190,6 +190,8 @@ class property(DynamicClassAttribute):
"""
member = None
_attr_type = None
_cls_type = None
def __get__(self, instance, ownerclass=None):
if instance is None:
@ -199,33 +201,36 @@ class property(DynamicClassAttribute):
raise AttributeError(
'%r has no attribute %r' % (ownerclass, self.name)
)
else:
if self.fget is None:
# look for a member by this name.
try:
return ownerclass._member_map_[self.name]
except KeyError:
raise AttributeError(
'%r has no attribute %r' % (ownerclass, self.name)
) from None
else:
return self.fget(instance)
if self.fget is not None:
# use previous enum.property
return self.fget(instance)
elif self._attr_type == 'attr':
# look up previous attibute
return getattr(self._cls_type, self.name)
elif self._attr_type == 'desc':
# use previous descriptor
return getattr(instance._value_, self.name)
# look for a member by this name.
try:
return ownerclass._member_map_[self.name]
except KeyError:
raise AttributeError(
'%r has no attribute %r' % (ownerclass, self.name)
) from None
def __set__(self, instance, value):
if self.fset is None:
raise AttributeError(
"<enum %r> cannot set attribute %r" % (self.clsname, self.name)
)
else:
if self.fset is not None:
return self.fset(instance, value)
raise AttributeError(
"<enum %r> cannot set attribute %r" % (self.clsname, self.name)
)
def __delete__(self, instance):
if self.fdel is None:
raise AttributeError(
"<enum %r> cannot delete attribute %r" % (self.clsname, self.name)
)
else:
if self.fdel is not None:
return self.fdel(instance)
raise AttributeError(
"<enum %r> cannot delete attribute %r" % (self.clsname, self.name)
)
def __set_name__(self, ownerclass, name):
self.name = name
@ -313,27 +318,38 @@ class _proto_member:
enum_class._member_names_.append(member_name)
# if necessary, get redirect in place and then add it to _member_map_
found_descriptor = None
descriptor_type = None
class_type = None
for base in enum_class.__mro__[1:]:
descriptor = base.__dict__.get(member_name)
if descriptor is not None:
if isinstance(descriptor, (property, DynamicClassAttribute)):
found_descriptor = descriptor
attr = base.__dict__.get(member_name)
if attr is not None:
if isinstance(attr, (property, DynamicClassAttribute)):
found_descriptor = attr
class_type = base
descriptor_type = 'enum'
break
elif (
hasattr(descriptor, 'fget') and
hasattr(descriptor, 'fset') and
hasattr(descriptor, 'fdel')
):
found_descriptor = descriptor
elif _is_descriptor(attr):
found_descriptor = attr
descriptor_type = descriptor_type or 'desc'
class_type = class_type or base
continue
else:
descriptor_type = 'attr'
class_type = base
if found_descriptor:
redirect = property()
redirect.member = enum_member
redirect.__set_name__(enum_class, member_name)
# earlier descriptor found; copy fget, fset, fdel to this one.
redirect.fget = found_descriptor.fget
redirect.fset = found_descriptor.fset
redirect.fdel = found_descriptor.fdel
if descriptor_type in ('enum','desc'):
# earlier descriptor found; copy fget, fset, fdel to this one.
redirect.fget = getattr(found_descriptor, 'fget', None)
redirect._get = getattr(found_descriptor, '__get__', None)
redirect.fset = getattr(found_descriptor, 'fset', None)
redirect._set = getattr(found_descriptor, '__set__', None)
redirect.fdel = getattr(found_descriptor, 'fdel', None)
redirect._del = getattr(found_descriptor, '__delete__', None)
redirect._attr_type = descriptor_type
redirect._cls_type = class_type
setattr(enum_class, member_name, redirect)
else:
setattr(enum_class, member_name, enum_member)

View file

@ -25,7 +25,7 @@ class CalltipWindow(TooltipBase):
text_widget: a Text widget with code for which call-tips are desired
"""
# Note: The Text widget will be accessible as self.anchor_widget
super(CalltipWindow, self).__init__(text_widget)
super().__init__(text_widget)
self.label = self.text = None
self.parenline = self.parencol = self.lastline = None
@ -54,7 +54,7 @@ class CalltipWindow(TooltipBase):
return
self.lastline = curline
self.anchor_widget.see("insert")
super(CalltipWindow, self).position_window()
super().position_window()
def showtip(self, text, parenleft, parenright):
"""Show the call-tip, bind events which will close it and reposition it.
@ -73,7 +73,7 @@ class CalltipWindow(TooltipBase):
self.parenline, self.parencol = map(
int, self.anchor_widget.index(parenleft).split("."))
super(CalltipWindow, self).showtip()
super().showtip()
self._bind_events()
@ -143,7 +143,7 @@ class CalltipWindow(TooltipBase):
# ValueError may be raised by MultiCall
pass
super(CalltipWindow, self).hidetip()
super().hidetip()
def _bind_events(self):
"""Bind event handlers."""

View file

@ -49,9 +49,9 @@ class Idb(bdb.Bdb):
filename = code.co_filename
lineno = frame.f_lineno
basename = os.path.basename(filename)
message = "%s:%s" % (basename, lineno)
message = f"{basename}:{lineno}"
if code.co_name != "?":
message = "%s: %s()" % (message, code.co_name)
message = f"{message}: {code.co_name}()"
return message
@ -213,7 +213,8 @@ class Debugger:
m1 = "%s" % str(type)
if value is not None:
try:
m1 = "%s: %s" % (m1, str(value))
# TODO redo entire section, tries not needed.
m1 = f"{m1}: {value}"
except:
pass
bg = "yellow"

View file

@ -87,7 +87,7 @@ class SequenceTreeItem(ObjectTreeItem):
continue
def setfunction(value, key=key, object=self.object):
object[key] = value
item = make_objecttreeitem("%r:" % (key,), value, setfunction)
item = make_objecttreeitem(f"{key!r}:", value, setfunction)
sublist.append(item)
return sublist

View file

@ -38,12 +38,13 @@ darwin = sys.platform == 'darwin'
def _sphinx_version():
"Format sys.version_info to produce the Sphinx version string used to install the chm docs"
major, minor, micro, level, serial = sys.version_info
release = '%s%s' % (major, minor)
release += '%s' % (micro,)
# TODO remove unneeded function since .chm no longer installed
release = f'{major}{minor}'
release += f'{micro}'
if level == 'candidate':
release += 'rc%s' % (serial,)
release += f'rc{serial}'
elif level != 'final':
release += '%s%s' % (level[0], serial)
release += f'{level[0]}{serial}'
return release
@ -950,7 +951,7 @@ class EditorWindow:
rf_list = []
file_path = self.recent_files_path
if file_path and os.path.exists(file_path):
with open(file_path, 'r',
with open(file_path,
encoding='utf_8', errors='replace') as rf_list_file:
rf_list = rf_list_file.readlines()
if new_file:
@ -1458,7 +1459,7 @@ class EditorWindow:
else:
self.reindent_to(y.compute_backslash_indent())
else:
assert 0, "bogus continuation type %r" % (c,)
assert 0, f"bogus continuation type {c!r}"
return "break"
# This line starts a brand new statement; indent relative to

View file

@ -22,7 +22,7 @@ class FileList:
# This can happen when bad filename is passed on command line:
messagebox.showerror(
"File Error",
"%r is a directory." % (filename,),
f"{filename!r} is a directory.",
master=self.root)
return None
key = os.path.normcase(filename)
@ -90,7 +90,7 @@ class FileList:
self.inversedict[conflict] = None
messagebox.showerror(
"Name Conflict",
"You now have multiple edit windows open for %r" % (filename,),
f"You now have multiple edit windows open for {filename!r}",
master=self.root)
self.dict[newkey] = edit
self.inversedict[edit] = newkey

View file

@ -191,7 +191,7 @@ class IdleConfTest(unittest.TestCase):
idle_dir = os.path.abspath(sys.path[0])
for ctype in conf.config_types:
config_path = os.path.join(idle_dir, '../config-%s.def' % ctype)
with open(config_path, 'r') as f:
with open(config_path) as f:
cls.config_string[ctype] = f.read()
cls.orig_warn = config._warn

View file

@ -159,7 +159,7 @@ class ModuleFunctionTest(unittest.TestCase):
for line, expected_output in test_lines:
self.assertEqual(flh(line), expected_output)
if expected_output:
mock_open.assert_called_with(expected_output[0], 'r')
mock_open.assert_called_with(expected_output[0])
if __name__ == '__main__':

View file

@ -328,7 +328,7 @@ class LineNumbersTest(unittest.TestCase):
self.assertEqual(self.linenumber.sidebar_text.index('@0,0'), '11.0')
# Generate a mouse-wheel event and make sure it scrolled up or down.
# The meaning of the "delta" is OS-dependant, so this just checks for
# The meaning of the "delta" is OS-dependent, so this just checks for
# any change.
self.linenumber.sidebar_text.event_generate('<MouseWheel>',
x=0, y=0,
@ -691,7 +691,7 @@ class ShellSidebarTest(unittest.TestCase):
self.assertIsNotNone(text.dlineinfo(text.index(f'{last_lineno}.0')))
# Scroll up using the <MouseWheel> event.
# The meaning delta is platform-dependant.
# The meaning of delta is platform-dependent.
delta = -1 if sys.platform == 'darwin' else 120
sidebar.canvas.event_generate('<MouseWheel>', x=0, y=0, delta=delta)
yield

View file

@ -52,9 +52,9 @@ else:
_modifier_masks = (MC_CONTROL, MC_ALT, MC_SHIFT, MC_META)
# a dictionary to map a modifier name into its number
_modifier_names = dict([(name, number)
_modifier_names = {name: number
for number in range(len(_modifiers))
for name in _modifiers[number]])
for name in _modifiers[number]}
# In 3.4, if no shell window is ever open, the underlying Tk widget is
# destroyed before .__del__ methods here are called. The following
@ -134,7 +134,7 @@ def expand_substates(states):
return nb
statelist = []
for state in states:
substates = list(set(state & x for x in states))
substates = list({state & x for x in states})
substates.sort(key=nbits, reverse=True)
statelist.append(substates)
return statelist
@ -258,9 +258,9 @@ _types = (
_binder_classes = (_ComplexBinder,) * 4 + (_SimpleBinder,) * (len(_types)-4)
# A dictionary to map a type name into its number
_type_names = dict([(name, number)
_type_names = {name: number
for number in range(len(_types))
for name in _types[number]])
for name in _types[number]}
_keysym_re = re.compile(r"^\w+$")
_button_re = re.compile(r"^[1-5]$")

View file

@ -42,7 +42,7 @@ def file_line_helper(line):
if match:
filename, lineno = match.group(1, 2)
try:
f = open(filename, "r")
f = open(filename)
f.close()
break
except OSError:

View file

@ -249,7 +249,7 @@ class PyShellEditorWindow(EditorWindow):
breaks = self.breakpoints
filename = self.io.filename
try:
with open(self.breakpointPath, "r") as fp:
with open(self.breakpointPath) as fp:
lines = fp.readlines()
except OSError:
lines = []
@ -279,7 +279,7 @@ class PyShellEditorWindow(EditorWindow):
if filename is None:
return
if os.path.isfile(self.breakpointPath):
with open(self.breakpointPath, "r") as fp:
with open(self.breakpointPath) as fp:
lines = fp.readlines()
for line in lines:
if line.startswith(filename + '='):
@ -441,7 +441,7 @@ class ModifiedInterpreter(InteractiveInterpreter):
# run from the IDLE source directory.
del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
default=False, type='bool')
command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
command = f"__import__('idlelib.run').run.main({del_exitf!r})"
return [sys.executable] + w + ["-c", command, str(self.port)]
def start_subprocess(self):
@ -574,9 +574,9 @@ class ModifiedInterpreter(InteractiveInterpreter):
self.runcommand("""if 1:
import sys as _sys
_sys.path = %r
_sys.path = {!r}
del _sys
\n""" % (path,))
\n""".format(path))
active_seq = None
@ -703,14 +703,14 @@ class ModifiedInterpreter(InteractiveInterpreter):
def prepend_syspath(self, filename):
"Prepend sys.path with file's directory if not already included"
self.runcommand("""if 1:
_filename = %r
_filename = {!r}
import sys as _sys
from os.path import dirname as _dirname
_dir = _dirname(_filename)
if not _dir in _sys.path:
_sys.path.insert(0, _dir)
del _filename, _sys, _dirname, _dir
\n""" % (filename,))
\n""".format(filename))
def showsyntaxerror(self, filename=None):
"""Override Interactive Interpreter method: Use Colorizing
@ -1536,7 +1536,7 @@ def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
except getopt.error as msg:
print("Error: %s\n%s" % (msg, usage_msg), file=sys.stderr)
print(f"Error: {msg}\n{usage_msg}", file=sys.stderr)
sys.exit(2)
for o, a in opts:
if o == '-c':
@ -1668,9 +1668,9 @@ def main():
if cmd or script:
shell.interp.runcommand("""if 1:
import sys as _sys
_sys.argv = %r
_sys.argv = {!r}
del _sys
\n""" % (sys.argv,))
\n""".format(sys.argv))
if cmd:
shell.interp.execsource(cmd)
elif script:

View file

@ -47,9 +47,8 @@ class WidgetRedirector:
tk.createcommand(w, self.dispatch)
def __repr__(self):
return "%s(%s<%s>)" % (self.__class__.__name__,
self.widget.__class__.__name__,
self.widget._w)
w = self.widget
return f"{self.__class__.__name__,}({w.__class__.__name__}<{w._w}>)"
def close(self):
"Unregister operations and revert redirection created by .__init__."
@ -143,8 +142,7 @@ class OriginalCommand:
self.orig_and_operation = (redir.orig, operation)
def __repr__(self):
return "%s(%r, %r)" % (self.__class__.__name__,
self.redir, self.operation)
return f"{self.__class__.__name__,}({self.redir!r}, {self.operation!r})"
def __call__(self, *args):
return self.tk_call(self.orig_and_operation + args)

View file

@ -174,7 +174,7 @@ class SocketIO:
except TypeError:
return ("ERROR", "Bad request format")
if oid not in self.objtable:
return ("ERROR", "Unknown object id: %r" % (oid,))
return ("ERROR", f"Unknown object id: {oid!r}")
obj = self.objtable[oid]
if methodname == "__methods__":
methods = {}
@ -185,7 +185,7 @@ class SocketIO:
_getattributes(obj, attributes)
return ("OK", attributes)
if not hasattr(obj, methodname):
return ("ERROR", "Unsupported method name: %r" % (methodname,))
return ("ERROR", f"Unsupported method name: {methodname!r}")
method = getattr(obj, methodname)
try:
if how == 'CALL':

View file

@ -52,13 +52,13 @@ def idle_formatwarning(message, category, filename, lineno, line=None):
"""Format warnings the IDLE way."""
s = "\nWarning (from warnings module):\n"
s += ' File \"%s\", line %s\n' % (filename, lineno)
s += f' File \"{filename}\", line {lineno}\n'
if line is None:
line = linecache.getline(filename, lineno)
line = line.strip()
if line:
s += " %s\n" % line
s += "%s: %s\n" % (category.__name__, message)
s += f"{category.__name__}: {message}\n"
return s
def idle_showwarning_subproc(
@ -239,6 +239,7 @@ def print_exception():
efile = sys.stderr
typ, val, tb = excinfo = sys.exc_info()
sys.last_type, sys.last_value, sys.last_traceback = excinfo
sys.last_exc = val
seen = set()
def print_exc(typ, exc, tb):

View file

@ -169,7 +169,7 @@ def view_file(parent, title, filename, encoding, modal=True, wrap='word',
with contents of the file.
"""
try:
with open(filename, 'r', encoding=encoding) as file:
with open(filename, encoding=encoding) as file:
contents = file.read()
except OSError:
showerror(title='File Load Error',

View file

@ -92,7 +92,7 @@ class OnHoverTooltipBase(TooltipBase):
e.g. after hovering over the anchor widget with the mouse for enough
time.
"""
super(OnHoverTooltipBase, self).__init__(anchor_widget)
super().__init__(anchor_widget)
self.hover_delay = hover_delay
self._after_id = None
@ -107,7 +107,7 @@ class OnHoverTooltipBase(TooltipBase):
self.anchor_widget.unbind("<Button>", self._id3) # pragma: no cover
except TclError:
pass
super(OnHoverTooltipBase, self).__del__()
super().__del__()
def _show_event(self, event=None):
"""event handler to display the tooltip"""
@ -139,7 +139,7 @@ class OnHoverTooltipBase(TooltipBase):
self.unschedule()
except TclError: # pragma: no cover
pass
super(OnHoverTooltipBase, self).hidetip()
super().hidetip()
class Hovertip(OnHoverTooltipBase):
@ -154,7 +154,7 @@ class Hovertip(OnHoverTooltipBase):
e.g. after hovering over the anchor widget with the mouse for enough
time.
"""
super(Hovertip, self).__init__(anchor_widget, hover_delay=hover_delay)
super().__init__(anchor_widget, hover_delay=hover_delay)
self.text = text
def showcontents(self):

View file

@ -32,7 +32,7 @@ except NameError:
if os.path.isdir(_icondir):
ICONDIR = _icondir
elif not os.path.isdir(ICONDIR):
raise RuntimeError("can't find icon directory (%r)" % (ICONDIR,))
raise RuntimeError(f"can't find icon directory ({ICONDIR!r})")
def listicons(icondir=ICONDIR):
"""Utility to display the available icons."""

Some files were not shown because too many files have changed in this diff Show more