Let’s say that we have Windows wheels for a CLI. To take a simple but realistic example, one can consider the CLI black
(a Python console-script entry point) and the wheels that are installed with black[jupyter]
.
My real motivation would be creation of apps and installers for Mercurial (a CLI) and potentially also TortoiseHg (a GUI), but this would be more complicated so let’s first consider the simpler case of Black.
I learned that tools like pipx
or uv tools
have downside on Windows, in particular for security and, consequently performance.
Example for black installed with pip in a virtual env (created from Python installed from the official installer):
$ Measure-Command { black --version }
TotalMilliseconds : 820
$ Measure-Command { C:\Users\me\venv-black\Scripts\python.exe -m black __version__ }
TotalMilliseconds : 250
The difference (approximately half a second, i.e. going to a startup time somehow acceptable for a CLI to something really slow leading to a bad UX) seem to be due to virus scan done each time black.exe is launched. The virus scan is triggered because black.exe is not considered safe because it is a modified binary created by distlib via pipx (see About .exe wrappers created by frontends when installing wheels on Windows? - #9 by pf_moore).
I learned that:
So we should create a proper Windows application that would provide the CLI black
globally and its installer.
How can it be done?
It should be quite simple to do. From black[jupyter]
we can get a list of wheels with version pinned. And we have the Python embedded distribution.
But the documentation is not very clear about how this can be done in practice.
- 4. Using Python on Windows — Python 3.13.1 documentation
- 4. Using Python on Windows — Python 3.13.1 documentation
- Deploying Python applications - Python Packaging User Guide
From these, it’s not clear to me how to do what @steve.dower suggested.
What I’d like to avoid would be disutils/setuptools extensions (like py2exe). If possible, I’d like to build the app from wheels, because we already have good wheels built and tested.
There was this thread https://discuss.python.org/t/installer-creation-based-on-distributions in 2023 but without a clear conclusion.
I tend to dislike PyOxidizer because (i) it strives to create a one file binary (which I don’t care and can lead to a lot of potential issue, in particular no data files and no updates/installs of Mercurial extensions), (ii) it’s no longer maintain by its creator.
I read about different tools, like briefcase (very oriented on Beeware tools i.e. GUI so I don’t know if it could be used for a CLI) and pynsist (no .msi installer).
For GUI, I also saw that Spyder has a good installer based on Miniforge and conda-forge.
I wonder if there are good news in this field in 2025.
PS: For my real use case (create an app and an msi installer for Mercurial) it would be great that pip install
would be available within the Python used for the app in order to manage Mercurial extensions.