patch [#33331] Time To Start Moving To Stdbool
[blender.git] / source / tests / bl_run_operators.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20
21 # semi-useful script, runs all operators in a number of different
22 # contexts, cheap way to find misc small bugs but is in no way a complete test.
23 #
24 # only error checked for here is a segfault.
25
26 import bpy
27 import sys
28
29 op_blacklist = (
30     "script.reload",
31     "export*.*",
32     "import*.*",
33     "*.save_*",
34     "*.read_*",
35     "*.open_*",
36     "*.link_append",
37     "render.render",
38     "render.play_rendered_anim",
39     "*.*_export",
40     "*.*_import",
41     "wm.blenderplayer_start",
42     "wm.url_open",
43     "wm.doc_view",
44     "wm.path_open",
45     "wm.theme_install",
46     "wm.context_*",
47     "wm.operator_cheat_sheet",
48     "wm.keyconfig_test",     # just annoying - but harmless
49     "wm.memory_statistics",  # another annoying one
50     "console.*",             # just annoying - but harmless
51     )
52
53
54 def filter_op_list(operators):
55     from fnmatch import fnmatchcase
56
57     def is_op_ok(op):
58         for op_match in op_blacklist:
59             if fnmatchcase(op, op_match):
60                 print("    skipping: %s (%s)" % (op, op_match))
61                 return False
62         return True
63
64     operators[:] = [op for op in operators if is_op_ok(op[0])]
65
66
67 def run_ops(operators, setup_func=None, reset=True):
68     print("\ncontext:", setup_func.__name__)
69     # first invoke
70     for op_id, op in operators:
71         if op.poll():
72             print("    operator:", op_id)
73             sys.stdout.flush()  # in case of crash
74
75             # disable will get blender in a bad state and crash easy!
76             if reset:
77                 bpy.ops.wm.read_factory_settings()
78
79             setup_func()
80
81             for mode in {'EXEC_DEFAULT', 'INVOKE_DEFAULT'}:
82                 try:
83                     op(mode)
84                 except:
85                     #import traceback
86                     #traceback.print_exc()
87                     pass
88
89     if not operators:
90         # run test
91         if reset:
92             bpy.ops.wm.read_factory_settings()
93         setup_func()
94
95
96 # contexts
97 def ctx_clear_scene():  # copied from batch_import.py
98     unique_obs = set()
99     for scene in bpy.data.scenes:
100         for obj in scene.objects[:]:
101             scene.objects.unlink(obj)
102             unique_obs.add(obj)
103
104     # remove obdata, for now only worry about the startup scene
105     for bpy_data_iter in (bpy.data.objects, bpy.data.meshes, bpy.data.lamps, bpy.data.cameras):
106         for id_data in bpy_data_iter:
107             bpy_data_iter.remove(id_data)
108
109
110 def ctx_editmode_mesh():
111     bpy.ops.object.mode_set(mode='EDIT')
112
113
114 def ctx_editmode_mesh_extra():
115     bpy.ops.object.vertex_group_add()
116     bpy.ops.object.shape_key_add(from_mix=False)
117     bpy.ops.object.shape_key_add(from_mix=True)
118     bpy.ops.mesh.uv_texture_add()
119     bpy.ops.mesh.vertex_color_add()
120     bpy.ops.object.material_slot_add()
121     # editmode last!
122     bpy.ops.object.mode_set(mode='EDIT')
123
124
125 def ctx_editmode_mesh_empty():
126     bpy.ops.object.mode_set(mode='EDIT')
127     bpy.ops.mesh.select_all(action='SELECT')
128     bpy.ops.mesh.delete()
129
130
131 def ctx_editmode_curves():
132     bpy.ops.curve.primitive_nurbs_circle_add()
133     bpy.ops.object.mode_set(mode='EDIT')
134
135
136 def ctx_editmode_curves_empty():
137     bpy.ops.curve.primitive_nurbs_circle_add()
138     bpy.ops.object.mode_set(mode='EDIT')
139     bpy.ops.curve.delete(type='ALL')
140
141
142 def ctx_editmode_surface():
143     bpy.ops.surface.primitive_nurbs_surface_torus_add()
144     bpy.ops.object.mode_set(mode='EDIT')
145
146
147 def ctx_editmode_mball():
148     bpy.ops.object.metaball_add()
149     bpy.ops.object.mode_set(mode='EDIT')
150
151
152 def ctx_editmode_text():
153     bpy.ops.object.text_add()
154     bpy.ops.object.mode_set(mode='EDIT')
155
156
157 def ctx_editmode_armature():
158     bpy.ops.object.armature_add()
159     bpy.ops.object.mode_set(mode='EDIT')
160
161
162 def ctx_editmode_armature_empty():
163     bpy.ops.object.armature_add()
164     bpy.ops.object.mode_set(mode='EDIT')
165     bpy.ops.armature.select_all(action='SELECT')
166     bpy.ops.armature.delete()
167
168
169 def ctx_editmode_lattice():
170     bpy.ops.object.add(type='LATTICE')
171     bpy.ops.object.mode_set(mode='EDIT')
172     # bpy.ops.object.vertex_group_add()
173
174
175 def ctx_object_empty():
176     bpy.ops.object.add(type='EMPTY')
177
178
179 def ctx_object_pose():
180     bpy.ops.object.armature_add()
181     bpy.ops.object.mode_set(mode='POSE')
182     bpy.ops.pose.select_all(action='SELECT')
183
184
185 def ctx_object_paint_weight():
186     bpy.ops.object.mode_set(mode='WEIGHT_PAINT')
187
188
189 def ctx_object_paint_vertex():
190     bpy.ops.object.mode_set(mode='VERTEX_PAINT')
191
192
193 def ctx_object_paint_sculpt():
194     bpy.ops.object.mode_set(mode='SCULPT')
195
196
197 def ctx_object_paint_texture():
198     bpy.ops.object.mode_set(mode='TEXTURE_PAINT')
199
200
201 def bpy_check_type_duplicates():
202     # non essential sanity check
203     bl_types = dir(bpy.types)
204     bl_types_unique = set(bl_types)
205
206     if len(bl_types) != len(bl_types_unique):
207         print("Error, found duplicates in 'bpy.types'")
208         for t in sorted(bl_types_unique):
209             tot = bl_types.count(t)
210             if tot > 1:
211                 print("    '%s', %d" % (t, tot))
212         import sys
213         sys.exit(1)
214
215
216 def main():
217
218     bpy_check_type_duplicates()
219
220     # bpy.ops.wm.read_factory_settings()
221     import bpy
222     operators = []
223     for mod_name in dir(bpy.ops):
224         mod = getattr(bpy.ops, mod_name)
225         for submod_name in dir(mod):
226             op = getattr(mod, submod_name)
227             operators.append(("%s.%s" % (mod_name, submod_name), op))
228
229     operators.sort(key=lambda op: op[0])
230
231     filter_op_list(operators)
232
233     # for testing, mix the list up.
234     #operators.reverse()
235
236     #import random
237     #random.shuffle(operators)
238
239     # 2 passes, first just run setup_func to make sure they are ok
240     for operators_test in ((), operators):
241         # Run the operator tests in different contexts
242         run_ops(operators_test, setup_func=lambda: None)
243         run_ops(operators_test, setup_func=ctx_clear_scene)
244         # object modes
245         run_ops(operators_test, setup_func=ctx_object_empty)
246         run_ops(operators_test, setup_func=ctx_object_pose)
247         run_ops(operators_test, setup_func=ctx_object_paint_weight)
248         run_ops(operators_test, setup_func=ctx_object_paint_vertex)
249         run_ops(operators_test, setup_func=ctx_object_paint_sculpt)
250         run_ops(operators_test, setup_func=ctx_object_paint_texture)
251         # mesh
252         run_ops(operators_test, setup_func=ctx_editmode_mesh)
253         run_ops(operators_test, setup_func=ctx_editmode_mesh_extra)
254         run_ops(operators_test, setup_func=ctx_editmode_mesh_empty)
255         # armature
256         run_ops(operators_test, setup_func=ctx_editmode_armature)
257         run_ops(operators_test, setup_func=ctx_editmode_armature_empty)
258         # curves
259         run_ops(operators_test, setup_func=ctx_editmode_curves)
260         run_ops(operators_test, setup_func=ctx_editmode_curves_empty)
261         run_ops(operators_test, setup_func=ctx_editmode_surface)
262         # other
263         run_ops(operators_test, setup_func=ctx_editmode_mball)
264         run_ops(operators_test, setup_func=ctx_editmode_text)
265         run_ops(operators_test, setup_func=ctx_editmode_lattice)
266
267         if not operators_test:
268             print("All setup functions run fine!")
269
270     print("Finished %r" % __file__)
271
272 if __name__ == "__main__":
273     main()