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

Note

Prerelease users should be aware that this document is currently in draftform. 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 newprofiling module asprofiling.sampling. This profiler enables low-overhead performance analysis ofrunning Python processes without requiring code modification or process restart.

Unlike deterministic profilers (cProfile andprofile) that instrumentevery function call, the sampling profiler periodically captures stack traces fromrunning processes. This approach provides virtually zero overhead while achievingsampling rates ofup to 1,000,000 Hz, making it the fastest sampling profileravailable for Python (at the time of its contribution) and ideal for debuggingperformance issues in production environments.

Key features include:

  • Zero-overhead profiling: Attach to any running Python process withoutaffecting 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-mprofiling.sampling1234

Profile with custom interval and duration, save to file:

python-mprofiling.sampling-i50-d30-oprofile.stats1234

Generate collapsed stacks for flamegraph:

python-mprofiling.sampling--collapsed1234

Profile all threads and sort by total time:

python-mprofiling.sampling-a--sort-tottime1234

The profiler generates statistical estimates of where time is spent:

Real-timesamplingstats:Mean:100261.5Hz(9.97µs)Min:86333.4Hz(11.58µs)Max:118807.2Hz(8.42µs)Samples:400001Captured498841samplesin5.00secondsSamplerate:99768.04samples/secErrorrate:0.72%ProfileStats:nsamplessample%tottime(s)cumul%cumtime(s)filename:lineno(function)43/4188580.00.00087.94.189case.py:667(TestCase.run)3293/4188120.70.03387.94.188case.py:613(TestCase._callTestMethod)158562/15856233.31.58633.31.586test_compile.py:725(TestSpecifics.test_compiler_recursion_limit.<locals>.check_limit)129553/12955327.21.29627.21.296ast.py:46(parse)0/1281290.00.00026.91.281test_ast.py:884(AST_Tests.test_ast_recursion_limit.<locals>.check_limit)7/674460.00.00014.20.674test_compile.py:729(TestSpecifics.test_compiler_recursion_limit)6/603800.00.00012.70.604test_ast.py:888(AST_Tests.test_ast_recursion_limit)3/500200.00.00010.50.500test_compile.py:727(TestSpecifics.test_compiler_recursion_limit)1/380110.00.0008.00.380test_ast.py:886(AST_Tests.test_ast_recursion_limit)1/250760.00.0005.30.251test_compile.py:728(TestSpecifics.test_compiler_recursion_limit)22361/223624.70.2244.70.224test_compile.py:1368(TestSpecifics.test_big_dict_literal)4/180080.00.0003.80.180test_ast.py:889(AST_Tests.test_ast_recursion_limit)11/176960.00.0003.70.177subprocess.py:1038(Popen.__init__)16968/169683.60.1703.60.170subprocess.py:1900(Popen._execute_child)2/169410.00.0003.60.169test_compile.py:730(TestSpecifics.test_compiler_recursion_limit)Legend:nsamples:Direct/Cumulativesamples(directexecuting/oncallstack)sample%:Percentageoftotalsamplesthisfunctionwasdirectlyexecutingtottime:Estimatedtotaltimespentdirectlyinthisfunctioncumul%:Percentageoftotalsampleswhenthisfunctionwasonthecallstackcumtime:Estimatedcumulativetime(includingtimeincalledfunctions)filename:lineno(function):FunctionlocationandnameSummaryofInterestingFunctions:FunctionswithHighestDirect/CumulativeRatio(HotSpots):1.000direct/cumulativeratio,33.3%directsamples:test_compile.py:(TestSpecifics.test_compiler_recursion_limit.<locals>.check_limit)1.000direct/cumulativeratio,27.2%directsamples:ast.py:(parse)1.000direct/cumulativeratio,3.6%directsamples:subprocess.py:(Popen._execute_child)FunctionswithHighestCallFrequency(IndirectCalls):418815indirectcalls,87.9%totalstackpresence:case.py:(TestCase.run)415519indirectcalls,87.9%totalstackpresence:case.py:(TestCase._callTestMethod)159470indirectcalls,33.5%totalstackpresence:test_compile.py:(TestSpecifics.test_compiler_recursion_limit)FunctionswithHighestCallMagnification(Cumulative/Direct):12267.9xcallmagnification,159470indirectcallsfrom13direct:test_compile.py:(TestSpecifics.test_compiler_recursion_limit)10581.7xcallmagnification,116388indirectcallsfrom11direct:test_ast.py:(AST_Tests.test_ast_recursion_limit)9740.9xcallmagnification,418815indirectcallsfrom43direct:case.py:(TestCase.run)

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

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

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

