What's new in Python 3.15
*************************

Editor:
   Hugo van Kemenade

This article explains the new features in Python 3.15, compared to
3.14.

For full details, see the changelog.

Note:

  Prerelease users should be aware that this document is currently in
  draft form. It will be updated substantially as Python 3.15 moves
  towards release, so it's worth checking back even after reading
  earlier versions.


Summary -- Release highlights
=============================

* **PEP 810**: Explicit lazy imports for faster startup times

* **PEP 814**: Add frozendict built-in type

* **PEP 799**: A dedicated profiling package for organizing Python
  profiling tools

* **PEP 799**: Tachyon: High frequency statistical sampling profiler

* **PEP 798**: Unpacking in Comprehensions

* **PEP 686**: Python now uses UTF-8 as the default encoding

* **PEP 782**: A new PyBytesWriter C API to create a Python bytes
  object

* The JIT compiler has been significantly upgraded

* Improved error messages


New features
============


**PEP 810**: Explicit lazy imports
----------------------------------

Large Python applications often suffer from slow startup times. A
significant contributor to this problem is the import system: when a
module is imported, Python must locate the file, read it from disk,
compile it to bytecode, and execute all top-level code. For
applications with deep dependency trees, this process can take
seconds, even when most of the imported code is never actually used
during a particular run.

Developers have worked around this by moving imports inside functions,
using "importlib" to load modules on demand, or restructuring code to
avoid unnecessary dependencies. These approaches work but make code
harder to read and maintain, scatter import statements throughout the
codebase, and require discipline to apply consistently.

Python now provides a cleaner solution through explicit "lazy" imports
using the new "lazy" soft keyword. When you mark an import as lazy,
Python defers the actual module loading until the imported name is
first used. This gives you the organizational benefits of declaring
all imports at the top of the file while only paying the loading cost
for modules you actually use.

The "lazy" keyword works with both "import" and "from ... import"
statements. When you write "lazy import heavy_module", Python does not
immediately load the module. Instead, it creates a lightweight proxy
object. The actual module loading happens transparently when you first
access the name:

   lazy import json
   lazy from datetime import datetime

   print("Starting up...")  # json and datetime not loaded yet

   data = json.loads('{"key": "value"}')  # json gets loads here
   now = datetime()  # datetime loads here

This mechanism is particularly useful for applications that import
many modules at the top level but may only use a subset of them in any
given run. The deferred loading reduces startup latency without
requiring code restructuring or conditional imports scattered
throughout the codebase.

In the case where loading a lazily imported module fails (for example,
if the module does not exist), Python raises the exception at the
point of first use rather than at import time. The associated
traceback includes both the location where the name was accessed and
the original import statement, making it straightforward to diagnose &
debug the failure.

For cases where you want to enable lazy loading globally without
modifying source code, Python provides the "-X lazy_imports" command-
line option and the "PYTHON_LAZY_IMPORTS" environment variable. Both
accept three values: "all" makes all imports lazy by default, "none"
disables lazy imports entirely (even explicit "lazy" statements become
eager), and "normal" (the default) respects the "lazy" keyword in
source code. The "sys.set_lazy_imports()" and "sys.get_lazy_imports()"
functions allow changing and querying this mode at runtime.

For more selective control, "sys.set_lazy_imports_filter()" accepts a
callable that determines whether a specific module should be loaded
lazily. The filter receives three arguments: the importing module's
name (or "None"), the imported module's name, and the fromlist (or
"None" for regular imports). It should return "True" to allow the
import to be lazy, or "False" to force eager loading. This allows
patterns like making only your own application's modules lazy while
keeping third-party dependencies eager:

   import sys

   def myapp_filter(importing, imported, fromlist):
       return imported.startswith("myapp.")
   sys.set_lazy_imports_filter(myapp_filter)
   sys.set_lazy_imports("all")

   import myapp.slow_module  # lazy (matches filter)
   import json               # eager (does not match filter)

The proxy type itself is available as "types.LazyImportType" for code
that needs to detect lazy imports programmatically.

There are some restrictions on where the "lazy" keyword can be used.
Lazy imports are only permitted at module scope; using "lazy" inside a
function, class body, or "try"/"except"/"finally" block raises a
"SyntaxError". Neither star imports nor future imports can be lazy
("lazy from module import *" and "lazy from __future__ import ..."
both raise "SyntaxError").

See also: **PEP 810** for the full specification and rationale.

(Contributed by Pablo Galindo Salgado and Dino Viehland in gh-142349.)


**PEP 814**: Add frozendict built-in type
-----------------------------------------

A new public immutable type "frozendict" is added to the "builtins"
module. It is not a "dict" subclass but inherits directly from
"object".

A "frozendict" can be hashed with "hash(frozendict)" if all keys and
values can be hashed.

See also: **PEP 814** for the full specification and rationale.


**PEP 799**: A dedicated profiling package
------------------------------------------

A new "profiling" module has been added to organize Python's built-in
profiling tools under a single, coherent namespace. This module
contains:

* "profiling.tracing": deterministic function-call tracing (relocated
  from "cProfile").

* "profiling.sampling": a new statistical sampling profiler (named
  Tachyon).

The "cProfile" module remains as an alias for backwards compatibility.
The "profile" module is deprecated and will be removed in Python 3.17.

See also: **PEP 799** for further details.

(Contributed by Pablo Galindo and László Kiss Kollár in gh-138122.)


Tachyon: High frequency statistical sampling profiler
-----------------------------------------------------

[image: Tachyon profiler logo][image]

A new statistical sampling profiler (Tachyon) has been added as
"profiling.sampling". This profiler enables low-overhead performance
analysis of running Python processes without requiring code
modification or process restart.

Unlike deterministic profilers (such as "profiling.tracing") that
instrument every function call, the sampling profiler periodically
captures stack traces from running processes.  This approach provides
virtually zero overhead while achieving sampling rates of **up to
1,000,000 Hz**, making it the fastest sampling profiler available for
Python (at the time of its contribution) and ideal for debugging
performance issues in production environments. This capability is
particularly valuable for debugging performance issues in production
systems where traditional profiling approaches would be too intrusive.

Key features include:

* **Zero-overhead profiling**: Attach to any running Python process
  without affecting its performance. Ideal for production debugging
  where you can't afford to restart or slow down your application.

* **No code modification required**: Profile existing applications
  without restart. Simply point the profiler at a running process by
  PID and start collecting data.

* **Flexible target modes**:

  * Profile running processes by PID ("attach") - attach to already-
    running applications

  * Run and profile scripts directly ("run") - profile from the very
    start of execution

  * Execute and profile modules ("run -m") - profile packages run as
    "python -m module"

* **Multiple profiling modes**: Choose what to measure based on your
  performance investigation:

  * **Wall-clock time** ("--mode wall", default): Measures real
    elapsed time including I/O, network waits, and blocking
    operations. Use this to understand where your program spends
    calendar time, including when waiting for external resources.

  * **CPU time** ("--mode cpu"): Measures only active CPU execution
    time, excluding I/O waits and blocking. Use this to identify CPU-
    bound bottlenecks and optimize computational work.

  * **GIL-holding time** ("--mode gil"): Measures time spent holding
    Python's Global Interpreter Lock. Use this to identify which
    threads dominate GIL usage in multi-threaded applications.

  * **Exception handling time** ("--mode exception"): Captures samples
    only from threads with an active exception. Use this to analyze
    exception handling overhead.

* **Thread-aware profiling**: Option to profile all threads ("-a") or
  just the main thread, essential for understanding multi-threaded
  application behavior.

* **Multiple output formats**: Choose the visualization that best fits
  your workflow:

  * "--pstats": Detailed tabular statistics compatible with "pstats".
    Shows function-level timing with direct and cumulative samples.
    Best for detailed analysis and integration with existing Python
    profiling tools.

  * "--collapsed": Generates collapsed stack traces (one line per
    stack). This format is specifically designed for creating flame
    graphs with external tools like Brendan Gregg's FlameGraph scripts
    or speedscope.

  * "--flamegraph": Generates a self-contained interactive HTML flame
    graph using D3.js. Opens directly in your browser for immediate
    visual analysis. Flame graphs show the call hierarchy where width
    represents time spent, making it easy to spot bottlenecks at a
    glance.

  * "--gecko": Generates Gecko Profiler format compatible with Firefox
    Profiler. Upload the output to Firefox Profiler for advanced
    timeline-based analysis with features like stack charts, markers,
    and network activity.

  * "--heatmap": Generates an interactive HTML heatmap visualization
    with line-level sample counts. Creates a directory with per-file
    heatmaps showing exactly where time is spent at the source code
    level.

* **Live interactive mode**: Real-time TUI profiler with a top-like
  interface ("--live"). Monitor performance as your application runs
  with interactive sorting and filtering.

* **Async-aware profiling**: Profile async/await code with task-based
  stack reconstruction ("--async-aware"). See which coroutines are
  consuming time, with options to show only running tasks or all tasks
  including those waiting.

