I'm developing a Python plugin, the target is integrating into QGIS the functionalities of a PyPI Python library called 'elevation'.
Is there an OS independent way of installing external Python libraries and making them available to the Python plugins?
I already know the different system specific procedures for installing an external Python dependency, what I'd like to do is to distribute my plugin across different environments without making people go crazy.
What I already know
Searching the web and other similar questions it seems that there isn't an OS independent solution.
Python is packaged and distributed inside the QGIS package, so in order to install external Python libraries you have to go through the OSGeo4W Shell and use pip from there.
- QGIS standalone and Python modules
- Installing Python setuptools into OSGeo4W Python
- How to install 3rd party python libraries for QGIS on Windows?
OS X Users
In this case QGIS uses the built-in Python which is prepackaged inside OS X and located at:
The issue here is that the default installed pip has some limitations and requires too many privileges.
A quick workaround is to use home-brew to install Python so that your pip can run against a user-modifiable Python framework. See the details of this approach here.
After installing all the Python libraries via pip, you just need to add their directories to the PATH variable.
Alternative way for OS X users
Inside the plugin Python code you can use the pip provided by the system in order to install the required packages. Then you can make the just installed package reachable adding it to the path.
import sys import pip pip.main(['install','--target=/Devel/test', 'elevation']) sys.path.append("/Devel/test")
Homemade but working solution (tested on both Linux and OS X)
I decided to go for the alternative way since it allows to keep the library update and maintenance separated from the plugin. Every time a new user installs the plugin the latest version of the elevation library is directly downloaded and installed by pip inside a subdirectory of the plugin.
self.plugin_dir = os.path.dirname(__file__) self.elevation_dir = os.path.join(self.plugin_dir, 'elevation') # Checking the presence of elevation library try: import elevation except: pip.main(['install', '--target=%s' % self.elevation_dir, 'elevation']) if self.elevation_dir not in sys.path: sys.path.append(self.elevation_dir)