SPL Bootstrap - Handle Python Version#
Introduction#
The pipeline implementation for our Software Product Line (SPL) repositories uses the pypeline Python application.
In order to start the pypeline application, we need to install Python (with a specified version) and create the Python virtual environment.
This step we call bootstrap and it is implemented here.
Note
Currently bootstrap supports only Windows for installing Python.
Workflow#
The bootstrap process is managed by two main scripts: a PowerShell script (bootstrap.ps1) for environment setup and a Python script (bootstrap.py) for dependency management. The diagram below shows the high-level workflow.
flowchart TD
A[bootstrap.ps1] --> B{Python installed?};
B -- No --> C[Install Python w/ Scoop 1️⃣];
B -- Yes --> D;
C --> D[Execute bootstrap.py];
D --> E{Dependencies changed?};
E -- No --> F[End];
E -- Yes --> G[Create/Update .venv 2️⃣];
G --> H[Install Dependencies];
H --> F;
This step will first install the
scoopwindows package manager and then callscoopto install the configured python version.The python virtual environment is updated in multiple steps:
create an empty virtual environment with python
venv.createinstall the package manager (e.g., poetry, uv, etc.) and
pip-system-certsfor using the system SSL certificatesrun the package manager to install the python dependencies
bootstrap.ps1#
Scoop configuration and installation
Python version detection and installation
Delegates to
bootstrap.pyfor virtual environment setup
bootstrap.py#
OS-agnostic virtual environment creation (Windows/Unix)
Smart caching with hash-based dependency tracking. Only runs if dependencies have been updated.
Package manager support: Poetry, UV, Pipenv
Automatic pip configuration for custom PyPI sources
bootstrap.json Configuration#
{
"python_version": "3.11",
"python_package_manager": "poetry>=2.1.0",
"scoop_ignore_scoopfile": true
}
Things to Improve#
Python Version Management#
Currently the bootstrap process installs a fixed Python version as specified in the bootstrap.json configuration file.
When checking if python is installed, it only verifies that the major and minor version match (e.g., 3.11),
but does not check for patch versions (e.g., 3.11.4 vs 3.11.5).
This can lead to situations that on different machines, slightly different patch versions of Python are installed.
Note
This might not be a big issue in most cases, but it can lead to inconsistencies in our particular case,
because we use the python venv module to create the initial virtual environment,
which will include the standard library of the installed Python version.
The solution could be:
to find all installed python versions in path and check if the exact version is already installed
it might be that python versions installed with scoop are not available in path, so we need to query scoop for installed versions
if the exact version is not installed, install it with scoop
the
bootstrap.pyshall fail if the python interpreter version does not match exactly the configured version. This can happen if the user runs thepypelineincluding theCreateVEnvstep which calls directly thebootstrap.pyscript.
Virtual Environment Management#
As mention above, the virtual environment is created in three steps:
create an empty virtual environment with python
venv.createinstall the package manager (e.g., poetry, uv, etc.) and
pip-system-certsfor using the system SSL certificatesrun the package manager to install the python dependencies
There is a problem with the second step: the package manager and pip-system certs are installed with pip.
These packages have their own dependencies, which are not tracked by pip because pip has no support for .lock files.
When step three is executed, the package manager might need to upgrade/downgrade some packages which were implicitly installed in step two and this can cause crashes due to dependency conflicts.
Solution 1: User-defined Initial Packages#
One way to solve this is to let the user define the list of package to install in step two in the bootstrap.json configuration file.
For example:
{
"python_version": "3.11.4",
"venv_initial_packages": [
"poetry==2.1.0",
"pip-system-certs==2.2.1",
"wrapt==1.14.0"
],
}
In case there is a conflict between the initial packages and the packages defined in the package manager lock file, the user can adjust the versions in the configuration file accordingly.
Solution 2: Install Package Manager with Scoop#
Another way could be to install both python and the package manager with scoop in the bootstrap.ps1 script,
so that pip is not involved at all in step two. This means that package manager will install exactly the version specified in the .lock file
and therefore always have a consistent set of dependencies.
The problem with this approach is that pip-system-certs is not available as a scoop package
and package installation will fail when ran against an on-premise PyPI server with self-signed certificates.
Package manager command#
Currently the command to install dependencies with the package manager is hardcoded in the bootstrap.py script
with extra arguments being supported via the bootstrap.json configuration file.
{
"python_package_manager_args": "--clean"
}
We added the feature to support extra arguments because we needed for some projects to pass the --clean to pipenv
to remove unused packages already existing in the virtual environment.
A better approach would be to let the user define the full command to install dependencies with the package manager. For example:
{
"venv_install_command": "poetry install --no-dev --clean"
}
This would give the user full control over how dependencies are installed.
Conclusion#
If all these improvements are implemented, the bootstrap process will be more reliable and flexible, ensuring consistent Python environments.
The configuration will allow users to tailor the bootstrap process to their specific needs.
{
"python_version": "3.11.4",
"venv_initial_packages": [
"poetry==2.1.0",
"pip-system-certs==2.2.1"
],
"venv_install_command": "poetry install --no-dev --clean"
}
This configuration will ensure that:
Python 3.11.4 is installed
The package manager and pip-system-certs are installed with the specified versions
Dependencies are installed with the specified command
Have fun bootstrapping! ✌️