Can 3rd party modules (ex. SciPy) be installed when an add-on is installed?

Trying to use SciPy in an add-on such that it is automatically installed when users install the add-on.

Related discussions took place a few years ago (here’s one). But as this user notes, a lot of solutions would require end users to install a module before installing an add-on.

Why not have in the init method of your addon check for scipy, if not there run a python.exe subprocess to an external script to install it via pip?

3 Likes

We do that for the Rhinoceros 3D importer import_3dm - bootstrap pip using ensurepip, then install into a user script path that is in Blender sys.path using subprocess to all the Python executable that is bundled with Blender.

1 Like

Thanks @bsavery & @jesterKing. Provided a solution to the linked question. Happy to incorporate additional feedback should you think of anything.

Does this assume that the computer has an aactive internet connection? Or are you talking about installing it from some kind of zip bundle?

That is one downside. Another is that complex things like scipy often have other dependencies, dependencies which sometimes need to be compiled.

1 Like

just a heads up when blender is installed into program files on windows, that code will have run as administrator since regular users do not have write permissions there.

2 Likes

@kurk I see that @stiv and @LazyDodo already pointed out the obvious issues.

For the ensurepip part I suggest using the --user argument. And maybe it is even possible to specify a separate location outside of --user, but still writable for the regular user (think bpy.utils.script_path_user).

Then for actually using the bootstrapped pip to install modules definitely use bpy.utils.script_path_user() as a location. I believe that one of the sys.path entries is bpy.utils.script_path_user()+/addons/modules. This I use to install the rhino3dm dependency for my add-on import_3dm.

3 Likes

Revisiting this after encountering issues with 2.83. An import scipy call is failing with a No module named 'scipy' error. The sub-process installation works well, and python recognizes that the dependency (scipy) has been installed locally. But 2.83 doesn’t seem to be making use of it. Still works on other local Blender builds. Haven’t been able to find anything related within the release notes. Probably missing something obvious. Might also be misunderstanding @jesterKing’s last post.

Here’s an example of how it’s being installed:

import bpy
import subprocess

py_exec = bpy.app.binary_path_python
# ensure pip is installed
subprocess.call([
    str(py_exec),
    "-m",
    "ensurepip",
    "--user"
])
# update pip
subprocess.call([
    str(py_exec),
    "-m",
    "pip",
    "install",
    "--upgrade",
    "pip"
])
# install packages
subprocess.call([
    str(py_exec),
    "-m",
    "pip",
    "install",
    "--user",
    "scipy"
])

Instead of --user, one can also use pip's --target option and provide a directory relative to Blender python executable.

At least on macOS, --user installs on ~/.local which is not in sys.path.

2 Likes

The module was installing itself in the appdata folder.
Thanks to the last reply I managed to piece it back together.
I forced installing in local environment by replacing the last line with
subprocess.call([str(py_exec),"-m", "pip", "install", f"--target={str(py_exec)[:-14]}" + "lib", "your_module"])

By the way the console kept bugging me to replace bpy.app.binary_path_python by sys.executable so I changed that too.
I didn’t need to launch in administrator mode (Windows).

Full script :

import subprocess
import sys
import os
from pathlib import Path

py_exec = str(sys.executable)
# Get lib directory
lib = os.path.join(Path(py_exec).parent.parent, "lib")
# Ensure pip is installed
subprocess.call([py_exec, "-m", "ensurepip", "--user" ])
# Update pip (not mandatory)
subprocess.call([py_exec, "-m", "pip", "install", "--upgrade", "pip" ])
# Install package
subprocess.call([py_exec,"-m", "pip", "install", f"--target={str(lib)}", "your_package"]
2 Likes

Hello, I just found this extremely valuable piece of code (at least for me) and was wondering why it’s so hard to find any trace of this approach, especially in the doc? is there a reason why pip doesn’t seem to be mentioned at all?

Thanks anyways !

probably because it’s a hacky workaround.

I’ve been trying this approach with no luck, I did go to the site_packages folder and found a read me that directed me to site.py, based on comments it is what I’m looking for to add directories to blenders sys.path but I’ve stalled, anybody find a good solve to this?