0
$\begingroup$

I am working under Blender 2.90 installed by snap.

If I try to run

subprocess.check_call([bpy.app.binary_path_python, "-m", "ensurepip"])

or

import ensurepip
ensurepip.bootstrap()

from within my Addon, I get told, that the site-packages of my Blender's Python are read-only. Is there any way to circumvent this?

$\endgroup$
7
  • $\begingroup$ Is this one helping? python - How to import SciPy in Blender? - Blender Stack Exchange $\endgroup$ – HikariTW Sep 15 '20 at 2:20
  • $\begingroup$ @HikariTW That thread was definitely interesting. However using the mentioned --user option installs the packages under ~/.local/lib/python3.7/site-packages. Is there any way to tell Blender to use those site-packages additionally to those installed under /snap/blender/45/2.90/python/lib/python3.7/site-packages which is unfortunately read-only (otherwise I would have installed my modules there in the first place). $\endgroup$ – TheBeautifulOrc Sep 15 '20 at 12:56
  • $\begingroup$ Which OS/build are you aiming for? I don't think modify snap install folder is a good idea. And if addon need to deal with various OS/condition, ensure pip is definitely not enough $\endgroup$ – HikariTW Sep 15 '20 at 13:11
  • $\begingroup$ I'm on KDE Neon but all I want is for Blender to recognize ```~/.local/lib/python3.7/site-packages````as a place to look for packages. $\endgroup$ – TheBeautifulOrc Sep 15 '20 at 13:33
  • $\begingroup$ Not familiar with kde neon, if you know exactly where the packages are: sys.path.append(R"~/.local/lib/python3.7/site-packages") might work? $\endgroup$ – HikariTW Sep 15 '20 at 13:41
1
$\begingroup$

Thanks to all the help, I was able to piece together a fully automatic solution that works at least on my system (tests on other Linux and Windows machines planned). It looks something like this:

import bpy
import sys
import importlib
import subprocess

# Blender's Python executable
pybin = bpy.app.binary_path_python

def add_user_site():
    # Locate users site-packages (writable)
    user_site = subprocess.check_output([pybin, "-m", "site", "--user-site"])
    user_site = user_site.decode("utf8").rstrip("\n")   # Convert to string and remove line-break
    # Add user packages to sys.path (if it exits)
    user_site_exists = user_site is not None
    if user_site not in sys.path and user_site_exists:
        sys.path.append(user_site)
    return user_site_exists

def enable_pip():
    if importlib.util.find_spec("pip") is None:
        subprocess.check_call([pybin, "-m", "ensurepip", "--user"])
        subprocess.check_call([pybin, "-m", "pip", "install", "--upgrade", "pip", "--user"])
    
def install_module(module : str):
    if importlib.util.find_spec(module) is None:
        subprocess.check_call([pybin, "-m", "pip", "install", module, "--user"])

user_site_added = add_user_site()
enable_pip()
# All the modules you need, that don't come shipped with Blender
modules = ["module1", "module2", ...] 
for module in modules:
    install_module(module)
# If there was no user-site before...
if not user_site_added:
    add_user_site()
$\endgroup$
2
  • 2
    $\begingroup$ Please note that automatic loading of user site-packages was intentionally disabled, see T76993. Manually appending to sys.path works, but there may be a different preferred approach in the future if progress is made on T71420. Until then this approach is a viable alternative. $\endgroup$ – Robert Gützkow Sep 15 '20 at 18:36
  • $\begingroup$ I'll be more than happy to drop this Frankenstein of a workaround as soon as Blender offers a more elegant solution :D $\endgroup$ – TheBeautifulOrc Sep 15 '20 at 22:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.