python api for ID property access by Joseph Eager, copied from blender 2.4x.
[blender.git] / release / scripts / modules / bpy / ops.py
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8-80 compliant>
20
21 # for slightly faster access
22 from _bpy import ops as ops_module
23
24 op_add = ops_module.add
25 op_remove = ops_module.remove
26 op_dir = ops_module.dir
27 op_call = ops_module.call
28 op_as_string = ops_module.as_string
29 op_get_rna = ops_module.get_rna
30
31 # Keep in sync with WM_types.h
32 context_dict = {
33     'INVOKE_DEFAULT': 0,
34     'INVOKE_REGION_WIN': 1,
35     'INVOKE_AREA': 2,
36     'INVOKE_SCREEN': 3,
37     'EXEC_DEFAULT': 4,
38     'EXEC_REGION_WIN': 5,
39     'EXEC_AREA': 6,
40     'EXEC_SCREEN': 7,
41 }
42
43
44 class bpy_ops(object):
45     '''
46     Fake module like class.
47
48      bpy.ops
49     '''
50
51     def __getattr__(self, module):
52         '''
53         gets a bpy.ops submodule
54         '''
55         if module.startswith('__'):
56             raise AttributeError(module)
57         return bpy_ops_submodule(module)
58
59     def add(self, pyop):
60         op_add(pyop)
61
62     def remove(self, pyop):
63         op_remove(pyop)
64
65     def __dir__(self):
66
67         submodules = set()
68
69         # add this classes functions
70         for id_name in dir(self.__class__):
71             if not id_name.startswith('__'):
72                 submodules.add(id_name)
73
74         for id_name in op_dir():
75             id_split = id_name.split('_OT_', 1)
76
77             if len(id_split) == 2:
78                 submodules.add(id_split[0].lower())
79             else:
80                 submodules.add(id_split[0])
81
82         return list(submodules)
83
84     def __repr__(self):
85         return "<module like class 'bpy.ops'>"
86
87
88 class bpy_ops_submodule(object):
89     '''
90     Utility class to fake submodules.
91
92     eg. bpy.ops.object
93     '''
94     __keys__ = ('module',)
95
96     def __init__(self, module):
97         self.module = module
98
99     def __getattr__(self, func):
100         '''
101         gets a bpy.ops.submodule function
102         '''
103         if func.startswith('__'):
104             raise AttributeError(func)
105         return bpy_ops_submodule_op(self.module, func)
106
107     def __dir__(self):
108
109         functions = set()
110
111         module_upper = self.module.upper()
112
113         for id_name in op_dir():
114             id_split = id_name.split('_OT_', 1)
115             if len(id_split) == 2 and module_upper == id_split[0]:
116                 functions.add(id_split[1])
117
118         return list(functions)
119
120     def __repr__(self):
121         return "<module like class 'bpy.ops.%s'>" % self.module
122
123
124 class bpy_ops_submodule_op(object):
125     '''
126     Utility class to fake submodule operators.
127
128     eg. bpy.ops.object.somefunc
129     '''
130
131     __keys__ = ('module', 'func')
132
133
134     def _get_doc(self):
135         return op_as_string(self.idname())
136
137     __doc__ = property(_get_doc)
138
139     def __init__(self, module, func):
140         self.module = module
141         self.func = func
142
143     def idname(self):
144         # submod.foo -> SUBMOD_OT_foo
145         return self.module.upper() + '_OT_' + self.func
146
147     def __call__(self, *args, **kw):
148
149         # Get the operator from blender
150         if len(args) > 2:
151             raise ValueError("1 or 2 args execution context is supported")
152
153         C_dict = None
154
155         if args:
156
157             C_exec = 'EXEC_DEFAULT'
158
159             if len(args) == 2:
160                 C_exec = args[0]
161                 C_dict = args[1]
162             else:
163                 if type(args[0]) != str:
164                     C_dict = args[0]
165                 else:
166                     C_exec = args[0]
167
168             try:
169                 context = context_dict[C_exec]
170             except:
171                 raise ValueError("Expected a single context argument in: " + \
172                  str(list(context_dict.keys())))
173
174             if len(args) == 2:
175                 C_dict = args[1]
176
177             return op_call(self.idname(), C_dict, kw, context)
178
179         else:
180             return op_call(self.idname(), C_dict, kw)
181
182     def get_rna(self):
183         '''
184         currently only used for 'bl_rna'
185         '''
186         return op_get_rna(self.idname())
187
188     def __repr__(self): # useful display, repr(op)
189         return op_as_string(self.idname())
190
191     def __str__(self): # used for print(...)
192         return "<function bpy.ops.%s.%s at 0x%x'>" % \
193                 (self.module, self.func, id(self))
194
195 ops_fake_module = bpy_ops()