This PEP was rejected in favour ofPEP 602. The potential alpha/beta alternationwas deemed too confusing and the two year cadence between releases deemed toolong.
For a long time, CPython’s nominal feature release cadence has been “every 18-24months”, and in recent years, has been pretty consistently on the “18 month”end of that window.PEP 607 provides some common background on the problemsthat arise due to that choice of cadence, as well as some of the risks thatneed to be accounted for when proposing to change it.
The proposal in this PEP aims to allow CPython’s user base to self-select intotwo distinct but overlapping groups:
As part of this proposal, the usage guidance given for beta releases wouldbecome “suitable for production use only in environments with sufficientlyrobust compatibility testing and operational monitoring capabilities”, ratherthan the currently unqualified “not for production use”.
Similarly, the guidance given for alpha releases would be amended to state“intended for library compatibility testing and the creation of ABI compatiblebinary artifacts”, rather than simply saying “not for production use”.
The PEP authors believe these outcomes can be achieved by amending CPython’spre-release management process as described in the Proposal section below.
This PEP also proposes that the frequency of X.Y.0 releases be adjusted tobegin each new release series in August every two years (starting in 2021,around two years after the release of Python 3.8.0).
Under this proposal, Python 3.9.0a1 would be released in December 2019, twomonths after the Python 3.8.0 baseline feature release in October 2019.
Assuming no further breaking changes were made to the full CPython ABI, the3.9.0b2 release would then follow 2 months later in February 2020, continuingthrough to 3.9.0b9 in April 2021.
Any time a breaking change to the full CPython ABI was introduced, the firstpre-release that included it would be marked as an alpha release.
3.9.0rc1 would be published in June 2021, 3.9.0rc2 in July 2021, and thenthe full release published as 3.9.0 in August 2021.
The cycle would start over again in October 2021, with the publicationof 3.10.0a1 (4 months after the creation of the 3.9.x maintenance branch).
The exact schedule of maintenance releases would be up to the release team,but assuming maintenance releases of 3.9.x were also to occur every other month(offset from the 3.10.0 beta releases), the overall release timelinewould look like:
If we assume two additional pre-releases were made that introduced breakingchanges to the full CPython ABI in the 3.9.0a5 and 3.9.0a7 releases, then theoverall calendar would look like:

Figure 1. Impact of the pre-release process changes on the calendar.
There are always two or three active maintenance branches in this model,which preserves the status quo in that respect. The major difference is thatwe would start encouraging publishers to provide pre-built binaries for thepre-freeze rolling releases in addition to providing them for the stablemaintenance branches.

