Split addon code up by purpose

This commit is contained in:
gandalf3
2017-07-07 17:56:49 -07:00
parent bbc1c8b3bf
commit fcf90a0e75
4 changed files with 103 additions and 134 deletions

View File

@@ -1,54 +1,26 @@
# -*- coding: utf-8 -*-
bl_info = {
'name': 'Package Manager',
'description': 'Testing package management',
'category': 'System',
'support': 'TESTING',
}
import bpy
from bpy.props import CollectionProperty
from bpy.types import PropertyGroup, Panel, UIList, AddonPreferences
class RepositoryProperty(PropertyGroup):
url = bpy.props.StringProperty(name="URL")
# from bpy.utils import register_class, unregister_class
import importlib
import sys
import logging
class PACKAGE_UL_repositories(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
split = layout.split(0.3)
split.prop(item, "name")
split.prop(item, "url")
def invoke(self, onctext, event):
pass
class PackagePreferences(AddonPreferences):
bl_idname = __package__
repositories = CollectionProperty(type=RepositoryProperty)
active_repository = bpy.props.IntProperty()
def draw(self, context):
layout = self.layout
row = layout.row()
row.template_list("PACKAGE_UL_repositories", "", self, "repositories", self, "active_repository")
col = row.column(align=True)
col.operator("package.add_repository", icon="ZOOMIN", text="")
col.operator("package.remove_repository", icon="ZOOMOUT", text="")
# class PackageManager:
# # For some reason accessing *Property objects stored in this class gives a TypeError:
# # UILayout.prop(): error with argument 1, "data" - Function.data expected a AnyType type, not tuple
# # But accessing them when not stored in a class or dict is fine?
# settings = bpy.props.PointerProperty(type=PackageSettings)
# last_response_code = bpy.props.PointerProperty(type=bpy.types.StringProperty)
log = logging.getLogger(__name__)
def register():
# Reload support
import sys
if '%s.pkg_ops' % __name__ in sys.modules:
import importlib
if '%s.blender_common' % __name__ in sys.modules:
def reload_mod(name):
print("Reloading %s" % name)
log.debug("Reloading %s", name)
modname = '%s.%s' % (__name__, name)
try:
old_module = sys.modules[modname]
@@ -61,26 +33,13 @@ def register():
sys.modules[modname] = new_module
return new_module
pkg_ops = reload_mod('pkg_ops')
pkg_ui = reload_mod('pkg_ui')
blender_common = reload_mod('blender_common')
else:
from . import (pkg_ops, pkg_ui)
from . import blender_common
bpy.utils.register_class(RepositoryProperty)
bpy.utils.register_class(PACKAGE_UL_repositories)
bpy.utils.register_class(PackagePreferences)
pkg_ops.register()
pkg_ui.register()
blender_common.register()
def unregister():
from . import (pkg_ops, pkg_ui)
pkg_ops.unregister()
pkg_ui.unregister();
bpy.utils.unregister_class(RepositoryProperty)
bpy.utils.unregister_class(PACKAGE_UL_repositories)
bpy.utils.unregister_class(PackagePreferences)
del bpy.types.Scene.custom
del bpy.types.Scene.custom_idx
blender_common.unregister()

View File

@@ -1,54 +1,36 @@
# -*- coding: utf-8 -*-
# This file is for code dealing specifically with blender
import bpy
import logging
from multiprocessing import Process, Pipe
from . import blenderpack
from bpy.props import CollectionProperty
from bpy.types import PropertyGroup, Panel, UIList, AddonPreferences, Operator
from .subprocess_adapter import SubprocessOperatorMixin
class SubprocessOperatorMixin:
timer = None
log = logging.getLogger("%s.SubprocessOperatorMixin" % __name__)
class RepositoryProperty(PropertyGroup):
url = bpy.props.StringProperty(name="URL")
# run once in invoke
def setup(self):
pass
# run on receipt of data from subprocess
def handle_response(self, resp):
class PACKAGE_UL_repositories(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
split = layout.split(0.3)
split.prop(item, "name")
split.prop(item, "url")
def invoke(self, onctext, event):
pass
def __init__(self):
self.pipe = Pipe()
self.subprocess = None
class PackagePreferences(AddonPreferences):
bl_idname = __package__
def execute(self, context):
return self.invoke(context, None)
repositories = CollectionProperty(type=RepositoryProperty)
active_repository = bpy.props.IntProperty()
def invoke(self, context, event):
self.subprocess.start()
# we have to explicitly close the end of the pipe we are NOT using,
# otherwise no exception will be generated when the other process closes its end.
self.pipe[1].close()
wm = context.window_manager
wm.modal_handler_add(self)
self.timer = wm.event_timer_add(.01, context.window)
self.setup()
return {'RUNNING_MODAL'}
def modal(self, context, event):
self.log.debug("polling")
try:
if self.pipe[0].poll():
newdata = self.pipe[0].recv()
else:
newdata = None
except EOFError:
self.log.debug("done polling")
return {'FINISHED'}
if newdata is not None:
self.handle_response(newdata)
return {'PASS_THROUGH'}
def draw(self, context):
layout = self.layout
row = layout.row()
row.template_list("PACKAGE_UL_repositories", "", self, "repositories", self, "active_repository")
col = row.column(align=True)
col.operator("package.add_repository", icon="ZOOMIN", text="")
col.operator("package.remove_repository", icon="ZOOMOUT", text="")
class PACKAGE_OT_fetch(SubprocessOperatorMixin, bpy.types.Operator):
bl_idname = "package.fetch"
@@ -88,11 +70,22 @@ class PACKAGE_OT_remove_repository(bpy.types.Operator):
def register():
bpy.utils.register_class(RepositoryProperty)
bpy.utils.register_class(PackagePreferences)
bpy.utils.register_class(PACKAGE_OT_fetch)
bpy.utils.register_class(PACKAGE_OT_add_repository)
bpy.utils.register_class(PACKAGE_OT_remove_repository)
bpy.utils.register_class(PACKAGE_UL_repositories)
def unregister():
bpy.utils.unregister_class(PACKAGE_OT_fetch)
bpy.utils.unregister_class(PACKAGE_OT_remove_repository)
bpy.utils.unregister_class(RepositoryProperty)
bpy.utils.unregister_class(PackagePreferences)
bpy.utils.unregister_class(PACKAGE_OT_fetch)
bpy.utils.unregister_class(PACKAGE_OT_add_repository)
bpy.utils.unregister_class(PACKAGE_OT_remove_repository)
bpy.utils.unregister_class(PACKAGE_UL_repositories)

View File

@@ -1,33 +0,0 @@
import bpy
from . import pkg_ops
class USERPREF_PT_packages(bpy.types.Panel):
bl_label = "Package Management"
bl_space_type = 'USER_PREFERENCES'
bl_region_type = 'WINDOW'
bl_options = {'HIDE_HEADER'}
@classmethod
def poll(cls, context):
userpref = context.user_preferences
return (userpref.active_section == 'PACKAGES')
def draw(self, context):
wm = context.window_manager
# see comment in __init__.py
pm_settings = wm.package_manager_settings
layout = self.layout
row = layout.row()
row.prop(pm_settings, "url")
row.operator(pkg_ops.PACKAGE_OT_fetch.bl_idname, text="Fetch")
row = layout.row()
# just a demonstration
row.label(text="Last response: %s" % pkg_ops.PACKAGE_OT_fetch.last_response)
def register():
bpy.utils.register_class(USERPREF_PT_packages)
def unregister():
bpy.utils.unregister_class(USERPREF_PT_packages)

50
subprocess_adapter.py Normal file
View File

@@ -0,0 +1,50 @@
import logging
from multiprocessing import Process, Pipe
class SubprocessOperatorMixin:
timer = None
log = logging.getLogger("%s.SubprocessOperatorMixin" % __name__)
# run once in invoke
def setup(self):
pass
# run on receipt of data from subprocess
def handle_response(self, resp):
pass
def __init__(self):
self.pipe = Pipe()
self.subprocess = None
def execute(self, context):
return self.invoke(context, None)
def invoke(self, context, event):
self.subprocess.start()
# we have to explicitly close the end of the pipe we are NOT using,
# otherwise no exception will be generated when the other process closes its end.
self.pipe[1].close()
wm = context.window_manager
wm.modal_handler_add(self)
self.timer = wm.event_timer_add(.01, context.window)
self.setup()
return {'RUNNING_MODAL'}
def modal(self, context, event):
self.log.debug("polling")
try:
if self.pipe[0].poll():
newdata = self.pipe[0].recv()
else:
newdata = None
except EOFError:
self.log.debug("done polling")
return {'FINISHED'}
if newdata is not None:
self.handle_response(newdata)
return {'PASS_THROUGH'}