Notes on Python editable installs

This page is managed by StJohn Piano.

Notes on Python editable installs

If you have any questions, comments, or suggestions - please contact StJohn Piano on Tela:
tela.app/id/stjohn_piano/7c51a6


Situation: You want to build a feature that will require changes to multiple Python packages that are in a dependency chain

It will be easiest to edit all the packages simultaneously.

This can be accomplished by using "editable installs" - the parent package will install a link file in its virtualenv that points to your local copy of the child package.

Any changes that you make in the local copy of a dependency package will be immediately reflected within the virtualenv of the parent package.

You can then work on all the packages at the same time, using a branch on each package repo with the same name e.g. feature/20240101_feature_name, until the feature is ready. Then you can go through the merge process for each package repo.

Demo

I have developed two simple Python packages:

https://github.com/sj-piano/python3-editable-installs-1

https://github.com/sj-piano/python3-editable-installs-2

python3-editable-installs-1 imports python3-editable-installs-2.

python3-editable-installs-2 has been released on Github, so there's a tag that can be used for specifying the package version.

I assume that you've aliased python to python3.

Open a terminal.

mkdir editable && cd editable

git clone git@github.com:sj-piano/python3-editable-installs-1.git

git clone git@github.com:sj-piano/python3-editable-installs-2.git

cd python3-editable-installs-1

python -m venv .venv

. .venv/bin/activate

pip install -r requirements.txt

Here's the contents of requirements.txt:

# PyPI imports
pytest==8.0.0

# Github imports
python3-editable-installs-2 @ git+https://github.com/sj-piano/python3-editable-installs-2@v0.1.1

Now if I run pip freeze, I see this output:

(.venv) stjohn@horizon python3-editable-installs-1 % pip freeze
iniconfig==2.0.0
packaging==23.2
pluggy==1.4.0
pytest==8.0.0
python3-editable-installs-2 @ git+https://github.com/sj-piano/python3-editable-installs-2@acbdb57c1744354c147deff3175b7e0a08e18ddf

Note: Although I specified a tag for python3-editable-installs-2 in requirements.txt, the tag is mapped to a commit hash, which is then used.

Ok, now that python3-editable-installs-1 has been set up, we can change python3-editable-installs-2 to be an editable install of the local copy of the package.

pip install --no-deps --editable ../python3-editable-installs-2

We don't need to uninstall it first. The new pip install command will overwrite the existing package.

We use the --no-deps option to prevent pip from changing any dependencies of the target package. This becomes useful in the situation where we are editing 3 packages simultaneously, for example if python3-editable-installs-2 had another child package called python3-editable-installs-3.

Now, run the test (stored in test/test_baz.py):

pytest test

This should succeed.

Now, in the local copy of python3-editable-installs-2, open the file editable_installs_2/foo.py and change the value of x from 1 to 2.

Now re-run the test command pytest test. It should fail.

Conclusion

What's happened here ? Well, you've changed the local copy of a dependency, and this change has been reflected immediately in the parent package that imports it.

This means that you can work on both packages simultaneously.

I recommend creating a new branch in each package repo, with the same name e.g. feature/20240101_feature_name. When the feature is ready, go through the merge process for each package repo.

This approach can be extended to 3 or more packages in a chain. Be sure to use the --no-deps option when making each editable install.

Extra

  • The PyCharm editor can't follow the editable install links. It will apply a red underline to the name of the editable package in the code. However, it can still run the tests.

Troubleshooting

If you get this type of error: ImportError: cannot import name '<foo>' from 'python-editable-installs2' (unknown location)
Then look at your PYTHONPATH variable ( echo $PYTHONPATH ), and try adding the path to the package manually ( export PYTHONPATH=$PYTHONPATH:/path/to/package )

If you're using PyCharm, then you'll have to open the Project Settings and manually add a new Content Root that points at the package. You'll then have to remove it again if you want to switch back. Note: Don't change the PYTHONPATH variable.

Sources

https://pip.pypa.io/en/stable/topics/local-project-installs

https://setuptools.pypa.io/en/latest/userguide/development_mode.html

https://pip.pypa.io/en/stable/cli/pip_install


Follow Tela Network on LinkedIn:
linkedin.com/company/tela-network

Follow Tela Network on Twitter:
twitter.com/tela_updates

Join Tela Network and become a consultant:
tela.network/join

Join the Tela Social channel on Telegram to get every new update:
t.me/tela_social

Follow Tela Network on Instagram:
instagram.com/tela_updates