* **Opcode-level profiling**: Gather bytecode opcode information for
  instruction-level profiling ("--opcodes"). Shows which bytecode
  instructions are executing, including specializations from the
  adaptive interpreter.

See "profiling.sampling" for the complete documentation, including all
available output formats, profiling modes, and configuration options.

(Contributed by Pablo Galindo and László Kiss Kollár in gh-135953 and
gh-138122.)


**PEP 798**: Unpacking in Comprehensions
----------------------------------------

List, set, and dictionary comprehensions, as well as generator
expressions, now support unpacking with "*" and "**".  This extends
the unpacking syntax from **PEP 448** to comprehensions, providing a
new syntax for combining an arbitrary number of iterables or
dictionaries into a single flat structure. This new syntax is a direct
alternative to nested comprehensions, "itertools.chain()", and
"itertools.chain.from_iterable()".  For example:

   >>> lists = [[1, 2], [3, 4], [5]]
   >>> [*L for L in lists]  # equivalent to [x for L in lists for x in L]
   [1, 2, 3, 4, 5]

   >>> sets = [{1, 2}, {2, 3}, {3, 4}]
   >>> {*s for s in sets}  # equivalent to {x for s in sets for x in s}
   {1, 2, 3, 4}

   >>> dicts = [{'a': 1}, {'b': 2}, {'a': 3}]
   >>> {**d for d in dicts}  # equivalent to {k: v for d in dicts for k,v in d.items()}
   {'a': 3, 'b': 2}

Generator expressions can similarly use unpacking to yield values from
multiple iterables:

   >>> gen = (*L for L in lists)  # equivalent to (x for L in lists for x in L)
   >>> list(gen)
   [1, 2, 3, 4, 5]

This change also extends to asynchronous generator expressions, such
that, for example, "(*a async for a in agen())" is equivalent to "(x
async for a in agen() for x in a)".

See also: **PEP 798** for further details.

(Contributed by Adam Hartz in gh-143055.)


Improved error messages
-----------------------

* The interpreter now provides more helpful suggestions in
  "AttributeError" exceptions when accessing an attribute on an object
  that does not exist, but a similar attribute is available through
  one of its members.

  For example, if the object has an attribute that itself exposes the
  requested name, the error message will suggest accessing it via that
  inner attribute:

     @dataclass
     class Circle:
        radius: float

        @property
        def area(self) -> float:
           return pi * self.radius**2

     class Container:
        def __init__(self, inner: Circle) -> None:
           self.inner = inner

     circle = Circle(radius=4.0)
     container = Container(circle)
     print(container.area)

  Running this code now produces a clearer suggestion:

     Traceback (most recent call last):
     File "/home/pablogsal/github/python/main/lel.py", line 42, in <module>
        print(container.area)
              ^^^^^^^^^^^^^^
     AttributeError: 'Container' object has no attribute 'area'. Did you mean: 'inner.area'?


Other language changes
======================

* Python now uses UTF-8 as the default encoding, independent of the
  system's environment. This means that I/O operations without an
  explicit encoding, for example, "open('flying-circus.txt')", will
  use UTF-8. UTF-8 is a widely-supported Unicode character encoding
  that has become a *de facto* standard for representing text,
  including nearly every webpage on the internet, many common file
  formats, programming languages, and more.

  This only applies when no "encoding" argument is given. For best
  compatibility between versions of Python, ensure that an explicit
  "encoding" argument is always provided. The opt-in encoding warning
  can be used to identify code that may be affected by this change.
  The special "encoding='locale'" argument uses the current locale
  encoding, and has been supported since Python 3.10.

  To retain the previous behaviour, Python's UTF-8 mode may be
  disabled with the "PYTHONUTF8=0" environment variable or the "-X
  utf8=0" command-line option.

  See also: **PEP 686** for further details.

  (Contributed by Adam Turner in gh-133711; PEP 686 written by Inada
  Naoki.)

* Several error messages incorrectly using the term "argument" have
  been corrected. (Contributed by Stan Ulbrych in gh-133382.)

* The interpreter now tries to provide a suggestion when "delattr()"
  fails due to a missing attribute. When an attribute name that
  closely resembles an existing attribute is used, the interpreter
  will suggest the correct attribute name in the error message. For
  example:

     >>> class A:
     ...     pass
     >>> a = A()
     >>> a.abcde = 1
     >>> del a.abcdf
     Traceback (most recent call last):
     ...
     AttributeError: 'A' object has no attribute 'abcdf'. Did you mean: 'abcde'?

  (Contributed by Nikita Sobolev and Pranjal Prajapati in gh-136588.)

* Unraisable exceptions are now highlighted with color by default.
  This can be controlled by environment variables. (Contributed by
  Peter Bierma in gh-134170.)

* The "__repr__()" of "ImportError" and "ModuleNotFoundError" now
  shows "name" and "path" as "name=<name>" and "path=<path>" if they
  were given as keyword arguments at construction time. (Contributed
  by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir in gh-74185.)

* The "__dict__" and "__weakref__" descriptors now use a single
  descriptor instance per interpreter, shared across all types that
  need them. This speeds up class creation, and helps avoid reference
  cycles. (Contributed by Petr Viktorin in gh-135228.)

* The "-W" option and the "PYTHONWARNINGS" environment variable can
  now specify regular expressions instead of literal strings to match
  the warning message and the module name, if the corresponding field
  starts and ends with a forward slash ("/"). (Contributed by Serhiy
  Storchaka in gh-134716.)

* Functions that take timestamp or timeout arguments now accept any
  real numbers (such as "Decimal" and "Fraction"), not only integers
  or floats, although this does not improve precision. (Contributed by
  Serhiy Storchaka in gh-67795.)

* Added "bytearray.take_bytes(n=None, /)" to take bytes out of a
  "bytearray" without copying. This enables optimizing code which must
  return "bytes" after working with a mutable buffer of bytes such as
  data buffering, network protocol parsing, encoding, decoding, and
  compression. Common code patterns which can be optimized with
  "take_bytes()" are listed below.


  Suggested optimizing refactors
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  +-----------------------------------+-----------------------------------+-----------------------------------+
  | Description                       | Old                               | New                               |
  |===================================|===================================|===================================|
  | Return "bytes" after working with | def read() -> bytes:     buffer = | def read() -> bytes:     buffer = |
  | "bytearray"                       | bytearray(1024)     ...           | bytearray(1024)     ...           |
  |                                   | return bytes(buffer)              | return buffer.take_bytes()        |
  +-----------------------------------+-----------------------------------+-----------------------------------+
  | Empty a buffer getting the bytes  | buffer = bytearray(1024) ... data | buffer = bytearray(1024) ... data |
  |                                   | = bytes(buffer) buffer.clear()    | = buffer.take_bytes()             |
  +-----------------------------------+-----------------------------------+-----------------------------------+
  | Split a buffer at a specific      | buffer = bytearray(b'abc\ndef') n | buffer = bytearray(b'abc\ndef') n |
  | separator                         | = buffer.find(b'\n') data =       | = buffer.find(b'\n') data =       |
  |                                   | bytes(buffer[:n + 1]) del         | buffer.take_bytes(n + 1)          |
  |                                   | buffer[:n + 1] assert data ==     |                                   |
  |                                   | b'abc' assert buffer ==           |                                   |
  |                                   | bytearray(b'def')                 |                                   |
  +-----------------------------------+-----------------------------------+-----------------------------------+
  | Split a buffer at a specific      | buffer = bytearray(b'abc\ndef') n | buffer = bytearray(b'abc\ndef') n |
  | separator; discard after the      | = buffer.find(b'\n') data =       | = buffer.find(b'\n')              |
  | separator                         | bytes(buffer[:n]) buffer.clear()  | buffer.resize(n) data =           |
  |                                   | assert data == b'abc' assert      | buffer.take_bytes()               |
  |                                   | len(buffer) == 0                  |                                   |
  +-----------------------------------+-----------------------------------+-----------------------------------+

  (Contributed by Cody Maloney in gh-139871.)

* Many functions related to compiling or parsing Python code, such as
  "compile()", "ast.parse()", "symtable.symtable()", and
  "importlib.abc.InspectLoader.source_to_code()", now allow the module
  name to be passed. It is needed to unambiguously filter syntax
  warnings by module name. (Contributed by Serhiy Storchaka in
  gh-135801.)

* Allowed defining the *__dict__* and *__weakref__* __slots__ for any
  class. (Contributed by Serhiy Storchaka in gh-41779.)

* Allowed defining any __slots__ for a class derived from "tuple"
  (including classes created by "collections.namedtuple()").
  (Contributed by Serhiy Storchaka in gh-41779.)

* The "slice" type now supports subscription, making it a *generic
  type*. (Contributed by James Hilton-Balfe in gh-128335.)


New modules
===========


math.integer
------------

This module provides access to the mathematical functions for integer
arguments (**PEP 791**). (Contributed by Serhiy Storchaka in
gh-81313.)


Improved modules
================


argparse
--------

