[Bf-extensions-cvs] [2769f4b5] master: development_edit_operator: update to 2.8x: T68541
meta-androcto
noreply at git.blender.org
Mon Sep 2 05:04:42 CEST 2019
Commit: 2769f4b5f5f4769cf9115fa7cdd1287540a795bf
Author: meta-androcto
Date: Mon Sep 2 13:04:25 2019 +1000
Branches: master
https://developer.blender.org/rBAC2769f4b5f5f4769cf9115fa7cdd1287540a795bf
development_edit_operator: update to 2.8x: T68541
===================================================================
M development_edit_operator.py
===================================================================
diff --git a/development_edit_operator.py b/development_edit_operator.py
index 257e61be..08e91d87 100644
--- a/development_edit_operator.py
+++ b/development_edit_operator.py
@@ -21,9 +21,9 @@ bl_info = {
"name": "Edit Operator Source",
"author": "scorpion81",
"version": (1, 2, 2),
- "blender": (2, 78, 0),
+ "blender": (2, 80, 0),
"location": "Text Editor > Edit > Edit Operator",
- "description": "Opens source file of chosen operator, if it is an add-on one",
+ "description": "Opens source file of chosen operator or call locations, if source not available",
"warning": "",
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/"
"Py/Scripts/Development/Edit_Operator_Source",
@@ -31,46 +31,117 @@ bl_info = {
import bpy
import sys
+import os
import inspect
from bpy.types import (
Operator,
Panel,
+ Header,
+ Menu,
+ PropertyGroup
)
-from bpy.props import EnumProperty
+from bpy.props import (
+ EnumProperty,
+ StringProperty,
+ IntProperty
+ )
+
+def stdlib_excludes():
+ #need a handy list of modules to avoid walking into
+ import distutils.sysconfig as sysconfig
+ excludes = []
+ std_lib = sysconfig.get_python_lib(standard_lib=True)
+ for top, dirs, files in os.walk(std_lib):
+ for nm in files:
+ if nm != '__init__.py' and nm[-3:] == '.py':
+ excludes.append(os.path.join(top, nm)[len(std_lib)+1:-3].replace('\\','.'))
+
+ return excludes
+
+def make_loc(prefix, c):
+ #too long and not helpful... omitting for now
+ space = ""
+ #if hasattr(c, "bl_space_type"):
+ # space = c.bl_space_type
+
+ region = ""
+ #if hasattr(c, "bl_region_type"):
+ # region = c.bl_region_type
+
+ label = ""
+ if hasattr(c, "bl_label"):
+ label = c.bl_label
+
+ return prefix+": " + space + " " + region + " " + label
+def walk_module(opname, mod, calls=[], exclude=[]):
+
+ for name, m in inspect.getmembers(mod):
+ if inspect.ismodule(m):
+ if m.__name__ not in exclude:
+ #print(name, m.__name__)
+ walk_module(opname, m, calls, exclude)
+ elif inspect.isclass(m):
+ if (issubclass(m, Panel) or \
+ issubclass(m, Header) or \
+ issubclass(m, Menu)) and mod.__name__ != "bl_ui":
+ if hasattr(m, "draw"):
+ loc = ""
+ file = ""
+ line = -1
+ src, n = inspect.getsourcelines(m.draw)
+ for i, s in enumerate(src):
+ if opname in s:
+ file = mod.__file__
+ line = n + i
+
+ if issubclass(m, Panel) and name != "Panel":
+ loc = make_loc("Panel", m)
+ calls.append([opname, loc, file, line])
+ if issubclass(m, Header) and name != "Header":
+ loc = make_loc("Header", m)
+ calls.append([opname, loc, file, line])
+ if issubclass(m, Menu) and name != "Menu":
+ loc = make_loc("Menu", m)
+ calls.append([opname, loc, file, line])
-def get_py_class_from_op(opname):
+
+def getclazz(opname):
opid = opname.split(".")
opmod = getattr(bpy.ops, opid[0])
op = getattr(opmod, opid[1])
- id = op.get_rna_type().identifier
- # C operators won't be added
- return getattr(bpy.types, id, None)
+ id = op.get_rna_type().bl_rna.identifier
+ try:
+ clazz = getattr(bpy.types, id)
+ return clazz
+ except AttributeError:
+ return None
def getmodule(opname):
- cls = get_py_class_from_op(opname)
- if cls is None:
- addon = False
+ addon = True
+ clazz = getclazz(opname)
+
+ if clazz is None:
+ return "", -1, False
+
+ modn = clazz.__module__
+
+ try:
+ line = inspect.getsourcelines(clazz)[1]
+ except IOError:
line = -1
+ except TypeError:
+ line = -1
+
+ if modn == 'bpy.types':
mod = 'C operator'
+ addon = False
+ elif modn != '__main__':
+ mod = sys.modules[modn].__file__
else:
- addon = True
- mod_name = cls.__module__
- try:
- line = inspect.getsourcelines(cls)[1]
- except IOError:
- line = -1
- except TypeError:
- line = -1
-
- if mod_name == 'bpy.types':
- addon = False
- elif mod_name != '__main__':
- mod = sys.modules[mod_name].__file__
- else:
- addon = False
- mod = mod_name
+ addon = False
+ mod = modn
return mod, line, addon
@@ -83,9 +154,9 @@ def get_ops():
opmoddir = dir(opmod)
for o in opmoddir:
name = opmodname + "." + o
- cls = get_py_class_from_op(name)
- if cls is not None:
- allops.append(name)
+ clazz = getclazz(name)
+ #if (clazz is not None) :# and clazz.__module__ != 'bpy.types'):
+ allops.append(name)
del opmoddir
# add own operator name too, since its not loaded yet when this is called
@@ -96,8 +167,27 @@ def get_ops():
return [(y, y, "", x) for x, y in enumerate(l)]
+class OperatorEntry(PropertyGroup):
+
+ label : StringProperty(
+ name="Label",
+ description="",
+ default=""
+ )
+
+ path : StringProperty(
+ name="Path",
+ description="",
+ default=""
+ )
+
+ line : IntProperty(
+ name="Line",
+ description="",
+ default=-1
+ )
-class EditOperator(Operator):
+class TEXT_OT_EditOperator(Operator):
bl_idname = "text.edit_operator"
bl_label = "Edit Operator"
bl_description = "Opens the source file of operators chosen from Menu"
@@ -105,61 +195,142 @@ class EditOperator(Operator):
items = get_ops()
- op: EnumProperty(
+ op : EnumProperty(
name="Op",
description="",
items=items
)
+
+ path : StringProperty(
+ name="Path",
+ description="",
+ default=""
+ )
+
+ line : IntProperty(
+ name="Line",
+ description="",
+ default=-1
+ )
+
+ def show_text(self, context, path, line):
+ found = False
+
+ for t in bpy.data.texts:
+ if t.filepath == path:
+ #switch to the wanted text first
+ context.space_data.text = t
+ ctx = context.copy()
+ ctx['edit_text'] = t
+ bpy.ops.text.jump(ctx, line=line)
+ found = True
+ break
+
+ if (found is False):
+ self.report({'INFO'},
+ "Opened file: " + path)
+ bpy.ops.text.open(filepath=path)
+ bpy.ops.text.jump(line=line)
+
+ def show_calls(self, context):
+ import bl_ui
+ import addon_utils
+
+ exclude = stdlib_excludes()
+ exclude.append("bpy")
+ exclude.append("sys")
+
+ calls = []
+ walk_module(self.op, bl_ui, calls, exclude)
+
+ for m in addon_utils.modules():
+ try:
+ mod = sys.modules[m.__name__]
+ walk_module(self.op, mod, calls, exclude)
+ except KeyError:
+ continue
+
+ for c in calls:
+ cl = context.scene.calls.add()
+ cl.name = c[0]
+ cl.label = c[1]
+ cl.path = c[2]
+ cl.line = c[3]
def invoke(self, context, event):
context.window_manager.invoke_search_popup(self)
return {'PASS_THROUGH'}
def execute(self, context):
- found = False
- path, line, addon = getmodule(self.op)
- if addon:
- for t in bpy.data.texts:
- if t.filepath == path:
- ctx = context.copy()
- ctx['edit_text'] = t
- bpy.ops.text.jump(ctx, line=line)
- found = True
- break
-
- if (found is False):
- self.report({'INFO'},
- "Opened file: " + path)
- bpy.ops.text.open(filepath=path)
- bpy.ops.text.jump(line=line)
-
- return {'FINISHED'}
+ if self.path != "" and self.line != -1:
+ #invocation of one of the "found" locations
+ self.show_text(context, self.path, self.line)
+ return {'FINISHED'}
else:
- self.report({'WARNING'},
- "Found no source file for " + self.op)
-
- return {'CANCELLED'}
+ context.scene.calls.clear()
+ path, line, addon = getmodule(self.op)
+
+ if addon:
+ self.show_text(context, path, line)
+
+ #add convenient "source" button, to toggle back from calls to source
+ c = context.scene.calls.add()
+ c.name = self.op
+ c.label = "Source"
+ c.path = path
+ c.line = line
+
+ self.show_calls(context)
+ context.area.tag_redraw()
+
+ return {'FINISHED'}
+ else:
+
+ self.report({'WARNING'},
+ "Found no source file for " + self.op)
+
+ self.show_calls(context)
+ context.area.tag_redraw()
+
+ return {'FINISHED'}
-class EditOperatorPanel(Panel):
- bl_idname = "D
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list