Well, here it is. All none of you reading this will have eagerly awaited it: The final Python packaging rant.
Opinion
In the following discourse, I will be criticizing a specific person very heavily. I would like to make clear that what I say is my opinion, and whatever I get wrong, is wrong.
History
First, a bit of history. In the beginning, Python for Windows shipped as a single MSI package. This had the usual task-centered MSI user interface with a feature tree, a page to override the installation path, and so on. It was, on the whole, good.
Python has for a long time been a very popular language, so at some point, Microsoft started supporting Python development and, in particular, its convenient deployment on Windows. They had already done the community a great service by making sure WiX was steadily evolving and improving, and apparently decided to hire a central figure in the Python-on-Windows development to further improve things.
This person, either before or after, came up with what must surely be the worst thing that ever happened to Windows Installer: burn. I have a comprehensive rant on the subject somewhere on this site already. In any case, I believe this developer, more than anything, needed a flagship project to demonstrate the awesome power of his creation, and unfortunately for everyone, he seized on Python. The resulting abomination, the Python executable installer, initially replaced a single MSI per platform with 22, and it looks like that number has increased to 25 by now. (Some of these packages do not contain a single file.)
I cannot blame the larger CPython community for this; most developers are centered on *nix and need not care much for how a Python environment makes its way onto a Windows system. The switch from a single MSI to the burn bundle was foisted upon Windows users purely as a consequence of the “peak syllogism”: “We must do something. This is something. Therefore, we must do this.”
After the burn bundle was introduced, at first I tried avoiding it and installing the needed MSIs manually, but that approach was obviously not viable, so I arranged myself with the new regime and used the limited customization features of the burn bundle to set it up to meet my needs.
For some reason that I have not tried investigating because I like my stomach where it is, it appears the time has come to make an even bigger mistake, however. I only noticed this recently, but the burn bundle is now to be replaced by a monstrosity called the “Python Install Manager”, and this thing definitely takes the crown of “worst idea ever”.
I mention this in my burn rant, but it is worth repeating here: The purpose of an application installer is to put the application onto the target system as easily and with as little friction as possible. On Windows, the best implementation of this goal is … an MSI package.
The worst implementation must be something that has to be installed as a separate package first, then run, possibly repeatedly, to create the actual application. The “Python Install Manager” has the following features:
-
It is distributed as both MSIX and MSI packages, with the MSI apparently deprecated ab initio. The MSIX has no customization capability, for example for the installation path, because it springs from Microsoft’s effort to make PCs into larger phones.
-
It does not allow the user to select features to install or omit from the installed Python environment, except that a distribution can provide different feature sets as “tags” if they feel like it.
-
It hijacks the
pycommand for no identifiable reason, and it overlays its subcommands over files that might exist in the file system, i.e.py installinstalls something, it doesn’t run a file named “install”. Despite the absence of the customary file extension, this might actually be a Python script.For some reason it also includes a “pymanager” command, presumably because someone did have a clue, namely that a separate command would fix this problem.
-
It relies (?) on “app execution aliases”, however, it was released with the knowledge that there is a bug in their management that prevents a newly installed application (in this case, the install manager) from overriding an existing alias. Before installing the thing, running
pythonon the command line will take you to the Microsoft Store to download Python. Intrusive, but possibly helpful. After installing the install manager, the same thing happens.
Stable interfaces
Obviously the Python-on-Windows developers, under the questionable leadership of the aforementioned person, do not care about stable interfaces, in this case, maintaining a deployment method for longer than their attention span. In this effort, it has been announced that the burn bundle is going away with Python 3.16, leaving the install manager as the only way supported by CPython to install Python on Windows. While seeing burn burn should be great news, I’m sorry to say that the replacement is, if anything, worse.
Software management
Among the first bugs I ever reported in the burn bundle was that it creates its Uninstall key in HKCU of the installing user. This can have fatal consequences in an enterprise environment where software is managed centrally, because deployment tools usually do their work on the target system using a dedicated user account. Deleting this user profile means losing the most accessible source of information about installed Python environments.
While the install manager MSI itself, to my great surprise, actually manages to create its Uninstall key in HKLM, it absolutely insists on only creating strictly per-user installations. There is an option to redirect the installation to a different path, but if it is used, no Uninstall key is created at all. This means that a software management tool either has to scan all user profiles for Python environments in the prescribed path, or load all user Registry hives. With the burn bundle, it is at least enough to look in the Registry of the dedicated deployment user, even though depending on the tool this may involve loading that profile while the scan is happening.
Without a large amount of work on the part of whatever admin gets stuck with it, this will result in old to ancient Python versions accumulating in user profiles because nobody ever cleans up after themselves.
The fix
A long time ago, when I submitted yet another bug against the burn bundle that included my standard postscript about the advantages of a single MSI, this developer suggested that if I liked that so much more, I should just make my own. At the time I dismissed that idea because I did not want to do all the work necessary to build Python, gather all the bits together, and turn them into a sensible package. However, thanks to the install manager, I noticed that since Python 3.12 or so, there are Zip archives available that contain the entire environment. These are what the, er, monstrosity uses itself, so I presume they will be around until someone comes up with a yet worse idea – I fear that this is possible, unlikely as it may seem right now.
These Zip archives are trivially easy to repackage into MSI form, including the necessary Registry bits to make the existing Python launcher work (another victim to be of the install manager).
https://github.com/chrullrich/wix-cpython/
Ceterum censeo: All the bugs listed above will henceforth be avoided by using MSI as the distribution package format.