* The "BooleanOptionalAction" action supports now single-dash long
  options and alternate prefix characters. (Contributed by Serhiy
  Storchaka in gh-138525.)

* Changed the *suggest_on_error* parameter of
  "argparse.ArgumentParser" to default to "True". This enables
  suggestions for mistyped arguments by default. (Contributed by Jakob
  Schluse in gh-140450.)

* Added backtick markup support in description and epilog text to
  highlight inline code when color output is enabled. (Contributed by
  Savannah Ostrowski in gh-142390.)


base64
------

* Added the *pad* parameter in "z85encode()". (Contributed by Hauke
  Dämpfling in gh-143103.)

* Added the *wrapcol* parameter in "b64encode()". (Contributed by
  Serhiy Storchaka in gh-143214.)

* Added the *ignorechars* parameter in "b64decode()". (Contributed by
  Serhiy Storchaka in gh-144001.)


binascii
--------

* Added functions for Ascii85, Base85, and Z85 encoding:

  * "b2a_ascii85()" and "a2b_ascii85()"

  * "b2a_base85()" and "a2b_base85()"

  * "b2a_z85()" and "a2b_z85()"

  (Contributed by James Seo and Serhiy Storchaka in gh-101178.)

* Added the *wrapcol* parameter in "b2a_base64()". (Contributed by
  Serhiy Storchaka in gh-143214.)

* Added the *ignorechars* parameter in "a2b_base64()". (Contributed by
  Serhiy Storchaka in gh-144001.)


calendar
--------

* Calendar pages generated by the "calendar.HTMLCalendar" class now
  support dark mode and have been migrated to the HTML5 standard for
  improved accessibility. (Contributed by Jiahao Li and Hugo van
  Kemenade in gh-137634.)

* The "calendar"'s command-line HTML output now accepts the year-month
  option: "python -m calendar -t html 2009 06". (Contributed by Pål
  Grønås Drange in gh-140212.)


collections
-----------

* Added "collections.Counter.__xor__()" and
  "collections.Counter.__ixor__()" to compute the symmetric difference
  between "Counter" objects. (Contributed by Raymond Hettinger in
  gh-138682.)


collections.abc
---------------

* "collections.abc.ByteString" has been removed from
  "collections.abc.__all__". "collections.abc.ByteString" has been
  deprecated since Python 3.12, and is scheduled for removal in Python
  3.17.

* The following statements now cause "DeprecationWarning"s to be
  emitted at runtime:

  * "from collections.abc import ByteString"

  * "import collections.abc; collections.abc.ByteString".

  "DeprecationWarning"s were already emitted if
  "collections.abc.ByteString" was subclassed or used as the second
  argument to "isinstance()" or "issubclass()", but warnings were not
  previously emitted if it was merely imported or accessed from the
  "collections.abc" module.


concurrent.futures
------------------

* Improved error reporting when a child process in a
  "concurrent.futures.ProcessPoolExecutor" terminates abruptly. The
  resulting traceback will now tell you the PID and exit code of the
  terminated process. (Contributed by Jonathan Berg in gh-139486.)


contextlib
----------

* Added support for arbitrary descriptors "__enter__()", "__exit__()",
  "__aenter__()", and "__aexit__()" in "ExitStack" and
  "contextlib.AsyncExitStack", for consistency with the "with" and
  "async with" statements. (Contributed by Serhiy Storchaka in
  gh-144386.)


dataclasses
-----------

* Annotations for generated "__init__" methods no longer include
  internal type names.


dbm
---

* Added new "reorganize()" methods to "dbm.dumb" and "dbm.sqlite3"
  which allow to recover unused free space previously occupied by
  deleted entries. (Contributed by Andrea Oliveri in gh-134004.)


difflib
-------

* Introduced the optional *color* parameter to
  "difflib.unified_diff()", enabling color output similar to **git
  diff**. This can be controlled by environment variables.
  (Contributed by Douglas Thor in gh-133725.)

* Improved the styling of HTML diff pages generated by the
  "difflib.HtmlDiff" class, and migrated the output to the HTML5
  standard. (Contributed by Jiahao Li in gh-134580.)


functools
---------

* "singledispatchmethod()" now supports non-*descriptor* callables.
  (Contributed by Serhiy Storchaka in gh-140873.)


hashlib
-------

* Ensure that hash functions guaranteed to be always *available* exist
  as attributes of "hashlib" even if they will not work at runtime due
  to missing backend implementations. For instance, "hashlib.md5" will
  no longer raise "AttributeError" if OpenSSL is not available and
  Python has been built without MD5 support. (Contributed by Bénédikt
  Tran in gh-136929.)


http.client
-----------

* A new *max_response_headers* keyword-only parameter has been added
  to "HTTPConnection" and "HTTPSConnection" constructors. This
  parameter overrides the default maximum number of allowed response
  headers. (Contributed by Alexander Enrique Urieles Nieto in
  gh-131724.)


http.cookies
------------

* Allow '"""' double quotes in cookie values. (Contributed by Nick
  Burns and Senthil Kumaran in gh-92936.)


inspect
-------

* Add parameters *inherit_class_doc* and *fallback_to_class_doc* for
  "getdoc()". (Contributed by Serhiy Storchaka in gh-132686.)


locale
------

* "setlocale()" now supports language codes with "@"-modifiers.
  "@"-modifiers are no longer silently removed in "getlocale()", but
  included in the language code. (Contributed by Serhiy Storchaka in
  gh-137729.)

* Undeprecate the "locale.getdefaultlocale()" function. (Contributed
  by Victor Stinner in gh-130796.)


math
----

* Add "math.isnormal()" and "math.issubnormal()" functions.
  (Contributed by Sergey B Kirpichev in gh-132908.)

* Add "math.fmax()", "math.fmin()" and "math.signbit()" functions.
  (Contributed by Bénédikt Tran in gh-135853.)


mimetypes
---------

* Add "application/dicom" MIME type for ".dcm" extension. (Contributed
  by Benedikt Johannes in gh-144217.)

* Add "application/node" MIME type for ".cjs" extension. (Contributed
  by John Franey in gh-140937.)

* Add "application/toml". (Contributed by Gil Forcada in gh-139959.)

* Add "image/jxl". (Contributed by Foolbar in gh-144213.)

* Rename "application/x-texinfo" to "application/texinfo".
  (Contributed by Charlie Lin in gh-140165.)

* Changed the MIME type for ".ai" files to "application/pdf".
  (Contributed by Stan Ulbrych in gh-141239.)


mmap
----

* "mmap.mmap" now has a *trackfd* parameter on Windows; if it is
  "False", the file handle corresponding to *fileno* will not be
  duplicated. (Contributed by Serhiy Storchaka in gh-78502.)

* Added the "mmap.mmap.set_name()" method to annotate an anonymous
  memory mapping if Linux kernel supports *PR_SET_VMA_ANON_NAME*
  (Linux 5.17 or newer). (Contributed by Donghee Na in gh-142419.)


os
--

* Add "os.statx()" on Linux kernel versions 4.11 and later with glibc
  versions 2.28 and later. (Contributed by Jeffrey Bosboom and Victor
  Stinner in gh-83714.)


os.path
-------

* Add support of the all-but-last mode in "realpath()". (Contributed
  by Serhiy Storchaka in gh-71189.)

* The *strict* parameter to "os.path.realpath()" accepts a new value,
  "os.path.ALLOW_MISSING". If used, errors other than
  "FileNotFoundError" will be re-raised; the resulting path can be
  missing but it will be free of symlinks. (Contributed by Petr
  Viktorin for **CVE 2025-4517**.)


pickle
------

* Add support for pickling private methods and nested classes.
  (Contributed by Zackery Spytz and Serhiy Storchaka in gh-77188.)


re
--

* "re.prefixmatch()" and a corresponding "prefixmatch()" have been
  added as alternate more explicit names for the existing "re.match()"
  and "match()" APIs. These are intended to be used to alleviate
  confusion around what *match* means by following the Zen of Python's
  *"Explicit is better than implicit"* mantra. Most other language
  regular expression libraries use an API named *match* to mean what
  Python has always called *search*. (Contributed by Gregory P. Smith
  in gh-86519.)


resource
--------

* Add new constants: "RLIMIT_NTHR", "RLIMIT_UMTXP", "RLIMIT_THREADS",
  "RLIM_SAVED_CUR", and "RLIM_SAVED_MAX". (Contributed by Serhiy
  Storchaka in gh-137512.)


shelve
------

* Added new "reorganize()" method to "shelve" used to recover unused
  free space previously occupied by deleted entries. (Contributed by
  Andrea Oliveri in gh-134004.)


socket
------

* Add constants for the ISO-TP CAN protocol. (Contributed by Patrick
  Menschel and Stefan Tatschner in gh-86819.)


sqlite3
-------

