From 334ba7871eafb26d7edfd21c05c0527b74ee3c74 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 22 Jan 2025 09:41:22 +0000 Subject: [PATCH] PEP 773: A Python Installation Manager for Windows (#4219) --- .github/CODEOWNERS | 1 + peps/pep-0773.rst | 1622 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1623 insertions(+) create mode 100644 peps/pep-0773.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6ac66492831..fbacbd2388a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -648,6 +648,7 @@ peps/pep-0767.rst @carljm peps/pep-0768.rst @pablogsal peps/pep-0769.rst @facundobatista peps/pep-0770.rst @sethmlarson @brettcannon +peps/pep-0773.rst @zooba # ... peps/pep-0777.rst @warsaw # ... diff --git a/peps/pep-0773.rst b/peps/pep-0773.rst new file mode 100644 index 00000000000..c26ce1f695c --- /dev/null +++ b/peps/pep-0773.rst @@ -0,0 +1,1622 @@ +PEP: 773 +Title: A Python Installation Manager for Windows +Author: Steve Dower +Discussions-To: https://discuss.python.org/t/77900/ +Status: Draft +Type: Standards Track +Topic: Release +Created: 21-Jan-2025 +Post-History: + `18-Dec-2024 `__, + `21-Jan-2025 `__, +Replaces: 397, 486 + + +Abstract +======== + +Installation of the python.org Python distribution on Windows is complex. +There are three main approaches with roughly equivalent levels of user +experience, and yet all of these suffer from different limitations, including +failing to satisfy modern usage scenarios. This PEP proposes a design for +a single Windows install workflow tool that satisfies all the needs of the +existing installers for the platform, while avoiding most of their limitations, +and provides the core team with the ability to manage releases for many years +to come. + +Reader's Note +------------- + +This document is a detailed *proposal*, intended to assist in an "approve" or +"reject" decision on the replacement of the existing install formats for Python +on Windows with a new format. It is not intended to be a binding specification, +nor is it user documentation or an interoperability specification. The actual +implementation may vary over time as needs change, and that is not to be +considered a "violation" of this PEP. Any interfaces and protocols meant for +public use will be independently documented and maintained in accordance with +standard deprecation timelines. + +Documentation on installing Python on Windows can be found at +`docs.python.org/using/windows.html `__. + +Background +========== + +There are a large range of needs users may have that lead to them wanting +to 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 version +to integrate with existing code or another application. Some are after a full +set of different interpreter versions to perform testing. + +In this section, we discuss the expectations that users have of "installing +Python", provide an overview of the existing installers for Windows, and +identify some of the gaps and challenges inherent in these offerings. + +Expectations +------------ + +Based on significant anecdotal experience and analysis of quantitative data +available (though not necessarily public), we make the following assertions +about the majority of Python users on Windows: + +* most users just want the latest stable version +* most users want a "one-click" (or fewer) install +* most users do not want to use administrator privileges +* most users will benefit from installing maintenance updates +* most users expect the ``python`` command to work after installation + +The primary support for these assertions is that the most popular installers +actively chosen by users are the latest stable release on python.org, and +the latest stable release on the Windows Store, both of which meet these +requirements. + +We make the following assumptions about other significant sets of users. +These may have some overlap between groups, and at least some users expect +all of them. + +* some users want to install Python programmatically +* some users want to install a particular version +* some users want to install many versions +* some users want to install for all users of their machine +* some users do not want Start Menu shortcuts +* some users want to install as part of their project's build process +* some users want to install as part of their project's install process +* some users intend to never update their install +* some users expect the ``py`` command to work after installation + +These assumptions have all been demonstrated over time to exist, though the +relative importance has not been quantified. The :ref:`NuGet packages +` and the :ref:`embeddable distro +` can meet most of these needs. + +Traditional Installer +--------------------- + +The traditional installer is an executable downloadable directly from +python.org that installs the entire development kit for Python. This includes +the CPython interpreter, the standard library, Python headers and import +libraries, builds of Tcl and Tk, the documentation as HTML files, the runtime +and standard library test suite, Start Menu shortcuts for Python and IDLE, +debugging symbols and debug builds of the binaries, the ``py.exe`` launcher +and its file associations, and functionality to modify the user's ``PATH`` +environment 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 worth +of options, listing the components that they need not install, as well as other +options 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 an +option to proceed with the install without displaying any UI. +Based on feedback and bug reports, all of these options are used by at least +some users. However, as we do not track install telemetry, we have no way to +know which options are more important than others. + +Behind the scenes, the traditional installer is a Burn bundle, generated using +the Wix Toolset installer framework, containing one or more MSI files for each +feature. This framework is used extensively by Microsoft themselves, and +provides the most direct method of using Windows Installer. The bundle is a +custom C++ application, based on their template, which allows us to customise +the overall behaviour of the installer to determine precisely which MSI files +should actually be installed. The process of copying files, updating the +registry, 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 installs +and automated CI system installs. While better alternatives are available, they +are not as obvious, and the hope is that a future design would make these +scenarios easier. + +Windows Store +------------- + +The Windows Store packages for CPython are produced as part of our normal +release process using almost all identical binaries to the other packages. +Due to being in an app store package, the primary ``python.exe`` is enhanced +to be able to determine its location properly, and alternative ``pip.exe`` and +other shortcuts are included to make up for the lack of ``PATH`` environment +variable settings. These are implemented in :file:`PC\\python_uwp.cpp` in our repo. + +These packages are installed by searching for Python in the Microsoft Store +app, which will find results for each major version since 3.8. Users then have +to select a version and install it. These packages include the CPython +interpreter, standard library, Tcl/Tk, IDLE, and pip, and create file +associations, Start Menu shortcuts, and global commands for ``python.exe``, +``python3.exe``, ``python3.X.exe``, ``pip[3[.X]].exe`` and ``idle[3[.X]].exe``. +No ``PATH`` modification is possible or required, though users may need to +manage their global shortcuts through the "Manage App Execution Alias" settings +page. + +In addition, Microsoft has added to a clean Windows install a default +``python.exe`` command. This captures attempts by users to launch Python on +a machine that has not yet installed it. When launched directly, the command +will open the Microsoft Store app to the page containing the recommended +Python app, typically the latest version. This app is entirely controlled by +Microsoft. Based on telemetry associated with the Python app (which *is* +controlled by the upstream Python project), approximately 300,000 installs +per month come through this redirector, making up about 90% of the total +installs of that version. + +Behind the scenes, the Store package is based on Microsoft's new installer +technology for apps known as APPX or MSIX. These are essentially plain ZIP +files with a small amount of metadata, except that installation is handled +by the operating system. They are always extracted to a fixed location, +accessible to all users but not modifiable by any, and automatically updated +to the latest release. The user's own data is stored in an OS-managed location +in their user profile, and is able to be reset, backed-up and restored using +regular OS functionality. + +Nuget Package +------------- + +The Nuget packages for CPython are produced and published as part of our +normal release process. The contents are identical to the traditional +installer. A Nuget package is published to nuget.org, which is a package +manager typically associated with .NET languages, but highly integrated with +any project supported by Visual Studio. This makes it a nice format for users +who 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, or +may be downloaded directly once the URL of the package is known. The package is +a plain ZIP file with some metadata. It contains the CPython interpreter, the +standard library, development headers and import libraries, and pip. It does +not execute any code at install time, and users must locate the package +themselves in order to launch the ``python.exe`` contained within. + +Embeddable Package +------------------ + +The embeddable package for CPython is produced and published as part of our +normal release process. It is published to python.org alongside the +traditional installer. The contents are identical, however, the layout is +changed to store all binaries at the top level, with the standard library +packed into a ZIP file. A ``._pth`` file is included to override ``sys.path`` +so that only the files that are part of the distro are used, and environment +variables or registry entries are ignored. + +This package does not include pip, as the intention is for it to be embedded +into a broader application. Other libraries should be installed at build time, +since after distribution the runtime is meant to be an internal implementation +detail of the app it is a part of. + +As well as its intended use, some users attempt to use this package as a +development kit rather than a runtime package. This is believed to be due to +those users preferring to avoid "heavyweight" installers, and believing that +this package is intended to be a "portable" install (extract and run), likely +because 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. + +Alternate Distributions +----------------------- + +While outside of our purview as the core team, alternate distributions of Python +for Windows often use a project, workflow or environment-centric model for +installation 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 other +dependencies. Examples of these tools include conda and uv. + +Two observations are worth making about these tools. Firstly, they are often +praised for being low impact, in that they usually don't install additional +entry points or files for the runtime, making the install fast and also isolated +to a single project. Secondly, their users often appreciate the ease of +selecting a particular version of a runtime, or alternatively, not having to +select at all because existing specifications (or constraints) can choose for +them. + +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 cognitive +overhead of learning how to use and combine multiple commands. + +It's also worth pointing out that the core team does not view these alternate +distributions as competitors to any upstream distribution. They are a +fundamental part of how the open source ecosystem is intended to work. Our own +distributions are a convenience for those who choose to use them, as not all +scenarios are well served by a workflow tool or even a pre-built package. + + +Challenges +---------- + +There are numerous challenges we face with the current set of installers, +which largely break down into two categories: mismatched or unachievable +user expectations, and general unreliability. + +The traditional installer has the highest level of unreliability. The Windows +Installer 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 are *defined* by the traditional installer, and so by +definition, 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 the +user's system without registration. If you have installed it once, and you +try to install it again, you will only even be able to manage (or upgrade) the +existing install. This can lead to installs moving on update, which will +break users. + +Additionally, the ``PATH`` environment variable cannot be intelligently +modified - at best, we can prepend or append the install path. This usually +results in the most recent install of Python being the highest priority. For +example, if the user has Python 3.14 installed and then installs (or updates) +3.13, the ``python`` command will switch from the later version to the earlier +version. + +The ``py.exe`` launcher, defined in :pep:`397` and implicitly updated by :pep:`514`, +is an attempt to avoid this particular issue. It uses its own logic for finding +installed versions without relying on ``PATH``. However, the PEP 514 logic does +not allow for prerelease or experimental builds to be treated specially, and so +``py.exe`` often prefers these builds by default over the non-experimental +version expected by the user. + +The Windows Store package is very reliable, with the exception of the global +shortcuts. Rather than modifying ``PATH`` to add its own directory, these +shortcuts are created in a single OS managed directory that has all the +shortcuts defined by any app. Users are able to modify their ``PATH`` to exclude +or de-prioritise this directory, leading to unreliable or inconsistent +behaviour, and historically we have also seen this caused by installers. +For example, installing Python from the Store followed by Python from the +traditional installer with its ``PATH`` modification enabled will almost always +shadow the Store package's Python with the later install. + +User expectations that are un-met by the Store package tend to be performance +and 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 difficult +to use hidden directories (such as ``AppData`` or ``TEMP``) to communicate +between different versions of Python, as each version has its own space. Apps +are subject to stricter security requirements that legacy applications usually +have disabled, such as DLL hijacking protection, which causes some libraries to fail. +The ``python3`` and ``python`` shortcuts are managed through system settings, +and the user interface is not very good (and not going to be improved, according +to Microsoft). Without managing these, it is relatively easy for an undesired +version to be launched, though in general the targets can only be changed +manually by the user, and not by merely installing another app. + +Both the Nuget package and the embeddable distro are as simple and reliable to +install as extracting an archive file, though it's worth noting that for many +Python users this is not a common task. They provide no install management at +all, 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 the +wrong installer. Both these packages are for specialised cases, and while they +are documented as such, the attraction of a plain ZIP file leads some users into +failure. + +Overview of PyManager +===================== + +("PyManager" name open for bikeshedding) + +PyManager is the internal name of our proposed replacement installer tool. It +will be distributed both in the Windows Store and on python.org as an MSIX +package. Downloading from either source will get an identical package, and +both will support automatic updates (through the Store) for new releases. + +The user visible name will be "Python Install Manager", published by the +Python Software Foundation. After publishing, we will request that Microsoft +adjust their ``python.exe`` stub to open to this new app. + +This app does not directly provide a version of Python, but it does provide the +global commands that users expect to work, as well as file associations and +Start 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 and +then launch it. From the user's perspective, they have the same initial +experience as today, with one added progress bar on first launch. + +The global commands provided by the app must be static and bundled into the app +itself. They can only change their behaviour at runtime, and cannot be +redirected to different executables except by the user (and then only to another +installed app). So the commands to be provided by PyManager are ``python.exe``, +``python3.exe``, ``py.exe``, ``pymanager.exe``. Each of these must have the +ability to inspect the user's system and choose the correct runtime to launch. +Additionally, ``py`` and ``pymanager`` will have management subcommands to allow +adding and removing runtimes. + +In line with :pep:`394` and the default behaviour of Windows, the recommended +command for launching Python is ``python.exe``. As provided by PyManager, this +will locate an existing install, either among those that PyManager manages or +using :pep:`514`, or it will install the latest available version of CPython and +select that. The ``python3.exe`` command behaves similarly, but is only allowed +to find 3.x installs from python.org. + +The ``py.exe`` command provided by PyManager will be recommended for most +management use, due to its brevity. ``py install ...``, ``py list ...`` and so +on. The proposed commands are detailed later. The existing behaviour of the +:pep:`397` launcher is preserved, however, launching through ``py`` will not +automatically install runtimes (by default). If one is requested but is not +installed, users will just get an error. The ``py run ...`` subcommand, however, +will install automatically, and supports the same options as bare ``py``. + +These commands are added at very low priority in the user's ``PATH`` by the OS. +Every existing configuration we may have created on a user's machine will take +precedence over these commands, and so these are a last resort in place of an +error message. As a result, we can generally assume that a user is launching +these commands because they haven't configured a stronger preference (for +example, a user who has activated an environment will never launch our +``python.exe``, because activation will put a different one ahead of it, and a +user who wants precisely the behaviour of the existing ``py.exe`` can just +install it and will never launch our new one). + +The ``pymanager.exe`` command is to allow for handling ambiguous situations. +Existing installs of Python and the launcher may shadow ``python.exe`` and +``py.exe``, but in an automated environment, this can make administrative +scripts unreliable, and so the ``pymanager`` command is unlikely to refer to +something other than PyManager. It has all the subcommands, and launching it +with no command specified will print help for the user. + + +Replacing other installers +-------------------------- + +Our intent is to immediately stop publishing individual versions to the Windows +Store, and to deprecate and phase out the traditional installer and Nuget +packages by Python 3.16. The embeddable distro would remain, but its listing on +python.org download pages would be phased out and it will be available only +through PyManager. + +PyManager will be made available as an app package downloadable manually from +python.org, and the double-click install experience is generally smooth. This +provides an equivalent to the current approach of downloading from our site. +It will bundle a recent (unspecified) version of CPython so that the download +can be moved to a non-internet connected machine and still provide a Python +runtime after install. + +Some automated deployment scenarios do not work with the newer MSIX format, and +so a simple MSI will also be provided on python.org. This will have no options +or user interface, and require administrative privileges, which are typically +available for these kinds of scenarios. This MSI would be discouraged for most +users, and the MSIX should be the default. + +It's worth noting that there is no way to make the MSI install fully compatible +with 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 on +regular download pages. + +Third-party tools that currently distribute their own builds of CPython will be +welcome to use ours, though will be expected to be the initial point of contact +for their users requiring support. + + +Project ownership and development +--------------------------------- + +PyManager will be developed and maintained in its own repository adjacent to +the 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 for +versions to match, or releases to be simultaneous. Unless otherwise arranged, +the PyManager release manager is whoever is the build manager for Windows. + + +Specification +============= + +.. note:: + In this document, all command line options will be shown with one or two + hyphens. In implementation, all options will support one or two hyphens or a + forward slash, to be permissive of both Windows and UNIX conventions. + +Exec subcommand +--------------- + +.. code:: text + + pymanager exec -V:tag [interpreter opts] [script.py|-m module|-c code] [script args] + pymanager exec -3.* ... + pymanager exec [--only-managed] [--[no-]install] [-V:|-3.*] ... + py [-V:|-3.*] ... + python ... + python3 ... + +This subcommand is used to select and launch a runtime. It is the default action +for the ``py`` command, and the only action supported by the ``python`` and +``python3`` commands. The default options are subtly different in each case for +consistency with existing use of these commands. + +This subcommand is available on both ``py`` and ``pymanager``. However, since +``py`` offers it by default, we would not expect users to use it there. The +intent is that the ``py``, ``python`` and ``python3`` commands are the default +ways to launch a runtime, and ``pymanager exec`` is for advanced scenarios. + +The ``-V:tag`` command is used to request a specific runtime from the command +line. The tag is a ``Company\\Tag`` pair, or just ``Tag`` if no slash is +included, and is used as defined by PEP 514. The ``-3.*`` option is interpreted +as ``-V:PythonCore\\3.*``. This option is only available for ``py`` and +``py exec`` 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 a +recognised pattern, it will either provide the tag to be used for search, or it +will override all other processing and its specified executable will be launched +without further effort being made. This is to handle the (unfortunate) legacy +support of arbitrary Windows-specific paths being allowed in what was meant to +be a portability feature. In general, shebangs including simple patterns like +``/usr/bin/python3.13`` are intended, while those that use ``/usr/bin/env +python`` are unlikely to be of benefit since the environment tends to be less +reliable than our search. + +If no tag is yet requested, the ``VIRTUAL_ENV`` environment variable will be +consulted to see if an environment has been activated. If so, that will become +the request. + +If a tag has been requested at this stage, the ``python3`` command will verify +that it matches ``PythonCore\\3.*`` and exit with an error if not. This allows +allows the ``python3`` command to be used in an active environment consistent +with other platforms, but not if the environment would not have included the +command. This applies to most existing versions of Python on Windows. (The +alternative to this behaviour is to make ``python3`` always error when an +environment is active, as anything else would behave inconsistently for the +user.) + +If no tag is requested, the default will be consulted. For ``python3``, this is +``PythonCore\\3``, but for all other commands it is read from configuration +(which might involve an environment variable). If it's still empty, any tag will +be allowed. + +The best installed runtime matching the tag is then selected and launched with +the remaining command line. + +If no matching runtime is found, and the ``--install`` option is set, it will be +installed and then launched. This is the default for ``py exec``, and also for +``python`` but only when no runtime was requested (which implies that no +runtimes were installed). In all other cases, if no install is found, an error +is printed and the process exits. + + +Install subcommand +------------------ + +.. code:: text + + py install [-s|--source ] [-f|--force] [-u|--upgrade] [tag ...] + py install [-s|--source ] [-t|--target ] [tag ...] + py install [-s|--source ] [-d|--download ] [tag ...] + py install --refresh + +.. note:: + This and all later subcommands are also available under ``pymanager``. + However, as we intend for ``py`` to be the usual command, we only show that + one. + +This subcommand will install one or more runtimes onto the current machine. +The tags are ``Company\\Tag`` pairs (or just ``Tag`` if no slash is included), +and are used to search the index file. Company names match as case-insensitive +prefixes, preferring a full match over a prefix, and tags use case-insensitive, +number-aware matches, with dotted numbers treated as versions. Tags must match +one of the listed "install for" tags, and entries list multiple such tags to +handle abbreviated requests. + +For example, the ``3.10.5`` entry would list all of ``3``, ``3.10`` and +``3.10.5`` as tags to be installed for. A request for ``3.10`` would match one +of these and so the entry is selected. Due to the number-aware matches, a +request for ``03.0010`` would also match, and ``3.10.50`` would not. + +Tags may also be specified as a constraint, using ``>``, ``>=``, ``<``, ``<=`` +or ``!=`` followed by the ``Company\\Tag`` or ``Tag`` value. When matching a +constraint only the primary tag metadata is used for comparisons. Since the +comparisons are version-aware, constraints such as ``>3.10`` will select +3.11 as a minimum, while ``>3.10.0`` may select 3.10.1. + +The behaviour of constraints against arbitrary tags is likely to be unintuitive +in some circumstances. It is anticipated that constraints will mainly be used +with upstream releases, which typically use version-shaped tags, and primarily +for cases where other metadata such as ``Requires-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 information +including package URLs and hashes for all installable versions. An alternate +index may be specified by the user or their administrator (see Configuration +below). Entries in the index file list the full tags they should be installed +for, and if an exact match is found the package will be selected. In the case +of no exact match, a prefix match will be used. In both cases, numbers in the +tag are treated logically - that is, ``3.1`` is a prefix of ``3.1.2`` but not of +``3.10``. + +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 the +existing install; the former will only replace it with a newer version, while +the latter will remove and replace even with the same version. + +Calling the command without providing any tags will install the latest default +version (in effect, the first non-prerelease entry in the index). +Passing ``--upgrade`` with no tags is an error. + +Passing ``--refresh`` will regenerate all metadata and shortcuts for all +installs. This is intentionally applied to all installs at once, as shortcut +prioritisation relies on all installs being consistent (for example, the latest +3.x version should get the ``python3.exe`` shortcut, which gets complicated if +users can choose to only refresh an older install). + +If a ``--target `` option is passed with only a single tag, that runtime +will be extracted to the specified directory without being registered as an +install (or generating aliases or shortcuts). This is intended to cover +embedding cases, or downloading the files for incompatible platforms. Passing +multiple tags with ``--target`` is an error. + +If the ``--download `` option is passed, runtimes will be downloaded to the +specified directory as their source packages, and an ``index.json`` will be +created referencing these files. This index can be referenced later to perform +offline installs with ``python install --source [tag ...]``. + + +Uninstall subcommand +-------------------- + +.. code:: text + + py uninstall [-y|--yes] [--purge] [tag ...] + +This subcommand will uninstall one or more runtimes on the current machine. Tags +are exactly as for the install command, including prefix matching, but only +inspect existing installs. Unless the ``--yes`` option is passed, the user will +be prompted before uninstalling each runtime. + +If the ``--purge`` option is passed with no tags, then (after confirmation) all +runtimes will be removed, along with shortcuts and any cached files. + + +List subcommand +--------------- + +.. code:: text + + py list [-f|--format ] [-1|--one] [--only-managed] [tag ...] + py list [-f|--format ] [-1|--one] [--online] [--source ] [tag ...] + py [--list|-0] + py [--list-paths|-0p] + +This subcommand will list any or all installs matching the specified tags or +ranges. If no tags are provided, lists all installs. Runtimes not managed by +PyManager (including an active virtual environment) may be listed separately. + +The default format is user-friendly. Other formats will include machine-readable +and single string formats (e.g. ``--format=prefix`` simply prints ``sys.prefix`` +on a line by itself). The exact list of formats is left to implementation. + +If ``--one`` is provided, only the best result is listed. This is to assist +shell scripts that want to locate the default (or a suitable) runtime without +launching it. (Note that "best" is loosely defined, but will always be the +user's preferred default environment if it is included in the results.) + +The ``--only-managed`` option omits runtimes that were discovered but are not +managed 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 option +is here rather than on the ``install`` subcommand because the filtering and +formatting options are already available on ``list``. + +The legacy ``--list``, ``--list-paths``, ``-0`` and ``-0p`` arguments from the +``py.exe`` launcher will also be provided. However, they will not support the +new options listed here, and are limited to reproducing the output from the +existing launcher. Unmanaged installs are not distinguishable in this listing. + + +Help subcommand +--------------- + +.. code:: text + + py help + +This subcommand will display the help text for each specified command, or if +none specified, will show the list of commands. Specifying one command is the +equivalent of ``py --help``. Showing the list of subcommands is the +default action for the ``pymanager`` command. + +The command is added primarily to offer a simple way to tell users how to find +more information: they can be told to run ``py help``. This avoids having to +override or extend the ``python -?`` output, which otherwise forwards to the +selected runtime and already prints at least one screen's worth of text. + +After an automatic install (e.g. running ``python`` with nothing installed), a +message will be displayed telling users that they can run ``py help`` for more +information on how to manage their installs. + + +Environment Variables +--------------------- + +No environment variables can be updated automatically when installing a Store +app, and so no updates will be done automatically. The core commands should +already be available on a correctly functioning machine. + +One directory within the user's PyManager data directory is set aside for +generated aliases. If desired, the user can add this directory to their ``PATH`` +themselves. The contents of this directory will be managed by PyManager, and +will contain executables to directly launch installed runtimes (for example, +``python3.exe`` and ``python3.13.exe`` for an install of Python 3.13). Whenever +aliases are added to this directory, ``PATH`` will be checked and if it is +missing, the user will be presented a message containing the path to add. + +Scripts installed by packages installed into a runtime will be in yet another +directory. Due to the current design, we do not believe it is safe to have them +all install into a single directory, or a directory shared by multiple runtimes. +However, a future development may include a command for PyManager to generate +its own entry points based on metadata in installed packages. + + +Start Menu Shortcuts +-------------------- + +A Start Menu shortcut will be added to launch PyManager documentation in the +user's default web browser. No applications are added to the Start Menu. + +When installing Python runtimes, the install definition may specify Start Menu +shortcuts to create for the install. + + +File Associations +----------------- + +Standard file associations will be created when installing PyManager, and will +launch scripts and packaged apps with PyManager's global ``python.exe`` alias. +This provides sensible behaviour for users who are double-clicking on scripts or +``.pyz`` files. + + +Windowed Executables +-------------------- + +For each of the global aliases described earlier, a ``*w.exe`` also exists. +These launch without creating or attaching a console window, which typically +means they will only display UI created by the script. For example, IDLE always +launches using ``pythonw.exe``, as this avoids an unnecessary native console. + +These commands otherwise behave identically to their console counterparts. + + +Configuration +------------- + +PyManager is configured using a hierarchy of JSON-based configuration files. +Command-line options always override configuration file options. Configuration +files in user editable locations may be disabled by a configuration or +command-line option. + +In ascending order of priority, these will be located: + +* within the app package +* specified by admin-only configuration (see below) +* in the ``base_config`` setting (default: none) +* in the ``user_config`` setting (default: ``%AppData%\\Python\\PyManager.json``) +* in the ``additional_config`` setting (default: ``%PYTHON_MANAGER_CONFIG%``) +* specified with the ``-c`` command line option + +The 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 other +applications or packages. For example, an alternative distribution may want to +include PyManager but have it locate installs from their own index. The app +package configuration allows reusing our build and overriding the default +settings. + +The ``user_config`` and ``additional_config`` settings are pre-configured in +earlier configuration files, allowing them to be overridden by admin-only +configuration or an alternate root configuration. If a configuration file +overwrites the setting that caused the file to be loaded, it is ignored. +The ``base_config`` setting is similar, but starts empty and is intended for +easy overriding through admin configuration. + +Admin-only configuration is provided to allow administrators to manage systems +under their control using existing tools, such as group policy or registry +updates. By design, these controls cannot be overridden, such that it is +possible for administrators to deploy policy that prevents or limits the use of +PyManager. These controls are essential to allow PyManager to be deployed safely +into certain environments, and without them, it would simply be disallowed and +those users would have no access to Python. + +The intent is for the main admin-only configuration to be a path to a new +``base_config`` configuration file that an administrator can deploy to any +controlled location. This allows a network administrator to control the source +of their users' default Python runtimes, without forcibly restricting them, or +to override the other sources for configuration files (apart from the command +line option). + + +Index Schema +------------ + +The index file is made available either online or locally, and provides +PyManager with all the information needed to find, select, install, and manage +any Python runtime. + +The index is stored as JSON. The main top level key is ``versions``, which +contains a list of objects. Each version object has its own schema version, and +there is no overall file schema version. Future changes may add additional +top-level keys to provide functionality that cannot be safely integrated into +an existing one. + +Version objects may be split between the index file and a ``__install__.json`` +stored in the root of each package archive. The entries in the bundled file will +fill in any gaps from the index file. This is intended to allow the typically +large ``shortcuts`` key to be removed from the index file, but may also extend +to ``alias``, ``executable`` and ``executable_args``. Omitting other keys from +the index may result in problems installing the package. + +A second top-level key ``next`` contains an optional URL to another index. This +may be used if PyManager cannot find a suitable package in the included +versions. The intent is to allow for older indexes to be archived and only +accessed when required, reducing the size of the initial download without +cutting off users from older versions. + +The initial schema is shown below: + +.. code:: python + + 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 + "displayName": 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. + "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": { + "": str, + } + } + ], + + # Full or partial URL to the next index file + "next": str, + } + + +Shebang Processing +------------------ + +For limited compatibility with scripts designed for sh-like shells, PyManager +will check scripts for a shebang line. A shebang line specifying a Python +command will be used (when not overridden on the command line) to select a +suitable runtime for the script. + +Unlike the support currently in the ``py.exe`` launcher, we propose to reduce +this functionality to only support Python commands where the command matches +a global alias listed for an install. (The existing launcher is able to run any +executable, and attempts to extract version information from the command, rather +than simple matching.) + +The specific patterns to be detected are left to the implementation. + + +Rationale +========= + +"Changing" the python.exe command +--------------------------------- + +It may be argued that the global ``python.exe`` alias provided by PyManager is +"not real Python" and so should use a different name. While this is strictly +true, there are three reasons we argue that it should be used. + +Firstly, thousands of users *daily* install through the Store page after being +led there by having typed ``python`` at the terminal of a clean machine. Due to +how this redirection is implemented, if the app they install does not provide a +``python`` command, then the redirection will remain in place. In order to +ensure that users do not get stuck always going back to the Store, we need to +provide this command. (The same applies to ``python3``.) + +Second, the alternative to the "not real" alias is not "the real" one. It's +nothing. We don't have the ability to replace the global static alias with one +that follows the user's preference or installs, and so the alternative would be +to provide nothing and have ``python`` 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 the ``python`` alias is more +complex than the default ``Programs/python.c``, the experience of using it is +identical. The alias is only launched in the absence of another expressed +preference (that is, there's nothing else on ``PATH``), it respects any +indirect preferences (such as through configuration or shebangs), and it +launches the most appropriate version of Python available on the user's machine. +This is much closer to the desired behaviour of the global ``python`` command +than any alternative. + +TODO: Note that this follows Gentoo's design as well + + +Replacing py.exe +---------------- + +The ``py.exe`` launcher exists to provide some of the functionality that will be +replicated by PyManager - specifically, the ability to launch an already +installed runtime. Despite its long history, the launcher does not seem to have +become the preferred method for most users, with many preferring the global +modifications to the ``PATH`` environment variable. However, the command itself +has come to be relied upon, and should be preserved as long as possible. This is +achieved in two ways. + +Firstly, we install our own ``py.exe`` alias with PyManager that provides the +same functionality, along with PyManager specific functionality. This is +intended to become the default/preferred install of ``py.exe`` over time. + +Second, we generate PEP 514 metadata (when requested) for each install, which +allows a legacy ``py.exe`` to continue to work normally with installs managed by +PyManager. + +Due to how the existing ``py.exe`` launcher configures itself, and how the MSIX +package for PyManager is constrained, it is not possible for PyManager's ``py`` +alias to override the launcher. As a result, users who install the launcher will +always find ``py`` resolving to the launcher. Ultimately, the only way to +resolve this in favour of PyManager is to uninstall the launcher, which can be +done through the standard Installed Apps control panel. + + +Interaction with venv +--------------------- + +An activated virtual environment, as implemented by the standard library +:mod:`venv` module, will modify the user's ``PATH`` environment variable to ensure +that 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 aliases +other than ``python``. + +This means that working virtual environments will behave as they do today with +no additional support from PyManager. + + + +Backwards Compatibility +======================= + +In general, there are no compatibility guarantees to the install process between +minor versions (``3.x`` to ``3.y``), and so "having to use a different +installer" is not considered compatibility breakage. The versions of Python +installed are only impacted by this change to the extent that the install method +modified their behaviour. In general, most installs will be closer to the +behaviour of having been built from source by the user themselves. + +That said, there are a number of changes that will impact certain users when +they do move to a new install process. This section outlines as many of these +changes as we are aware of, in no particular order, and will likely form the +basis of a migration guide. + + +Scripted downloads +------------------ + +Users who wrote scripts to generate the download filename of our old installer +will find those scripts are broken. These URLs were never guaranteed stable or +predictable, and so we have no recourse to do anything other than apologise and +suggest users use our own tooling for downloads. + +The deprecation period for the traditional installer allows time for these users +to learn about the upcoming change. + + +Scripted installs +----------------- + +Users who wrote scripts to execute our installer with particular options will +have to change their script. Most options have been removed, to begin with, and +those that remain have new spelling. Since it is not possible to reach a state +where options for the old installer are being passed to the new without manual +intervention (that is, someone has to change the command already), this is +considered an acceptable change. + +The deprecation period for the traditional installer allows time for these users +to learn about the upcoming change. + + +Old runtime installed +--------------------- + +Users with existing runtimes installed will find them selected by PyManager and +its aliases, provided the registration is not corrupt. + +The priority order among installed runtimes has changed to only include +prerelease versions when specifically requested (for example, ``-V:3`` will +match 3.14.0 rather than 3.15.0a1, but ``-V:3.15`` will match 3.15.0a1), and to +correctly sort text suffixes on tags (for example, 3.14t is now *lower* +priority than 3.14). + +While it is possible to provide warnings in cases where this may be impacting a +user, such warnings would be considered very noisy (e.g. a message every time +you launch ``python`` because you have a prerelease installed that wasn't +selected) and require complicating the selection logic unnecessarily. This +change will be documented only. + + +Old ``py.exe`` launcher installed +--------------------------------- + +Users who do not manually uninstall an old ``py.exe`` launcher will find that +both their existing and new installs of Python are found, though where versions +match the existing install will take priority over the new install (whereas the +new ``py`` would select the new install). + +They will also find that commands such as ``py list`` do not work. The solution +here is to use Windows Settings to uninstall the launcher. + +There is no way to detect that a user has accidentally left an old ``py`` +installed, or to remove it for them. This change will be documented only. + + +Misconfigured venv activated +---------------------------- + +Users who activate a corrupt or misconfigured virtual environment that is either +missing its ``python.exe`` or has it not on ``PATH`` may receive a different +error from before. + +PyManager's global ``python`` alias will be found and executed instead, +suppressing any system "not found" error. As it fails to find the environment's +actual runtime, it will then fail, though the code and message may be different. + +As this scenario requires an already corrupt system, this change will be +documented only. + + +Old version availability +------------------------ + +Python versions prior to the first release of PyManager can be backfilled into +the python.org index, either based on newly repackaged archives or using the +almost equivalent packages from Nuget (the latter does not include Tcl/Tk, +making them significantly incompatible for some users, but this is likely okay +for especially old versions). + + +Administrator installs +---------------------- + +Installing a copy of Python for all users is no longer possible, as PyManager +will only install into the user's own directory. No scenario has been presented +to show that per-machine installs are in line with our intent for the upstream +distribution, and so we will simply not provide an option for them. Third +parties who desire this functionality are encouraged to provide their own +distributions. + +PyManager can only be installed for all users, and can be extensively configured +by an administrator, including to constrain the actual runtimes which users may +install. Additionally, PyManager supports local extraction for bundling, and so +embedding apps can easily generate their own layout, which can be installed for +all users if they so desire. + +As this scenario requires administrator intervention with or without any +changes, this will be documented only. + + +Build-time installs +------------------- + +Users currently using Nuget packages will also have to change to a new workflow. +Further investigation is required to determine how best to support this, as it +is possible that the PyManager MSIX package may not be installable on all +continuous integration systems. No differences are anticipated between a package +installed by PyManager compared to one installed by Nuget. + +Users using the embeddable distro may have to change to a new method for +discovering the URL to the packages, though the recommendation would be to use +PyManager to discover and install. No differences are anticipated due to the +change of installer, and the embeddable distro package would be identical to +today. + + +Security Implications +===================== + +In this section we compare the security implications of the installer itself to +the existing installers. The implications of Python being installed on a machine +are out of scope, and the ability of a malicious user to execute the installer +is also out of scope. + +The typical risk introduced by an installer is that an elevated install may make +changes to a system that allow a low-privileged user to later affect a +high-privilege user, for example, by inappropriately setting access control on +shared 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, due +to using older installer technology. Typical users are directed towards the MSIX +or Windows Store install paths, which are safe, and it is assumed that users +of the MSI are capable of ensuring the security of their install process (for +example, by correctly quoting their commands to launch the installer and +ensuring the initial system configuration is suitable). + +Once PyManager is installed on a machine, it is likely that malicious users will +use it to install Python. The admin-only configuration described earlier in +"Configuration" is intended to control these scenarios. Ultimately though, an +attacker who can run PyManager is able to do whatever the user can do, and only +a complete application whitelisting approach can prevent the use of Python. + +TODO: Notes about security of package acquisition (tl;dr: TLS) + +Runtime installs by PyManager are fully accessible by, and modifiable by, the +current user. This is equivalent to typical installs using the traditional +installer or a Nuget package, but is more vulnerable to tampering than a Store +install or a per-machine install with the traditional installer. It is not +possible to fully protect an install from the user who installed it. + +The aliases generated by PyManager when installing a runtime are designed to +use a signed, unmodified executable that uses an adjacent data file to launch +the correct target. This can be easily abused to direct the launcher to launch +an alternative, however, the only way to resolve this would sacrifice the trust +in 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 user +may launch, or any part of the standard library. Importantly, since aliases are +not 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 useful +functionality to some users, as it would allow an install to be completely +unmodifiable by the regular user (excluding virtual environments and the user +site folders). Such functionality may be manually imitated by an administrator +using PyManager and other OS commands, but it is not considered a critical +workflow. The recommended alternative is for an administrator to provide +PyManager and override its configuration. + + +Impact on Existing PEPs +======================= + +This proposal would effectively replace :pep:`397` ("Python launcher for Windows") +and :pep:`486` ("Make the Python Launcher aware of virtual environments") by +defining the same functionality as part of a new tool with the same name. Both +are already considered final, and the launcher is defined by its documentation +and normal compatibility processes. New functionality is based on the current +implementation, and not the original PEP text. + +This proposal has no impact on :pep:`394` ("The “python” Command on Unix-Like +Systems"), and is believed to be consistent with it in devising an approach for +Windows that allows similar guidance to be given to users on all platforms. + +This proposal has no impact on :pep:`514` ("Python registration in the Windows +registry"), and in fact improves our ability to follow it with a more flexible +system for registering our own runtimes. Tools that follow PEP 514 will find any +runtimes that choose to use the registration, regardless of how they were +installed. + + +How to Teach This +================= + +Basic Use +--------- + +A central goal of this proposal is that "type 'python' in your terminal" will be +sufficient instruction for the most basic cases. Thanks to the redirector added +by Microsoft, following this instruction will at least result in something +useful happening, and with PyManager we can ensure that "something useful" means +that the user is running the latest version. + +To explain what is actually happening, we propose the following as introductory +text: + +.. code:: text + + Python installs on Windows are managed using an installer tool. After it has + been installed, you can run ``python`` to launch the interpreter, and it will + choose the best version already installed, available online, or referenced by + the script you are launching (if any). If you have a preference for a + particular version, you can specify it with ``py -V:`` followed + by the rest of your command. + + To install a version of Python without running any command, use ``py install + ``. You can see all of your installs with ``py list`` and remove them + with ``py uninstall ``. Run ``py help`` to see all the options that + are available. + + Because each version of Python will be shared by all your projects, we + recommend using virtual environments. This will usually be created for a + particular Python version by running ``py -V: -m venv .venv``, and + activated with ``.venv\Scripts\Activate``. Now, rather than the install + manager, ``python`` or ``py`` will always launch your virtual environment, and + any packages you install are only available while this environment is active. + To get access to the manager again, you can ``deactivate`` the environment, or + use ``py ``. + +Many Python projects include information about how to launch their projects as +part of their own README files. Historically, such information has been +complicated due to the range of options available to users. We propose that, +after the install manager is published, such guidance could be written along +these lines: + +.. code:: text + + To install and use our application, first install Python following the + guidance 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, then +the ``python`` or ``python3`` command can be shown, and on Windows both will +operate as intended for users with the install manager. + +Instructions currently referring to ``py`` for Windows can continue to do so, as +the install manager provides a practically equivalent command. Projects that +wish to provide Windows-specific instructions, such as by using the ``-V:`` +or ``--install`` options to install the correct version, should also link to the +:ref:`documentation ` as guidance for +ensuring that the install manager is installed. + + +Uninstallation +-------------- + +Complete uninstallation is an important topic to cover before a user is likely +to consider removing the install manager. Since not all parts of installs can be +automatically cleaned up when removing the manager, we choose not to remove most +of them. So while the default ``python`` and ``py`` commands will go away, all +the runtimes that were installed are still present and usable. + +We suggest an explanation like this: + +.. code:: text + + Before you uninstall the Python install manager, you'll want to uninstall any + runtimes 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 left + behind. If you already removed the manager, you can reinstall it and run the + above uninstall command again to clean up. Individual runtimes can be + uninstalled by replacing the ``--purge`` option with the tag, found by looking + at ``python list``. + + +Configuration +------------- + +Configuration files are a common feature that will be documented, but do not +need to be taught to regular users. Similarly, advanced deployment options, such +as those that might be used by system administrators or organisations wanting +their users to use a preferred index, are best covered in reference material. + + +Custom Index +------------ + +We suggest that indexes only need to be introduced when instructing users to +install a specialised runtime or distribution. Administrators seeking to provide +an index are anticipated to actively seek out the relevant information in the +documentation. + +To explain how and when to use an alternate index, we propose text along these +lines: + +.. code:: text + + Our distribution can be installed on Windows using the Python Install Manager + (include link) by referencing our index: + + ``py install --source latest`` + + This index contains all our versions. Use ``py list --source `` to + see everything that is available. + + +Reference Implementation +======================== + +The reference implementation is available at https://github.com/zooba/pymanager/ +with a precompiled MSIX package under the Releases at +https://github.com/zooba/pymanager/releases. This sample includes a bundled +index, rather than a hosted one, and references a range of existing Nuget +packages to allow install testing. + + +Rejected Ideas +============== + +Make PyManager available on all platforms +----------------------------------------- + +While we are not inherently opposed to this idea, it relies on many more +components being aligned before it can become possible. + +Firstly, as it stands, the reference implementation has a lot of +Windows-specific knowledge. Equivalent knowledge for other platforms would need +to be collated and implemented, as well as any additional behaviours specific to +non-Windows platforms. + +Second, we need a source of pre-built, relocatable binaries that can be +extracted onto the system. While such sources do exist, due to our position in +the supply chain, we cannot justifiably use them (they should be using us). For +Windows, our own binaries already meet these criteria, so we can repackage them +without modification. + +Third, the current implementation relies on a bundled Python runtime, which must +be isolated from any user interference for obvious reasons. This would also +require the relocatable binaries mentioned above, which we currently only have +for 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 those +platforms, we consider this idea out of scope for this PEP. It may be pursued in +the future. + + +Include a runtime pre-installed with the manager +------------------------------------------------ + +The proposal is to have a full Python runtime included with PyManager, so that +its ``python.exe`` alias can refer directly to it rather than resolving to the +best available version dynamically. + +It is very important for stability and updates that runtime releases are +fully independent of the manager. Updating the manager should be possible +without affecting any existing runtime installs, and likewise there should be +no requirement to update the manager to get a newer runtime. + +Hypothetically, if we were to include Python 3.14.0 with the manager such that +it did not need to be installed, it would be a breaking change to later replace +that with 3.15.0. As we only have a single install for the manager, this would +result in the newest installs getting the oldest runtime. + +This would also ignore the status of PyManager's ``python`` alias as being of an +unspecified version - when the user is launching this alias, it's because they +didn't care what version they get enough to specify one. In that situation, we +ought to select the best available, and allow them the options to stabilise it +as is appropriate (whether through a shebang or an active environment). + + +Include a runtime INSTEAD OF the manager +---------------------------------------- + +This is the current situation, which we are trying to change. If you made this +argument, and somehow still read this far, please go back and start again. + + +Use a built-in module rather than subcommands +--------------------------------------------- + +Two alternatives to using commands like ``py list`` or ``py install`` that have +been proposed are to use either dedicated modules, invoked like ``py -m list`` +and ``py -m install``, or a single dedicated module invoked like ``py -m manage +list``. This idea is rejected on the basis that it attempts to reuse existing +semantics for a scenario that cannot be reliably implemented by those semantics, +and so will require a special case that is harder to explain, understand, and +maintain. + +The main reason this idea is rejected is due to the interaction of two otherwise +desirable semantics: first, that the default ``py`` command should launch the +latest available runtime as if it were launched directly; and second, that the +behaviour of ``-m`` should not be treated as a special case in some +circumstances. If the first part were dropped, we would freely modify the +command to behave as users expect - nobody would be raising compatibility +concerns at all if we were agreed to completely break compatibility. However, if +the second constraint were dropped, users would bear the burden of the ensuring +confusion. (We aren't proposing dropping either - this is a rejected idea, after +all - but it helps to illustrate what the options are.) + +First, since one of the subcommands is intended to install your first runtime, +we cannot treat ``python -m [manage] install`` as if it is running through the +default runtime - there isn't one! It inherently requires special case handling +in 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 initial +``sys.path`` for matching module names. This is a considerably more broad search +than a bare name. ``py -m install`` would gladly execute ``install.py``, +``install.pyc``, ``install.pyd``, ``install\\__init__.py``, and more after +searching a number of directories found by inspecting the file system, the +environment, the registry, as well as any transitively included paths found in +those. Compared to ``py install``, which would *only* look for a file called +precisely ``install`` in the current working directory, the ``-m`` behaviour is +far more likely to be already relied upon by real scenarios. (For example, +Django projects typically have a ``manage.py`` script, meaning that ``py -m +manage`` would always behave incorrectly.) + +Changing ``py -m install`` to *not* behave like ``-m``, but instead to execute +an internal command, is vastly more likely to break users than changing +``py install``. As such, this idea is rejected. + + +Use a new command-line option rather than subcommands +----------------------------------------------------- + +A reasonable alternative to subcommands is to specify their names with leading +punctuation, like an option rather than a subcommand. For example, this may look +like ``py /install ...`` rather than ``py install``, or ``py --list``. Because +some of these are currently errors for a normal CPython interpreter, they +could be added without any backwards compatibility concern. + +Notably, however, the typical Windows format of a leading slash is not an error +in CPython. Windows users therefore cannot directly transfer existing knowledge +and must learn a new way to specify options. As we are proposing a Windows +specific tool, this is a terrible start. Additionally, those users familiar with +Unix-style command lines will recognise the misuse of options as commands. + +We desire to create a clean interface, and starting with a design that includes +obvious warts or learning challenges is counter to that goal. Modern tools +universally use subcommands for these purposes, and so the idea to use something +different is rejected. + + +Improving the current traditional installer instead +--------------------------------------------------- + +Rather than creating a new install mechanism, we could invest in maintaining the +current installer. At this stage, however, our current installer is based +entirely on retired technology. Windows is no longer developing the Windows +Installer service, and Wix are no longer improving the version of their toolset +that 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 Windows +Installer is not used for CPython, and generally has caused more issues than it +has ever solved (for example, accidental downgrades due to automatically +collected file version information). + +The implementation of the Burn bundle, which is our primary source of installer +logic, is in C++ and integrated into a framework that few core developers are +familiar with. This makes maintenance challenging, and is not a good long term +position to take. Migrating desired features such as registration-free installs +into the Burn bundle is not possible (without writing the end-to-end +reimplementation and integrating it as an afterthought). + +Our view is that maintaining the current traditional installer is at least as +much effort as implementing a new installer, and would not provide meaningful +benefits for the core team or for our users. As such, this idea is rejected. + + +Delete the Store package completely +----------------------------------- + +Removing the Store packages would reduce the number of options users face when +choosing a Python runtime. By all measures apart from reliability and security, +the traditional installer is entirely sufficient as a substitute. The effort to +migrate parts of the ecosystem to more secure settings (such as not relying on +DLL hijacking) has largely occurred, but some packages remain that still only +work with less secure configurations, and moving all users back to these +configurations would ensure that users of these packages would not face the +issues they face today. + +However, the majority of users of the Store packages appear to have no +complaints. Anecdotally, they are often fully satisfied by the Store install, +and particularly appreciate the ease and reliability of installation. (And on a +personal note, this author has been using Store packages exclusively since +Python 3.8 with no blocking issues.) + +The greatest number of issues have been caused by misconfigured ``PATH`` +variables and the default ``python.exe`` redirector installed by Microsoft. In +other words, entirely unrelated to our own package (though sometimes related to +unresolvable issues in our other installer). For the sake of the high number of +successful installs through this path, we consider the burden of diagnosing and +assisting impacted users to be worthwhile, and consider the idea to simply drop +the Store package rejected. + +That said, when PyManager is published to the Store, we would plan to delist all +existing runtimes on the Store to ensure users find the manager. This only +impacts new installs, and anyone who has previously installed a particular +version (even on another machine, if they were logged in) will be able to +continue to use and install those versions. + + +Rely on WinGet or equivalents +----------------------------- + +WinGet, Chocolatey, and other similar tools are not installers in the sense that +we require. They use their own repository of metadata to download, validate, and +run installers. Without our own installer, they have nothing to run, and so +cannot be used. + +It is possible that their metadata will not support installing PyManager and +then running it to install a particular runtime. If this is the case, they may +need to investigate using our binary packages directly. + +Currently, none of these install tools are officially supported by CPython, and +so we have no obligation to make them work. + + +Make every version a Windows Store package +------------------------------------------ + +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 of +overwhelming the user, while greatly simplifying our own reponsibilities for +package management. + +This approach would leave a significant burden on whichever contributor has +access to the Store publishing interface, as updating packages is a manual +operation. Additionally, it would leave every Python runtime with the technical +limitations outlined earlier. As such, this idea is rejected. + +Making every version a MSIX package rather than a ZIP, even though this avoids +the Store publishing interface, would still impose technical limitations on +users. It is also rejected. + + +Just publish the plain ZIP file +------------------------------- + +Publishing the plain ZIP file is part of the plan, however, it will not be +visibly listed (for example, on the python.org downloads pages, though they will +be visible in the FTP view). An alternative would be to publish and list these +packages, 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 configure +a Python install at all. Not only do they not want to choose the install +location, they do not want to choose a version, or even have to search for a +download provider or instructions. However, they do want to be able to find an +install later, launch, update or remove it, or list all known installs. + +It is also worth recognising that there will be more ZIP files than are +currently listed on the Download pages, and so the list of files will become +longer. Choosing the correct download is already challenging for users (those +who bypass the primary "Download" button and view the list of all available +versions 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 to +use 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 download +and extract operation, allowing users to have the same experience as a ZIP file. + + +Only publish PyManager to one place +----------------------------------- + +Whether the Windows Store or python.org, it would be viable to publish to only +one location. + +However, users strongly expect to be able to download *something* from +python.org. If we were to remove any option at all, we would inevitably hurt our +users. Without an MSIX available on python.org, users have no way to transfer +the package to another machine, or to fully script the initial install of the +manager. + +Many users rely on the Windows Store app to install packages, and the built-in +redirector in Windows can only open to a Store page. As such, removing the Store +app is equivalent to denying hundreds of thousands of installs each month. + +Additionally, automatic updates are only supported through the Store. We would +have to implement automatic updates manually if we did not publish there. It is +possible to have the MSIX from python.org find its own updates on the Store, and +we can assume that machines without access are responsible for their own +updates. + +The two builds are practically identical. The only difference between the MSIX +we 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 as +part of the publish process. Otherwise, there is no additional cost to producing +and publishing both packages. + + +Inline Script Metadata +---------------------- + +PEP 723 introduced inline script metadata, a structured comment intended for +third-party tools to interpret and then launch a Python script in the correct +environment. An example taken from that PEP: + +.. code:: python + + # /// script + # requires-python = ">=3.11" + # dependencies = [ + # "requests<3", + # "rich", + # ] + # /// + +PyManager has no integrated support for installing dependencies, and does not +propose adding any. As a result, we could not fully implement handling of this +metadata, and as we consider partial handling to be worse than nothing, we +choose not to implement any. + +It is possible for a user to specify the constraint directly as an option, for +example, ``py -V:>=3.11 my-script.py`` to get the selection behaviour. + +We could also detect the metadata and warn if the selected runtime does not +match its requirement, but this is not part of the initial proposal. + + +Open Issues +=========== + +TODO: Raise open issues + + +Footnotes +========= + +TODO: Collate references + + +Copyright +========= + +This document is placed in the public domain or under the +CC0-1.0-Universal license, whichever is more permissive.