Skip to content

Latest commit

 

History

History
1006 lines (715 loc) · 36.4 KB

File metadata and controls

1006 lines (715 loc) · 36.4 KB

What's new in Python 3.15

Editor:TBD

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

For full details, see the :ref:`changelog <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

New features

High frequency statistical sampling profiler

A new statistical sampling profiler has been added to the new :mod:`!profiling` module as :mod:`!profiling.sampling`. This profiler enables low-overhead performance analysis of running Python processes without requiring code modification or process restart.

Unlike deterministic profilers (:mod:`cProfile` and :mod:`profile`) 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.

Key features include:

  • Zero-overhead profiling: Attach to any running Python process without affecting its performance
  • No code modification required: Profile existing applications without restart
  • Real-time statistics: Monitor sampling quality during data collection
  • Multiple output formats: Generate both detailed statistics and flamegraph data
  • Thread-aware profiling: Option to profile all threads or just the main thread

Profile process 1234 for 10 seconds with default settings:

python -m profiling.sampling 1234

Profile with custom interval and duration, save to file:

python -m profiling.sampling -i 50 -d 30 -o profile.stats 1234

Generate collapsed stacks for flamegraph:

python -m profiling.sampling --collapsed 1234

Profile all threads and sort by total time:

python -m profiling.sampling -a --sort-tottime 1234

The profiler generates statistical estimates of where time is spent:

Real-time sampling stats: Mean: 100261.5Hz (9.97µs) Min: 86333.4Hz (11.58µs) Max: 118807.2Hz (8.42µs) Samples: 400001
Captured 498841 samples in 5.00 seconds
Sample rate: 99768.04 samples/sec
Error rate: 0.72%
Profile Stats:
      nsamples   sample%   tottime (s)    cumul%   cumtime (s)  filename:lineno(function)
      43/418858       0.0         0.000      87.9         4.189  case.py:667(TestCase.run)
    3293/418812       0.7         0.033      87.9         4.188  case.py:613(TestCase._callTestMethod)
  158562/158562      33.3         1.586      33.3         1.586  test_compile.py:725(TestSpecifics.test_compiler_recursion_limit.<locals>.check_limit)
  129553/129553      27.2         1.296      27.2         1.296  ast.py:46(parse)
      0/128129       0.0         0.000      26.9         1.281  test_ast.py:884(AST_Tests.test_ast_recursion_limit.<locals>.check_limit)
        7/67446       0.0         0.000      14.2         0.674  test_compile.py:729(TestSpecifics.test_compiler_recursion_limit)
        6/60380       0.0         0.000      12.7         0.604  test_ast.py:888(AST_Tests.test_ast_recursion_limit)
        3/50020       0.0         0.000      10.5         0.500  test_compile.py:727(TestSpecifics.test_compiler_recursion_limit)
        1/38011       0.0         0.000       8.0         0.380  test_ast.py:886(AST_Tests.test_ast_recursion_limit)
        1/25076       0.0         0.000       5.3         0.251  test_compile.py:728(TestSpecifics.test_compiler_recursion_limit)
    22361/22362       4.7         0.224       4.7         0.224  test_compile.py:1368(TestSpecifics.test_big_dict_literal)
        4/18008       0.0         0.000       3.8         0.180  test_ast.py:889(AST_Tests.test_ast_recursion_limit)
      11/17696       0.0         0.000       3.7         0.177  subprocess.py:1038(Popen.__init__)
    16968/16968       3.6         0.170       3.6         0.170  subprocess.py:1900(Popen._execute_child)
        2/16941       0.0         0.000       3.6         0.169  test_compile.py:730(TestSpecifics.test_compiler_recursion_limit)

Legend:
  nsamples: Direct/Cumulative samples (direct executing / on call stack)
  sample%: Percentage of total samples this function was directly executing
  tottime: Estimated total time spent directly in this function
  cumul%: Percentage of total samples when this function was on the call stack
  cumtime: Estimated cumulative time (including time in called functions)
  filename:lineno(function): Function location and name

Summary of Interesting Functions:

Functions with Highest Direct/Cumulative Ratio (Hot Spots):
  1.000 direct/cumulative ratio, 33.3% direct samples: test_compile.py:(TestSpecifics.test_compiler_recursion_limit.<locals>.check_limit)
  1.000 direct/cumulative ratio, 27.2% direct samples: ast.py:(parse)
  1.000 direct/cumulative ratio, 3.6% direct samples: subprocess.py:(Popen._execute_child)

Functions with Highest Call Frequency (Indirect Calls):
  418815 indirect calls, 87.9% total stack presence: case.py:(TestCase.run)
  415519 indirect calls, 87.9% total stack presence: case.py:(TestCase._callTestMethod)
  159470 indirect calls, 33.5% total stack presence: test_compile.py:(TestSpecifics.test_compiler_recursion_limit)

Functions with Highest Call Magnification (Cumulative/Direct):
  12267.9x call magnification, 159470 indirect calls from 13 direct: test_compile.py:(TestSpecifics.test_compiler_recursion_limit)
  10581.7x call magnification, 116388 indirect calls from 11 direct: test_ast.py:(AST_Tests.test_ast_recursion_limit)
  9740.9x call magnification, 418815 indirect calls from 43 direct: case.py:(TestCase.run)

The profiler automatically identifies performance bottlenecks through statistical analysis, highlighting functions with high CPU usage and call frequency patterns.

This capability is particularly valuable for debugging performance issues in production systems where traditional profiling approaches would be too intrusive.

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

Improved error messages

  • The interpreter now provides more helpful suggestions in :exc:`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, e.g. 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 :ref:`opt-in encoding warning <io-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 :envvar:`PYTHONUTF8=0 <PYTHONUTF8>` environment variable or the :option:`-X utf8=0 <-X>` command line option.

    .. seealso:: :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 :func:`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  # doctest: +ELLIPSIS
    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 :ref:`environment variables <using-on-controlling-color>`. (Contributed by Peter Bierma in :gh:`134170`.)

  • The :meth:`~object.__repr__` of :class:`ImportError` and :class:`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 :attr:`~object.__dict__` and :attr:`!__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 :option:`-W` option and the :envvar:`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 :class:`~decimal.Decimal` and :class:`~fractions.Fraction`), not only integers or floats, although this does not improve precision. (Contributed by Serhiy Storchaka in :gh:`67795`.)

New modules

  • None yet.

Improved modules

collections

collections.abc

dbm

difflib

hashlib

  • Ensure that hash functions guaranteed to be always available exist as attributes of :mod:`hashlib` even if they will not work at runtime due to missing backend implementations. For instance, hashlib.md5 will no longer raise :exc:`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