* The command-line interface has several new features:

  * SQL keyword completion on <tab>. (Contributed by Long Tan in
    gh-133393.)

  * Prompts, error messages, and help text are now colored. This is
    enabled by default, see Controlling color for details.
    (Contributed by Stan Ulbrych and Łukasz Langa in gh-133461.)

  * Table, index, trigger, view, column, function, and schema
    completion on <tab>. (Contributed by Long Tan in gh-136101.)


ssl
---

* Indicate through "ssl.HAS_PSK_TLS13" whether the "ssl" module
  supports "External PSKs" in TLSv1.3, as described in RFC 9258.
  (Contributed by Will Childs-Klein in gh-133624.)

* Added new methods for managing groups used for SSL key agreement

  * "ssl.SSLContext.set_groups()" sets the groups allowed for doing
    key agreement, extending the previous
    "ssl.SSLContext.set_ecdh_curve()" method. This new API provides
    the ability to list multiple groups and supports fixed-field and
    post-quantum groups in addition to ECDH curves. This method can
    also be used to control what key shares are sent in the TLS
    handshake.

  * "ssl.SSLSocket.group()" returns the group selected for doing key
    agreement on the current connection after the TLS handshake
    completes. This call requires OpenSSL 3.2 or later.

  * "ssl.SSLContext.get_groups()" returns a list of all available key
    agreement groups compatible with the minimum and maximum TLS
    versions currently set in the context. This call requires OpenSSL
    3.5 or later.

  (Contributed by Ron Frederick in gh-136306.)

* Added a new method "ssl.SSLContext.set_ciphersuites()" for setting
  TLS 1.3 ciphers. For TLS 1.2 or earlier,
  "ssl.SSLContext.set_ciphers()" should continue to be used. Both
  calls can be made on the same context and the selected cipher suite
  will depend on the TLS version negotiated when a connection is made.
  (Contributed by Ron Frederick in gh-137197.)

* Added new methods for managing signature algorithms:

  * "ssl.get_sigalgs()" returns a list of all available TLS signature
    algorithms. This call requires OpenSSL 3.4 or later.

  * "ssl.SSLContext.set_client_sigalgs()" sets the signature
    algorithms allowed for certificate-based client authentication.

  * "ssl.SSLContext.set_server_sigalgs()" sets the signature
    algorithms allowed for the server to complete the TLS handshake.

  * "ssl.SSLSocket.client_sigalg()" returns the signature algorithm
    selected for client authentication on the current connection. This
    call requires OpenSSL 3.5 or later.

  * "ssl.SSLSocket.server_sigalg()" returns the signature algorithm
    selected for the server to complete the TLS handshake on the
    current connection. This call requires OpenSSL 3.5 or later.

  (Contributed by Ron Frederick in gh-138252.)


subprocess
----------

* "subprocess.Popen.wait()": when "timeout" is not "None" and the
  platform supports it, an efficient event-driven mechanism is used to
  wait for process termination:

  * Linux >= 5.3 uses "os.pidfd_open()" + "select.poll()".

  * macOS and other BSD variants use "select.kqueue()" +
    "KQ_FILTER_PROC" + "KQ_NOTE_EXIT".

  * Windows keeps using "WaitForSingleObject" (unchanged).

  If none of these mechanisms are available, the function falls back
  to the traditional busy loop (non-blocking call and short sleeps).
  (Contributed by Giampaolo Rodola in gh-83069).


symtable
--------

* Add "symtable.Function.get_cells()" and "symtable.Symbol.is_cell()"
  methods. (Contributed by Yashp002 in gh-143504.)


symtable
--------

* Add "symtable.Function.get_cells()" and "symtable.Symbol.is_cell()"
  methods. (Contributed by Yashp002 in gh-143504.)


sys
---

* Add "sys.abi_info" namespace to improve access to ABI information.
  (Contributed by Klaus Zimmermann in gh-137476.)


tarfile
-------

* "data_filter()" now normalizes symbolic link targets in order to
  avoid path traversal attacks. (Contributed by Petr Viktorin in
  gh-127987 and **CVE 2025-4138**.)

* "extractall()" now skips fixing up directory attributes when a
  directory was removed or replaced by another kind of file.
  (Contributed by Petr Viktorin in gh-127987 and **CVE 2024-12718**.)

* "extract()" and "extractall()" now (re-)apply the extraction filter
  when substituting a link (hard or symbolic) with a copy of another
  archive member, and when fixing up directory attributes. The former
  raises a new exception, "LinkFallbackError". (Contributed by Petr
  Viktorin for **CVE 2025-4330** and **CVE 2024-12718**.)

* "extract()" and "extractall()" no longer extract rejected members
  when "errorlevel()" is zero. (Contributed by Matt Prodani and Petr
  Viktorin in gh-112887 and **CVE 2025-4435**.)

* "extract()" and "extractall()" now replace slashes by backslashes in
  symlink targets on Windows to prevent creation of corrupted links.
  (Contributed by Christoph Walcher in gh-57911.)


timeit
------

* The command-line interface now colorizes error tracebacks by
  default. This can be controlled with environment variables.
  (Contributed by Yi Hong in gh-139374.)


tkinter
-------

* The "tkinter.Text.search()" method now supports two additional
  arguments: *nolinestop* which allows the search to continue across
  line boundaries; and *strictlimits* which restricts the search to
  within the specified range. (Contributed by Rihaan Meher in
  gh-130848.)

* A new method "tkinter.Text.search_all()" has been introduced. This
  method allows for searching for all matches of a pattern using Tcl's
  "-all" and "-overlap" options. (Contributed by Rihaan Meher in
  gh-130848.)

* Added new methods "pack_content()", "place_content()" and
  "grid_content()" which use Tk commands with new names (introduced in
  Tk 8.6) instead of "*_slaves()" methods which use Tk commands with
  outdated names. (Contributed by Serhiy Storchaka in gh-143754.)


tomllib
-------

* The "tomllib" module now supports TOML 1.1.0. This is a backwards
  compatible update, meaning that all valid TOML 1.0.0 documents are
  parsed the same way.

  The changes, according to the official TOML changelog, are:

  * Allow newlines and trailing commas in inline tables.

    Previously an inline table had to be on a single line and couldn't
    end with a trailing comma. This is now relaxed so that the
    following is valid:

       tbl = {
          key      = "a string",
          moar-tbl =  {
             key = 1,
          },
       }

  * Add "\xHH" notation to basic strings for codepoints under 255, and
    the "\e" escape for the escape character:

       null = "null byte: \x00; letter a: \x61"
       csi = "\e["

  * Seconds in datetime and time values are now optional. The
    following are now valid:

       dt = 2010-02-03 14:15
       t  = 14:15

  (Contributed by Taneli Hukkinen in gh-142956.)


types
-----

* Expose the write-through "locals()" proxy type as
  "types.FrameLocalsProxyType". This represents the type of the
  "frame.f_locals" attribute, as described in **PEP 667**.


unicodedata
-----------

* The Unicode database has been updated to Unicode 17.0.0.

* Add "unicodedata.isxidstart()" and "unicodedata.isxidcontinue()"
  functions to check whether a character can start or continue a
  Unicode Standard Annex #31 identifier. (Contributed by Stan Ulbrych
  in gh-129117.)

* Add the "iter_graphemes()" function to iterate over grapheme
  clusters according to rules defined in Unicode Standard Annex #29,
  "Unicode Text Segmentation". Add "grapheme_cluster_break()",
  "indic_conjunct_break()" and "extended_pictographic()" functions to
  get the properties of the character which are related to the above
  algorithm. (Contributed by Serhiy Storchaka and Guillaume Sanchez in
  gh-74902.)


unittest
--------

* "unittest.TestCase.assertLogs()" will now accept a formatter to
  control how messages are formatted. (Contributed by Garry Cairns in
  gh-134567.)


urllib.parse
------------

* Add the *missing_as_none* parameter to "urlsplit()", "urlparse()"
  and "urldefrag()" functions. Add the *keep_empty* parameter to
  "urlunsplit()" and "urlunparse()" functions. This allows to
  distinguish between empty and not defined URI components and
  preserve empty components. (Contributed by Serhiy Storchaka in
  gh-67041.)


venv
----

* On POSIX platforms, platlib directories will be created if needed
  when creating virtual environments, instead of using "lib64 -> lib"
  symlink. This means purelib and platlib of virtual environments no
  longer share the same "lib" directory on platforms where
  "sys.platlibdir" is not equal to "lib". (Contributed by Rui Xi in
  gh-133951.)


warnings
--------

* Improve filtering by module in "warnings.warn_explicit()" if no
  *module* argument is passed. It now tests the module regular
  expression in the warnings filter not only against the filename with
  ".py" stripped, but also against module names constructed starting
  from different parent directories of the filename (with
  "/__init__.py", ".py" and, on Windows, ".pyw" stripped).
  (Contributed by Serhiy Storchaka in gh-135801.)


xml.parsers.expat
-----------------

* Add "SetAllocTrackerActivationThreshold()" and
  "SetAllocTrackerMaximumAmplification()" to xmlparser objects to tune
  protections against disproportional amounts of dynamic memory usage
  from within an Expat parser. (Contributed by Bénédikt Tran in
  gh-90949.)