Improved error messages

  • The interpreter now provides more helpful suggestions inAttributeErrorexceptions when accessing an attribute on an object that does not exist, buta similar attribute is available through one of its members.

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

    @dataclassclassCircle:radius:float@propertydefarea(self)->float:returnpi*self.radius**2classContainer:def__init__(self,inner:Circle)->None:self.inner=innercircle=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 usesUTF-8 as the default encoding, independent of the system’senvironment. 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-supportedUnicode character encoding that has become ade facto standard for representing text, including nearly every webpageon the internet, many common file formats, programming languages, and more.

    This only applies when noencoding argument is given. For bestcompatibility between versions of Python, ensure that an explicitencodingargument is always provided. Theopt-in encoding warningcan be used to identify code that may be affected by this change.The specialencoding='locale' argument uses the current localeencoding, and has been supported since Python 3.10.

    To retain the previous behaviour, Python’s UTF-8 mode may be disabled withthePYTHONUTF8=0 environment variable or the-Xutf8=0 command line option.

    See also

    PEP 686 for further details.

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

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

  • The interpreter now tries to provide a suggestion whendelattr() 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:

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

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

  • Unraisable exceptions are now highlighted with color by default. This can becontrolled byenvironment variables.(Contributed by Peter Bierma ingh-134170.)

  • The__repr__() ofImportError andModuleNotFoundErrornow shows “name” and “path” asname=<name> andpath=<path> if they were givenas keyword arguments at construction time.(Contributed by Serhiy Storchaka, Oleg Iarygin, and Yoav Nir ingh-74185.)

  • The__dict__ and__weakref__ descriptors now use asingle descriptor instance per interpreter, shared across all types thatneed them.This speeds up class creation, and helps avoid reference cycles.(Contributed by Petr Viktorin ingh-135228.)

  • The-W option and thePYTHONWARNINGS environment variablecan now specify regular expressions instead of literal strings to matchthe warning message and the module name, if the corresponding field startsand ends with a forward slash (/).(Contributed by Serhiy Storchaka ingh-134716.)

  • Functions that take timestamp or timeout arguments now accept any realnumbers (such asDecimal andFraction),not only integers or floats, although this does not improve precision.(Contributed by Serhiy Storchaka ingh-67795.)

New modules

  • None yet.

Improved modules

collections

  • Addedcollections.Counter.__xor__() andcollections.Counter.__ixor__() to compute the symmetric differencebetweenCounter objects.(Contributed by Raymond Hettinger ingh-138682.)

collections.abc

  • collections.abc.ByteString has been removed fromcollections.abc.__all__.collections.abc.ByteString has beendeprecated since Python 3.12, and is scheduled for removal in Python 3.17.

  • The following statements now causeDeprecationWarnings to be emitted atruntime:

    • fromcollections.abcimportByteString

    • importcollections.abc;collections.abc.ByteString.

    DeprecationWarnings were already emitted ifcollections.abc.ByteString was subclassed or used as the secondargument toisinstance() orissubclass(), but warnings were notpreviously emitted if it was merely imported or accessed from thecollections.abc module.

dbm

  • Added newreorganize() methods todbm.dumb anddbm.sqlite3which allow to recover unused free space previously occupied by deleted entries.(Contributed by Andrea Oliveri ingh-134004.)

difflib

hashlib

  • Ensure that hash functions guaranteed to be alwaysavailable exist asattributes ofhashlib even if they will not work at runtime due tomissing backend implementations. For instance,hashlib.md5 will nolonger raiseAttributeError if OpenSSL is not available and Pythonhas been built without MD5 support.(Contributed by Bénédikt Tran ingh-136929.)

http.client

  • A newmax_response_headers keyword-only parameter has been added toHTTPConnection andHTTPSConnectionconstructors. This parameter overrides the default maximum number of allowedresponse headers.(Contributed by Alexander Enrique Urieles Nieto ingh-131724.)

