If bpy fails to import, assume we are in subprocess and only import subproc.py

This commit is contained in:
Ellwood Zwovic
2017-08-15 00:30:47 -07:00
parent 3bb59b5ac2
commit 3cd746a26a

View File

@@ -42,17 +42,22 @@ else:
from . import utils from . import utils
from .bpkg import Package from .bpkg import Package
import bpy try:
from collections import OrderedDict import bpy
import multiprocessing except ImportError:
from . import subproc
else:
mp_context = multiprocessing.get_context() from collections import OrderedDict
mp_context.set_executable(bpy.app.binary_path_python) import multiprocessing
# global list of all known packages, indexed by name mp_context = multiprocessing.get_context()
_packages = OrderedDict() mp_context.set_executable(bpy.app.binary_path_python)
class ConsolidatedPackage: # global list of all known packages, indexed by name
_packages = OrderedDict()
class ConsolidatedPackage:
""" """
Stores a grouping of different versions of the same package Stores a grouping of different versions of the same package
""" """
@@ -114,7 +119,7 @@ class ConsolidatedPackage:
def __iter__(self): def __iter__(self):
return (pkg for pkg in self.versions) return (pkg for pkg in self.versions)
class SubprocMixin: class SubprocMixin:
"""Mix-in class for things that need to be run in a subprocess.""" """Mix-in class for things that need to be run in a subprocess."""
log = logging.getLogger(__name__ + '.SubprocMixin') log = logging.getLogger(__name__ + '.SubprocMixin')
@@ -242,7 +247,7 @@ class SubprocMixin:
raise NotImplementedError() raise NotImplementedError()
class PACKAGE_OT_install(SubprocMixin, bpy.types.Operator): class PACKAGE_OT_install(SubprocMixin, bpy.types.Operator):
bl_idname = 'package.install' bl_idname = 'package.install'
bl_label = 'Install package' bl_label = 'Install package'
bl_description = 'Downloads and installs a Blender add-on package' bl_description = 'Downloads and installs a Blender add-on package'
@@ -322,7 +327,7 @@ class PACKAGE_OT_install(SubprocMixin, bpy.types.Operator):
self.log.error('Process died without telling us! Exit code was 0 though') self.log.error('Process died without telling us! Exit code was 0 though')
self.report({'WARNING'}, 'Error downloading package, but process finished OK. This is weird.') self.report({'WARNING'}, 'Error downloading package, but process finished OK. This is weird.')
class PACKAGE_OT_uninstall(SubprocMixin, bpy.types.Operator): class PACKAGE_OT_uninstall(SubprocMixin, bpy.types.Operator):
bl_idname = 'package.uninstall' bl_idname = 'package.uninstall'
bl_label = 'Install package' bl_label = 'Install package'
bl_description = "Remove installed package files from filesystem" bl_description = "Remove installed package files from filesystem"
@@ -381,12 +386,12 @@ class PACKAGE_OT_uninstall(SubprocMixin, bpy.types.Operator):
def get_packages_from_disk(refresh=False) -> list: def get_packages_from_disk(refresh=False) -> list:
"""Get list of packages installed on disk""" """Get list of packages installed on disk"""
import addon_utils import addon_utils
return [Package.from_module(mod) for mod in addon_utils.modules(refresh=refresh)] return [Package.from_module(mod) for mod in addon_utils.modules(refresh=refresh)]
def get_packages_from_repo() -> list: def get_packages_from_repo() -> list:
"""Get list of packages from cached repository lists (does not refresh them from server)""" """Get list of packages from cached repository lists (does not refresh them from server)"""
import pathlib import pathlib
storage_path = pathlib.Path(bpy.utils.user_resource('CONFIG', 'packages', create=True)) / 'repo.json' storage_path = pathlib.Path(bpy.utils.user_resource('CONFIG', 'packages', create=True)) / 'repo.json'
@@ -398,7 +403,7 @@ def get_packages_from_repo() -> list:
pkg.repository = repo.name pkg.repository = repo.name
return repo.packages return repo.packages
class PACKAGE_OT_refresh_packages(bpy.types.Operator): class PACKAGE_OT_refresh_packages(bpy.types.Operator):
bl_idname = "package.refresh_packages" bl_idname = "package.refresh_packages"
bl_label = "Refresh Packages" bl_label = "Refresh Packages"
bl_description = "Scan for packages on disk" bl_description = "Scan for packages on disk"
@@ -414,7 +419,7 @@ class PACKAGE_OT_refresh_packages(bpy.types.Operator):
return {'FINISHED'} return {'FINISHED'}
class PACKAGE_OT_refresh_repositories(SubprocMixin, bpy.types.Operator): class PACKAGE_OT_refresh_repositories(SubprocMixin, bpy.types.Operator):
bl_idname = "package.refresh_repositories" bl_idname = "package.refresh_repositories"
bl_label = "Refresh Repositories" bl_label = "Refresh Repositories"
bl_description = 'Check repositories for new and updated packages' bl_description = 'Check repositories for new and updated packages'
@@ -512,10 +517,10 @@ class PACKAGE_OT_refresh_repositories(SubprocMixin, bpy.types.Operator):
self.log.error('Refresh process died without telling us! Exit code was 0 though') self.log.error('Refresh process died without telling us! Exit code was 0 though')
self.report({'WARNING'}, 'Error refreshing package lists, but process finished OK. This is weird.') self.report({'WARNING'}, 'Error refreshing package lists, but process finished OK. This is weird.')
#TODO: #TODO:
# monkey patch refresh_repositories and add refresh_packages in the success callback # monkey patch refresh_repositories and add refresh_packages in the success callback
# this way refresh_packages is always called after repositories have been refreshed # this way refresh_packages is always called after repositories have been refreshed
class PACKAGE_OT_refresh(bpy.types.Operator): class PACKAGE_OT_refresh(bpy.types.Operator):
bl_idname = "package.refresh" bl_idname = "package.refresh"
bl_label = "Refresh" bl_label = "Refresh"
bl_description = "Check for new and updated packages" bl_description = "Check for new and updated packages"
@@ -525,7 +530,7 @@ class PACKAGE_OT_refresh(bpy.types.Operator):
# getattr(bpy.ops, __package__).refresh_packages() # getattr(bpy.ops, __package__).refresh_packages()
return {'FINISHED'} return {'FINISHED'}
class RepositoryProperty(bpy.types.PropertyGroup): class RepositoryProperty(bpy.types.PropertyGroup):
url = bpy.props.StringProperty(name="URL") url = bpy.props.StringProperty(name="URL")
status = bpy.props.EnumProperty(name="Status", items=[ status = bpy.props.EnumProperty(name="Status", items=[
("OK", "Okay", "FILE_TICK"), ("OK", "Okay", "FILE_TICK"),
@@ -533,7 +538,7 @@ class RepositoryProperty(bpy.types.PropertyGroup):
("NOCONNECT", "Could not connect", "QUESTION"), ("NOCONNECT", "Could not connect", "QUESTION"),
]) ])
class PACKAGE_UL_repositories(bpy.types.UIList): class PACKAGE_UL_repositories(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname): def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
layout.alignment='LEFT' layout.alignment='LEFT'
if len(item.name) == 0: if len(item.name) == 0:
@@ -541,7 +546,7 @@ class PACKAGE_UL_repositories(bpy.types.UIList):
else: else:
layout.label(item.name) layout.label(item.name)
class PACKAGE_OT_add_repository(bpy.types.Operator): class PACKAGE_OT_add_repository(bpy.types.Operator):
bl_idname = "package.add_repository" bl_idname = "package.add_repository"
bl_label = "Add Repository" bl_label = "Add Repository"
@@ -567,7 +572,7 @@ class PACKAGE_OT_add_repository(bpy.types.Operator):
context.area.tag_redraw() context.area.tag_redraw()
return {'FINISHED'} return {'FINISHED'}
class PACKAGE_OT_remove_repository(bpy.types.Operator): class PACKAGE_OT_remove_repository(bpy.types.Operator):
bl_idname = "package.remove_repository" bl_idname = "package.remove_repository"
bl_label = "Remove Repository" bl_label = "Remove Repository"
@@ -576,7 +581,7 @@ class PACKAGE_OT_remove_repository(bpy.types.Operator):
prefs.repositories.remove(prefs.active_repository) prefs.repositories.remove(prefs.active_repository)
return {'FINISHED'} return {'FINISHED'}
class USERPREF_PT_packages(bpy.types.Panel): class USERPREF_PT_packages(bpy.types.Panel):
bl_label = "Package Management" bl_label = "Package Management"
bl_space_type = 'USER_PREFERENCES' bl_space_type = 'USER_PREFERENCES'
bl_region_type = 'WINDOW' bl_region_type = 'WINDOW'
@@ -893,7 +898,7 @@ class USERPREF_PT_packages(bpy.types.Panel):
draw_package(_packages[pkgname], row) draw_package(_packages[pkgname], row)
class WM_OT_package_toggle_expand(bpy.types.Operator): class WM_OT_package_toggle_expand(bpy.types.Operator):
bl_idname = "wm.package_toggle_expand" bl_idname = "wm.package_toggle_expand"
bl_label = "" bl_label = ""
bl_description = "Toggle display of extended information for given package (hold shift to collapse all other packages)" bl_description = "Toggle display of extended information for given package (hold shift to collapse all other packages)"
@@ -916,7 +921,7 @@ class WM_OT_package_toggle_expand(bpy.types.Operator):
return {'FINISHED'} return {'FINISHED'}
class PACKAGE_OT_toggle_enabled(bpy.types.Operator): class PACKAGE_OT_toggle_enabled(bpy.types.Operator):
bl_idname = "package.toggle_enabled" bl_idname = "package.toggle_enabled"
bl_label = "" bl_label = ""
bl_description = "Enable given package if it's disabled, and vice versa if it's enabled" bl_description = "Enable given package if it's disabled, and vice versa if it's enabled"
@@ -957,7 +962,7 @@ class PACKAGE_OT_toggle_enabled(bpy.types.Operator):
return {'FINISHED'} return {'FINISHED'}
class PACKAGE_OT_disable(bpy.types.Operator): class PACKAGE_OT_disable(bpy.types.Operator):
bl_idname = "package.disable" bl_idname = "package.disable"
bl_label = "" bl_label = ""
bl_description = "Disable given package" bl_description = "Disable given package"
@@ -982,7 +987,7 @@ class PACKAGE_OT_disable(bpy.types.Operator):
_packages[self.package_name].enabled = False _packages[self.package_name].enabled = False
return ret return ret
class PackageManagerPreferences(bpy.types.AddonPreferences): class PackageManagerPreferences(bpy.types.AddonPreferences):
bl_idname = __package__ bl_idname = __package__
repositories = bpy.props.CollectionProperty( repositories = bpy.props.CollectionProperty(
@@ -991,11 +996,11 @@ class PackageManagerPreferences(bpy.types.AddonPreferences):
) )
active_repository = bpy.props.IntProperty() active_repository = bpy.props.IntProperty()
def validate_packagelist(pkglist: list) -> list: def validate_packagelist(pkglist: list) -> list:
"""Ensures all packages have required fields; strips out bad packages and returns them in a list""" """Ensures all packages have required fields; strips out bad packages and returns them in a list"""
pass pass
def build_composite_packagelist(installed: list, available: list) -> OrderedDict: def build_composite_packagelist(installed: list, available: list) -> OrderedDict:
"""Merge list of installed and available packages into one dict, keyed by package name""" """Merge list of installed and available packages into one dict, keyed by package name"""
log = logging.getLogger(__name__ + ".build_composite_packagelist") log = logging.getLogger(__name__ + ".build_composite_packagelist")
@@ -1065,7 +1070,7 @@ def build_composite_packagelist(installed: list, available: list) -> OrderedDict
return OrderedDict(sorted(masterlist.items())) return OrderedDict(sorted(masterlist.items()))
def register(): def register():
bpy.utils.register_class(PACKAGE_OT_install) bpy.utils.register_class(PACKAGE_OT_install)
bpy.utils.register_class(PACKAGE_OT_uninstall) bpy.utils.register_class(PACKAGE_OT_uninstall)
bpy.utils.register_class(PACKAGE_OT_toggle_enabled) bpy.utils.register_class(PACKAGE_OT_toggle_enabled)
@@ -1097,7 +1102,7 @@ def register():
bpy.utils.register_class(PackageManagerPreferences) bpy.utils.register_class(PackageManagerPreferences)
def unregister(): def unregister():
bpy.utils.unregister_class(PACKAGE_OT_install) bpy.utils.unregister_class(PACKAGE_OT_install)
bpy.utils.unregister_class(PACKAGE_OT_uninstall) bpy.utils.unregister_class(PACKAGE_OT_uninstall)
bpy.utils.unregister_class(PACKAGE_OT_toggle_enabled) bpy.utils.unregister_class(PACKAGE_OT_toggle_enabled)