* Add "SetBillionLaughsAttackProtectionActivationThreshold()" and
  "SetBillionLaughsAttackProtectionMaximumAmplification()" to
  xmlparser objects to tune protections against billion laughs
  attacks. (Contributed by Bénédikt Tran in gh-90949.)


zlib
----

* Allow combining two Adler-32 checksums via "adler32_combine()".
  (Contributed by Callum Attryde and Bénédikt Tran in gh-134635.)

* Allow combining two CRC-32 checksums via "crc32_combine()".
  (Contributed by Bénédikt Tran in gh-134635.)


Optimizations
=============

* Builds using Visual Studio 2026 (MSVC 18) may now use the new tail-
  calling interpreter. Results on Visual Studio 18.1.1 report between
  15-20% speedup on the geometric mean of pyperformance on Windows
  x86-64 over the switch-case interpreter on an AMD Ryzen 7 5800X. We
  have observed speedups ranging from 14% for large pure-Python
  libraries to 40% for long-running small pure-Python scripts on
  Windows. This was made possible by a new feature introduced in MSVC
  18. (Contributed by Chris Eibl, Ken Jin, and Brandt Bucher in
  gh-143068. Special thanks to the MSVC team including Hulon Jenkins.)

* "mimalloc" is now used as the default allocator for for raw memory
  allocations such as via "PyMem_RawMalloc()" for better performance
  on *free-threaded builds*. (Contributed by Kumar Aditya in
  gh-144914.)


base64 & binascii
-----------------

* CPython's underlying base64 implementation now encodes 2x faster and
  decodes 3x faster thanks to simple CPU pipelining optimizations.
  (Contributed by Gregory P. Smith and Serhiy Storchaka in gh-143262.)

* Implementation for Ascii85, Base85, and Z85 encoding has been
  rewritten in C. Encoding and decoding is now two orders of magnitude
  faster and consumes two orders of magnitude less memory.
  (Contributed by James Seo and Serhiy Storchaka in gh-101178.)


csv
---

* "csv.Sniffer.sniff()" delimiter detection is now up to 1.6x faster.
  (Contributed by Maurycy Pawłowski-Wieroński in gh-137628.)


Upgraded JIT compiler
=====================

Results from the pyperformance benchmark suite report 4-5% geometric
mean performance improvement for the JIT over the standard CPython
interpreter built with all optimizations enabled on x86-64 Linux. On
AArch64 macOS, the JIT has a 7-8% speedup over the tail calling
interpreter with all optimizations enabled. The speedups for JIT
builds versus no JIT builds range from roughly 15% slowdown to over
100% speedup (ignoring the "unpack_sequence" microbenchmark) on x86-64
Linux and AArch64 macOS systems.

Attention:

  These results are not yet final.

The major upgrades to the JIT are:

* LLVM 21 build-time dependency

* New tracing frontend

* Basic register allocation in the JIT

* More JIT optimizations

* Better machine code generation

-[ LLVM 21 build-time dependency ]-

The JIT compiler now uses LLVM 21 for build-time stencil generation.
As always, LLVM is only needed when building CPython with the JIT
enabled; end users running Python do not need LLVM installed.
Instructions for installing LLVM can be found in the JIT compiler
documentation for all supported platforms.

(Contributed by Savannah Ostrowski in gh-140973.)

-[ A new tracing frontend ]-

The JIT compiler now supports significantly more bytecode operations
and control flow than in Python 3.14, enabling speedups on a wider
variety of code. For example, simple Python object creation is now
understood by the 3.15 JIT compiler. Overloaded operations and
generators are also partially supported. This was made possible by an
overhauled JIT tracing frontend that records actual execution paths
through code, rather than estimating them as the previous
implementation did.

(Contributed by Ken Jin in gh-139109. Support for Windows added by
Mark Shannon in gh-141703.)

-[ Basic register allocation in the JIT ]-

A basic form of register allocation has been added to the JIT
compiler's optimizer. This allows the JIT compiler to avoid certain
stack operations altogether and instead operate on registers. This
allows the JIT to produce more efficient traces by avoiding reads and
writes to memory.

(Contributed by Mark Shannon in gh-135379.)

-[ More JIT optimizations ]-

More constant-propagation is now performed. This means when the JIT
compiler detects that certain user code results in constants, the code
can be simplified by the JIT.

(Contributed by Ken Jin and Savannah Ostrowski in gh-132732.)

The JIT avoids *reference count*s where possible. This generally
reduces the cost of most operations in Python.

(Contributed by Ken Jin, Donghee Na, Zheao Li, Hai Zhu, Savannah
Ostrowski, Reiden Ong, Noam Cohen, Tomas Roun, PuQing, and Cajetan
Rodrigues in gh-134584.)

-[ Better machine code generation ]-

The JIT compiler's machine code generator now produces better machine
code for x86-64 and AArch64 macOS and Linux targets. In general, users
should experience lower memory usage for generated machine code and
more efficient machine code versus the old JIT.

(Contributed by Brandt Bucher in gh-136528 and gh-136528.
Implementation for AArch64 contributed by Mark Shannon in gh-139855.
Additional optimizations for AArch64 contributed by Mark Shannon and
Diego Russo in gh-140683 and gh-142305.)


Removed
=======


ctypes
------

* Removed the undocumented function "ctypes.SetPointerType()", which
  has been deprecated since Python 3.13. (Contributed by Bénédikt Tran
  in gh-133866.)


glob
----

* Removed the undocumented "glob.glob0()" and "glob.glob1()"
  functions, which have been deprecated since Python 3.13. Use
  "glob.glob()" and pass a directory to its *root_dir* argument
  instead. (Contributed by Barney Gale in gh-137466.)


http.server
-----------

* Removed the "CGIHTTPRequestHandler" class and the "--cgi" flag from
  the **python -m http.server** command-line interface. They were
  deprecated in Python 3.13. (Contributed by Bénédikt Tran in
  gh-133810.)


importlib.resources
-------------------

* Removed deprecated "package" parameter from
  "importlib.resources.files()" function. (Contributed by Semyon Moroz
  in gh-138044.)


pathlib
-------

* Removed deprecated "pathlib.PurePath.is_reserved()". Use
  "os.path.isreserved()" to detect reserved paths on Windows.
  (Contributed by Nikita Sobolev in gh-133875.)


platform
--------

* Removed the "platform.java_ver()" function, which was deprecated
  since Python 3.13. (Contributed by Alexey Makridenko in gh-133604.)


sre_*
-----

* Removed "sre_compile", "sre_constants" and "sre_parse" modules.
  (Contributed by Stan Ulbrych in gh-135994.)


sysconfig
---------

* Removed the *check_home* parameter of "sysconfig.is_python_build()".
  (Contributed by Filipe Laíns in gh-92897.)


threading
---------

* Remove support for arbitrary positional or keyword arguments in the
  C implementation of "RLock" objects. This was deprecated in Python
  3.14. (Contributed by Bénédikt Tran in gh-134087.)


typing
------

* The undocumented keyword argument syntax for creating "NamedTuple"
  classes (for example, "Point = NamedTuple("Point", x=int, y=int)")
  is no longer supported. Use the class-based syntax or the functional
  syntax instead. (Contributed by Bénédikt Tran in gh-133817.)

* Using "TD = TypedDict("TD")" or "TD = TypedDict("TD", None)" to
  construct a "TypedDict" type with zero fields is no longer
  supported. Use "class TD(TypedDict): pass" or "TD = TypedDict("TD",
  {})" instead. (Contributed by Bénédikt Tran in gh-133823.)

* Code like "class ExtraTypeVars(P1[S], Protocol[T, T2]): ..." now
  raises a "TypeError", because "S" is not listed in "Protocol"
  parameters. (Contributed by Nikita Sobolev in gh-137191.)

* Code like "class B2(A[T2], Protocol[T1, T2]): ..." now correctly
  handles type parameters order: it is "(T1, T2)", not "(T2, T1)" as
  it was incorrectly inferred in runtime before. (Contributed by
  Nikita Sobolev in gh-137191.)

* "typing.ByteString" has been removed from "typing.__all__".
  "typing.ByteString" has been deprecated since Python 3.9, and is
  scheduled for removal in Python 3.17.

* The following statements now cause "DeprecationWarning"s to be
  emitted at runtime:

  * "from typing import ByteString"

  * "import typing; typing.ByteString".

  "DeprecationWarning"s were already emitted if "typing.ByteString"
  was subclassed or used as the second argument to "isinstance()" or
  "issubclass()", but warnings were not previously emitted if it was
  merely imported or accessed from the "typing" module.

* Deprecated "typing.no_type_check_decorator()" has been removed.
  (Contributed by Nikita Sobolev in gh-133601.)


wave
----

* Removed the "getmark()", "setmark()" and "getmarkers()" methods of
  the "Wave_read" and "Wave_write" classes, which were deprecated
  since Python 3.13. (Contributed by Bénédikt Tran in gh-133873.)


