Welcome to mirror list, hosted at ThFree Co, Russian Federation.

ops.py « bpy « modules « scripts « release - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 56346d453a268c3f9715173463767ef20689a31e (plain)
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)