background_plane_manager/auto_modules.py

145 lines
5.9 KiB
Python
Raw Normal View History

2023-09-28 11:34:41 +02:00
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
import os, sys
import subprocess
from pathlib import Path
# THIRD_PARTY = Path(__file__).resolve().parent / "libs"# os.path.join(os.path.dirname(os.path.abspath(__file__)), "libs")
# DEFAULT_CACHE_DIR = Path(__file__).resolve().parent / "cache"# os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache")
# SUBPROCESS_DIR = PYTHON_PATH.parent
PYTHON_PATH = Path(sys.executable)
BLENDER_SITE_PACKAGE = PYTHON_PATH.parents[1] / 'lib' / 'site-packages'
# or: BLENDER_SITE_PACKAGE = Path(bpy.utils.resource_path('LOCAL')) / 'python' / 'lib' / 'site-packages'
def module_can_be_imported(name):
try:
__import__(name)
return True
except ModuleNotFoundError:
return False
def install_pip():
# pip can not necessarily be imported into Blender after this
subprocess.run([str(PYTHON_PATH), "-m", "ensurepip"])
def install_package(name):
# import logging
# logging.debug(f"Using {PYTHON_PATH} for installation")
## !!! try with , '--user' ?
subprocess.run([str(PYTHON_PATH), "-m", "pip", "install", name])
def setup(dependencies):
'''
Get a set containing multiple tuple of (module, package) names pair (str)
install pip with ensurepip if needed, try to import, install, retry
'''
os.environ['PYTHONUSERBASE'] = str(BLENDER_SITE_PACKAGE)
if not module_can_be_imported("pip"):
install_pip()
for module_name, package_name in dependencies:
if not module_can_be_imported(module_name):
print(f'Installing module: {module_name} - package: {package_name}')
install_package(package_name)
module_can_be_imported(package_name)
### --- classic install (not used)
def pip_install(package_name):
'''Get a package name (str) and try to install and print in console'''
print(f'---Installing {package_name}---')
try:
output = subprocess.check_output([bpy.app.binary_path_python, '-m', 'pip', 'install', package_name])
print(output)
except subprocess.CalledProcessError as e:
print(e.output)
return e.output
def pip_install_and_import(dependencies):
'''
Get a set containing multiple tuple of (module, package) names pair (str)
try to import, if import fail, try to install then try to reimport
'''
# os.environ['PYTHONUSERBASE'] = str(BLENDER_SITE_PACKAGE)
for module_name, package_name in dependencies:
# '--user'# install for all version of blender (suposely in app data roaming or config files...)
# '--no-deps'# dont update dependancy (in this case, avoid installing downloading a duplication of numpy)
try:
__import__(module_name)
continue
except ImportError:
try:
## auto install dependancy (need to run as admin)
print(f'Installing module: {module_name} - package: {package_name}') #"--user" ?
#### Using target
## within built-in modules (need run as admin in most case)
# subprocess.check_call([str(PYTHON_PATH), "-m", "pip", "install", f'--target={BLENDER_SITE_PACKAGE}', package_name])
done = False
## within external modules (if script files are there)
external_scripts = bpy.context.preferences.filepaths.script_directory
print('external_scripts: ', external_scripts)
print('__file__: ', __file__)
in_external = str(Path(__file__)).startswith(str(Path(external_scripts)))
if external_scripts and len(external_scripts) > 2 and in_external:
external_scripts = Path(external_scripts)
if external_scripts.exists():
external_modules = external_scripts / 'modules'
print(f'using external scripts modules: {external_modules}')
external_modules.mkdir(exist_ok=True)# dont raise error if already exists
# cmd = [str(PYTHON_PATH), "-m", "pip", "install", f'--target={external_modules}', package_name]
cmd = [str(PYTHON_PATH), "-m", "pip", '--no-cache-dir', "install", f'--target={external_modules}', package_name, '--no-deps']
print('Run', ' '.join(cmd))
subprocess.check_call(cmd)
done=True
## within user local modules (if not in external scripts)
if not done:
user_module = Path(bpy.utils.user_resource('SCRIPTS', path='modules', create=True)) # create the folder if not exists
print(f'Using users modules: {user_module}')
# cmd = [str(PYTHON_PATH), "-m", "pip", "install", f'--target={user_module}', package_name]
cmd = [str(PYTHON_PATH), "-m", "pip", '--no-cache-dir', "install", f'--target={user_module}', package_name, '--no-deps']
print('Run', ' '.join(cmd))
subprocess.check_call(cmd)
except Exception as e:
print(f'{package_name} install error: {e}')
print('Maybe try restarting blender as Admin')
return e
try:
__import__(module_name)
except ImportError as e:
print(f'!!! module {module_name} still cannot be imported')
return e
"""
## addons Paths
# natives
built_in_addons = os.path.join(bpy.utils.resource_path('LOCAL') , path='scripts', 'addons')
# users
users_addons = bpy.utils.user_resource('SCRIPTS', path='addons')
#external
external_addons = None
external_script_dir = bpy.context.preferences.filepaths.script_directory
if external_script_dir and len(external_script_dir) > 2:
external_addons = os.path.join(external_script_dir, 'addons')
"""