http.cookies

  • Allow ‘"’ double quotes in cookie values.(Contributed by Nick Burns and Senthil Kumaran ingh-92936.)

locale

  • setlocale() now supports language codes with@-modifiers.@-modifier are no longer silently removed ingetlocale(),but included in the language code.(Contributed by Serhiy Storchaka ingh-137729.)

math

mmap

  • mmap.mmap now has atrackfd parameter on Windows;if it isFalse, the file handle corresponding tofileno willnot be duplicated.(Contributed by Serhiy Storchaka ingh-78502.)

os.path

resource

shelve

  • Added newreorganize() method toshelve used to recover unused freespace previously occupied by deleted entries.(Contributed by Andrea Oliveri ingh-134004.)

socket

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

sqlite3

  • Thecommand-line interface has several new features:

    • SQL keyword completion on <tab>.(Contributed by Long Tan ingh-133393.)

    • Prompts, error messages, and help text are now colored.This is enabled by default, seeControlling color fordetails.(Contributed by Stan Ulbrych and Łukasz Langa ingh-133461.)

ssl

  • Indicate throughssl.HAS_PSK_TLS13 whether thessl modulesupports “External PSKs” in TLSv1.3, as described in RFC 9258.(Contributed by Will Childs-Klein ingh-133624.)

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

    • ssl.SSLContext.set_groups() sets the groups allowed for doingkey agreement, extending the previousssl.SSLContext.set_ecdh_curve() method.This new API provides the ability to list multiple groups andsupports fixed-field and post-quantum groups in addition to ECDHcurves. This method can also be used to control what key sharesare sent in the TLS handshake.

    • ssl.SSLSocket.group() returns the group selected for doing keyagreement 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 keyagreement groups compatible with the minimum and maximum TLS versionscurrently set in the context. This call requires OpenSSL 3.5 or later.

    (Contributed by Ron Frederick ingh-136306.)

  • Added a new methodssl.SSLContext.set_ciphersuites() for setting TLS 1.3ciphers. For TLS 1.2 or earlier,ssl.SSLContext.set_ciphers() shouldcontinue to be used. Both calls can be made on the same context and theselected cipher suite will depend on the TLS version negotiated when aconnection is made.(Contributed by Ron Frederick ingh-137197.)

  • Added new methods for managing signature algorithms:

    (Contributed by Ron Frederick ingh-138252.)

sys

  • Addsys.abi_info namespace to improve access to ABI information.(Contributed by Klaus Zimmermann ingh-137476.)

tarfile

timeit

  • The command-line interface now colorizes error tracebacksby default. This can be controlled withenvironment variables.(Contributed by Yi Hong ingh-139374.)

types

unittest

xml.parsers.expat

zlib

Optimizations

module_name

  • TODO

Deprecated

CLI

  • Deprecate-b and-bb command line optionsand 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, noBytesWarning will be raisedfor these cases; use a type checker instead.

    (Contributed by Nikita Sobolev ingh-136355.)

hashlib

  • In hash function constructors such asnew() or thedirect hash-named constructors such asmd5() andsha256(), their optional initial data parameter couldalso be passed a keyword argument nameddata= orstring= invarioushashlib implementations.

    Support for thestring keyword argument name is now deprecated andis slated for removal in Python 3.19. Prefer passing the initial data asa positional argument for maximum backwards compatibility.

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

__version__

Pending removal in Python 3.16

