Merge branch 'blender2.7'
[blender.git] / doc / python_api / rst / info_gotcha.rst
1
2 *******
3 Gotchas
4 *******
5
6 This document attempts to help you work with the Blender API in areas
7 that can be troublesome and avoid practices that are known to give instability.
8
9
10 .. _using_operators:
11
12 Using Operators
13 ===============
14
15 Blender's operators are tools for users to access, that Python can access them too is very useful
16 nevertheless operators have limitations that can make them cumbersome to script.
17
18 Main limits are...
19
20 - Can't pass data such as objects, meshes or materials to operate on (operators use the context instead)
21 - The return value from calling an operator gives the success (if it finished or was canceled),
22   in some cases it would be more logical from an API perspective to return the result of the operation.
23 - Operators poll function can fail where an API function would raise an exception giving details on exactly why.
24
25
26 Why does an operator's poll fail?
27 ---------------------------------
28
29 When calling an operator gives an error like this:
30
31    >>> bpy.ops.action.clean(threshold=0.001)
32    RuntimeError: Operator bpy.ops.action.clean.poll() failed, context is incorrect
33
34 Which raises the question as to what the correct context might be?
35
36 Typically operators check for the active area type, a selection or active object they can operate on,
37 but some operators are more picky about when they run.
38
39 In most cases you can figure out what context an operator needs
40 simply be seeing how it's used in Blender and thinking about what it does.
41
42 Unfortunately if you're still stuck - the only way to **really** know
43 whats going on is to read the source code for the poll function and see what its checking.
44
45 For Python operators it's not so hard to find the source
46 since it's included with Blender and the source file/line is included in the operator reference docs.
47
48 Downloading and searching the C code isn't so simple,
49 especially if you're not familiar with the C language but by searching the
50 operator name or description you should be able to find the poll function with no knowledge of C.
51
52 .. note::
53
54    Blender does have the functionality for poll functions to describe why they fail,
55    but its currently not used much, if you're interested to help improve our API
56    feel free to add calls to ``CTX_wm_operator_poll_msg_set`` where its not obvious why poll fails.
57
58       >>> bpy.ops.gpencil.draw()
59       RuntimeError: Operator bpy.ops.gpencil.draw.poll() Failed to find Grease Pencil data to draw into
60
61
62 The operator still doesn't work!
63 --------------------------------
64
65 Certain operators in Blender are only intended for use in a specific context,
66 some operators for example are only called from the properties window where they check the current material,
67 modifier or constraint.
68
69 Examples of this are:
70
71 - :mod:`bpy.ops.texture.slot_move`
72 - :mod:`bpy.ops.constraint.limitdistance_reset`
73 - :mod:`bpy.ops.object.modifier_copy`
74 - :mod:`bpy.ops.buttons.file_browse`
75
76 Another possibility is that you are the first person to attempt to use this operator
77 in a script and some modifications need to be made to the operator to run in a different context,
78 if the operator should logically be able to run but fails when accessed from a script
79 it should be reported to the bug tracker.
80
81
82 Stale Data
83 ==========
84
85 No updates after setting values
86 -------------------------------
87
88 Sometimes you want to modify values from Python and immediately access the updated values, eg:
89
90 Once changing the objects :class:`bpy.types.Object.location`
91 you may want to access its transformation right after from :class:`bpy.types.Object.matrix_world`,
92 but this doesn't work as you might expect.
93
94 Consider the calculations that might go into working out the object's final transformation, this includes:
95
96 - animation function curves.
97 - drivers and their Python expressions.
98 - constraints
99 - parent objects and all of their f-curves, constraints etc.
100
101 To avoid expensive recalculations every time a property is modified,
102 Blender defers making the actual calculations until they are needed.
103
104 However, while the script runs you may want to access the updated values.
105 In this case you need to call :class:`bpy.types.Scene.update` after modifying values, for example:
106
107 .. code-block:: python
108
109    bpy.context.object.location = 1, 2, 3
110    bpy.context.scene.update()
111
112
113 Now all dependent data (child objects, modifiers, drivers... etc)
114 has been recalculated and is available to the script.
115
116
117 Can I redraw during the script?
118 -------------------------------
119
120 The official answer to this is no, or... *"You don't want to do that"*.
121
122 To give some background on the topic...
123
124 While a script executes Blender waits for it to finish and is effectively locked until its done,
125 while in this state Blender won't redraw or respond to user input.
126 Normally this is not such a problem because scripts distributed with Blender
127 tend not to run for an extended period of time,
128 nevertheless scripts *can* take ages to execute and its nice to see whats going on in the view port.
129
130 Tools that lock Blender in a loop and redraw are highly discouraged
131 since they conflict with Blenders ability to run multiple operators
132 at once and update different parts of the interface as the tool runs.
133
134 So the solution here is to write a **modal** operator, that is - an operator which defines a modal() function,
135 See the modal operator template in the text  editor.
136
137 Modal operators execute on user input or setup their own timers to run frequently,
138 they can handle the events or pass through to be handled by the keymap or other modal operators.
139
140 Transform, Painting, Fly-Mode and File-Select are example of a modal operators.
141
142 Writing modal operators takes more effort than a simple ``for`` loop
143 that happens to redraw but is more flexible and integrates better with Blenders design.
144
145
146 **Ok, Ok! I still want to draw from Python**
147
148 If you insist - yes its possible, but scripts that use this hack won't be considered
149 for inclusion in Blender and any issues with using it won't be considered bugs,
150 this is also not guaranteed to work in future releases.
151
152 .. code-block:: python
153
154    bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
155
156
157 Modes and Mesh Access
158 =====================
159
160 When working with mesh data you may run into the problem where a script fails to run as expected in edit-mode.
161 This is caused by edit-mode having its own data which is only written back to the mesh when exiting edit-mode.
162
163 A common example is that exporters may access a mesh through ``obj.data`` (a :class:`bpy.types.Mesh`)
164 but the user is in edit-mode, where the mesh data is available but out of sync with the edit mesh.
165
166 In this situation you can...
167
168 - Exit edit-mode before running the tool.
169 - Explicitly update the mesh by calling :class:`bmesh.types.BMesh.to_mesh`.
170 - Modify the script to support working on the edit-mode data directly, see: :mod:`bmesh.from_edit_mesh`.
171 - Report the context as incorrect and only allow the script to run outside edit-mode.
172
173
174 .. _info_gotcha_mesh_faces:
175
176 N-Gons and Tessellation
177 =======================
178
179 Since 2.63 NGons are supported, this adds some complexity
180 since in some cases you need to access triangles still (some exporters for example).
181
182 There are now 3 ways to access faces:
183
184 - :class:`bpy.types.MeshPolygon` -
185   this is the data structure which now stores faces in object mode
186   (access as ``mesh.polygons`` rather than ``mesh.faces``).
187 - :class:`bpy.types.MeshLoopTriangle` -
188   the result of tessellating polygons into triangles
189   (access as ``mesh.loop_triangles``).
190 - :class:`bmesh.types.BMFace` -
191   the polygons as used in editmode.
192
193 For the purpose of the following documentation,
194 these will be referred to as polygons, loop triangles and bmesh-faces respectively.
195
196 5+ sided faces will be referred to as ``ngons``.
197
198
199 Support Overview
200 ----------------
201
202 .. list-table::
203    :header-rows: 1
204    :stub-columns: 1
205
206    * - Usage
207      - :class:`bpy.types.MeshPolygon`
208      - :class:`bpy.types.MeshTessFace`
209      - :class:`bmesh.types.BMFace`
210    * - Import/Create
211      - Poor *(inflexible)*
212      - Good *(supported as upgrade path)*
213      - Best
214    * - Manipulate
215      - Poor *(inflexible)*
216      - Poor *(loses ngons)*
217      - Best
218    * - Export/Output
219      - Good *(ngon support)*
220      - Good *(When ngons can't be used)*
221      - Good *(ngons, extra memory overhead)*
222
223 .. note::
224
225    Using the :mod:`bmesh` API is completely separate API from :mod:`bpy`,
226    typically you would would use one or the other based on the level of editing needed,
227    not simply for a different way to access faces.
228
229
230 Creating
231 --------
232
233 All 3 datatypes can be used for face creation.
234
235 - polygons are the most efficient way to create faces but the data structure is _very_ rigid and inflexible,
236   you must have all your vertices and faces ready and create them all at once.
237   This is further complicated by the fact that each polygon does not store its own verts,
238   rather they reference an index and size in :class:`bpy.types.Mesh.loops` which are a fixed array too.
239 - bmesh-faces are most likely the easiest way for new scripts to create faces,
240   since faces can be added one by one and the api has features intended for mesh manipulation.
241   While :class:`bmesh.types.BMesh` uses more memory it can be managed by only operating on one mesh at a time.
242
243
244 Editing
245 -------
246
247 Editing is where the 3 data types vary most.
248
249 - Polygons are very limited for editing,
250   changing materials and options like smooth works but for anything else
251   they are too inflexible and are only intended for storage.
252 - Tessfaces should not be used for editing geometry because doing so will cause existing ngons to be tessellated.
253 - BMesh-Faces are by far the best way to manipulate geometry.
254
255
256 Exporting
257 ---------
258
259 All 3 data types can be used for exporting,
260 the choice mostly depends on whether the target format supports ngons or not.
261
262 - Polygons are the most direct & efficient way to export providing they convert into the output format easily enough.
263 - Tessfaces work well for exporting to formats which don't support ngons,
264   in fact this is the only place where their use is encouraged.
265 - BMesh-Faces can work for exporting too but may not be necessary if polygons can be used
266   since using bmesh gives some overhead because its not the native storage format in object mode.
267
268
269 EditBones, PoseBones, Bone... Bones
270 ===================================
271
272 Armature Bones in Blender have three distinct data structures that contain them.
273 If you are accessing the bones through one of them, you may not have access to the properties you really need.
274
275 .. note::
276
277    In the following examples ``bpy.context.object`` is assumed to be an armature object.
278
279
280 Edit Bones
281 ----------
282
283 ``bpy.context.object.data.edit_bones`` contains a editbones;
284 to access them you must set the armature mode to edit mode first (editbones do not exist in object or pose mode).
285 Use these to create new bones, set their head/tail or roll, change their parenting relationships to other bones, etc.
286
287 Example using :class:`bpy.types.EditBone` in armature editmode:
288
289 This is only possible in edit mode.
290
291    >>> bpy.context.object.data.edit_bones["Bone"].head = Vector((1.0, 2.0, 3.0))
292
293 This will be empty outside of editmode.
294
295    >>> mybones = bpy.context.selected_editable_bones
296
297 Returns an editbone only in edit mode.
298
299    >>> bpy.context.active_bone
300
301
302 Bones (Object Mode)
303 -------------------
304
305 ``bpy.context.object.data.bones`` contains bones.
306 These *live* in object mode, and have various properties you can change,
307 note that the head and tail properties are read-only.
308
309 Example using :class:`bpy.types.Bone` in object or pose mode:
310
311 Returns a bone (not an editbone) outside of edit mode
312
313    >>> bpy.context.active_bone
314
315 This works, as with blender the setting can be edited in any mode
316
317    >>> bpy.context.object.data.bones["Bone"].use_deform = True
318
319 Accessible but read-only
320
321    >>> tail = myobj.data.bones["Bone"].tail
322
323
324 Pose Bones
325 ----------
326
327 ``bpy.context.object.pose.bones`` contains pose bones.
328 This is where animation data resides, i.e. animatable transformations
329 are applied to pose bones, as are constraints and ik-settings.
330
331 Examples using :class:`bpy.types.PoseBone` in object or pose mode:
332
333 .. code-block:: python
334
335    # Gets the name of the first constraint (if it exists)
336    bpy.context.object.pose.bones["Bone"].constraints[0].name
337
338    # Gets the last selected pose bone (pose mode only)
339    bpy.context.active_pose_bone
340
341
342 .. note::
343
344    Notice the pose is accessed from the object rather than the object data,
345    this is why blender can have 2 or more objects sharing the same armature in different poses.
346
347 .. note::
348
349    Strictly speaking PoseBone's are not bones, they are just the state of the armature,
350    stored in the :class:`bpy.types.Object` rather than the :class:`bpy.types.Armature`,
351    the real bones are however accessible from the pose bones - :class:`bpy.types.PoseBone.bone`
352
353
354 Armature Mode Switching
355 -----------------------
356
357 While writing scripts that deal with armatures you may find you have to switch between modes,
358 when doing so take care when switching out of edit-mode not to keep references
359 to the edit-bones or their head/tail vectors.
360 Further access to these will crash blender so its important the script
361 clearly separates sections of the code which operate in different modes.
362
363 This is mainly an issue with editmode since pose data can be manipulated without having to be in pose mode,
364 however for operator access you may still need to enter pose mode.
365
366
367 Data Names
368 ==========
369
370
371 Naming Limitations
372 ------------------
373
374 A common mistake is to assume newly created data is given the requested name.
375
376 This can cause bugs when you add some data (normally imported) then reference it later by name.
377
378 .. code-block:: python
379
380    bpy.data.meshes.new(name=meshid)
381
382    # normally some code, function calls...
383    bpy.data.meshes[meshid]
384
385
386 Or with name assignment...
387
388 .. code-block:: python
389
390    obj.name = objname
391
392    # normally some code, function calls...
393    obj = bpy.data.meshes[objname]
394
395
396 Data names may not match the assigned values if they exceed the maximum length, are already used or an empty string.
397
398
399 Its better practice not to reference objects by names at all,
400 once created you can store the data in a list, dictionary, on a class etc,
401 there is rarely a reason to have to keep searching for the same data by name.
402
403 If you do need to use name references, its best to use a dictionary to maintain
404 a mapping between the names of the imported assets and the newly created data,
405 this way you don't run this risk of referencing existing data from the blend file, or worse modifying it.
406
407 .. code-block:: python
408
409    # typically declared in the main body of the function.
410    mesh_name_mapping = {}
411
412    mesh = bpy.data.meshes.new(name=meshid)
413    mesh_name_mapping[meshid] = mesh
414
415    # normally some code, or function calls...
416
417    # use own dictionary rather than bpy.data
418    mesh = mesh_name_mapping[meshid]
419
420
421 Library Collisions
422 ------------------
423
424 Blender keeps data names unique - :class:`bpy.types.ID.name` so you can't name two objects,
425 meshes, scenes etc the same thing by accident.
426
427 However when linking in library data from another blend file naming collisions can occur,
428 so its best to avoid referencing data by name at all.
429
430 This can be tricky at times and not even blender handles this correctly in some case
431 (when selecting the modifier object for eg you can't select between multiple objects with the same name),
432 but its still good to try avoid problems in this area.
433
434
435 If you need to select between local and library data, there is a feature in ``bpy.data`` members to allow for this.
436
437 .. code-block:: python
438
439    # typical name lookup, could be local or library.
440    obj = bpy.data.objects["my_obj"]
441
442    # library object name look up using a pair
443    # where the second argument is the library path matching bpy.types.Library.filepath
444    obj = bpy.data.objects["my_obj", "//my_lib.blend"]
445
446    # local object name look up using a pair
447    # where the second argument excludes library data from being returned.
448    obj = bpy.data.objects["my_obj", None]
449
450    # both the examples above also works for 'get'
451    obj = bpy.data.objects.get(("my_obj", None))
452
453
454 Relative File Paths
455 ===================
456
457 Blenders relative file paths are not compatible with standard Python modules such as ``sys`` and ``os``.
458
459 Built in Python functions don't understand blenders ``//`` prefix which denotes the blend file path.
460
461 A common case where you would run into this problem is when exporting a material with associated image paths.
462
463    >>> bpy.path.abspath(image.filepath)
464
465
466 When using blender data from linked libraries there is an unfortunate complication
467 since the path will be relative to the library rather than the open blend file.
468 When the data block may be from an external blend file pass the library argument from the :class:`bpy.types.ID`.
469
470    >>> bpy.path.abspath(image.filepath, library=image.library)
471
472
473 These returns the absolute path which can be used with native Python modules.
474
475
476 Unicode Problems
477 ================
478
479 Python supports many different encodings so there is nothing stopping you from
480 writing a script in ``latin1`` or ``iso-8859-15``.
481
482 See `pep-0263 <https://www.python.org/dev/peps/pep-0263/>`_
483
484 However this complicates matters for Blender's Python API because ``.blend`` files don't have an explicit encoding.
485
486 To avoid the problem for Python integration and script authors we have decided all strings in blend files
487 **must** be ``UTF-8``, ``ASCII`` compatible.
488
489 This means assigning strings with different encodings to an object names for instance will raise an error.
490
491 Paths are an exception to this rule since we cannot ignore the existence of non ``UTF-8`` paths on users file-system.
492
493 This means seemingly harmless expressions can raise errors, eg.
494
495    >>> print(bpy.data.filepath)
496    UnicodeEncodeError: 'ascii' codec can't encode characters in position 10-21: ordinal not in range(128)
497
498    >>> bpy.context.object.name = bpy.data.filepath
499    Traceback (most recent call last):
500      File "<blender_console>", line 1, in <module>
501    TypeError: bpy_struct: item.attr= val: Object.name expected a string type, not str
502
503
504 Here are 2 ways around filesystem encoding issues:
505
506    >>> print(repr(bpy.data.filepath))
507
508    >>> import os
509    >>> filepath_bytes = os.fsencode(bpy.data.filepath)
510    >>> filepath_utf8 = filepath_bytes.decode('utf-8', "replace")
511    >>> bpy.context.object.name = filepath_utf8
512
513
514 Unicode encoding/decoding is a big topic with comprehensive Python documentation,
515 to avoid getting stuck too deep in encoding problems - here are some suggestions:
516
517 - Always use utf-8 encoding or convert to utf-8 where the input is unknown.
518 - Avoid manipulating filepaths as strings directly, use ``os.path`` functions instead.
519 - Use ``os.fsencode()`` / ``os.fsdecode()`` instead of built in string decoding functions when operating on paths.
520 - To print paths or to include them in the user interface use ``repr(path)`` first
521   or ``"%r" % path`` with string formatting.
522
523 .. note::
524
525    Sometimes it's preferable to avoid string encoding issues by using bytes instead of Python strings,
526    when reading some input its less trouble to read it as binary data
527    though you will still need to decide how to treat any strings you want to use with Blender,
528    some importers do this.
529
530
531 Strange errors using 'threading' module
532 =======================================
533
534 Python threading with Blender only works properly when the threads finish up before the script does.
535 By using ``threading.join()`` for example.
536
537 Here is an example of threading supported by Blender:
538
539 .. code-block:: python
540
541    import threading
542    import time
543
544    def prod():
545        print(threading.current_thread().name, "Starting")
546
547        # do something vaguely useful
548        import bpy
549        from mathutils import Vector
550        from random import random
551
552        prod_vec = Vector((random() - 0.5, random() - 0.5, random() - 0.5))
553        print("Prodding", prod_vec)
554        bpy.data.objects["Cube"].location += prod_vec
555        time.sleep(random() + 1.0)
556        # finish
557
558        print(threading.current_thread().name, "Exiting")
559
560    threads = [threading.Thread(name="Prod %d" % i, target=prod) for i in range(10)]
561
562
563    print("Starting threads...")
564
565    for t in threads:
566        t.start()
567
568    print("Waiting for threads to finish...")
569
570    for t in threads:
571        t.join()
572
573
574 This an example of a timer which runs many times a second and moves
575 the default cube continuously while Blender runs **(Unsupported)**.
576
577 .. code-block:: python
578
579    def func():
580        print("Running...")
581        import bpy
582        bpy.data.objects['Cube'].location.x += 0.05
583
584    def my_timer():
585        from threading import Timer
586        t = Timer(0.1, my_timer)
587        t.start()
588        func()
589
590    my_timer()
591
592 Use cases like the one above which leave the thread running once the script finishes
593 may seem to work for a while but end up causing random crashes or errors in Blender's own drawing code.
594
595 So far, no work has gone into making Blender's Python integration thread safe,
596 so until its properly supported, best not make use of this.
597
598 .. note::
599
600    Pythons threads only allow co-currency and won't speed up your scripts on multi-processor systems,
601    the ``subprocess`` and ``multiprocess`` modules can be used with Blender and make use of multiple CPU's too.
602
603
604 Help! My script crashes Blender
605 ===============================
606
607 **TL;DR:** Do not keep direct references to Blender data (of any kind) when modifying the container
608 of that data, and/or when some undo/redo may happen (e.g. during modal operators execution...).
609 Instead, use indices (or other data always stored by value in Python, like string keys...),
610 that allow you to get access to the desired data.
611
612 Ideally it would be impossible to crash Blender from Python
613 however there are some problems with the API where it can be made to crash.
614
615 Strictly speaking this is a bug in the API but fixing it would mean adding memory verification
616 on every access since most crashes are caused by the Python objects referencing Blenders memory directly,
617 whenever the memory is freed or re-allocated, further Python access to it can crash the script.
618 But fixing this would make the scripts run very slow,
619 or writing a very different kind of API which doesn't reference the memory directly.
620
621 Here are some general hints to avoid running into these problems.
622
623 - Be aware of memory limits,
624   especially when working with large lists since Blender can crash simply by running out of memory.
625 - Many hard to fix crashes end up being because of referencing freed data,
626   when removing data be sure not to hold any references to it.
627 - Re-allocation can lead to the same issues
628   (e.g. if you add a lot of items to some Collection,
629   this can lead to re-allocating the underlying container's memory,
630   invalidating all previous references to existing items).
631 - Modules or classes that remain active while Blender is used,
632   should not hold references to data the user may remove, instead,
633   fetch data from the context each time the script is activated.
634 - Crashes may not happen every time, they may happen more on some configurations/operating-systems.
635 - Be wary of recursive patterns, those are very efficient at hiding the issues described here.
636
637 .. note::
638
639    To find the line of your script that crashes you can use the ``faulthandler`` module.
640    See the `faulthandler docs <https://docs.python.org/dev/library/faulthandler.html>`_.
641
642    While the crash may be in Blenders C/C++ code,
643    this can help a lot to track down the area of the script that causes the crash.
644
645 .. note::
646
647    Some container modifications are actually safe, because they will never re-allocate existing data
648    (e.g. linked lists containers will never re-allocate existing items when adding or removing others).
649
650    But knowing which cases are safe and which aren't implies a deep understanding of Blender's internals.
651    That's why, unless you are willing to dive into the RNA C implementation, it's simpler to
652    always assume that data references will become invalid when modifying their containers,
653    in any possible way.
654
655
656 **Don’t:**
657
658 .. code-block:: python
659
660    class TestItems(bpy.types.PropertyGroup):
661        name: bpy.props.StringProperty()
662
663    bpy.utils.register_class(TestItems)
664    bpy.types.Scene.test_items = bpy.props.CollectionProperty(type=TestItems)
665
666    first_item = bpy.context.scene.test_items.add()
667    for i in range(100):
668        bpy.context.scene.test_items.add()
669
670    # This is likely to crash, as internal code may re-allocate
671    # the whole container (the collection) memory at some point.
672    first_item.name = "foobar"
673
674
675 **Do:**
676
677 .. code-block:: python
678
679    class TestItems(bpy.types.PropertyGroup):
680        name: bpy.props.StringProperty()
681
682    bpy.utils.register_class(TestItems)
683    bpy.types.Scene.test_items = bpy.props.CollectionProperty(type=TestItems)
684
685    first_item = bpy.context.scene.test_items.add()
686    for i in range(100):
687        bpy.context.scene.test_items.add()
688
689    # This is safe, we are getting again desired data *after*
690    # all modifications to its container are done.
691    first_item = bpy.context.scene.test_items[0]
692    first_item.name = "foobar"
693
694
695 Undo/Redo
696 ---------
697
698 Undo invalidates all :class:`bpy.types.ID` instances (Object, Scene, Mesh, Lamp... etc).
699
700 This example shows how you can tell undo changes the memory locations.
701
702    >>> hash(bpy.context.object)
703    -9223372036849950810
704    >>> hash(bpy.context.object)
705    -9223372036849950810
706
707    # ... move the active object, then undo
708
709    >>> hash(bpy.context.object)
710    -9223372036849951740
711
712 As suggested above, simply not holding references to data when Blender is used
713 interactively by the user is the only way to ensure the script doesn't become unstable.
714
715
716 Undo & Library Data
717 ^^^^^^^^^^^^^^^^^^^
718
719 One of the advantages with Blenders library linking system that undo
720 can skip checking changes in library data since it is assumed to be static.
721
722 Tools in Blender are not allowed to modify library data.
723
724 Python however does not enforce this restriction.
725
726 This can be useful in some cases, using a script to adjust material values for example.
727 But its also possible to use a script to make library data point to newly created local data,
728 which is not supported since a call to undo will remove the local data
729 but leave the library referencing it and likely crash.
730
731 So it's best to consider modifying library data an advanced usage of the API
732 and only to use it when you know what you're doing.
733
734
735 Edit Mode / Memory Access
736 -------------------------
737
738 Switching edit-mode ``bpy.ops.object.mode_set(mode='EDIT')`` / ``bpy.ops.object.mode_set(mode='OBJECT')``
739 will re-allocate objects data,
740 any references to a meshes vertices/polygons/uvs, armatures bones,
741 curves points etc cannot be accessed after switching edit-mode.
742
743 Only the reference to the data its self can be re-accessed, the following example will crash.
744
745 .. code-block:: python
746
747    mesh = bpy.context.active_object.data
748    polygons = mesh.polygons
749    bpy.ops.object.mode_set(mode='EDIT')
750    bpy.ops.object.mode_set(mode='OBJECT')
751
752    # this will crash
753    print(polygons)
754
755
756 So after switching edit-mode you need to re-access any object data variables,
757 the following example shows how to avoid the crash above.
758
759 .. code-block:: python
760
761    mesh = bpy.context.active_object.data
762    polygons = mesh.polygons
763    bpy.ops.object.mode_set(mode='EDIT')
764    bpy.ops.object.mode_set(mode='OBJECT')
765
766    # polygons have been re-allocated
767    polygons = mesh.polygons
768    print(polygons)
769
770
771 These kinds of problems can happen for any functions which re-allocate
772 the object data but are most common when switching edit-mode.
773
774
775 Array Re-Allocation
776 -------------------
777
778 When adding new points to a curve or vertices/edges/polygons to a mesh,
779 internally the array which stores this data is re-allocated.
780
781 .. code-block:: python
782
783    bpy.ops.curve.primitive_bezier_curve_add()
784    point = bpy.context.object.data.splines[0].bezier_points[0]
785    bpy.context.object.data.splines[0].bezier_points.add()
786
787    # this will crash!
788    point.co = 1.0, 2.0, 3.0
789
790 This can be avoided by re-assigning the point variables after adding the new one or by storing
791 indices to the points rather than the points themselves.
792
793 The best way is to sidestep the problem altogether add all the points to the curve at once.
794 This means you don't have to worry about array re-allocation and its faster too
795 since reallocating the entire array for every point added is inefficient.
796
797
798 Removing Data
799 -------------
800
801 **Any** data that you remove shouldn't be modified or accessed afterwards,
802 this includes f-curves, drivers, render layers, timeline markers, modifiers, constraints
803 along with objects, scenes, collections, bones.. etc.
804
805 The ``remove()`` api calls will invalidate the data they free to prevent common mistakes.
806
807 The following example shows how this precaution works.
808
809 .. code-block:: python
810
811    mesh = bpy.data.meshes.new(name="MyMesh")
812    # normally the script would use the mesh here...
813    bpy.data.meshes.remove(mesh)
814    print(mesh.name)  # <- give an exception rather than crashing:
815
816    # ReferenceError: StructRNA of type Mesh has been removed
817
818
819 But take care because this is limited to scripts accessing the variable which is removed,
820 the next example will still crash.
821
822 .. code-block:: python
823
824    mesh = bpy.data.meshes.new(name="MyMesh")
825    vertices = mesh.vertices
826    bpy.data.meshes.remove(mesh)
827    print(vertices)  # <- this may crash
828
829
830 sys.exit
831 ========
832
833 Some Python modules will call ``sys.exit()`` themselves when an error occurs,
834 while not common behavior this is something to watch out for because it may seem
835 as if Blender is crashing since ``sys.exit()`` will close Blender immediately.
836
837 For example, the ``argparse`` module will print an error and exit if the arguments are invalid.
838
839 An ugly way of troubleshooting this is to set ``sys.exit = None`` and see what line of Python code is quitting,
840 you could of course replace ``sys.exit`` with your own function but manipulating Python in this way is bad practice.