No pip → No sip
published on Thursday, March 14, 2019
PyQt5 now provide wheels that allow installing directly from PyPI without ever touching an installer exe file. This is awesome! And it used to work great until I ran into this error:
Weird, I got this error only on an automated build, where I was doing something like python setup.py install and having PyQt5 listed there in the install_requires field. The log clearly showed that both PyQt5 and PyQt5-sip were installed and both were on the filesystem.
After some investigation, I found that the problem can be fixed by letting pip perform the PyQt installation beforehand, e.g.:
But what is the reason? It has to do with the fact that PyQt5.sip was split into a separate package from PyQt5.
Now, under the hood, setup.py uses easy_install to install dependencies, which installs the namespace package PyQt5 and PyQt5.sip as separate eggs, but fails to properly setup a namespace package that would leave sip importable even after the main package was imported.
Pip, on the other hand, just installs the contents of both packages into the same folder, which means that sip can be found without problem.
I can reproduce this on my machine. In a fresh virtualenv:
Conclusion
The lesson is clear: pip and setuptools behave very different when used to install packages.
Since pip is a dedicated installer, it is often superior and should be the preferred mode of installation, even during development. I suggest always using pip install over the python setup.py command, even if you have the package checked out locally, i.e replace:
With the introduction of wheels, the responsibilities became clearer than ever before:
- The job of setuptools is to build packages on the developer machine.
- The job of pip is to install packages.
Preferrably you would distribute wheels for all your packages, even in the case of simple pure python packages without C extensions. The end-user should not even need to run any setup script on their machine or even have setuptools installed in most cases. To this end, I don't think there is hardly any reason to write distutils.core based setup scripts anymore.