Pending removal in Python 3.17

  • collections.abc:

    • collections.abc.ByteString is scheduled for removal in Python 3.17.

      Useisinstance(obj,collections.abc.Buffer) to test ifobjimplements thebuffer protocol at runtime. For usein type annotations, either useBuffer or a unionthat explicitly specifies the types your code supports (e.g.,bytes|bytearray|memoryview).

      ByteString was originally intended to be an abstract class thatwould serve as a supertype of bothbytes andbytearray.However, since the ABC never had any methods, knowing that an object was aninstance ofByteString never actually told you anything usefulabout the object. Other common buffer types such asmemoryviewwere also never understood as subtypes ofByteString (either atruntime or by static type checkers).

      SeePEP 688 for more details.(Contributed by Shantanu Jain ingh-91896.)

  • typing:

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

    • typing.ByteString, deprecated since Python 3.9, is scheduled for removal inPython 3.17.

      Useisinstance(obj,collections.abc.Buffer) to test ifobjimplements thebuffer protocol at runtime. For usein type annotations, either useBuffer or a unionthat explicitly specifies the types your code supports (e.g.,bytes|bytearray|memoryview).

      ByteString was originally intended to be an abstract class thatwould serve as a supertype of bothbytes andbytearray.However, since the ABC never had any methods, knowing that an object was aninstance ofByteString never actually told you anything usefulabout the object. Other common buffer types such asmemoryviewwere also never understood as subtypes ofByteString (either atruntime or by static type checkers).

      SeePEP 688 for more details.(Contributed by Shantanu Jain ingh-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 asnew() or thedirect hash-named constructors such asmd5() andsha256(), their optional initial data parameter couldalso be passed a keyword argument nameddata= orstring= invarioushashlib implementations.

      Support for thestring keyword argument name is now deprecatedand slated for removal in Python 3.19.

      Before Python 3.13, thestring keyword parameter was not correctlysupported depending on the backend implementation of hash functions.Prefer passing the initial data as a positional argument for maximumbackwards compatibility.

Pending removal in Python 3.20

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 exclusivegroups are deprecated.

    • Passing the undocumented keyword argumentprefix_chars toadd_argument_group() is nowdeprecated.

    • Theargparse.FileType type converter is deprecated.

  • builtins:

    • Generators:throw(type,exc,tb) andathrow(type,exc,tb)signature is deprecated: usethrow(exc) andathrow(exc) instead,the single argument signature.

    • Currently Python accepts numeric literals immediately followed by keywords,for example0inx,1orx,0if1else2. It allows confusing andambiguous expressions like[0x1forxiny] (which can be interpreted as[0x1forxiny] or[0x1forxiny]). A syntax warning is raisedif the numeric literal is immediately followed by one of keywordsand,else,for,if,in,is andor. In a future release itwill 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 ofint.

    • Support for__float__() method returning a strict subclass offloat: these methods will be required to return an instance offloat.

    • Support for__complex__() method returning a strict subclass ofcomplex: these methods will be required to return an instance ofcomplex.

    • Delegation ofint() to__trunc__() method.

    • Passing a complex number as thereal orimag argument in thecomplex() constructor is now deprecated; it should only be passedas a single positional argument.(Contributed by Serhiy Storchaka ingh-109218.)

  • calendar:calendar.January andcalendar.February constants aredeprecated and replaced bycalendar.JANUARY andcalendar.FEBRUARY.(Contributed by Prince Roshan ingh-103636.)

  • codecs: useopen() instead ofcodecs.open(). (gh-133038)

  • codeobject.co_lnotab: use thecodeobject.co_lines() methodinstead.

  • datetime:

    • utcnow():usedatetime.datetime.now(tz=datetime.UTC).

    • utcfromtimestamp():usedatetime.datetime.fromtimestamp(timestamp,tz=datetime.UTC).

  • gettext: Plural value must be an integer.

  • importlib:

    • cache_from_source()debug_override parameter isdeprecated: use theoptimization parameter instead.

  • importlib.metadata:

    • EntryPoints tuple interface.

    • ImplicitNone on return values.

  • logging: thewarn() method has been deprecatedsince Python 3.3, usewarning() instead.

  • mailbox: Use of StringIO input and text mode is deprecated, useBytesIO and binary mode instead.

  • os: Callingos.register_at_fork() in multi-threaded process.

  • pydoc.ErrorDuringImport: A tuple value forexc_info parameter isdeprecated, use an exception instance.

  • re: More strict rules are now applied for numerical group referencesand group names in regular expressions. Only sequence of ASCII digits is nowaccepted as a numerical reference. The group name in bytes patterns andreplacement strings can now only contain ASCII letters and digits andunderscore.(Contributed by Serhiy Storchaka ingh-91760.)

  • shutil:rmtree()’sonerror parameter is deprecated inPython 3.12; use theonexc parameter instead.

  • ssl options and protocols:

    • ssl.SSLContext without protocol argument is deprecated.

    • ssl.SSLContext:set_npn_protocols() andselected_npn_protocol() are deprecated: use ALPNinstead.

    • 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:

  • typing.Text (gh-92332).

  • The internal classtyping._UnionGenericAlias is no longer used to implementtyping.Union. To preserve compatibility with users using this privateclass, a compatibility shim will be provided until at least Python 3.17. (Contributed byJelle Zijlstra ingh-105499.)

  • unittest.IsolatedAsyncioTestCase: it is deprecated to return a valuethat is notNone 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 partialwrites.

  • xml.etree.ElementTree: Testing the truth value of anElement is deprecated. In a future release itwill always returnTrue. Prefer explicitlen(elem) orelemisnotNone tests instead.

  • sys._clear_type_cache() is deprecated:usesys._clear_internal_caches() instead.

Removed

ctypes

  • Removed the undocumented functionctypes.SetPointerType(),which has been deprecated since Python 3.13.(Contributed by Bénédikt Tran ingh-133866.)

glob

  • Removed the undocumentedglob.glob0() andglob.glob1()functions, which have been deprecated since Python 3.13. Useglob.glob() and pass a directory to itsroot_dir argument instead.(Contributed by Barney Gale ingh-137466.)

http.server

  • Removed theCGIHTTPRequestHandler classand the--cgi flag from thepython -m http.servercommand-line interface. They were deprecated in Python 3.13.(Contributed by Bénédikt Tran ingh-133810.)

importlib.resources

pathlib

  • Removed deprecatedpathlib.PurePath.is_reserved().Useos.path.isreserved() to detect reserved paths on Windows.(Contributed by Nikita Sobolev ingh-133875.)

platform

  • Removed theplatform.java_ver() function,which was deprecated since Python 3.13.(Contributed by Alexey Makridenko ingh-133604.)

sre_*

  • Removedsre_compile,sre_constants andsre_parse modules.(Contributed by Stan Ulbrych ingh-135994.)

sysconfig

threading

  • Remove support for arbitrary positional or keyword arguments in the Cimplementation ofRLock objects. This was deprecatedin Python 3.14.(Contributed by Bénédikt Tran ingh-134087.)

typing

  • The undocumented keyword argument syntax for creatingNamedTuple 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 ingh-133817.)

  • UsingTD=TypedDict("TD") orTD=TypedDict("TD",None) toconstruct aTypedDict type with zero field is nolonger supported. UseclassTD(TypedDict):passorTD=TypedDict("TD",{}) instead.(Contributed by Bénédikt Tran ingh-133823.)

  • Code likeclassExtraTypeVars(P1[S],Protocol[T,T2]):... now raisesaTypeError, becauseS is not listed inProtocol parameters.(Contributed by Nikita Sobolev ingh-137191.)

  • Code likeclassB2(A[T2],Protocol[T1,T2]):... now correctly handlestype parameters order: it is(T1,T2), not(T2,T1)as it was incorrectly infered in runtime before.(Contributed by Nikita Sobolev ingh-137191.)

  • typing.ByteString has been removed fromtyping.__all__.typing.ByteString has been deprecated since Python 3.9, and isscheduled for removal in Python 3.17.

  • The following statements now causeDeprecationWarnings to be emitted atruntime:

    • fromtypingimportByteString

    • importtyping;typing.ByteString.

    DeprecationWarnings were already emitted iftyping.ByteStringwas subclassed or used as the second argument toisinstance() orissubclass(), but warnings were not previously emitted if it was merelyimported or accessed from thetyping module.

unicodedata

  • The Unicode database has been updated to Unicode 17.0.0.

wave

  • Removed thegetmark(),setmark() andgetmarkers() methodsof theWave_read andWave_write classes,which were deprecated since Python 3.13.(Contributed by Bénédikt Tran ingh-133873.)

zipimport

Porting to Python 3.15

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

Build changes

  • Removed implicit fallback to the bundled copy of thelibmpdec library.Now this should be explicitly enabled with--with-system-libmpdecset tono or with--without-system-libmpdec.(Contributed by Sergey B Kirpichev ingh-115119.)

C API changes

New features

Porting to Python 3.15

Deprecated C APIs

Removed C APIs

The following functions are removed in favor ofPyConfig_Get().Thepythoncapi-compat project can be used to getPyConfig_Get()on Python 3.13 and older.