zipimport
---------

* Remove deprecated "zipimport.zipimporter.load_module()". Use
  "zipimport.zipimporter.exec_module()" instead. (Contributed by
  Jiahao Li in gh-133656.)


Deprecated
==========


New deprecations
----------------

* "base64":

  * Accepting the "+" and "/" characters with an alternative alphabet
    in "b64decode()" and "urlsafe_b64decode()" is now deprecated. In
    future Python versions they will be errors in the strict mode and
    discarded in the non-strict mode. (Contributed by Serhiy Storchaka
    in gh-125346.)

* CLI:

  * Deprecate "-b" and "-bb" command-line options and schedule them to
    become no-ops in Python 3.17. These were primarily helpers for the
    Python 2 -> 3 transition. Starting with Python 3.17, no
    "BytesWarning" will be raised for these cases; use a type checker
    instead.

    (Contributed by Nikita Sobolev in gh-136355.)

* "hashlib":

  * In hash function constructors such as "new()" or the direct hash-
    named constructors such as "md5()" and "sha256()", the optional
    initial data parameter could also be passed as a keyword argument
    named "data=" or "string=" in various "hashlib" implementations.

    Support for the "string" keyword argument name is now deprecated
    and is slated for removal in Python 3.19. Prefer passing the
    initial data as a positional argument for maximum backwards
    compatibility.

    (Contributed by Bénédikt Tran in gh-134978.)

* "__version__"

  * The "__version__", "version" and "VERSION" attributes have been
    deprecated in these standard library modules and will be removed
    in Python 3.20. Use "sys.version_info" instead.

    * "argparse"

    * "csv"

    * "ctypes"

    * "ctypes.macholib"

    * "decimal" (use "decimal.SPEC_VERSION" instead)

    * "http.server"

    * "imaplib"

    * "ipaddress"

    * "json"

    * "logging" ("__date__" also deprecated)

    * "optparse"

    * "pickle"

    * "platform"

    * "re"

    * "socketserver"

    * "tabnanny"

    * "tkinter.font"

    * "tkinter.ttk"

    * "wsgiref.simple_server"

    * "xml.etree.ElementTree"

    * "xml.sax.expatreader"

    * "xml.sax.handler"

    * "zlib"

    (Contributed by Hugo van Kemenade and Stan Ulbrych in gh-76007.)


Pending removal in Python 3.16
------------------------------

* The import system:

  * Setting "__loader__" on a module while failing to set
    "__spec__.loader" is deprecated. In Python 3.16, "__loader__" will
    cease to be set or taken into consideration by the import system
    or the standard library.

* "array":

  * The "'u'" format code ("wchar_t") has been deprecated in
    documentation since Python 3.3 and at runtime since Python 3.13.
    Use the "'w'" format code ("Py_UCS4") for Unicode characters
    instead.

* "asyncio":

  * "asyncio.iscoroutinefunction()" is deprecated and will be removed
    in Python 3.16; use "inspect.iscoroutinefunction()" instead.
    (Contributed by Jiahao Li and Kumar Aditya in gh-122875.)

  * "asyncio" policy system is deprecated and will be removed in
    Python 3.16. In particular, the following classes and functions
    are deprecated:

    * "asyncio.AbstractEventLoopPolicy"

    * "asyncio.DefaultEventLoopPolicy"

    * "asyncio.WindowsSelectorEventLoopPolicy"

    * "asyncio.WindowsProactorEventLoopPolicy"

    * "asyncio.get_event_loop_policy()"

    * "asyncio.set_event_loop_policy()"

    Users should use "asyncio.run()" or "asyncio.Runner" with
    *loop_factory* to use the desired event loop implementation.

    For example, to use "asyncio.SelectorEventLoop" on Windows:

       import asyncio

       async def main():
           ...

       asyncio.run(main(), loop_factory=asyncio.SelectorEventLoop)

    (Contributed by Kumar Aditya in gh-127949.)

* "builtins":

  * Bitwise inversion on boolean types, "~True" or "~False" has been
    deprecated since Python 3.12, as it produces surprising and
    unintuitive results ("-2" and "-1"). Use "not x" instead for the
    logical negation of a Boolean. In the rare case that you need the
    bitwise inversion of the underlying integer, convert to "int"
    explicitly ("~int(x)").

* "functools":

  * Calling the Python implementation of "functools.reduce()" with
    *function* or *sequence* as keyword arguments has been deprecated
    since Python 3.14.

* "logging":

  * Support for custom logging handlers with the *strm* argument is
    deprecated and scheduled for removal in Python 3.16. Define
    handlers with the *stream* argument instead. (Contributed by
    Mariusz Felisiak in gh-115032.)

* "mimetypes":

  * Valid extensions start with a '.' or are empty for
    "mimetypes.MimeTypes.add_type()". Undotted extensions are
    deprecated and will raise a "ValueError" in Python 3.16.
    (Contributed by Hugo van Kemenade in gh-75223.)

* "shutil":

  * The "ExecError" exception has been deprecated since Python 3.14.
    It has not been used by any function in "shutil" since Python 3.4,
    and is now an alias of "RuntimeError".

* "symtable":

  * The "Class.get_methods" method has been deprecated since Python
    3.14.

* "sys":

  * The "_enablelegacywindowsfsencoding()" function has been
    deprecated since Python 3.13. Use the
    "PYTHONLEGACYWINDOWSFSENCODING" environment variable instead.

* "sysconfig":

  * The "sysconfig.expand_makefile_vars()" function has been
    deprecated since Python 3.14. Use the "vars" argument of
    "sysconfig.get_paths()" instead.

* "tarfile":

  * The undocumented and unused "TarFile.tarfile" attribute has been
    deprecated since Python 3.13.


Pending removal in Python 3.17
------------------------------

