Installation of the python.org Python distribution on Windows is complex.There are three main approaches with roughly equivalent levels of userexperience, and yet all of these suffer from different limitations, includingfailing to satisfy modern usage scenarios. This PEP proposes a design fora single Windows install workflow tool that satisfies all the needs of theexisting installers for the platform, while avoiding most of their limitations,and provides the core team with the ability to manage releases for many yearsto come.
With the new installer, the recommended command to launch the default Python onWindows will bepython, while the command for managing multiple versions(including launching a specific one) will bepy. Users can also opt-in tohaving globalpython3.x commands by adding an extra entry to theirPATHenvironment variable. We recommend starting with the “How to teach this” sectionfor the most concise high-level overview of the features.
The existing.exe installer andpy launcher will be deprecated and nolonger released from two years after this PEP is accepted. The existingembeddable distro will no longer be listed as a download, but will be availablethrough the install manager. The Windows Store app will be immediately replacedwith the install manager.
This document is a detailedproposal, intended to assist in an “approve” or“reject” decision on the replacement of the existing install formats for Pythonon Windows with a new format. It is not intended to be a binding specification,nor is it user documentation or an interoperability specification. The actualimplementation may vary over time as needs change, and that is not to beconsidered a “violation” of this PEP. Any interfaces and protocols meant forpublic use will be independently documented and maintained in accordance withstandard deprecation timelines.
Documentation on installing Python on Windows can be found atdocs.python.org/using/windows.html.
There are a large range of needs users may have that lead to them wantingto install a Python runtime. Many, likely most, are interested in running(perhaps writing) short scripts, such as those that perform a simple task,or help teach someone a concept. Some users are looking for a specific versionto integrate with existing code or another application. Some are after a fullset of different interpreter versions to perform testing.
In this section, we discuss the expectations that users have of “installingPython”, provide an overview of the existing installers for Windows, andidentify some of the gaps and challenges inherent in these offerings.
Based on significant anecdotal experience and analysis of quantitative dataavailable (though not necessarily public), we make the following assertionsabout the majority of Python users on Windows:
python command to work after installationThe primary support for these assertions is that the most popular installersactively chosen by users are the latest stable release on python.org, andthe latest stable release on the Windows Store, both of which meet theserequirements.
We make the following assumptions about other significant sets of users.These may have some overlap between groups, and at least some users expectall of them.
py command to work after installationThese assumptions have all been demonstrated over time to exist, though therelative importance has not been quantified. TheNuGet packages and theembeddable distro can meet most of these needs.
The traditional installer is an executable downloadable directly frompython.org that installs the entire development kit for Python. This includesthe CPython interpreter, the standard library, Python headers and importlibraries, builds of Tcl and Tk, the documentation as HTML files, the runtimeand standard library test suite, Start Menu shortcuts for Python and IDLE,debugging symbols and debug builds of the binaries, thepy.exe launcherand its file associations, and functionality to modify the user’sPATHenvironment variable, enable long-path support on their system, pre-generate.pyc files for the standard library, and install pip.As of 3.13, it also includes a set of experimental free-threaded binaries.Many of these components are optional.
After downloading the executable, users are presented with a “quick install”option, which installs into their user directory with most options enabled.We believe that most users select this option.
A second option alongside the quick install takes the user to two pages worthof options, listing the components that they need not install, as well as otheroptions such as the install directory and whether to install for all users.
All of these options may be specified on the command line, and there is also anoption to proceed with the install without displaying any UI.Based on feedback and bug reports, all of these options are used by at leastsome users. However, as we do not track install telemetry, we have no way toknow which options are more important than others.
Behind the scenes, the traditional installer is a Burn bundle, generated usingthe Wix Toolset installer framework, containing one or more MSI files for eachfeature. This framework is used extensively by Microsoft themselves, andprovides the most direct method of using Windows Installer. The bundle is acustom C++ application, based on their template, which allows us to customisethe overall behaviour of the installer to determine precisely which MSI filesshould actually be installed. The process of copying files, updating theregistry, and generating shortcuts is handled entirely by Windows Installer.
As well as the intended uses, it is understood that many users will (attempt to)use the traditional installer for other scenarios, such as unregistered installsand automated CI system installs. While better alternatives are available, theyare not as obvious, and the hope is that a future design would make thesescenarios easier.
The Windows Store packages for CPython are produced as part of our normalrelease process using almost all identical binaries to the other packages.Due to being in an app store package, the primarypython.exe is enhancedto be able to determine its location properly, and alternativepip.exe andother shortcuts are included to make up for the lack ofPATH environmentvariable settings. These are implemented inPC\python_uwp.cpp in our repo.
These packages are installed by searching for Python in the Microsoft Storeapp, which will find results for each major version since 3.8. Users then haveto select a version and install it. These packages include the CPythoninterpreter, standard library, Tcl/Tk, IDLE, and pip, and create fileassociations, Start Menu shortcuts, and global commands forpython.exe,python3.exe,python3.X.exe,pip[3[.X]].exe andidle[3[.X]].exe.NoPATH modification is possible or required, though users may need tomanage their global shortcuts through the “Manage App Execution Alias” settingspage.
In addition, Microsoft has added to a clean Windows install a defaultpython.exe command. This captures attempts by users to launch Python ona machine that has not yet installed it. When launched directly, the commandwill open the Microsoft Store app to the page containing the recommendedPython app, typically the latest version. This app is entirely controlled byMicrosoft. Based on telemetry associated with the Python app (whichiscontrolled by the upstream Python project), approximately 300,000 installsper month come through this redirector, making up about 90% of the totalinstalls of that version.
Behind the scenes, the Store package is based on Microsoft’s new installertechnology for apps known as APPX or MSIX. These are essentially plain ZIPfiles with a small amount of metadata, except that installation is handledby the operating system. They are always extracted to a fixed location,accessible to all users but not modifiable by any, and automatically updatedto the latest release. The user’s own data is stored in an OS-managed locationin their user profile, and is able to be reset, backed-up and restored usingregular OS functionality.
The NuGet packages for CPython are produced and published as part of ournormal release process. The contents are identical to the traditionalinstaller. A NuGet package is published to nuget.org, which is a packagemanager typically associated with .NET languages, but highly integrated withany project supported by Visual Studio. This makes it a nice format for userswho want a lightweight install of Python as part of their regular build process,and can simplify embedding scenarios.
The packages are installed using any tool capable of using the NuGet API, ormay be downloaded directly once the URL of the package is known. The package isa plain ZIP file with some metadata. It contains the CPython interpreter, thestandard library, development headers and import libraries, and pip. It doesnot execute any code at install time, and users must locate the packagethemselves in order to launch thepython.exe contained within.
The embeddable package for CPython is produced and published as part of ournormal release process. It is published to python.org alongside thetraditional installer. The contents are identical, however, the layout ischanged to store all binaries at the top level, with the standard librarypacked into a ZIP file. A._pth file is included to overridesys.pathso that only the files that are part of the distro are used, and environmentvariables or registry entries are ignored.
This package does not include pip, as the intention is for it to be embeddedinto a broader application. Other libraries should be installed at build time,since after distribution the runtime is meant to be an internal implementationdetail of the app it is a part of.
As well as its intended use, some users attempt to use this package as adevelopment kit rather than a runtime package. This is believed to be due tothose users preferring to avoid “heavyweight” installers, and believing thatthis package is intended to be a “portable” install (extract and run), likelybecause it is the only ZIP file option listed on the python.org download pages(speaking to the importance of clarity and limiting options on those pages).It is hoped that a future installer design will avoid or limit this confusion.
While outside of our purview as the core team, alternate distributions of Pythonfor Windows often use a project, workflow or environment-centric model forinstallation of the runtime. By this, we mean that the tool is installed first,and is used to create a working space that includes a runtime, as well as otherdependencies. Examples of these tools include conda and uv.
Two observations are worth making about these tools. Firstly, they are oftenpraised for being low impact, in that they usually don’t install additionalentry points or files for the runtime, making the install fast and also isolatedto a single project. Secondly, their users often appreciate the ease ofselecting a particular version of a runtime, or alternatively, not having toselect at all because existing specifications (or constraints) can choose forthem.
These tools tend to meet many of the second set of expectations described above,usually combining multiple tasks in a single command to reduce the cognitiveoverhead of learning how to use and combine multiple commands.
It’s also worth pointing out that the core team does not view these alternatedistributions as competitors to any upstream distribution. They are afundamental part of how the open source ecosystem is intended to work. Our owndistributions are a convenience for those who choose to use them, as not allscenarios are well served by a workflow tool or even a pre-built package.
There are numerous challenges we face with the current set of installers,which largely break down into two categories: mismatched or unachievableuser expectations, and general unreliability.
The traditional installer has the highest level of unreliability. The WindowsInstaller technology is very old, and effectively no longer under development.While its basic functionality is okay, interference may come from many sources,such as virus scanners, other installers, system configuration, admin policies,and even other files in the same directory as the installer. On top of this,most of its advanced and beneficial functionality such as update patches,incremental updates, and automatic rollback are unimportant for Python users.
Most user expectations aredefined by the traditional installer, and so bydefinition, it meets them. One primary gap is that it is not able to create an“unmanaged” install - that is, the equivalent of only copying files onto theuser’s system without registration. If you have installed it once, and youtry to install it again, you will only even be able to manage (or upgrade) theexisting install. This can lead to installs moving on update, which willbreak users.
Additionally, thePATH environment variable cannot be intelligentlymodified - at best, we can prepend or append the install path. This usuallyresults in the most recent install of Python being the highest priority. Forexample, if the user has Python 3.14 installed and then installs (or updates)3.13, thepython command will switch from the later version to the earlierversion.
Thepy.exe launcher, defined inPEP 397 and implicitly updated byPEP 514,is an attempt to avoid this particular issue. It uses its own logic for findinginstalled versions without relying onPATH. However, the PEP 514 logic doesnot allow for prerelease or experimental builds to be treated specially, and sopy.exe often prefers these builds by default over the non-experimentalversion expected by the user.
The Windows Store package is very reliable, with the exception of the globalshortcuts. Rather than modifyingPATH to add its own directory, theseshortcuts are created in a single OS managed directory that has all theshortcuts defined by any app. Users are able to modify theirPATH to excludeor de-prioritise this directory, leading to unreliable or inconsistentbehaviour, and historically we have also seen this caused by installers.For example, installing Python from the Store followed by Python from thetraditional installer with itsPATH modification enabled will almost alwaysshadow the Store package’s Python with the later install.
User expectations that are un-met by the Store package tend to be performanceand technical. Due to the overhead of launching an app, Python starts up slower.Because apps are designed to be isolated from each other, it is more difficultto use hidden directories (such asAppData orTEMP) to communicatebetween different versions of Python, as each version has its own space. Appsare subject to stricter security requirements that legacy applications usuallyhave disabled, such as DLL hijacking protection, which causes some libraries to fail.Thepython3 andpython shortcuts are managed through system settings,and the user interface is not very good (and not going to be improved, accordingto Microsoft). Without managing these, it is relatively easy for an undesiredversion to be launched, though in general the targets can only be changedmanually by the user, and not by merely installing another app.
Both the NuGet package and the embeddable distro are as simple and reliable toinstall as extracting an archive file, though it’s worth noting that for manyPython users this is not a common task. They provide no install management atall, and cannot be reliably updated other than by deleting and re-extracting.User expectations that are un-met are almost always due to users selecting thewrong installer. Both these packages are for specialised cases, and while theyare documented as such, the attraction of a plain ZIP file leads some users intofailure.
PyManager is the internal name of our proposed replacement installer tool. Itwill be distributed both in the Windows Store and on python.org as an MSIXpackage. Downloading from either source will get an identical package, andboth will support automatic updates (through the Store) for new releases.
The user visible name will be “Python Install Manager”, published by thePython Software Foundation. After publishing, we will request that Microsoftadjust theirpython.exe stub to open to this new app.
This app does not directly provide a version of Python, but it does provide theglobal commands that users expect to work, as well as file associations andStart menu shortcuts. The OS will prompt users to launch the app after install,which will trigger an automatic install of the current release of CPython andthen launch it. From the user’s perspective, they have the same initialexperience as today, with one added progress bar on first launch.
The global commands provided by the app must be static and bundled into the appitself. They can only change their behaviour at runtime, and cannot beredirected to different executables except by the user (and then only to anotherinstalled app). So the commands to be provided by PyManager arepython.exe,python3.exe,py.exe,pymanager.exe. Each of these must have theability to inspect the user’s system and choose the correct runtime to launch.Additionally,py andpymanager will have management subcommands to allowadding and removing runtimes.
In line withPEP 394 and the default behaviour of Windows, the recommendedcommand for launching Python ispython.exe. As provided by PyManager, thiswill locate an existing install, either among those that PyManager manages orusingPEP 514, or it will install the latest available version of CPython andselect that. Thepython3.exe command behaves similarly, but is only allowedto find 3.x installs from python.org.
Thepy.exe command provided by PyManager will be recommended for mostmanagement use, due to its brevity.pyinstall...,pylist... and soon. The proposed commands are detailed later. The existing behaviour of thePEP 397 launcher is preserved, however, launching throughpy will notautomatically install runtimes (by default). If one is requested but is notinstalled, users will just get an error. Thepyexec... subcommand,however, will install automatically, and supports the same options as barepy.
These commands are added at very low priority in the user’sPATH by the OS.Every existing configuration we may have created on a user’s machine will takeprecedence over these commands, and so these are a last resort in place of anerror message. As a result, we can generally assume that a user is launchingthese commands because they haven’t configured a stronger preference (forexample, a user who has activated an environment will never launch ourpython.exe, because activation will put a different one ahead of it, and auser who wants precisely the behaviour of the existingpy.exe can justinstall it and will never launch our new one).
Thepymanager.exe command is to allow for handling ambiguous situations.Existing installs of Python and the launcher may shadowpython.exe andpy.exe, but in an automated environment, this can make administrativescripts unreliable, and so thepymanager command is unlikely to refer tosomething other than PyManager. It has all the subcommands, and launching itwith no command specified will print help for the user.
Our intent is to immediately stop publishing individual versions to the WindowsStore, and to deprecate and phase out the traditional installer by Python 3.16.The embeddable distro will remain, but its listing on python.org download pageswill be phased out and it will be available only through PyManager. No changeswill be made to the NuGet packages.
PyManager will be made available as an app package downloadable manually frompython.org, and the double-click install experience is generally smooth. Thisprovides an equivalent to the current approach of downloading from our site.It will bundle a recent (unspecified) version of CPython so that the downloadcan be moved to a non-internet connected machine and still provide a Pythonruntime after install.
Some automated deployment scenarios do not work with the newer MSIX format, andso a simple MSI will also be provided on python.org. This will have no optionsor user interface, and require administrative privileges, which are typicallyavailable for these kinds of scenarios. Additionally, the MSI will be requiredby users on non-standard systems, such as Wine, that do not support the MSIXformat. While not officially supported, the MSI will enable these platforms tocontinue using upstream distributions of CPython. The MSI would be discouragedfor most other users, and the MSIX is considered the default.
It’s worth noting that there is no way to make the MSI install fully compatiblewith the MSIX, and users with both will likely encounter confusion or problems.It is anticipated that only users without Store app support will use the MSI.
Our release processes will start publishing plain ZIP packages to python.org.These will be available from the FTP pages, but will not be listed directly onregular download pages.
Third-party tools that currently distribute their own builds of CPython will bewelcome to use ours, though will be expected to be the initial point of contactfor their users requiring support.
PyManager will be developed and maintained in its own repository adjacent tothe CPython repository, and under the same terms. The CPython CLA will apply,and all (and only) core developers will have commit rights.
PyManager releases are independent from CPython releases. There is no need forversions to match, or releases to be simultaneous. Unless otherwise arranged,the PyManager release manager is whoever is the build manager for Windows.
Note
In this document, all command line options will be shown with one or twohyphens. In implementation, all options will support one or two hyphens or aforward slash, to be permissive of both Windows and UNIX conventions.
py [-V:<TAG>] [interpreter opts] [script.py|-m module|-c code] [script args]py [-3.*] [interpreter opts] [script.py|-m module|-c code] [script args]python ...python3 ...pymanager exec -V:tag ...pymanager exec -3.* ...
This subcommand is used to select and launch a runtime. It is the default actionfor thepy command, and the only action supported by thepython andpython3 commands. The default options are subtly different in each case forconsistency with existing use of these commands.
This subcommand is available on bothpy andpymanager. However, sincepy offers it by default, we would not expect users to use it there. Theintent is that thepy,python andpython3 commands are the defaultways to launch a runtime, andpymanagerexec is for advanced scenarios.
The-V:tag command is used to request a specific runtime from the commandline. The tag is aCompany\\Tag pair, or justTag if no slash isincluded, and is used as defined by PEP 514. The-3.* option is interpretedas-V:PythonCore\\3.*. This option is only available forpy andpyexec variants.
If no tag is specified on the command line, and a script file is specified,the script will be inspected for a shebang. If one is found that matches arecognised pattern, it will either provide the tag to be used for search, or itwill override all other processing and its specified executable will be launchedwithout further effort being made. This is to handle the (unfortunate) legacysupport of arbitrary Windows-specific paths being allowed in what was meant tobe a portability feature. In general, shebangs including simple patterns like/usr/bin/python3.13 are intended, while those that use/usr/bin/envpython are unlikely to be of benefit since the environment tends to be lessreliable than our search.
If no tag is yet requested, theVIRTUAL_ENV environment variable will beconsulted to see if an environment has been activated. If so, that will becomethe request.
If a tag has been requested at this stage, thepython3 command will verifythat it matchesPythonCore\\3.* and exit with an error if not. This allowsallows thepython3 command to be used in an active environment consistentwith other platforms, but not if the environment would not have included thecommand. This applies to most existing versions of Python on Windows. (Thealternative to this behaviour is to makepython3 always error when anenvironment is active, as anything else would behave inconsistently for theuser.)
If no tag is requested, the default will be consulted. Forpython3, this isPythonCore\\3, but for all other commands it is read from configuration(which might involve an environment variable). If it’s still empty, any tag willbe allowed.
The best installed runtime matching the tag is then selected and launched withthe remaining command line.
If no matching runtime is found, thepyexec andpymanagerexec commandswill automatically install and launch one (user configuration permitting). Thepy,python andpython3 commands will report and error and exit.However, in the case where no runtimes are available at all, including nonedetected from other installers, the first runtime will be automaticallyinstalled. This provides a useful first-launch experience, where a new user whohas just installed PyManager will directly launch the latest (or requested)version of CPython. After this first time, errors will again be reported when arequested runtime is not found.
py install [-s|--source <URL>] [-f|--force] [-u|--upgrade] tag [...]py install [-s|--source <URL>] [-t|--target <DIR>] tagpy install [-s|--source <URL>] [-d|--download <DIR>] tag [...]py install --refresh
Note
This and all later subcommands are also available underpymanager.However, as we intend forpy to be the usual command, we only show thatone.
This subcommand will install one or more runtimes onto the current machine.The tags areCompany\\Tag pairs (or justTag if no slash is included),and are used to search the index file. Company names match as case-insensitiveprefixes, preferring a full match over a prefix, and tags use case-insensitive,number-aware matches, with dotted numbers treated as versions. Tags must matchone of the listed “install for” tags, and entries list multiple such tags tohandle abbreviated requests. The special tagdefault resolves to the user’sconfigured default (typically3; see Configuration later for details onconfiguring settings).
Tags may also be specified as a constraint, using>,>=,<,<=or!= followed by theCompany\\Tag orTag value. When matching aconstraint only the primary tag metadata is used for comparisons. Since thecomparisons are version-aware, constraints such as>3.10 will select3.11 as a minimum, while>3.10.0 may select 3.10.1.
The behaviour of constraints against arbitrary tags is likely to be unintuitivein some circumstances. It is anticipated that constraints will mainly be usedwith upstream releases, which typically use version-shaped tags, and primarilyfor cases where other metadata such asRequires-Python are being handled.Users are expected to use shorter tags for convenience, rather than ranges.
The default index file is hosted on python.org, and contains install informationincluding package URLs and hashes for all installable versions. An alternateindex may be specified by the user using a configuration file or the--source command line option, or their administrator through a configurationfile. The requested tag is matched against the index file, and if an exact matchis found the package will be selected. In the case of no exact match, a prefixmatch will be used. In both cases, numbers in the tag are treated logically -that is,3.1 is a prefix of3.1.2 but not of3.10. See Index Schemabelow for information on exactly how install tags are specified in the indexfile.
If a tag is already satisfied by an existing install, nothing will be installed.The user must pass an--upgrade or--force option to replace theexisting install; the former will only replace it with a newer version, whilethe latter will remove and replace even with the same version.
Calling the command without providing any tags will not install anything, butwill display the help text and an error (as for any invalid option). However,passing--upgrade with no tags will attempt to upgrade all installs.
Passing--refresh will regenerate all metadata and shortcuts for allinstalls. This is intentionally applied to all installs at once, as shortcutprioritisation relies on all installs being consistent (for example, the latest3.x version should get thepython3.exe shortcut, which gets complicated ifusers can choose to only refresh an older install).
If a--target<DIR> option is passed with only a single tag, that runtimewill be extracted to the specified directory without being registered as aninstall (or generating aliases or shortcuts). This is intended to coverembedding cases, or downloading the files for incompatible platforms. Passingmultiple tags with--target is an error.
If the--download<DIR> option is passed, runtime packages are downloadedbut not installed. They are stored in the specified directory as their sourcepackages, and anindex.json is created that references these files. Thisindex can be used later to perform offline installs withpythoninstall--source<index.json>[tag...].
py uninstall [-y|--yes] [--purge] [tag ...]
This subcommand will uninstall one or more runtimes on the current machine. Tagsare exactly as for the install command, including prefix matching, but onlyinspect existing installs. Unless the--yes option is passed, the user willbe prompted before uninstalling each runtime.
If the--purge option is passed with no tags, then (after confirmation) allruntimes will be removed, along with shortcuts and any cached files. Passing anytags with--purge will produce an error.
Uninstalling PyManager does not uninstall any runtimes that were installed. Fortechnical reasons, this would not be reliably possible (we cannot run arbitrarycode at uninstall time), and so instead we deliberately ensure that anythingthat has been installed will continue to work. Reinstalling PyManager allowsmanagement of these installs to resume. Runningpyuninstall--purge beforeuninstalling PyManager will perform a complete uninstall.
py list [-f|--format <FMT>] [-1|--one] [--only-managed] [tag ...]py list [-f|--format <FMT>] [-1|--one] [--online] [--source <URL>] [tag ...]py [--list|--list-paths|-0|-0p]
This subcommand will list any or all installs matching the specified tags orranges. If no tags are provided, lists all installs. Runtimes not managed byPyManager (including an active virtual environment) may be listed separately.
The default format is user-friendly. Other formats will include machine-readableand single string formats (e.g.--format=prefix simply printssys.prefixon a line by itself). The exact list of formats is left to the implementation.
If--one is provided, only the best result is listed. This is to assistshell scripts that want to locate the default (or a suitable) runtime withoutlaunching it. (Note that “best” is loosely defined, but will always be theuser’s preferred default environment if it is included in the results.)
The--only-managed option omits runtimes that were discovered but are notmanaged by PyManager, for example, those found using a regular PEP 514 lookup.
Passing--source (or--online to implicitly pass the default source)will search an online index rather than currently installed runtimes. The optionis here rather than on theinstall subcommand because the filtering andformatting options are already available onlist.
The legacy--list,--list-paths,-0 and-0p arguments from thepy.exe launcher will also be provided. However, they will not support thenew options listed here, and are limited to reproducing the output from theexisting launcher. Unmanaged installs are not distinguishable in this listing.
py help <COMMAND>
This subcommand will display the help text for each specified command, or ifnone specified, will show the list of commands. Specifying one command is theequivalent ofpy<COMMAND>--help. Showing the list of subcommands is thedefault action for thepymanager command.
The command is added primarily to offer a simple way to tell users how to findmore information: they can be told to runpyhelp. This avoids having tooverride or extend thepython-? output, which otherwise forwards to theselected runtime and already prints at least one screen’s worth of text.
After an automatic install (e.g. runningpython with nothing installed), amessage will be displayed telling users that they can runpyhelp for moreinformation on how to manage their installs.
No environment variables can be updated automatically when installing a Storeapp, and so no updates will be done automatically. The core commands shouldalready be available on a correctly functioning machine.
One directory within the user’s PyManager data directory is set aside forgenerated aliases. If desired, the user can add this directory to theirPATHthemselves. The contents of this directory will be managed by PyManager, andwill contain executables to directly launch installed runtimes (for example,python3.exe andpython3.13.exe for an install of Python 3.13). Wheneveraliases are added to this directory,PATH will be checked and if it ismissing, the user will be presented a message containing the path to add.
Scripts installed by packages installed into a runtime will be in yet anotherdirectory. Due to the current design, we do not believe it is safe to have themall install into a single directory, or a directory shared by multiple runtimes.However, a future development may include a command for PyManager to generateits own entry points based on metadata in installed packages.
A Start Menu shortcut will be added to launch PyManager documentation in theuser’s default web browser. No applications are added to the Start Menu.
When installing Python runtimes, the install definition may specify Start Menushortcuts to create for the install.
Standard file associations will be created when installing PyManager, and willlaunch scripts and packaged apps with PyManager’s globalpython.exe alias.This provides sensible behaviour for users who are double-clicking on scripts or.pyz files.
For each of the global aliases described earlier, a*w.exe also exists.These launch without creating or attaching a console window, which typicallymeans they will only display UI created by the script. For example, IDLE alwayslaunches usingpythonw.exe, as this avoids an unnecessary native console.
These commands otherwise behave identically to their console counterparts.
PyManager is configured using a hierarchy of JSON-based configuration files.Command-line options always override configuration file options. Configurationfiles in user editable locations may be disabled by a configuration orcommand-line option.
In ascending order of priority, these will be located:
base_config setting (default: none)user_config setting (default:%AppData%\\Python\\PyManager.json)additional_config setting (default:%PYTHON_MANAGER_CONFIG%)-c command line optionThe specific behaviour of each configuration option is left to implementation.However, a number of intended options are discussed in other sections.
App package configuration is provided to allow PyManager to be embedded in otherapplications or packages. For example, an alternative distribution may want toinclude PyManager but have it locate installs from their own index. The apppackage configuration allows reusing our build and overriding the defaultsettings.
Theuser_config andadditional_config settings are pre-configured inearlier configuration files, allowing them to be overridden by admin-onlyconfiguration or an alternate root configuration. If a configuration fileoverwrites the setting that caused the file to be loaded, it is ignored.Thebase_config setting is similar, but starts empty and is intended foreasy overriding through admin configuration.
Admin-only configuration is provided to allow administrators to manage systemsunder their control using existing tools, such as group policy or registryupdates. By design, these controls cannot be overridden, such that it ispossible for administrators to deploy policy that prevents or limits the use ofPyManager. These controls are essential to allow PyManager to be deployed safelyinto certain environments, and without them, it would simply be disallowed andthose users would have no access to Python.
The intent is for the main admin-only configuration to be a path to a newbase_config configuration file that an administrator can deploy to anycontrolled location. This allows a network administrator to control the sourceof their users’ default Python runtimes, without forcibly restricting them, orto override the other sources for configuration files (apart from the commandline option).
The index file is made available either online or locally, and providesPyManager with all the information needed to find, select, install, and manageany Python runtime.
The index is stored as JSON. The main top level key isversions, whichcontains a list of objects. Each version object has its own schema version, andthere is no overall file schema version. Future changes may add additionaltop-level keys to provide functionality that cannot be safely integrated intoan existing one.
Version objects may be split between the index file and a__install__.jsonstored in the root of each package archive. The entries in the bundled file willfill in any gaps from the index file. This is intended to allow the typicallylargeshortcuts key to be removed from the index file, but may also extendtoalias,executable andexecutable_args. Omitting other keys fromthe index may result in problems installing the package. Ensuring correctbehaviour is left to the implementation - this is not an interoperability point,and so we do not intend to specify the details here (beyond the normal compatibilityrequirements that apply).
A second top-level keynext contains an optional URL to another index. Thismay be used if PyManager cannot find a suitable package in the includedversions. The intent is to allow for older indexes to be archived and onlyaccessed when required, reducing the size of the initial download withoutcutting off users from older versions. When searching for a suitable install,later indexes will not be searched if a viable candidate is found (in otherwords, the first index consulted should have the latest versions in it).
The initial schema is shown below:
SCHEMA={"versions":[{# Should be 1."schema":int,# Unique ID used for install detection/side-by-side.# Must be valid as a filename."id":str,# Name to display in the UI"display-name":str,# Version used to sort packages. Also determines prerelease status.# Should follow Python's format, but is only compared among releases# with the same Company."sort-version":Version,# Specifies platforms to consider this package for.# Initially, 'win32' is the only supported value. Others may be# defined in the future. This condition is evaluated silently, and# is not intended to replace platform requests in "install-for"."platform":[str],# Company field, used for filtering and displayed as the publisher."company":str,# Default tag, mainly for UI purposes.# It should also be specified in 'install-for' and 'run-for'."tag":str,# List of tags to install this package for. This does not have to be# unique across all installs; the first match will be selected.# For example, the 3.10.5 package may list '3', '3.10' and# '3.10.5' so that any of those may be specified to install it.# Matches are number aware, so that 3.1 is not a prefix of 3.10."install-for":[str],# List of tags to run this package for. Does not have to be unique# across all installs; the first match will be selected. The target# is the executable path relative to the root of the archive.# Explicit args (optional) are inserted before user args."run-for":[{"tag":str,"target":str,"args":[str],"windowed":int},...],# List of global CLI aliases to create for this package. Does not# have to be unique across all installs; the first match will be# created."alias":[{"name":str,"target":str,"windowed":int},...],# List of shortcuts to create for this package. Additional keys on# each instance are allowed based on the value of 'kind'.# Initially, 'kind' supports the following values:# * 'pep514' - other keys define registry values to set# * 'start' - generate shortcuts in the user's Start Menu# * 'uninstall' - generate an Add/Remove Programs entry"shortcuts":[{"kind":str,...},...]# Default executable path, relative to the root of the archive.# Usually the values from 'run-for' will be used instead, and this# is mainly for display purposes."executable":str,# Default executable args"executable_args":[str],# URL to download the package archive from"url":str,# Optional set of hashes to validate the download. Hashes are stored# as hex digests. Any hash supported by hashlib without OpenSSL is# permitted."hash":{"<hash_name>":str,}}],# URL (or relative path) to the next index file"next":str,}
For limited compatibility with scripts designed for sh-like shells, PyManagerwill check scripts for a shebang line. A shebang line specifying a Pythoncommand will be used (when not overridden on the command line) to select asuitable runtime for the script.
Unlike the support currently in thepy.exe launcher, we propose to reducethis functionality to only support Python commands where the command matchesa global alias listed for an install, with anything not matching being treatedas an arbitrary executable path. In practice, this is expected to produce thesame (or better) results for non-contrived cases, but may result in subtlechanges where users are relying on unspecified edge case behaviours of theexisting launcher.
The specific patterns to be detected are left to the implementation, but shouldbe largely compatible with the existing launcher.
It may be argued that the globalpython.exe alias provided by PyManager is“not real Python” and so should use a different name. While this is strictlytrue, there are three reasons we argue that it should be used.
Firstly, thousands of usersdaily install through the Store page after beingled there by having typedpython at the terminal of a clean machine. Due tohow this redirection is implemented, if the app they install does not provide apython command, then the redirection will remain in place. In order toensure that users do not get stuck always going back to the Store, we need toprovide this command. (The same applies topython3.)
Second, the alternative to the “not real” alias is not “the real” one. It’snothing. We don’t have the ability to replace the global static alias with onethat follows the user’s preference or installs, and so the alternative would beto provide nothing and havepython be an error in all cases. This is worse,and in our opinion, actively harmful to Python’s reputation.
Third, although the underlying implementation of thepython alias is morecomplex than the defaultPrograms/python.c, the experience of using it isidentical. The alias is only launched in the absence of another expressedpreference (that is, there’s nothing else onPATH), it respects anyindirect preferences (such as through configuration or shebangs), and itlaunches the most appropriate version of Python available on the user’s machine.This is much closer to the desired behaviour of the globalpython commandthan any alternative.
It has been noted that Gentoo also distributes an intelligentpythoncommand, in order to serve their users better than a simple symlink.
Thepy.exe launcher exists to provide some of the functionality that will bereplicated by PyManager - specifically, the ability to launch an alreadyinstalled runtime. Despite its long history, the launcher does not seem to havebecome the preferred method for most users, with many preferring the globalmodifications to thePATH environment variable. However, the command itselfhas come to be relied upon, and should be preserved as long as possible. This isachieved in two ways.
Firstly, we install our ownpy.exe alias with PyManager that provides thesame functionality, along with PyManager specific functionality. This isintended to become the default/preferred install ofpy.exe over time.
Second, we generate PEP 514 metadata (when requested) for each install, whichallows a legacypy.exe to continue to work normally with installs managed byPyManager.
Due to how the existingpy.exe launcher configures itself, and how the MSIXpackage for PyManager is constrained, it is not possible for PyManager’spyalias to override the launcher. As a result, users who install the launcher willalways findpy resolving to the launcher. Ultimately, the only way toresolve this in favour of PyManager is to uninstall the launcher, which can bedone through the standard Installed Apps control panel.
We propose to update the existing launcher, which will continue to be releasedwith the traditional installer, to detect attempted use of the new subcommandsand provide a useful message for the user rather than the current error. Thesewarnings can also detect the unlikely case where a user is intentionallylaunching extensionless files by those names and retain that behaviour, allowinga viable alternative for users who cannot make other changes to their setup.
An activated virtual environment, as implemented by the standard libraryvenv module, will modify the user’sPATH environment variable to ensurethat the venv launcher will take precedence over other executables. As a result,when a venv has been activated, PyManager can only be launched by its aliasesother thanpython. When an active virtual environment is detected, it willbe treated as the user’s default runtime (except for uninstall), which ensuresthat other commands will also behave as expected.
This means that working virtual environments will behave as they do today withno additional support from PyManager.
In general, there are no compatibility guarantees to the install process betweenminor versions (3.x to3.y), and so “having to use a differentinstaller” is not considered compatibility breakage. The versions of Pythoninstalled are only impacted by this change to the extent that the install methodmodified their behaviour. In general, most installs will be closer to thebehaviour of having been built from source by the user themselves.
That said, there are a number of changes that will impact certain users whenthey do move to a new install process. This section outlines as many of thesechanges as we are aware of, in no particular order, and will likely form thebasis of a migration guide.
Users who wrote scripts to generate the download filename of our old installerwill find those scripts are broken. These URLs were never guaranteed stable orpredictable, and so we have no recourse to do anything other than apologise andsuggest users use our own tooling for downloads.
The deprecation period for the traditional installer allows time for these usersto learn about the upcoming change. Where possible, we will add deprecationwarnings to the traditional installer.
Users who wrote scripts to execute our installer with particular options willhave to change their script. Most options have been removed, to begin with, andthose that remain have new spelling. Since it is not possible to reach a statewhere options for the old installer are being passed to the new without manualintervention (that is, someone has to change the command already), this isconsidered an acceptable change.
The deprecation period for the traditional installer allows time for these usersto learn about the upcoming change. Where possible, we will add deprecationwarnings to the traditional installer.
Users with existing runtimes installed will find them selected by PyManager andits aliases, provided the registration is not corrupt.
The priority order among installed runtimes has changed to only includeprerelease versions when specifically requested (for example,-V:3 willmatch 3.14.0 rather than 3.15.0a1, but-V:3.15 will match 3.15.0a1), and tocorrectly sort text suffixes on tags (for example, 3.14t is nowlowerpriority than 3.14).
While it is possible to provide warnings in cases where this may be impacting auser, such warnings would be considered very noisy (e.g. a message every timeyou launchpython because you have a prerelease installed that wasn’tselected) and require complicating the selection logic unnecessarily. Thischange will be documented only.
py.exe launcher installedUsers who do not manually uninstall an oldpy.exe launcher will find thatboth their existing and new installs of Python are found, though where versionsmatch the existing install will take priority over the new install (whereas thenewpy would select the new install).
They will also find that commands such aspylist do not work. The solutionhere is to use Windows Settings to uninstall the launcher.
There is no way to detect that a user has accidentally left an oldpyinstalled, or to remove it for them. This change will be documented only.
Users who activate a corrupt or misconfigured virtual environment that is eithermissing itspython.exe or has it not onPATH may receive a differenterror from before.
PyManager’s globalpython alias will be found and executed instead,suppressing any system “not found” error. As it fails to find the environment’sactual runtime, it will then fail, though the code and message may be different.
As this scenario requires an already corrupt system, this change will bedocumented only.
Python versions prior to the first release of PyManager can be backfilled intothe python.org index, either based on newly repackaged archives or using thealmost equivalent packages from NuGet (the latter does not include Tcl/Tk,making them significantly incompatible for some users, but this is likely okayfor especially old versions).
As of this PEP’s acceptance, the plan is to create packages for all versions ofPython 3.10.0 onwards (including patch releases, but excluding pre-releases), so that all non-EOL releases canbe fully installed using PyManager. Versions from Python 3.5.0 onwards (excludingpre-releases) will directly reference the packages on NuGet, making them easilyavailable in reduced form. Neither approach requires rebuilding the existingreleases, nor are any changes required to the sources of those releases.
Installing a copy of Python for all users is no longer possible, as PyManagerwill only install into the user’s own directory. No scenario has been presentedto show that per-machine installs are in line with our intent for the upstreamdistribution, and so we will simply not provide an option for them. Thirdparties who desire this functionality are encouraged to provide their owndistributions.
PyManager can only be installed for all users, though an MSIX does not requireadministrative privileges to install, and can be extensively configured by anadministrator, including to constrain the actual runtimes which users mayinstall. Additionally, PyManager supports local extraction for bundling, and soembedding apps can easily generate their own layout, which can be installed forall users if they so desire.
As this scenario requires administrator intervention with or without anychanges, this will be documented only.
Users using the embeddable distro may have to change to a new method fordiscovering the URL to the packages, though the recommendation would be to usePyManager to discover and install. No differences are anticipated due to thechange of installer, and the embeddable distro package would be identical totoday.
No changes to the NuGet packages are proposed.
The current proposal only makes an Intel 64-bit build of PyManager available.This will prevent users on 32-bit only operating systems or CPUs from being ableto install PyManager. As this is a vanishingly small proportion of machinestoday, and an even smaller proportion of developer machines (the target audiencefor PyManager), we are not concerned about excluding users.
Windows ARM64 machines support running binaries built for Intel 64-bit throughefficient emulation. CPython 32-bit builds will still be available as they havean important role in integrating with 32-bit executables, which does not allowsubstitution of 64-bit binaries. As PyManager runs as a standalone executable,this is not a necessary feature for the manager.
The existing installer optionally allows installation of the Python standardlibrary test suite, and optional installation of debug symbols. Neither of theseare necessary for most users, but they are convenient for some. Preliminarytesting shows that omitting the test suite and debug symbols saves about 60% ofthe size of the compressed package (from 46MB to 18MB).
The “default” CPython packages installed by PyManager will therefore not includethe test suite or the debug symbols. However, there will be a second set ofpackages that do include these extras, grouped underPythonTest (as opposedto the default,PythonCore). For example, wherepyinstall3.13 wouldinstall the default,pyinstallPythonTest\\3.13 would install a secondruntime with the additional files (which can either be launched withpy-V:PythonTest\\3.13, or simplypy-V:3.13 if no equivalentPythonCoreversion is installed).
Debug binaries are no longer distributed, and all other optional features areincluded by default.
Unlike the current Windows Store install, no globalpip command is included(the traditional installer also does not include a globalpip command,unless the options to modifyPATH and to install pip are selected; the firstof these is off by default). This impacts global installation of packages, whichis already discouraged, but has no impact on activated virtual environments.
The existing recommendation remains, which is to runpython-mpip orpy-V:<TAG>-mpip to launch pip.
In this section we compare the security implications of the installer itself tothe existing installers. The implications of Python being installed on a machineare out of scope, and the ability of a malicious user to execute the installeris also out of scope.
The typical risk introduced by an installer is that an elevated install may makechanges to a system that allow a low-privileged user to later affect ahigh-privilege user, for example, by inappropriately setting access control onshared folders. PyManager only operates as the same privilege level as the user,and therefore cannot introduce any escalation path.
An install using the MSI described earlier may introduce additional risks, dueto using older installer technology. Typical users are directed towards the MSIXor Windows Store install paths, which are safe, and it is assumed that usersof the MSI are capable of ensuring the security of their install process (forexample, by correctly quoting their commands to launch the installer andensuring the initial system configuration is suitable).
Once PyManager is installed on a machine, it is likely that malicious users willuse it to install Python. The admin-only configuration described earlier in“Configuration” is intended to control these scenarios. Ultimately though, anattacker who can run PyManager is able to do whatever the user can do, and onlya complete application whitelisting approach can prevent the use of Python.
Acquisition of packages over HTTPS is protected by the connection security. Weuse native Windows download mechanisms that support public and enterprisecertificates, as well as authenticated proxy servers. The feed may includehashes for downloadable packages, which will be verified, but there is nothird-party hosted verification built into PyManager. This is consistent withtoday’s model.
Runtime installs by PyManager are fully accessible by, and modifiable by, thecurrent user. This is equivalent to typical installs using the traditionalinstaller or a NuGet package, but is more vulnerable to tampering than a Storeinstall or a per-machine install with the traditional installer. It is notpossible to fully protect an install from the user who installed it.Reinstalling or updating an install performs a clean install, which will revertany tampering that may have occurred since the original install.
The aliases generated by PyManager when installing a runtime are designed touse a signed, unmodified executable that uses an adjacent data file to launchthe correct target. This can be easily abused to direct the launcher to launchan alternative, however, the only way to resolve this would sacrifice the trustin the executable itself, making it trivial to replace it instead of the data.Such risk already exists, and is equivalent to replacing the script that a usermay launch, or any part of the standard library. Importantly, since aliases arenot shared between users, there is no escalation of privilege along this route.
PyManager has no mechanism to perform a per-machine install. This may be usefulfunctionality to some users, as it would allow an install to be completelyunmodifiable by the regular user (excluding virtual environments and the usersite folders). Such functionality may be manually imitated by an administratorusing PyManager and other OS commands, but it is not considered a criticalworkflow. The recommended alternative is for an administrator to providePyManager and override its configuration.
This proposal would effectively replacePEP 397 (“Python launcher for Windows”)andPEP 486 (“Make the Python Launcher aware of virtual environments”) bydefining the same functionality as part of a new tool with the same name. Bothare already considered final, and the launcher is defined by its documentationand normal compatibility processes. New functionality is based on the currentimplementation, and not the original PEP text.
This proposal has no impact onPEP 394 (“The “python” Command on Unix-LikeSystems”), and is believed to be consistent with it in devising an approach forWindows that allows similar guidance to be given to users on all platforms.
This proposal has no impact onPEP 514 (“Python registration in the Windowsregistry”), and in fact improves our ability to follow it with a more flexiblesystem for registering our own runtimes. Tools that follow PEP 514 will find anyruntimes that choose to use the registration, regardless of how they wereinstalled.
A central goal of this proposal is that “type ‘python’ in your terminal” will besufficient instruction for the most basic cases. Thanks to the redirector addedby Microsoft, following this instruction will at least result in somethinguseful happening, and with PyManager we can ensure that “something useful” meansthat the user is running the latest version.
To explain what is actually happening, we propose the following as introductorytext:
Python installs on Windows are managed using an installer tool. After it hasbeen installed, you can run ``python`` to launch the interpreter, and it willchoose the best version already installed, available online, or referenced bythe script you are launching (if any). If you have a preference for aparticular version, you can specify it with ``py -V:<version>`` followedby the rest of your command.To install a version of Python without running any command, use ``py install<version>``. You can see all of your installs with ``py list`` and remove themwith ``py uninstall <version>``. Run ``py help`` to see all the options thatare available.Because each version of Python will be shared by all your projects, werecommend using virtual environments. This will usually be created for aparticular Python version by running ``py -V:<version> -m venv .venv``, andactivated with ``.venv\Scripts\Activate``. Now, rather than the installmanager, ``python`` or ``py`` will always launch your virtual environment, andany packages you install are only available while this environment is active.To get access to the manager again, you can ``deactivate`` the environment, oruse ``py <command>``.
Many Python projects include information about how to launch their projects aspart of their own README files. Historically, such information has beencomplicated due to the range of options available to users. We propose that,after the install manager is published, such guidance could be written alongthese lines:
To install and use our application, first install Python following theguidance for your operating system at https://docs.python.org/using/. Then,create a virtual environment and use 'pip' to install.``python3 -m venv .venv````source .venv/bin/activate`` or ``.venv\Scripts\Activate`` (on Windows)``python -m pip install OurAwesomePackage``...
If instructions will not include information about virtual environments, thenthepython orpython3 command can be shown, and on Windows both willoperate as intended for users with the install manager.
Instructions currently referring topy for Windows can continue to do so, asthe install manager provides a practically equivalent command. Projects thatwish to provide Windows-specific instructions, such as by using the-V:or--install options to install the correct version, should also link to thedocumentation as guidance forensuring that the install manager is installed.
Complete uninstallation is an important topic to cover before a user is likelyto consider removing the install manager. Since not all parts of installs can beautomatically cleaned up when removing the manager, we choose not to remove mostof them. So while the defaultpython andpy commands will go away, allthe runtimes that were installed are still present and usable.
We suggest an explanation like this:
Before you uninstall the Python install manager, you'll want to uninstall anyruntimes that you added. This can be done easily with the "purge" option:``py uninstall --purge``This will remove all installs and any shortcuts that would otherwise be leftbehind. If you already removed the manager, you can reinstall it and run theabove uninstall command again to clean up. Individual runtimes can beuninstalled by specifying the tag instead of ``--purge``. Tags can be foundby looking at ``python list``.
Configuration files are a common feature that will be documented, but do notneed to be taught to regular users. Similarly, advanced deployment options, suchas those that might be used by system administrators or organisations wantingtheir users to use a preferred index, are best covered in reference material.
We suggest that indexes only need to be introduced when instructing users toinstall a specialised runtime or distribution. Administrators seeking to providean index are anticipated to actively seek out the relevant information in thedocumentation.
To explain how and when to use an alternate index, we propose text along theselines:
Our distribution can be installed on Windows using the Python Install Manager(include link) by referencing our index:``py install --source <your index URL here> latest``This index contains all our versions. Use ``py list --source <URL>`` tosee everything that is available.
The reference implementation is available atthe author’s repositorywith a precompiled MSIX package underReleases. This sample includes a bundledindex, rather than a hosted one, and references a range of existing NuGetpackages to allow install testing.
Reference documentation can also be found inthe same repository.
While we are not inherently opposed to this idea, it relies on many morecomponents being aligned before it can become possible.
Firstly, as it stands, the reference implementation has a lot ofWindows-specific knowledge. Equivalent knowledge for other platforms would needto be collated and implemented, as well as any additional behaviours specific tonon-Windows platforms.
Second, we need a source of pre-built, relocatable binaries that can beextracted onto the system. While such sources do exist, due to our position inthe supply chain, we cannot justifiably use them (they should be using us). ForWindows, our own binaries already meet these criteria, so we can repackage themwithout modification.
Third, the current implementation relies on a bundled Python runtime, which mustbe isolated from any user interference for obvious reasons. This would alsorequire the relocatable binaries mentioned above, which we currently only havefor Windows.
Due to the additional steps needed to make this functional on other platforms,and the fact that there isn’t a need to replace existing installers for thoseplatforms, we consider this idea out of scope for this PEP. It may be pursued inthe future (and the contributors most likely to do so have indicated that theyare looking into it and would be able to use a consistent interface).
The proposal is to have a full Python runtime included with PyManager, so thatitspython.exe alias can refer directly to it rather than resolving to thebest available version dynamically.
It is very important for stability and updates that runtime releases arefully independent of the manager. Updating the manager should be possiblewithout affecting any existing runtime installs, and likewise there should beno requirement to update the manager to get a newer runtime.
Hypothetically, if we were to include Python 3.14.0 with the manager such thatit did not need to be installed, it would be a breaking change to later replacethat with 3.15.0. As we only have a single install for the manager, this wouldresult in the newest installs getting the oldest runtime.
This would also ignore the status of PyManager’spython alias as being of anunspecified version - when the user is launching this alias, it’s because theydidn’t care what version they get enough to specify one. In that situation, weought to select the best available, and allow them the options to stabilise itas is appropriate (whether through a shebang or an active environment).
This is the current situation, which we are trying to change. If you read thisfar and still chose to make this argument, please go back and start again.
Two alternatives to using commands likepylist orpyinstall that havebeen proposed are to use either dedicated modules, invoked likepy-mlistandpy-minstall, or a single dedicated module invoked likepy-mmanagelist. This idea is rejected on the basis that it attempts to reuse existingsemantics for a scenario that cannot be reliably implemented by those semantics,and so will require a special case that is harder to explain, understand, andmaintain.
The main reason this idea is rejected is due to the interaction of two otherwisedesirable semantics: first, that the defaultpy command should launch thelatest available runtime as if it were launched directly; and second, that thebehaviour of-m should not be treated as a special case in somecircumstances. If the first part were dropped, we would freely modify thecommand to behave as users expect - nobody would be raising compatibilityconcerns at all if we were agreed to completely break compatibility. However, ifthe second constraint were dropped, users would bear the burden of the ensuringconfusion. (We aren’t proposing dropping either - this is a rejected idea, afterall - but it helps to illustrate what the options are.)
First, since one of the subcommands is intended to install your first runtime,we cannot treatpython-m[manage]install as if it is running through thedefault runtime - there isn’t one! It inherently requires special case handlingin order to read the command and execute it through a different program.
Additionally, Python allows other options to precede or mingle with the-m,which would have to be supported by this special case.
Finally, the semantics of the-m option include searching the initialsys.path for matching module names. This is a considerably more broad searchthan a bare name.py-minstall would gladly executeinstall.py,install.pyc,install.pyd,install\\__init__.py, and more aftersearching a number of directories found by inspecting the file system, theenvironment, the registry, as well as any transitively included paths found inthose. Compared topyinstall, which wouldonly look for a file calledpreciselyinstall in the current working directory, the-m behaviour isfar more likely to be already relied upon by real scenarios. (For example,Django projects typically have amanage.py script, meaning thatpy-mmanage would always behave incorrectly.)
Changingpy-minstall tonot behave like-m, but instead to executean internal command, is vastly more likely to break users than changingpyinstall. As such, this idea is rejected.
A reasonable alternative to subcommands is to specify their names with leadingpunctuation, like an option rather than a subcommand. For example, this may looklikepy/install... rather thanpyinstall, orpy--list. Becausesome of these are currently errors for a normal CPython interpreter, theycould be added without any backwards compatibility concern.
Notably, however, the typical Windows format of a leading slash is not an errorin CPython. Windows users therefore cannot directly transfer existing knowledgeand must learn a new way to specify options. As we are proposing a Windowsspecific tool, this is a terrible start. Additionally, those users familiar withUnix-style command lines will recognise the misuse of options as commands.
We desire to create a clean interface, and starting with a design that includesobvious warts or learning challenges is counter to that goal. Modern toolsuniversally use subcommands for these purposes, and so the idea to use somethingdifferent is rejected.
Rather than creating a new install mechanism, we could invest in maintaining thecurrent installer. At this stage, however, our current installer is basedentirely on retired technology. Windows is no longer developing the WindowsInstaller service, and Wix are no longer improving the version of their toolsetthat we use. Migrating to a newer Wix Toolset is a significant amount of work,and ultimately still leaves us tied to old technologies.
As mentioned earlier, the most beneficial functionality provided by WindowsInstaller is not used for CPython, and generally has caused more issues than ithas ever solved (for example, accidental downgrades due to automaticallycollected file version information).
The implementation of the Burn bundle, which is our primary source of installerlogic, is in C++ and integrated into a framework that few core developers arefamiliar with. This makes maintenance challenging, and is not a good long termposition to take. Migrating desired features such as registration-free installsinto the Burn bundle is not possible (without writing the end-to-endreimplementation and integrating it as an afterthought).
Our view is that maintaining the current traditional installer is at least asmuch effort as implementing a new installer, and would not provide meaningfulbenefits for the core team or for our users. As such, this idea is rejected.
Removing the Store packages would reduce the number of options users face whenchoosing a Python runtime. By all measures apart from reliability and security,the traditional installer is entirely sufficient as a substitute. The effort tomigrate parts of the ecosystem to more secure settings (such as not relying onDLL hijacking) has largely occurred, but some packages remain that still onlywork with less secure configurations, and moving all users back to theseconfigurations would ensure that users of these packages would not face theissues they face today.
However, the majority of users of the Store packages appear to have nocomplaints. Anecdotally, they are often fully satisfied by the Store install,and particularly appreciate the ease and reliability of installation. (And on apersonal note, this author has been using Store packages exclusively sincePython 3.8 with no blocking issues.)
The greatest number of issues have been caused by misconfiguredPATHvariables and the defaultpython.exe redirector installed by Microsoft. Inother words, entirely unrelated to our own package (though sometimes related tounresolvable issues in our other installer). For the sake of the high number ofsuccessful installs through this path, we consider the burden of diagnosing andassisting impacted users to be worthwhile, and consider the idea to simply dropthe Store package rejected.
That said, when PyManager is published to the Store, we would plan to delist allexisting runtimes on the Store to ensure users find the manager. This onlyimpacts new installs, and anyone who has previously installed a particularversion (even on another machine, if they were logged in) will be able tocontinue to use and install those versions.
WinGet, Chocolatey, and other similar tools are not installers in the sense thatwe require. They use their own repository of metadata to download, validate, andrun installers. Without our own installer, they have nothing to run, and socannot be used.
It is possible that their metadata will not support installing PyManager andthen running it to install a particular runtime. If this is the case, they mayneed to investigate using our binary packages directly.
Currently, none of these install tools are officially supported by CPython, andso we have no obligation to make them work.
It is possible to release each version to the Windows Store as we currently do,but make them unlisted and rely on an installer (potentially PyManager, WinGet,or another tool that can install Store packages). This would avoid the risk ofoverwhelming the user, while greatly simplifying our own reponsibilities forpackage management.
This approach would leave a significant burden on whichever contributor hasaccess to the Store publishing interface, as updating packages is a manualoperation. Additionally, it would leave every Python runtime with the technicallimitations outlined earlier. As such, this idea is rejected.
Making every version a MSIX package rather than a ZIP, even though this avoidsthe Store publishing interface, would still impose technical limitations onusers. It is also rejected.
Publishing the plain ZIP file is part of the plan, however, it will not bevisibly listed (for example, on the python.org download pages, though they willbe visible in the FTP view). An alternative would be to publish and list thesepackages, and expect users to download and manually extract and configure them.
Given the workflows we see, we believe that most users do not want to configurea Python install at all. Not only do they not want to choose the installlocation, they do not want to choose a version, or even have to search for adownload provider or instructions. However, they do want to be able to find aninstall later, launch, update or remove it, or list all known installs.
It is also worth recognising that there will be more ZIP files than arecurrently listed on the Download pages, and so the list of files will becomelonger. Choosing the correct download is already challenging for users (thosewho bypass the primary “Download” button and view the list of all availableversions and then files), and we have no desire to make it more challenging.
The index protocol and download list will be available for tools that wish touse it, or for users who are willing to navigate JSON in order to find the URL.The--target option on the install command also provides a trivial downloadand extract operation, allowing users to have the same experience as a ZIP file.And the--download option can give users the ZIP file still zipped.
Whether the Windows Store or python.org, it would be viable to publish to onlyone location.
However, users strongly expect to be able to downloadsomething frompython.org. If we were to remove any option at all, we would inevitably hurt ourusers. Without an MSIX available on python.org, users have no way to transferthe package to another machine, or to fully script the initial install of themanager.
Many users rely on the Windows Store app to install packages, and the built-inredirector in Windows can only open to a Store page. As such, removing the Storeapp is equivalent to denying hundreds of thousands of installs each month.
The two builds are practically identical. The only difference between the MSIXwe provide to the Store and the one that goes to python.org is package signing:we sign the python.org package ourselves, while the Store package is signed aspart of the publish process. Otherwise, there is no additional cost to producingand publishing both packages.
PEP 723 introduced inline script metadata, a structured comment intended forthird-party tools to interpret and then launch a Python script in the correctenvironment. An example taken from that PEP:
# /// script# requires-python = ">=3.11"# dependencies = [# "requests<3",# "rich",# ]# ///
PyManager has no integrated support for installing dependencies, and does notpropose adding any. As a result, we could not fully implement handling of thismetadata, and as we consider partial handling to be worse than nothing, wechoose not to implement any.
It is possible for a user to specify the constraint directly as an option, forexample,py-V:>=3.11my-script.py to get the selection behaviour.
We could also detect the metadata and warn if the selected runtime does notmatch its requirement, but this is not part of the initial proposal.
This document is placed in the public domain or under theCC0-1.0-Universal license, whichever is more permissive.
Source:https://github.com/python/peps/blob/main/peps/pep-0773.rst
Last modified:2025-04-28 22:24:29 GMT