1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8-80 compliant>
# for slightly faster access
from _bpy import ops as _ops_module
# op_add = _ops_module.add
_op_dir = _ops_module.dir
_op_poll = _ops_module.poll
_op_call = _ops_module.call
_op_as_string = _ops_module.as_string
_op_get_rna_type = _ops_module.get_rna_type
_op_get_bl_options = _ops_module.get_bl_options
_ModuleType = type(_ops_module)
# -----------------------------------------------------------------------------
# Callable Operator Wrapper
class _BPyOpsSubModOp:
"""
Utility class to fake submodule operators.
eg. bpy.ops.object.somefunc
"""
__slots__ = ("_module", "_func")
def _get_doc(self):
idname = self.idname()
sig = _op_as_string(self.idname())
# XXX You never quite know what you get from bpy.types,
# with operators... Operator and OperatorProperties
# are shadowing each other, and not in the same way for
# native ops and py ones! See T39158.
# op_class = getattr(bpy.types, idname)
op_class = _op_get_rna_type(idname)
descr = op_class.description
return "%s\n%s" % (sig, descr)
@staticmethod
def _parse_args(args):
C_dict = None
C_exec = 'EXEC_DEFAULT'
C_undo = False
is_dict = is_exec = is_undo = False
for arg in args:
if is_dict is False and isinstance(arg, dict):
if is_exec is True or is_undo is True:
raise ValueError("dict arg must come first")
C_dict = arg
is_dict = True
elif is_exec is False and isinstance(arg, str):
if is_undo is True:
raise ValueError("string arg must come before the boolean")
C_exec = arg
is_exec = True
elif is_undo is False and isinstance(arg, int):
C_undo = arg
is_undo = True
else:
raise ValueError("1-3 args execution context is supported")
return C_dict, C_exec, C_undo
@staticmethod
def _view_layer_update(context):
view_layer = context.view_layer
if view_layer: # None in background mode
view_layer.update()
else:
import bpy
for scene in bpy.data.scenes:
for view_layer in scene.view_layers:
view_layer.update()
__doc__ = property(_get_doc)
def __init__(self, module, func):
self._module = module
self._func = func
def poll(self, *args):
C_dict, C_exec, _C_undo = _BPyOpsSubModOp._parse_args(args)
return _op_poll(self.idname_py(), C_dict, C_exec)
def idname(self):
# submod.foo -> SUBMOD_OT_foo
return self._module.upper() + "_OT_" + self._func
def idname_py(self):
# submod.foo -> SUBMOD_OT_foo
return self._module + "." + self._func
def __call__(self, *args, **kw):
import bpy
context = bpy.context
# Get the operator from blender
wm = context.window_manager
# Run to account for any RNA values the user changes.
# NOTE: We only update active view-layer, since that's what
# operators are supposed to operate on. There might be some
# corner cases when operator need a full scene update though.
_BPyOpsSubModOp._view_layer_update(context)
if args:
C_dict, C_exec, C_undo = _BPyOpsSubModOp._parse_args(args)
ret = _op_call(self.idname_py(), C_dict, kw, C_exec, C_undo)
else:
ret = _op_call(self.idname_py(), None, kw)
if 'FINISHED' in ret and context.window_manager == wm:
_BPyOpsSubModOp._view_layer_update(context)
return ret
def get_rna_type(self):
"""Internal function for introspection"""
return _op_get_rna_type(self.idname())
@property
def bl_options(self):
return _op_get_bl_options(self.idname())
def __repr__(self): # useful display, repr(op)
return _op_as_string(self.idname())
def __str__(self): # used for print(...)
return ("<function bpy.ops.%s.%s at 0x%x'>" %
(self._module, self._func, id(self)))
# -----------------------------------------------------------------------------
# Sub-Module Access
def _bpy_ops_submodule__getattr__(module, func):
# Return a value from `bpy.ops.{module}.{func}`
if func.startswith("__"):
raise AttributeError(func)
return _BPyOpsSubModOp(module, func)
def _bpy_ops_submodule__dir__(module):
functions = set()
module_upper = module.upper()
for id_name in _op_dir():
id_split = id_name.split("_OT_", 1)
if len(id_split) == 2 and module_upper == id_split[0]:
functions.add(id_split[1])
return list(functions)
def _bpy_ops_submodule(module):
result = _ModuleType("bpy.ops." + module)
result.__getattr__ = lambda func: _bpy_ops_submodule__getattr__(module, func)
result.__dir__ = lambda: _bpy_ops_submodule__dir__(module)
return result
# -----------------------------------------------------------------------------
# Module Access
def __getattr__(module):
# Return a value from `bpy.ops.{module}`.
if module.startswith("__"):
raise AttributeError(module)
return _bpy_ops_submodule(module)
def __dir__():
submodules = set()
for id_name in _op_dir():
id_split = id_name.split("_OT_", 1)
if len(id_split) == 2:
submodules.add(id_split[0].lower())
else:
submodules.add(id_split[0])
return list(submodules)
|