ops.py 6.3 KB

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