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:
site.getsitepackages()
, iterate through the directories and check for the existence of the given package directories (i.e. package1-{version}.dist-info
or pacakge1-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 distributionspip list
or pip show package1
from within setup.py - this does not seem to work when the setup script is executed via pip install .
as pip is not on the import path itselfpkg_resources.working_set
works with python setup.py install
but not with pip install .
probably for similar reasons as calling pip doesn't work: the working set contains only wheel
and setuptools
when calling the setup with pip 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.)