# 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 799: A dedicated profiling package for organizing Python profiling tools

- PEP 799: Tachyon: High frequency statistical sampling profiler profiling tools

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

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

- Improved error messages

## New features

### 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

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 flamegraphs with external tools like Brendan Gregg’s FlameGraph scripts or speedscope.

  - `--flamegraph`: Generates a self-contained interactive HTML flamegraph using D3.js. Opens directly in your browser for immediate visual analysis. Flamegraphs 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 (https://profiler.firefox.com). 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.)

### 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 `bytearray` |
      def read() -> bytes:
          buffer = bytearray(1024)
          ...
          return bytes(buffer)
      def read() -> bytes:
          buffer = bytearray(1024)
          ...
          return buffer.take_bytes()
  Empty a buffer getting the bytes |
      buffer = bytearray(1024)
      ...
      data = bytes(buffer)
      buffer.clear()
      buffer = bytearray(1024)
      ...
      data = buffer.take_bytes()
  Split a buffer at a specific separator |
      buffer = bytearray(b'abc\ndef')
      n = buffer.find(b'\n')
      data = bytes(buffer[:n + 1])
      del buffer[:n + 1]
      assert data == b'abc'
      assert buffer == bytearray(b'def')
      buffer = bytearray(b'abc\ndef')
      n = buffer.find(b'\n')
      data = buffer.take_bytes(n + 1)
  Split a buffer at a specific separator; discard after the separator |
      buffer = bytearray(b'abc\ndef')
      n = buffer.find(b'\n')
      data = bytes(buffer[:n])
      buffer.clear()
      assert data == b'abc'
      assert len(buffer) == 0
      buffer = bytearray(b'abc\ndef')
      n = buffer.find(b'\n')
      buffer.resize(n)
      data = buffer.take_bytes()

  (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.)

## 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.)

### 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.)

### 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.)

### 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/node` MIME type for `.cjs` extension. (Contributed by John Franey in gh-140937.)

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

- 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.)

### 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.)

### 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.)

### 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)

### 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.)

### unittest

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

### 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

### csv

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

## 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

- 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__` attribute has 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`

    - `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.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__` attribute has 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`

  - `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`.

  - Delegation of `int()` to `__trunc__()` method.

  - 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.

- `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 `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 `PyUnstable_Object_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.)

### 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)

### 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.)

- 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.)

- `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.)