Figure 2. Testing matrix in the 18-month cadence vs. the 24-month
Package publishers targeting the full CPython ABI that choose to providepre-built binaries for the rolling pre-freeze releases would at least needto build new wheel archives following the 3.9.0a1 release. Whether they neededto publish updated binaries after subsequent alpha releases (e.g. 3.9.0a5 or3.9.0a7 releases in the example timeline) would depend on whether or not theywere actually affected by the ABI breaks in those later releases.
As with the status quo, all package publishers wishing to provide pre-builtbinaries for the final release will need to build new wheel archives followingthe ABI freeze date. Unlike the status quo, this date will be clearly markedby the publication of the first release candidate, and it will occur earlyenough to give publishers a couple of months to get ready for the final release.
If this PEP is accepted, the primary channels used to communicate the updatedpre-release management process to end users would be the Python 3.9 What’s Newdocument, and the release announcements themselves.
This section provides initial drafts of text that could be used for thosepurposes.
The following subsection would be added to the Python 3.9 What’s New document,and then linked from each of the Python 3.9 alpha and beta announcements.
As detailed inPEP 605, the pre-release management process has been updated toproduce a rolling series of beta releases that are considered suitable forproduction use in environments with sufficiently robust integration testing andoperational monitoring capabilities.
Under this new rolling model, the alpha and beta releases are intermingled aspart of a combined “pre-freeze” period, with alpha releases indicating breaksin the full CPython ABI that may require recompilation of extension modules orembedding applications, and beta releases indicating full binary compatibilitywith the immediately preceding pre-release.
Unlike previous releases, publishing pre-built binaries for 3.9.0 alpha and betareleases is actively encouraged, as a new pre-release ABI flag (“p”) is nowset when building and loading extension modules prior to the full CPython ABIfreeze, ensuring that all such pre-freeze extension module builds will beignored by post-freeze interpreter builds.
The full CPython ABI will be frozen, and the pre-release flag dropped from theABI flags, in 3.9.0rc1, which is expected to occur 2 months prior to the final3.9.0 release (refer to the release schedule inPEP 596 for exact target dates).
For application developers, migrating to the rolling release stream providesthe opportunity to be actively involved in the design and development ofenhancements to the standard library and reference interpreter prior to thenext stable release. It also provides the opportunity to benefit frominterpreter performance enhancements up to a year or more before they becomeavailable in a stable release.
For library developers that publish pre-built wheel archives, opting in tosupporting the 3.9.x rolling release stream in addition to the 3.8 stablerelease series requires no specific action if the project is already publishingeither pure Python wheels (tagged aspy3-none-any), or builds against thestable C ABI (tagged ascp38-abi3-<platform>, or the equivalent from anearlier CPython 3.x release). These same wheel archives will also be usable onthe subsequent 3.9 stable release series.
For library developers that publish pre-built wheel archives that are builtagainst the full CPython ABI, the binaries for the 3.9 stable release serieswill need to be built after the full CPython ABI freeze (i.e. using 3.9.0rc1 orlater).
Developers of these libraries may also opt in to supporting the rolling releasestream by building against the 3.9.0a1 release (or a subsequent beta release)and publishing the result as normal.
In the ideal case, binaries built this way will continue working all the waythrough to the last pre-freeze release. However, if the project is affected bya change in the full CPython C ABI during the pre-freeze period, then it willbe necessary to publish a maintenance update that rebuilds the affected binariesagainst the alpha release that changed the relevant interface. In these cases,a correspondingPython-Requires entry should be added to the projectmetadata. For example, if a project is affected by an ABI change introduced in3.9.0a5, then thePython-Requires entry to add would be:
Python-Requires:>="3.9.0b6";python_version=="3.9"andfull_python_version!="3.9.0a5"
(This additional metadata ensures that the updated version won’t be installed onearlier pre-releases in the 3.9 series that offer an older variant of the ABI)
As for application developers, library developers that choose to support therolling release stream will have the opportunity to provide feedback on new andupdated API designsbefore they’re locked down for multiple years in a stablerelease (or before they’re included as a provisional API in a stable releaseseries).
This is the first preview release of Python 3.9. As an alpha release, it isintended for library and application compatibility testing and the creation ofABI compatible binary artifacts. It is not recommended for use in productionenvironments.
CPython has switched to a new pre-release management process that is designedto produce a rolling series of beta releases that are considered suitable forproduction use in environments with sufficiently robust integration testing andoperational monitoring capabilities. Refer to the Python 3.9 What’s Newdocument (hyperlinked to relevant section) for details.
Many new features for Python 3.9 are still being planned and written. Among themajor new features and changes already implemented:
The next pre-release of Python 3.9 is expected to be 3.8.0b2, currently scheduled for 2020-02-02.
This is the second preview release of Python 3.9. As a beta release, it isfully binary compatible with the preceding 3.9.0a1 release. It is recommendedfor production use only in environments with sufficiently robust integrationtesting and operational monitoring capabilities.
(Remainder as per 3.9.0a1 announcement, with updates for implemented changesand the next expected release being 3.9.0b3)
This is the fifth preview release of Python 3.9. As an alpha release, it isNOT fully binary compatible with the preceding 3.9.0b4 release. This release isintended for library and application compatibility testing and the creation ofABI compatible binary artifacts. It is not recommended for use in productionenvironments.
ob_example added to thePyObject structtp_example removed from thePyTypeObject structProjects that are supporting the rolling release stream and require a rebuildto restore binary compatibility should add the following metadata to theirupdated release:
Python-Requires:>="3.9.0b6";python_version=="3.9"andfull_python_version!="3.9.0a5"
(Remainder as per 3.9.0a1 announcement, with updates for implemented changesand the next expected release being 3.9.0b6)
This is the first release candidate for Python 3.9. As a release candidate,this release is now feature complete, the full CPython ABI is now frozen, andthe pre-release marker has been removed from the ABI compatibility flags. It isrecommended for production use only in environments with sufficiently robustintegration testing and operational monitoring capabilities.
With the full CPython ABI now frozen, library developers targeting that ABI areencouraged to build and publish binaries for the stable 3.9.x series.
Application developers that have not been testing against the rolling releasestream are encouraged to test their applications against the release candidateand report any compatibility regressions not already mentioned in the PortingGuide (hyperlinked to relevant What’s New section).
A second release candidate is planned for 2021-07-02, and then the final 3.9.0release is planned for 2021-08-02.
Some of the major new features and changes in this release:
The current CPython pre-release and release management processes were developedin an era where automated continuous integration and operational monitoringsystems were still relatively immature. Since that time, many organisationshave adopted deployment models that allow them to incorporate new CPythonfeature releases without adding substantially more risk than they incur for anyother code change. Newer deployment models, such as lightweight task specificapplication containers, also make it easier to combine an application with alanguage runtime in a CI pipeline, and then keep them together until the entirecontainer image is later replaced by an updated one.
In light of those changes in the wider environment,PEP 602 has proposedreducing the feature delivery latency for the Python standard library andCPython reference interpreter by increasing the frequency of CPython featurereleases from every 18-24 months to instead occur every 12 months.
Unfortunately, for many organisations, the cost of adopting a new Python releasedoesn’t automatically scale down with a reduced number of changes in the release,as the primary costs aren’t associated with resolving any discovered issues;the primary costs are associated with thesearch for issues. This search mayinvolve manual testing of software systems, human review of written materials,and other activities where the time required scales with the size of theexisting system, rather than with the number of changes between the versions ofPython.
For third party library developers, costs are primarily associated with thenumber of distinct Python versions in widespread usage. This currently tendsto be influenced by a combination of which releases are still activelymaintained by python-dev, and which releases are the latest versions offeredby particular redistributors (with the Debian, Ubuntu LTS, and RHEL/CentOSsystem Python versions being particularly popular development targets). Inaddition to the basic CI cost of testing against more Python versions, havingmore variants in widespread use can make it more difficult to determine when afault report is an actual error in the project, or an issue in the reportinguser’s environment.
PEP 602 proposes that affected organisations and projects simply switch toadopting every second or third CPython release, rather than attempting to adoptevery release, but that creates its own set of new problems to be resolved, bothpractical (e.g. deprecations would need to cover more than one release if we’reexpecting users to routinely skip releases) and cultural (e.g. with a largernumber of versions in active use, there is a much higher chance that open sourcelibrary maintainers will receive bug reports that only occur on Python versionsthat they’re not using themselves).
PEP 598 was an initial attempt by one of the authors of this PEP to proposean alternative scheme to reduce feature delivery latency by adopting asemantic versioning style policy that allowed for the incremental delivery ofbackwards compatible features within a release series, until that seriesreached feature complete status. That variant still had the undesirableconsequence of imposing visible changes on end users that are happy enoughwith the current release management model.
This PEP takes the view that bothPEP 598 andPEP 602 share a common flaw: theyare attempting to satisfy the needs of two quite distinct audiences within theconstraints of a single release model, which results in conflicting designrequirements, and the need for awkward trade-offs between those conflictingrequirements. The proposal in this PEP aims to avoid that flaw by proposing thecreation of twodistinct production-ready release streams, with the existingrelease stream being largely left alone, while the new release stream istailored towards the audience that would most benefit from a reduction infeature delivery latency.
The proposal in this PEP arises from making the following key assumptions:
The core of the proposal in this PEP is changing the CPython pre-release processto produce a rolling stream of incremental feature releases at a regularcadence, and to ensure that most of those builds offer a sufficient level ofstability as to be suitable for use in appropriately managed production systems.
By adopting this approach, the proposal aims to provide an improved outcomefor almost all Python users and contributors:
That said, it is acknowledged that not all the outcomes of this proposal will bebeneficial for all members of the wider Python ecosystem:
The majority of the proposed changes in this PEP only affect the handling ofpre-release versions. The one change affecting full release versions is asuggested change to their cadence.
With the rolling pre-freeze releases available to users that are looking touse leading edge versions of the reference interpreter and standard library,this PEP proposes that the frequency of X.Y.0 releases be adjusted to publisha new stable release in August every two years (starting in 2021,around two years after the release of Python 3.8.0).
This change is arguably orthogonal to the proposed changes to the handling ofthe pre-freeze release period, but the connection is that without thosepre-release management changes, the downsides of a two-year full release cadencewould probably outweigh the upsides, whereas the opposite is true for a12-month release cadence (i.e. with the pre-release management changes proposedin this PEP in place, the downsides of a 12-month full release cadence wouldoutweigh the upsides).
Rather than continuing the status quo where the pre-release alpha and betaphases are distinct and sequential, this PEP proposes that they instead becombined into a single “pre-freeze” phase with a monotonically increasing serialnumber on the releases.
Rather than denoting distinct phases, the “alpha” and “beta” names wouldinstead indicate whether or not the release contains breaking changes to thefull CPython C ABI:
Rather than being released monthly for a period of a few months while preparinga new X.Y.0 release, pre-freeze releases would instead be consistently publishedevery two months.
The only time this would not be the case is during the two month releasecandidate period for an upcoming X.Y.0 release (see the release candidatesection below for more details). This means two otherwise scheduled releaseswould be skipped (one corresponding with the first release candidate date, onewith the final release date).
The pre-freeze phase would typically be expected to start 2 months after thepreceding stable X.Y.0 release.
The first pre-freeze release for any new release series will always be X.Y.0a1(as there is no preceding release with the same ABI version markers to judgebinary compatibility against).
Pre-freeze releases would gain an additional flag in their C ABI compatibilitymarkers to avoid binary compatibility issues with the eventual stable release.
This PEP proposes that the policy for beta releases be set as follows:
abi3 stable C ABI wouldbe expected to become a permanent part of that ABI unless and until thatstable ABI version is retired completely (Note: there are no current plansto increment the stable ABI version)This PEP proposes that the policy for alpha releases be set as follows:
Under this PEP, an alpha release would be published whenever it isn’t possibleto publish a release that satisfies the criteria for a beta release, andallowing some additional time before making the release won’t resolve the issue.
It is expected that the full CPython API changing in a way that breaks ABIcompatibility (for example, a field may have been added to or removed from apublic struct definition) will be the most likely reason for publishingadditional alpha releases beyond the initial compatibility tag definingX.Y.0a1 release, but the decision for any particular release rests with therelease manager.
Given the proposed changes to the alpha and beta release phases, the releasecandidate phase would see the following related adjustments:
In addition to allowing more time for end user feedback on the releasecandidate, this adjusted policy also provides additional time for maintainersof Python projects to build and publish pre-built wheel archives for the newstable release series, significantly improving the initial user experience ofthe X.Y.0 release.
The CPython stable ABI[5] makes the commitment that binary extension modulesbuilt against any particular CPython release will continue to work on futureCPython releases that support the same stable ABI version (this version iscurrentlyabi3).
Under the proposed rolling pre-freeze release model, this commitment would beextended to also apply to the beta releases: once an intentional addition to theabi3 stable ABI for the upcoming Python version has been shipped in a betarelease, then it will not be removed from future releases for as long as theabi3 stable ABI remains supported.
Two main mechanisms will be available for obtaining community feedback onadditions to the stable ABI:
As a slight readability and usability improvement, this PEP also proposes theintroduction of aliases for each major stable ABI version:
#define Py_LIMITED_API_3_3 0x03030000#define Py_LIMITED_API_3_4 0x03040000#define Py_LIMITED_API_3_5 0x03050000#define Py_LIMITED_API_3_6 0x03060000#define Py_LIMITED_API_3_7 0x03070000#define Py_LIMITED_API_3_8 0x03080000#define Py_LIMITED_API_3_9 0x03090000//etc...
These would be used both in extension module code to set the target ABIversion:
#define Py_LIMITED_API Py_LIMITED_API_3_8And also in the CPython interpreter implementation to check which symbols shouldbe made available:
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= Py_LIMITED_API_3_9//APython3.9+additiontothestableABIwouldappearhere#endif
The documentation for the rolling pre-freeze releases and the stable C ABI wouldmake it clear that extension modules built against the stable ABI in a laterpre-freeze release may not load correctly on an earlier pre-freeze release.
The documentation for alpha releases and the stable C ABI would make it clearthat even extension modules built against the stable ABI in an alpha releasemay not load correctly on the next release if two alpha releases are publishedin a row (this situation would ideally be rare).
This PEP proposes two changes to the management of the full CPython ABI.
The proposal in this PEP requires that release managers be able to appropriatelymark a pre-freeze release as either an alpha or a beta release based on whetheror not it includes an ABI breaking change.
To assist in that process, core developers would be requested to include a“(CPython ABI break)” marker at the beginning of all NEWS file snippets forchanges that introduce a breaking change in the full CPython C ABI.
The “CPython” marker is included to make it clear that these annotations relateto the full CPython ABI, not the stable ABI.
For commit messages, the shorter marker “(ABI break)” would be placed at thestart of the summary line for the commit.
The pre-merge bots will be updated to ensure that if the ABI break markerappears in one of the two locations, it appears in both of them.
If the marker is inadvertently omitted from the initial commit message and NEWSentry, then the commit message marker should be included in the subsequentcommit that adds the marker to the NEWS entry.
In addition to being useful for release managers, these markers should also beuseful for developers investigating unexpected segfaults when testing againstthe affected release.
The full CPython ABI has long operated under a policy where binarycompatibility only applies within a release series after the ABI has beendeclared frozen, and only source compatibility applies between differentrelease series.
This policy means that extension modules built against CPython pre-releasesprior to the ABI freeze for that release series may not actually load correctlyon the final release.
This is due to the fact that the extension module may be relying on provisionalor previously deprecated interfaces that were changed or removed in a lateralpha or beta release, or it may be due to public structures used by theextension module changing size due to the addition of new fields.
Historically, adoption of alpha and beta releases has been low enough that thishasn’t really been a problem in practice. However, this PEP proposes to activelyencourage widespread operational use of beta releases, which makes it desirableto ensure that users of those releases won’t inadvertently publish binaryextension modules that cause segfaults for users running the release candidatesand final releases.
To that end, this PEP proposes amending the extension moduleSOABI markeron non-Windows systems to include a new “p” flag for CPython pre-releases, andonly switch back to omitting that flag once the ABI for that particular X.Y.0version has been frozen on entry to the release candidate stage.
With this change, alpha and beta releases of 3.9.0 would get an SOABI tag ofcpython-39p, while all release candidates and final builds (for both 3.9.0and later 3.9.x releases) would get an unqualified SOABI tag ofcpython-39
Debug builds would still add the “d” to the end of the tag, givingcpython-39pd for debug builds of pre-releases.
On Windows systems, the suffix for taggedpyd files in pre-release buildswould include “p” as a pre-release marker immediately after the version number,giving markers like “cp39p-win_amd64”.
A proposed reference implementation for this change is available at[4] (Note:at time of writing, that implementation had not yet been tested on Windows).
When a project first opts in to providing pre-built binary wheels for therolling pre-freeze release series, they don’t need to do anything special: theywould add the rolling release series to their build and test matrices andpublish binary archives that are flagged as being compatible with that releaseseries, just as they would if providing pre-built binary wheels after thefull CPython ABI freeze for that release series.
However, if the project is affected by a CPython ABI compatibility break in therolling release stream, then they will need to issue a version update thatincludes both the new binary build, and a new environment constrainedPython-Requires marker.
For example, if a project supporting the rolling release stream was affected bya CPython ABI compatibility break in the 3.9.0a5 release, then they would addthe following metadata entry on the version that published the updated binarybuild:
Python-Requires:>="3.9.0b6";python_version=="3.9"andfull_python_version!="3.9.0a5"
What this does is add an additional compatibility constraint as part of thepublished packages, so Python 3.9.0 beta versions prior to 3.9.0b6 won’tconsider the updated package as a candidate for installation, and the onlyalpha release that will consider the package is 3.9.0a5 itself.
Actual release dates may be scheduled up to a month earlier or later atthe discretion of the release manager, based on release team availability, andthe timing of other events (e.g. PyCon US, or the annual core developersprints). However, as one goal of the proposal is to provide a consistentrelease cadence, adjustments should ideally be rare.
Within a release series, the exact frequency of maintenance releases wouldstill be up to the release manager and the binary release team; this PEPonly proposes an expected cadence for pre-releases and X.Y.0 releases.
However, for the sake of the example timelines, the PEP assumes maintenancereleases every other month, allowing them to alternate months with the rollingpre-freeze releases.
The release manager and Steering Council would also retain the power to amendvarious details of the proposal in this PEP. Possible amendments include (butare not limited to):
The intent of the concrete proposal in the PEP is to provide a clearillustrative example for reviewers to consider, not to constrain our abilityto adjust specific details based on practical experience with the process.
For large parts of Python’s user base,availability of new CPython featurereleases isn’t the limiting factor on their adoption of those new releases(this effect is visible in such metrics as PyPI download metadata).
As such, any proposal based on speeding up full feature releases needs to strikea balance between meeting the needs of users who would be adopting each releaseas it became available, and those that would now be in a position of adoptingevery 2nd, 3rd, or 4th release, rather than being able to migrate to almostevery release at some point within its lifecycle.
This proposal aims to approach the problem from a different angle by defining anew production-ready release stream that is more specifically tailored to theinterests of operating environments that are able to consume new releases asfast as the CPython core team is prepared to produce them.
Using the “a” and “b” initials for the proposed rolling releases is a designconstraint imposed by some of the pragmatic aspects of the way CPython versionnumbers are published.
Specifically, alpha releases, beta releases, and release candidates are reportedin some places using the strings “a”, “b”, and “c” respectively, while in othersthey’re reported using the hex digits0xA,0xB, and0xC. We want topreserve that, while also ensuring that anyPython-Requires constraintsare expressed against the beta releases rather than the alpha releases (sincethe latter may not enforce theabi3 stability requirements if two alphareleases occur in succession).
However, there isn’t anything forcing us to say that the “a” stands for “alpha”or the “b” stands for “beta”.
That means that if we wanted to increase adoption amongst folks that wereonly being put off by the “beta” label, then it may make sense to emphasisethe “*A*BI breaking” and “*B*inary compatible” names over the “alpha”and “beta” names, giving:
This iteration of the PEP doesn’t go that far, as limiting initial adoptionof the rolling pre-freeze releases to folks that are comfortable with the“beta” label is likely to be a good thing, as it is the early adopters of thesereleases that are going to encounter any unexpected consequences that occurat the level of the wider Python ecosystem, and we’re going to need them tobe willing to take an active part in getting those issues resolved.
Moving away from the “beta” naming would then become an option to keep in mindfor the future, assuming the resulting experience is sufficiently positive thatwe decide the approach is worth continuing.
Rather than using the beta period for rolling releases, another option would beto alternate between traditional stable releases (for 3.8.x, 3.10.x, etc), andrelease series that used the new rolling release cadence (for 3.9.x, 3.11.x,etc).
This idea suffers from the same core problem asPEP 598 andPEP 602: it imposeschanges on end users that are happy with the status quo without offering themany clear compensating benefit.
It’s also affected by one of the main concerns raised againstPEP 598: at leastsome core developers and end users strongly prefer that no particular semanticsbe assigned to thevalue of any of the numbers in a release version. Thesecommunity members instead prefer that all the semantic significance beassociated with theposition within the release number that is changing.
By contrast, the rolling pre-freeze release proposal aims to address that concernby ensuring that the proposed changes in policy all revolve around whether aparticular release is an alpha release, beta release, release candidate, orfinal release.
Steve Dower’s initial write-up of this proposal[1] suggested the use ofcalendar versioning for the rolling release stream (so the first rollingpre-release after Python 3.8.0 would have been Python 2019.12 rather than3.9.0b1).
Paul Moore pointed out[2] two major practical problems with that proposal:
Python-Requires metadata processing in packaging tools withno clear way of fixing it reliably (since all calendar versions would appearas newer than any standard version)This PEP aims to address both of those problems by using the established betaversion numbers for the rolling releases.
As an example, consider the following question: “Does Python 2021.12 includeall the new features released in Python 3.9.0?”. With calendar versioning onthe rolling releases, that’s impossible to answer without consulting a releasecalendar to see when 3.9.0rc1 was branched off from the rolling release series.
By contrast, the equivalent question for rolling pre-freeze releases isstraightforward to answer: “Does Python 3.10.0b2 include all the new featuresreleased in Python 3.9.0?”. Just from formulating the question, the answer isclearly “Yes, unless they were provisional features that got removed”.
The beta numbering approach also avoids other questions raised by the calendarversioning concept, such as howsys.version_info,PY_VERSION_HEX,site-packages directory naming, and installed Python binary and extensionmodule naming would work.
When adding new features, core developers would be strongly encouraged tosupport feature detection and graceful fallback to alternative approaches viamechanisms that don’t rely on eithersys.version_info or runtime code objectintrospection.
In most cases, a simplehasattr check on the affected module will serve thispurpose, but when it doesn’t, alternative approaches would be considered as partof the feature addition. Prior art in this area includes thepickle.HIGHEST_PROTOCOL attribute, thehashlib.algorithms_available set,and the variousos.supports_* sets that theos module already offers forplatform dependent capability detection.
It would also be possible to add features that need to be explicitly enabledvia a__future__ import when first included in the rolling pre-freeze releases,even if that feature flag was subsequently enabled by default before its firstappearance in an X.Y.0 release candidate.
The rationale behind these approaches is that explicit detection/enabling likethis would make it straightforward for users of the rolling pre-freeze releasestream to notice when we remove or change provisional features(e.g.from__future__ imports break on compile if the feature flag nolonger exists), or to safely fall back on previous functionality.
The interpreter’s rich attribute lookup machinery means we can also choose toadd warnings for provisional or deprecated imports and attributes that we don’thave any practical way to add for checks against the value ofsys.version_info.
The core development team currently activelydiscourage the creation ofpublic pre-built binaries for an X.Y series prior to the ABI freeze date.
The reason we do that is to avoid the risk of painful debugging sessionson the stable X.Y.0 release that get traced back to “Oh, our dependency‘superfast-binary-operation’ was affected by a CPython ABI break inX.Y.0a3, but the project hasn’t published a new build since then”.
With the proposed pre-freeze ABI flag in place, this aspect of therelease adoption process continues on essentially unchanged from thestatus quo: a new CPython X.Y release series hits ABI freeze -> packagemaintainers publish new binary extension modules for that releaseseries -> end users only get segfaults due to actual bugs, not justbuilds against an incompatible ABI.
The primary goal of the new pre-freeze ABI flag is then to improvethe user experience of the rolling pre-freeze releases themselves, byallowing pre-built binary archives to be published for those releaseswithout risking the problems that currently cause us to activelydiscourage the publication of binary artifacts prior to ABI freeze.
In the ideal case, package maintainers will only need to publishone pre-freeze binary build at X.Y.0a1, and then a post-freezebuild after X.Y.0rc1. The only situations that shouldrequirea rebuild in the meantime are those where the project wasactually affected by a CPython ABI break in an intervening alpharelease.
As a concrete example, consider the scenario where we end up having threereleases that include ABI breaks: X.Y.0a1, X.Y.0a5, X.Y.0a7. The X.Y.0a7 ABI isthen the ABI that carries through all the subsequent beta releases and intoX.Y.0rc1. (This is the scenario illustrated in figure 1)
Forcing everyone to rebuild the world every time there’s an alpha release inthe rolling release stream would almost certainly lead to publishers decidingsupporting the rolling releases was more trouble than it was worth, so we wantto allow modules built against X.Y.0a1 to be loaded against X.Y.0a7, as they’reprobably going to be compatible (there are very few projects that use everyC API that CPython publishes, and most ABI breaks affect a single specific API).
Once we publish X.Y.0rc1 though, we want to ensure that any binaries that werebuilt against X.Y.0a1 and X.Y.0a4 are completely removed from the end userexperience. It would be nice to be able to keep the builds against X.Y.0a7 andany subsequent beta releases (since it turned out those actually were builtagainst the post-freeze ABI, even if we didn’t know that at the time), butlosing them isn’t anyworse than the status quo.
This means that the pre-freeze flag is “the simplest thing that could possiblywork” to solve this problem - it’s just a new ABI flag, and we already havethe tools available to deal with ABI flags (both in the interpreter and inpackage publication and installation tools).
Since the ABI flags have changed relative to the pre-releases, projects don’teven need to publish a new release: they can upload new wheel archives to theirexisting releases, just as they can today.
A cleverer scheme that was able to retroactively accept everything builtagainst the last alpha or subsequent beta releases would likely be possible,but it isn’t considerednecessary for adoption of this PEP, as even if weinitially start out with a simple pre-release ABI flag, it would still bepossible to devise a more sophisticated approach in the future.
In an ideal world, all breaking changes to the full CPython ABI would land inX.Y.0a1 alongside the filesystem layout changes, and the ABI for the releaseseries would remain stable after that.
However, recent history doesn’t suggest that we’d be able to actually make thatcommitment and stick to it, so the PEP assumes that ABI changes will be madeprogressively throughout the pre-freeze period, and the full lockdown will occuronly with the creation of the X.Y.z maintenance branch when preparing X.Y.0rc1.
The major change for CPython core development is the need to keep the masterbranch more consistently release ready.
While the main requirement for that would be to keep the stable BuildBot fleetgreen, there would also be encouragement to keep the development version ofthe documentation up to date for the benefit of users of the rolling pre-freezereleases. This will include providing draft What’s New entries for changes asthey are implemented, although the initial versions may be relatively sparse,and then expanded based on feedback from beta release users.
For core developers working on the CPython C API, there would also be a newrequirement to consistently mark ABI breaking changes in their NEWS filesnippets.
On the specific topic of the stable ABI, most API designs will be able to gothrough a process where they’re first introduced as a provisional part of thefull CPython API (allowing changes between pre-freeze releases), and onlypromoted to the stable ABI once developers are confident that the interfaceis genuinely stable.
It’s only in rare cases where an API serves no useful purpose outside thestable ABI that it may make sense to publish an alpha release containing aprovisional stable ABI addition rather than iterating on the design in theprovisional CPython API instead.
If this PEP is successful in its aims, then supporting the rolling pre-freezerelease stream shouldn’t be subtantially more painful for library authors thansupporting the stable releases.
For publishers of pure Python packages, this would be a matter of publishing“py3” tagged wheel archives, and potentially adding the rolling pre-freezerelease stream to their test matrix if that option is available to them.
For publishers of binary extension modules, the preferred option would be totarget the stable C ABI (if feasible), and thus enjoy an experience similar tothat of pure Python packages, where a single pre-built wheel archive is able tocover multiple versions of Python, including the rolling pre-freeze releasestream.
This option isn’t going to be viable for all libraries, and the desired outcomefor those authors is that they be able to support the rolling releases bybuilding and publishing one additional wheel archive, built against the initialX.Y.0a1 release. The subsequent build against X.Y.0rc1 or later is then the samebuild that would have been needed if only supporting the final stable release.
Additional wheel builds beyond those two should then only be needed if thatparticular library is directly affected by an ABI break in any other alpharelease that occurs between those two points.
Having a rolling pre-freeze release stream available may also make it more feasiblefor more CI providers to offer a “CPython beta release” testing option. At themoment, this feature is only available from CI providers that are willing andable to put the necessary time and effort into creating, testing, and publishingtheir own builds from the CPython master branch (e.g.[6]).
Based on discussions at SciPy 2019, NEP (NumPy Enhancement Proposal) 29 hasbeen drafted[3] to propose a common convention across the Scientific Pythonecosystem for dropping support for older Python versions.
While the exact formulation of that policy is still being discussed, the draftproposal (as of October 20, 2019) recommends that projects support any Pythonfeature release published within the last 42 months, with a minimum ofsupporting the latest 2 Python feature releases.
For an 18-month feature release cadence, that works out to always supporting atleast the two most recent feature releases, and then dropping support for allX.Y.Z releases around 6 months after X.(Y+2).0 is released. This means there isa 6-month period roughly every other year where the three most recent featurereleases are supported.
For a 12-month release cadence, it would work out to always supporting atleast the three most recent feature releases, and then dropping support for allX.Y.Z releases around 6 months after X.(Y+3).0 is released. This means thatfor half of each year, the four most recent feature releases would be supported,with the other half of each year hopefully being used to get ready for thatyear’s feature release.
For a 24-month release cadence, the second clause takes priority over the first,and the recommended Python version support period increases to 48 months fromthe initial X.Y.0 release in order to consistently support the two most recentCPython feature releases. For projects that also support the rolling releasestream, the number of supported feature releases would increase to three.
With the proposal in this PEP, it is expected that the focus of coredevelopment sprints would shift slightly based on the current locationin the two-year cycle.
In release years, the timing of PyCon US is suitable for new contributors towork on bug fixes and smaller features before the first release candidate goesout, while the Language Summit and core developer discussions can focus onplans for the next release series.
The pre-alpha core development sprint in release years will provide anopportunity to incorporate feedback received on the previous release, eitheras part of the next maintenance release (for bug fixes and feedback onprovisional APIs), or as part of the first alpha release of the next releaseseries (for feedback received on stable APIs).
Those initial alpha releases would also be the preferred target for ABI breakingchanges to the full CPython ABI (while changes later in the release cyclewould still be permitted as described in this PEP, landing them in the X.Y.0a1release means that they won’t trigger any additional work for publishers ofpre-built binary packages).
The Steering Council elections for the next release cycle are also likely tooccur around the same time as the pre-alpha development sprints.
In non-release years, the focus for both events would just be on the upcomingmaintenance and pre-freeze releases. These less intense years would hopefullyprovide an opportunity to tackle various process changes and infrastructureupgrades without impacting the release candidate preparation process.
Some rolling release Linux distributions (e.g. Arch, Gentoo) may be in aposition to consume the new rolling pre-freeze releases proposed in this PEP,but it is expected that most distributions would continue to use the establishedreleases.
The specific dates for final releases proposed in this PEP are chosen to alignwith the feature freeze schedules for the annual October releases of the Ubuntuand Fedora Linux distributions.
For both Fedora and Ubuntu, it means that the release candidate phase alignswith the development period for a distro release, which is the ideal time forthem to test a new version and provide feedback on potential regressions andcompatibility concerns.
For Ubuntu, this also means that their April LTS releases will have benefitedfrom a full short-term release cycle using the new system Python version, whilestill having that CPython release be open to upstream bug fixes for most of thetime until the next Ubuntu LTS release.
The one Linux release cycle alignment that is likely to be consistently poorwith the specific proposal in this PEP is with Debian, as that has been releasedin the first half of odd-numbered years since 2005 (roughly 12 months offsetfrom Ubuntu LTS releases).
With the annual release proposal inPEP 602, both Debian and Ubuntu LTS wouldconsistently get a system Python version that is around 6 months old, butwould also consistently select different Python versions from each other.
With a two-year cadence, and CPython releases in the latter half of the year,they’re likely to select the same version as each other, but one of them willbe choosing a CPython release that is more than 18 months behind the latest betareleases by the time the Linux distribution ships.
If that situation does occur, and is deemed undesirable (but not sufficientlyundesirable forDebian to choose to adjust their release timing), then that’swhere the additional complexity of the “incremental feature release” proposalinPEP 598 may prove worthwhile.
(Moving CPython releases to the same half of the year as the Debian and UbuntuLTS releases would potentially help mitigate the problem, but also createsnew problems where a slip in the CPython release schedule could directly affectthe release schedule for a Linux distribution, or else result in a distributionshipping a Python version that ismore than 18 months old)
For the purposes of this PEP, a “simple” deployment environment is any use casewhere it is straightforward to ensure that all target environments are updatedto a new Python release at the same time (or at least in advance of the rolloutof new higher level application versions), and any pre-release testing thatoccurs need only target a single Python micro version.
The simplest such case would be scripting for personal use, where the testingand target environments are the exact same environment.
Similarly simple environments would be containerised web services, where thesame Python container is used in the CI pipeline as is used on deployment, andany application that bundles its own Python runtime, rather than relying on apre-existing Python deployment on the target system.
For these use cases, there is a straightforward mechanism to minimise theimpact of this PEP: continue using the stable releases, and ignore the rollingpre-freeze releases.
To actually adopt the rolling pre-freeze releases in these environments, themain challenge will be handling the potential for extension module segfaultswhen the next pre-freeze release is an alpha release rather than a betarelease, indicating that the CPython ABI may have changed in an incompatibleway.
If all extension modules in use target the stable ABI, then there’s no problem,and everything will work just as smoothly as it does on the stable releases.
Alternatively, “rebuild and recache all extension modules” could become astandard activity undertaken as part of updating to an alpha release.
Finally, it would also be reasonable to just not worry about it until somethingactually breaks, and then handle it like any other library compatibility issuefound in a new alpha or beta release.
Aside from extension module ABI compatibility, the other main point of additionalcomplexity when using the rolling pre-freeze releases would be “roll-back”compatibility for independently versioned features, such as pickle and SQLite,where use of new or provisional features in the beta stream may create filesthat are not readable by the stable release. Applications that use thesekinds of features and also require the ability to reliably roll-back to aprevious stable CPython release would, as today, be advised to avoid adoptingpre-release versions.
For the purposes of this PEP, “complex” deployment environments are use caseswhich don’t meet the “simple deployment” criteria above. They may involvemultiple distinct versions of Python, use of a personalised build of Python,or “gatekeepers” who are required to approve use of a new version prior todeployment.
For example, organisations that install Python on their users’ machines as partof a standard operating environment fall into this category, as do those thatprovide a standard build environment. Distributions such as conda-forge orWinPython that provide collections of consistently built and verified packagesare impacted in similar ways.
These organisations tend to either prefer high stability (for example, all ofthose who are happily using the system Python in a stable Linux distributionlike Debian, RHEL/CentOS, or Ubuntu LTS as their preferred Python environment)or fast turnaround (for example, those who regularly contribute toward thelatest CPython pre-releases).
In some cases, both usage models may exist within the same organisation fordifferent purposes, such as:
Under any release model, each new release of Python generates work for theseorganisations. This work may involve legal, security or technical reviews ofPython itself, assessment and verification of impactful changes, reapplicationof patches, recompilation and testing of third-party dependencies, andonly then deployment.
Organisations that can take updates quickly should be able to make use of themore frequent beta releases. While each update will still require similarinvestigative work to what they require today, the volume of work required perrelease should be reduced as each release will be more similar to the previousthan it is under the present model. One advantage of the proposedrelease-every-2-months model is that organisations can choose their own adoptioncadence from adopting every beta release, to adopting one per quarter, or oneevery 6 months, or one every year. Beyond that, it would likely make more senseto continue using the stable releases instead.
For organisations with stricter evaluations or a preference for stability, thelonger release cycle for stable releases will reduce the annual effort requiredto update, the longer release candidate period will allow more time to dointernal testing before the X.Y.0 release, and the greater use by othersduring the beta period will provide more confidence in the initial releases.Meanwhile, the organisation can confidently upgrade through maintenancereleases for a longer time without fear of breaking changes.
Thanks to Łukasz Langa for creatingPEP 602 and prompting this discussion ofpossible improvements to the CPython release cadence, and to Kyle Stanleyand h-vetinari for constructive feedback on the initial draft of this PEP.
This document is placed in the public domain or under the CC0-1.0-Universallicense, whichever is more permissive.
Source:https://github.com/python/peps/blob/main/peps/pep-0605.rst
Last modified:2025-02-01 08:59:27 GMT