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 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 profile module as profile.sample. This profiler enables low-overhead performance analysis of running Python processes without requiring code modification or process restart.

Unlike deterministic profilers (cProfile and 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 200,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 profile.sample 1234

Profile with custom interval and duration, save to file:

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

Generate collapsed stacks for flamegraph:

python -m profile.sample --collapsed 1234

Profile all threads and sort by total time:

python -m profile.sample -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.)

Other language changes

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

New modules

  • None yet.

Improved modules

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

  • Add the 'm' flag for dbm.gnu.open() which allows to disable the use of mmap(2). This may harm performance, but improve crash tolerance. (Contributed by Serhiy Storchaka in gh-66234.)

difflib

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

math

os.path

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

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)

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

tarfile

zlib

Optimizations

module_name

  • TODO

Deprecated

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

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

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

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

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 field is no longer supported. Use class TD(TypedDict): pass or TD = TypedDict("TD", {}) instead. (Contributed by Bénédikt Tran in gh-133823.)

unittest

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

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

Porting to Python 3.15

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

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

C API changes

New features

Porting to Python 3.15

Deprecated C APIs

  • TODO

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

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.