* "collections.abc":

  * "collections.abc.ByteString" is scheduled for removal in Python
    3.17.

    Use "isinstance(obj, collections.abc.Buffer)" to test if "obj"
    implements the buffer protocol at runtime. For use in type
    annotations, either use "Buffer" or a union that explicitly
    specifies the types your code supports (e.g., "bytes | bytearray |
    memoryview").

    "ByteString" was originally intended to be an abstract class that
    would serve as a supertype of both "bytes" and "bytearray".
    However, since the ABC never had any methods, knowing that an
    object was an instance of "ByteString" never actually told you
    anything useful about the object. Other common buffer types such
    as "memoryview" were also never understood as subtypes of
    "ByteString" (either at runtime or by static type checkers).

    See **PEP 688** for more details. (Contributed by Shantanu Jain in
    gh-91896.)

* "encodings":

  * Passing non-ascii *encoding* names to
    "encodings.normalize_encoding()" is deprecated and scheduled for
    removal in Python 3.17. (Contributed by Stan Ulbrych in gh-136702)

* "typing":

  * Before Python 3.14, old-style unions were implemented using the
    private class "typing._UnionGenericAlias". This class is no longer
    needed for the implementation, but it has been retained for
    backward compatibility, with removal scheduled for Python 3.17.
    Users should use documented introspection helpers like
    "typing.get_origin()" and "typing.get_args()" instead of relying
    on private implementation details.

  * "typing.ByteString", deprecated since Python 3.9, is scheduled for
    removal in Python 3.17.

    Use "isinstance(obj, collections.abc.Buffer)" to test if "obj"
    implements the buffer protocol at runtime. For use in type
    annotations, either use "Buffer" or a union that explicitly
    specifies the types your code supports (e.g., "bytes | bytearray |
    memoryview").

    "ByteString" was originally intended to be an abstract class that
    would serve as a supertype of both "bytes" and "bytearray".
    However, since the ABC never had any methods, knowing that an
    object was an instance of "ByteString" never actually told you
    anything useful about the object. Other common buffer types such
    as "memoryview" were also never understood as subtypes of
    "ByteString" (either at runtime or by static type checkers).

    See **PEP 688** for more details. (Contributed by Shantanu Jain in
    gh-91896.)


Pending removal in Python 3.18
------------------------------

* "decimal":

  * The non-standard and undocumented "Decimal" format specifier
    "'N'", which is only supported in the "decimal" module's C
    implementation, has been deprecated since Python 3.13.
    (Contributed by Serhiy Storchaka in gh-89902.)


Pending removal in Python 3.19
------------------------------

* "ctypes":

  * Implicitly switching to the MSVC-compatible struct layout by
    setting "_pack_" but not "_layout_" on non-Windows platforms.

* "hashlib":

  * In hash function constructors such as "new()" or the direct hash-
    named constructors such as "md5()" and "sha256()", their optional
    initial data parameter could also be passed a keyword argument
    named "data=" or "string=" in various "hashlib" implementations.

    Support for the "string" keyword argument name is now deprecated
    and slated for removal in Python 3.19.

    Before Python 3.13, the "string" keyword parameter was not
    correctly supported depending on the backend implementation of
    hash functions. Prefer passing the initial data as a positional
    argument for maximum backwards compatibility.


Pending removal in Python 3.20
------------------------------

* The "__version__", "version" and "VERSION" attributes have been
  deprecated in these standard library modules and will be removed in
  Python 3.20. Use "sys.version_info" instead.

  * "argparse"

  * "csv"

  * "ctypes"

  * "ctypes.macholib"

  * "decimal" (use "decimal.SPEC_VERSION" instead)

  * "http.server"

  * "imaplib"

  * "ipaddress"

  * "json"

  * "logging" ("__date__" also deprecated)

  * "optparse"

  * "pickle"

  * "platform"

  * "re"

  * "socketserver"

  * "tabnanny"

  * "tkinter.font"

  * "tkinter.ttk"

  * "wsgiref.simple_server"

  * "xml.etree.ElementTree"

  * "xml.sax.expatreader"

  * "xml.sax.handler"

  * "zlib"

  (Contributed by Hugo van Kemenade and Stan Ulbrych in gh-76007.)


Pending removal in future versions
----------------------------------

The following APIs will be removed in the future, although there is
currently no date scheduled for their removal.

* "argparse":

  * Nesting argument groups and nesting mutually exclusive groups are
    deprecated.

  * Passing the undocumented keyword argument *prefix_chars* to
    "add_argument_group()" is now deprecated.

  * The "argparse.FileType" type converter is deprecated.

* "builtins":

  * Generators: "throw(type, exc, tb)" and "athrow(type, exc, tb)"
    signature is deprecated: use "throw(exc)" and "athrow(exc)"
    instead, the single argument signature.

  * Currently Python accepts numeric literals immediately followed by
    keywords, for example "0in x", "1or x", "0if 1else 2".  It allows
    confusing and ambiguous expressions like "[0x1for x in y]" (which
    can be interpreted as "[0x1 for x in y]" or "[0x1f or x in y]").
    A syntax warning is raised if the numeric literal is immediately
    followed by one of keywords "and", "else", "for", "if", "in", "is"
    and "or".  In a future release it will be changed to a syntax
    error. (gh-87999)

  * Support for "__index__()" and "__int__()" method returning non-int
    type: these methods will be required to return an instance of a
    strict subclass of "int".

  * Support for "__float__()" method returning a strict subclass of
    "float": these methods will be required to return an instance of
    "float".

  * Support for "__complex__()" method returning a strict subclass of
    "complex": these methods will be required to return an instance of
    "complex".

  * Passing a complex number as the *real* or *imag* argument in the
    "complex()" constructor is now deprecated; it should only be
    passed as a single positional argument. (Contributed by Serhiy
    Storchaka in gh-109218.)

* "calendar": "calendar.January" and "calendar.February" constants are
  deprecated and replaced by "calendar.JANUARY" and
  "calendar.FEBRUARY". (Contributed by Prince Roshan in gh-103636.)

* "codecs": use "open()" instead of "codecs.open()". (gh-133038)

* "codeobject.co_lnotab": use the "codeobject.co_lines()" method
  instead.

* "datetime":

  * "utcnow()": use "datetime.datetime.now(tz=datetime.UTC)".

  * "utcfromtimestamp()": use
    "datetime.datetime.fromtimestamp(timestamp, tz=datetime.UTC)".

* "gettext": Plural value must be an integer.

* "importlib":

  * "cache_from_source()" *debug_override* parameter is deprecated:
    use the *optimization* parameter instead.

* "importlib.metadata":

  * "EntryPoints" tuple interface.

  * Implicit "None" on return values.

* "logging": the "warn()" method has been deprecated since Python 3.3,
  use "warning()" instead.

* "mailbox": Use of StringIO input and text mode is deprecated, use
  BytesIO and binary mode instead.

* "os": Calling "os.register_at_fork()" in a multi-threaded process.

* "os.path": "os.path.commonprefix()" is deprecated, use
  "os.path.commonpath()" for path prefixes. The
  "os.path.commonprefix()" function is being deprecated due to having
  a misleading name and module. The function is not safe to use for
  path prefixes despite being included in a module about path
  manipulation, meaning it is easy to accidentally introduce path
  traversal vulnerabilities into Python programs by using this
  function.

* "pydoc.ErrorDuringImport": A tuple value for *exc_info* parameter is
  deprecated, use an exception instance.

* "re": More strict rules are now applied for numerical group
  references and group names in regular expressions.  Only sequence of
  ASCII digits is now accepted as a numerical reference.  The group
  name in bytes patterns and replacement strings can now only contain
  ASCII letters and digits and underscore. (Contributed by Serhiy
  Storchaka in gh-91760.)

* "shutil": "rmtree()"'s *onerror* parameter is deprecated in Python
  3.12; use the *onexc* parameter instead.

* "ssl" options and protocols:

  * "ssl.SSLContext" without protocol argument is deprecated.

  * "ssl.SSLContext": "set_npn_protocols()" and
    "selected_npn_protocol()" are deprecated: use ALPN instead.

  * "ssl.OP_NO_SSL*" options

  * "ssl.OP_NO_TLS*" options

  * "ssl.PROTOCOL_SSLv3"

  * "ssl.PROTOCOL_TLS"

  * "ssl.PROTOCOL_TLSv1"

  * "ssl.PROTOCOL_TLSv1_1"

  * "ssl.PROTOCOL_TLSv1_2"

  * "ssl.TLSVersion.SSLv3"

  * "ssl.TLSVersion.TLSv1"

  * "ssl.TLSVersion.TLSv1_1"

* "threading" methods:

  * "threading.Condition.notifyAll()": use "notify_all()".

  * "threading.Event.isSet()": use "is_set()".

  * "threading.Thread.isDaemon()", "threading.Thread.setDaemon()": use
    "threading.Thread.daemon" attribute.

  * "threading.Thread.getName()", "threading.Thread.setName()": use
    "threading.Thread.name" attribute.

  * "threading.currentThread()": use "threading.current_thread()".

  * "threading.activeCount()": use "threading.active_count()".

* "typing.Text" (gh-92332).

* The internal class "typing._UnionGenericAlias" is no longer used to
  implement "typing.Union". To preserve compatibility with users using
  this private class, a compatibility shim will be provided until at
  least Python 3.17. (Contributed by Jelle Zijlstra in gh-105499.)

* "unittest.IsolatedAsyncioTestCase": it is deprecated to return a
  value that is not "None" from a test case.

* "urllib.parse" deprecated functions: "urlparse()" instead

  * "splitattr()"

  * "splithost()"

  * "splitnport()"

  * "splitpasswd()"

  * "splitport()"

  * "splitquery()"

  * "splittag()"

  * "splittype()"

  * "splituser()"

  * "splitvalue()"

  * "to_bytes()"

* "wsgiref": "SimpleHandler.stdout.write()" should not do partial
  writes.

* "xml.etree.ElementTree": Testing the truth value of an "Element" is
  deprecated. In a future release it will always return "True". Prefer
  explicit "len(elem)" or "elem is not None" tests instead.

* "sys._clear_type_cache()" is deprecated: use
  "sys._clear_internal_caches()" instead.


C API changes
=============


New features
------------

* Add the following functions for the new "frozendict" type:

  * "PyAnyDict_Check()"

  * "PyAnyDict_CheckExact()"

  * "PyFrozenDict_Check()"

  * "PyFrozenDict_CheckExact()"

  * "PyFrozenDict_New()"

  (Contributed by Victor Stinner in gh-141510.)

* Add "PySys_GetAttr()", "PySys_GetAttrString()",
  "PySys_GetOptionalAttr()", and "PySys_GetOptionalAttrString()"
  functions as replacements for "PySys_GetObject()". (Contributed by
  Serhiy Storchaka in gh-108512.)

* Add "PyUnstable_Unicode_GET_CACHED_HASH" to get the cached hash of a
  string. See the documentation for caveats. (Contributed by Petr
  Viktorin in gh-131510.)

* Add API for checking an extension module's ABI compatibility:
  "Py_mod_abi", "PyABIInfo_Check()", "PyABIInfo_VAR" and "Py_mod_abi".
  (Contributed by Petr Viktorin in gh-137210.)

* Implement **PEP 782**, the PyBytesWriter API. Add functions:

  * "PyBytesWriter_Create()"

  * "PyBytesWriter_Discard()"

  * "PyBytesWriter_FinishWithPointer()"

  * "PyBytesWriter_FinishWithSize()"

  * "PyBytesWriter_Finish()"

  * "PyBytesWriter_Format()"

  * "PyBytesWriter_GetData()"

  * "PyBytesWriter_GetSize()"

  * "PyBytesWriter_GrowAndUpdatePointer()"

  * "PyBytesWriter_Grow()"

  * "PyBytesWriter_Resize()"

  * "PyBytesWriter_WriteBytes()"

  (Contributed by Victor Stinner in gh-129813.)

* Add a new "PyImport_CreateModuleFromInitfunc()" C-API for creating a
  module from a *spec* and *initfunc*. (Contributed by Itamar Oren in
  gh-116146.)

* Add "PyTuple_FromArray()" to create a "tuple" from an array.
  (Contributed by Victor Stinner in gh-111489.)

* Add "PyObject_Dump()" to dump an object to "stderr". It should only
  be used for debugging. (Contributed by Victor Stinner in gh-141070.)

* Add "PyUnstable_ThreadState_SetStackProtection()" and
  "PyUnstable_ThreadState_ResetStackProtection()" functions to set the
  stack protection base address and stack protection size of a Python
  thread state. (Contributed by Victor Stinner in gh-139653.)

* Add "PyUnstable_SetImmortal()" C-API function to mark objects as
  *immortal*. (Contributed by Kumar Aditya in gh-143300.)


Changed C APIs
--------------

* If the "Py_TPFLAGS_MANAGED_DICT" or "Py_TPFLAGS_MANAGED_WEAKREF"
  flag is set then "Py_TPFLAGS_HAVE_GC" must be set too. (Contributed
  by Sergey Miryanov in gh-134786.)

* "PyDateTime_IMPORT" is now thread safe. Code that directly checks
  "PyDateTimeAPI" for "NULL" should be updated to call
  "PyDateTime_IMPORT" instead. (Contributed by Kumar Aditya in
  gh-141563.)


Porting to Python 3.15
----------------------

* Private functions promoted to public C APIs:

  The pythoncapi-compat project can be used to get most of these new
  functions on Python 3.14 and older.


Removed C APIs
--------------

* Remove deprecated "PyUnicode" functions:

  * "PyUnicode_AsDecodedObject()": Use "PyCodec_Decode()" instead.

  * "PyUnicode_AsDecodedUnicode()": Use "PyCodec_Decode()" instead;
    Note that some codecs (for example, "base64") may return a type
    other than "str", such as "bytes".

  * "PyUnicode_AsEncodedObject()": Use "PyCodec_Encode()" instead.

  * "PyUnicode_AsEncodedUnicode()": Use "PyCodec_Encode()" instead;
    Note that some codecs (for example, "base64") may return a type
    other than "bytes", such as "str".

  (Contributed by Stan Ulbrych in gh-133612.)

* "PyImport_ImportModuleNoBlock()": deprecated alias of
  "PyImport_ImportModule()". (Contributed by Bénédikt Tran in
  gh-133644.)

* "PyWeakref_GetObject()" and "PyWeakref_GET_OBJECT": use
  "PyWeakref_GetRef()" instead. The pythoncapi-compat project can be
  used to get "PyWeakref_GetRef()" on Python 3.12 and older.
  (Contributed by Bénédikt Tran in gh-133644.)

* Remove deprecated "PySys_ResetWarnOptions()". Clear
  "sys.warnoptions" and "warnings.filters" instead.

  (Contributed by Nikita Sobolev in gh-138886.)

The following functions are removed in favor of "PyConfig_Get()". The
pythoncapi-compat project can be used to get "PyConfig_Get()" on
Python 3.13 and older.

* Python initialization functions:

  * "Py_GetExecPrefix()": use "PyConfig_Get("base_exec_prefix")"
    ("sys.base_exec_prefix") instead. Use
    "PyConfig_Get("exec_prefix")" ("sys.exec_prefix") if virtual
    environments need to be handled.

  * "Py_GetPath()": use "PyConfig_Get("module_search_paths")"
    ("sys.path") instead.

  * "Py_GetPrefix()": use "PyConfig_Get("base_prefix")"
    ("sys.base_prefix") instead. Use "PyConfig_Get("prefix")"
    ("sys.prefix") if virtual environments need to be handled.

  * "Py_GetProgramFullPath()": use "PyConfig_Get("executable")"
    ("sys.executable") instead.

  * "Py_GetProgramName()": use "PyConfig_Get("executable")"
    ("sys.executable") instead.

  * "Py_GetPythonHome()": use "PyConfig_Get("home")" or the
    "PYTHONHOME" environment variable instead.

  (Contributed by Bénédikt Tran in gh-133644.)


Deprecated C APIs
-----------------

* For unsigned integer formats in "PyArg_ParseTuple()", accepting
  Python integers with value that is larger than the maximal value for
  the C type or less than the minimal value for the corresponding
  signed integer type of the same size is now deprecated. (Contributed
  by Serhiy Storchaka in gh-132629.)

* "PyBytes_FromStringAndSize(NULL, len)" and "_PyBytes_Resize()" are
  *soft deprecated*, use the "PyBytesWriter" API instead. (Contributed
  by Victor Stinner in gh-129813.)

* "_PyObject_CallMethodId()", "_PyObject_GetAttrId()" and
  "_PyUnicode_FromId()" are deprecated since 3.15 and will be removed
  in 3.20. Instead, use "PyUnicode_InternFromString()" and cache the
  result in the module state, then call "PyObject_CallMethod()" or
  "PyObject_GetAttr()". (Contributed by Victor Stinner in gh-141049.)

* Deprecate "cval" field of the "PyComplexObject" type. Use
  "PyComplex_AsCComplex()" and "PyComplex_FromCComplex()" to convert a
  Python complex number to/from the C "Py_complex" representation.
  (Contributed by Sergey B Kirpichev in gh-128813.)

* Functions "_Py_c_sum()", "_Py_c_diff()", "_Py_c_neg()",
  "_Py_c_prod()", "_Py_c_quot()", "_Py_c_pow()" and "_Py_c_abs()" are
  *soft deprecated*. (Contributed by Sergey B Kirpichev in gh-128813.)

* "bytes_warning" is deprecated since 3.15 and will be removed in
  3.17. (Contributed by Nikita Sobolev in gh-136355.)

* "Py_INFINITY" macro is *soft deprecated*, use the C11 standard
  "<math.h>" "INFINITY" instead. (Contributed by Sergey B Kirpichev in
  gh-141004.)

* "Py_MATH_El" and "Py_MATH_PIl" are deprecated since 3.15 and will be
  removed in 3.20. (Contributed by Sergey B Kirpichev in gh-141004.)


Build changes
=============

* Removed implicit fallback to the bundled copy of the "libmpdec"
  library. Now this should be explicitly enabled with "--with-system-
  libmpdec" set to "no" or with "--without-system-libmpdec".
  (Contributed by Sergey B Kirpichev in gh-115119.)

* The new configure option "--with-missing-stdlib-config=FILE" allows
  distributors to pass a JSON configuration file containing custom
  error messages for *standard library* modules that are missing or
  packaged separately. (Contributed by Stan Ulbrych and Petr Viktorin
  in gh-139707.)

* The new configure option "--with-pymalloc-hugepages" enables huge
  page support for pymalloc arenas. When enabled, arena size increases
  to 2 MiB and allocation uses "MAP_HUGETLB" (Linux) or
  "MEM_LARGE_PAGES" (Windows) with automatic fallback to regular
  pages. On Windows, use "build.bat --pymalloc-hugepages". At runtime,
  huge pages must be explicitly enabled by setting the
  "PYTHON_PYMALLOC_HUGEPAGES" environment variable to "1".

* Annotating anonymous mmap usage is now supported if Linux kernel
  supports *PR_SET_VMA_ANON_NAME* (Linux 5.17 or newer). Annotations
  are visible in "/proc/<pid>/maps" if the kernel supports the feature
  and "-X dev" is passed to the Python or Python is built in debug
  mode. (Contributed by Donghee Na in gh-141770.)


Porting to Python 3.15
======================

This section lists previously described changes and other bugfixes
that may require changes to your code.

* "sqlite3.Connection" APIs have been cleaned up.

  * All parameters of "sqlite3.connect()" except *database* are now
    keyword-only.

  * The first three parameters of methods "create_function()" and
    "create_aggregate()" are now positional-only.

  * The first parameter of methods "set_authorizer()",
    "set_progress_handler()" and "set_trace_callback()" is now
    positional-only.

  (Contributed by Serhiy Storchaka in gh-133595.)

* "resource.RLIM_INFINITY" is now always positive. Passing a negative
  integer value that corresponded to its old value (such as "-1" or
  "-3", depending on platform) to "resource.setrlimit()" and
  "resource.prlimit()" is now deprecated. (Contributed by Serhiy
  Storchaka in gh-137044.)

* "mmap.mmap.resize()" has been removed on platforms that don't
  support the underlying syscall, instead of raising a "SystemError".

* A resource warning is now emitted for an unclosed
  "xml.etree.ElementTree.iterparse()" iterator if it opened a file.
  Use its "close()" method or the "contextlib.closing()" context
  manager to close it. (Contributed by Osama Abdelkader and Serhiy
  Storchaka in gh-140601.)

* If a short option and a single-dash long option are passed to
  "argparse.ArgumentParser.add_argument()", *dest* is now inferred
  from the single-dash long option. For example, in
  "add_argument('-f', '-foo')", *dest* is now "'foo'" instead of
  "'f'". Pass an explicit *dest* argument to preserve the old
  behavior. (Contributed by Serhiy Storchaka in gh-138697.)