http.cookies

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

locale

math

mmap

  • :class:`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.path

resource

shelve

socket

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

sqlite3

ssl

sys

tarfile

timeit

types

unittest

xml.parsers.expat

zlib

Optimizations

module_name

  • TODO

Deprecated

CLI

  • Deprecate :option:`-b` and :option:`!-bb` command line options and schedule them to become no-op in Python 3.17. These were primarily helpers for the Python 2 -> 3 transition. Starting with Python 3.17, no :exc:`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 :func:`~hashlib.new` or the direct hash-named constructors such as :func:`~hashlib.md5` and :func:`~hashlib.sha256`, their optional initial data parameter could also be passed a keyword argument named data= or string= in various :mod:`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__

Removed

ast

  • The constructors of AST node types in the :mod:`ast` module now raise a :exc:`TypeError` when a required argument is omitted or when a keyword argument that does not map to a field on the AST node is passed. These cases had previously raised a :exc:`DeprecationWarning` since Python 3.13. (Contributed by Brian Schubert and Jelle Zijlstra in :gh:`137600` and :gh:`105858`.)

ctypes

glob

http.server

importlib.resources

pathlib

platform

sre_*

sysconfig

threading

  • Remove support for arbitrary positional or keyword arguments in the C implementation of :class:`~threading.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 :class:`~typing.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 :class:`~typing.TypedDict` type with zero field 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 :exc:`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 infered in runtime before. (Contributed by Nikita Sobolev in :gh:`137191`.)

  • :class:`typing.ByteString` has been removed from typing.__all__. :class:`!typing.ByteString` has been deprecated since Python 3.9, and is scheduled for removal in Python 3.17.

  • The following statements now cause DeprecationWarnings to be emitted at runtime:

    • from typing import ByteString
    • import typing; typing.ByteString.

    DeprecationWarnings were already emitted if :class:`typing.ByteString` was subclassed or used as the second argument to :func:`isinstance` or :func:`issubclass`, but warnings were not previously emitted if it was merely imported or accessed from the :mod:`!typing` module.

unicodedata

  • The Unicode database has been updated to Unicode 17.0.0.

wave

zipimport

Porting to Python 3.15

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

Build changes

C API changes

New features

Porting to Python 3.15

Deprecated C APIs

Removed C APIs

The following functions are removed in favor of :c:func:`PyConfig_Get`. The pythoncapi-compat project can be used to get :c:func:`!PyConfig_Get` on Python 3.13 and older.