We have multiple versions of our package: package1 and package1-unstable - similar to tensorflow and tf-nightly. These are different packages on PyPi but install the same module. This then causes issues when both of these packages are installed as they overlap and write into the same directories in the site-packages folder. When one is removed, the other package stays but most of the module code is now removed, resulting in an even worse, dysfunctional state.
What is the cleanest way to detect colliding packages?
We can hardcode that package1 and package1-unstable are mutually incompatible. We use setup.py for the installation.
My thinking was to use a wrapper class around the install command class.
class Install(install):
def run(self):
if name == "package1":
self.ensure_not_installed("package1-unstable")
else:
self.ensure_not_installed("package1")
install.run(self)
def ensure_not_installed(pkg_name):
"""Raises an error when pkg_name is installed."""
...
...
cmdclass={'install': Install},
This approach seems to work as a general direction. However, I'm unsure yet about how to list exhaustively the installed packages. I'm testing the approaches with both pip install . and python setup.py install.
A couple of approaches that I tried are:
- use
site.getsitepackages(), iterate through the directories and check for the existence of the given package directories (i.e.package1-{version}.dist-infoorpacakge1-unstable-{version}.dist-info- this can work, but this feels hacky / manual / I'm not confident yet that it's going to work in a portable way across all OSes and python distributions - try to call
pip listorpip show package1from within setup.py - this does not seem to work when the setup script is executed viapip install .as pip is not on the import path itself pkg_resources.working_setworks withpython setup.py installbut not withpip install .probably for similar reasons as calling pip doesn't work: the working set contains onlywheelandsetuptoolswhen calling the setup withpip install .
in the general case you can't implement this as part of setup.py as pip will build your package to a wheel, cache it, and then never invoke setup.py after that. you're probably best to have some sort of post-installation tests which are run in a different way (makefile, tox.ini, etc.)