Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1528 from pypeclub/bugfix/1050-blender-cannot-ini…
Browse files Browse the repository at this point in the history
…tialize-avalon-if-blender_user_scripts-is-already-used
  • Loading branch information
mkolar authored May 21, 2021
2 parents 72e966d + df5c4ae commit 1373d7f
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 6 deletions.
24 changes: 19 additions & 5 deletions openpype/hosts/blender/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,32 @@ def add_implementation_envs(env, _app):
env["PYTHONPATH"] = os.pathsep.join(python_path_parts)

# Modify Blender user scripts path
previous_user_scripts = set()
# Implementation path is added to set for easier paths check inside loops
# - will be removed at the end
previous_user_scripts.add(implementation_user_script_path)

openpype_blender_user_scripts = (
env.get("OPENPYPE_BLENDER_USER_SCRIPTS") or ""
)
for path in openpype_blender_user_scripts.split(os.pathsep):
if path and os.path.exists(path):
previous_user_scripts.add(os.path.normpath(path))

blender_user_scripts = env.get("BLENDER_USER_SCRIPTS") or ""
previous_user_scripts = []
for path in blender_user_scripts.split(os.pathsep):
if path and os.path.exists(path):
path = os.path.normpath(path)
if path != implementation_user_script_path:
previous_user_scripts.append(path)
previous_user_scripts.add(os.path.normpath(path))

# Remove implementation path from user script paths as is set to
# `BLENDER_USER_SCRIPTS`
previous_user_scripts.remove(implementation_user_script_path)
env["BLENDER_USER_SCRIPTS"] = implementation_user_script_path

# Set custom user scripts env
env["OPENPYPE_BLENDER_USER_SCRIPTS"] = os.pathsep.join(
previous_user_scripts
)
env["BLENDER_USER_SCRIPTS"] = implementation_user_script_path

# Define Qt binding if not defined
if not env.get("QT_PREFERRED_BINDING"):
Expand Down
4 changes: 3 additions & 1 deletion openpype/hosts/blender/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import bpy

from .lib import append_user_scripts

from avalon import api as avalon
from pyblish import api as pyblish

Expand All @@ -29,7 +31,7 @@ def install():
pyblish.register_plugin_path(str(PUBLISH_PATH))
avalon.register_plugin_path(avalon.Loader, str(LOAD_PATH))
avalon.register_plugin_path(avalon.Creator, str(CREATE_PATH))

append_user_scripts()
avalon.on("new", on_new)
avalon.on("open", on_open)

Expand Down
127 changes: 127 additions & 0 deletions openpype/hosts/blender/api/lib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import os
import traceback
import importlib

import bpy
import addon_utils


def load_scripts(paths):
"""Copy of `load_scripts` from Blender's implementation.
It is possible that whis function will be changed in future and usage will
be based on Blender version.
"""
import bpy_types

loaded_modules = set()

previous_classes = [
cls
for cls in bpy.types.bpy_struct.__subclasses__()
]

def register_module_call(mod):
register = getattr(mod, "register", None)
if register:
try:
register()
except:
traceback.print_exc()
else:
print("\nWarning! '%s' has no register function, "
"this is now a requirement for registerable scripts" %
mod.__file__)

def unregister_module_call(mod):
unregister = getattr(mod, "unregister", None)
if unregister:
try:
unregister()
except:
traceback.print_exc()

def test_reload(mod):
# reloading this causes internal errors
# because the classes from this module are stored internally
# possibly to refresh internal references too but for now, best not to.
if mod == bpy_types:
return mod

try:
return importlib.reload(mod)
except:
traceback.print_exc()

def test_register(mod):
if mod:
register_module_call(mod)
bpy.utils._global_loaded_modules.append(mod.__name__)

from bpy_restrict_state import RestrictBlend

with RestrictBlend():
for base_path in paths:
for path_subdir in bpy.utils._script_module_dirs:
path = os.path.join(base_path, path_subdir)
if not os.path.isdir(path):
continue

bpy.utils._sys_path_ensure_prepend(path)

# Only add to 'sys.modules' unless this is 'startup'.
if path_subdir != "startup":
continue
for mod in bpy.utils.modules_from_path(path, loaded_modules):
test_register(mod)

addons_paths = []
for base_path in paths:
addons_path = os.path.join(base_path, "addons")
if not os.path.exists(addons_path):
continue
addons_paths.append(addons_path)
addons_module_path = os.path.join(addons_path, "modules")
if os.path.exists(addons_module_path):
bpy.utils._sys_path_ensure_prepend(addons_module_path)

if addons_paths:
# Fake addons
origin_paths = addon_utils.paths

def new_paths():
paths = origin_paths() + addons_paths
return paths

addon_utils.paths = new_paths
addon_utils.modules_refresh()

# load template (if set)
if any(bpy.utils.app_template_paths()):
import bl_app_template_utils
bl_app_template_utils.reset(reload_scripts=False)
del bl_app_template_utils

for cls in bpy.types.bpy_struct.__subclasses__():
if cls in previous_classes:
continue
if not getattr(cls, "is_registered", False):
continue
for subcls in cls.__subclasses__():
if not subcls.is_registered:
print(
"Warning, unregistered class: %s(%s)" %
(subcls.__name__, cls.__name__)
)


def append_user_scripts():
user_scripts = os.environ.get("OPENPYPE_BLENDER_USER_SCRIPTS")
if not user_scripts:
return

try:
load_scripts(user_scripts.split(os.pathsep))
except Exception:
print("Couldn't load user scripts \"{}\"".format(user_scripts))
traceback.print_exc()

0 comments on commit 1373d7f

Please sign in to comment.