Tools/Debugging/Python Trace

From Blender Developer Wiki
Jump to: navigation, search

Tracing Python Code

Tracing code is a handy way to check what the code is doing, where stepping over line by line is impractical.

If a certain operation isn't behaving properly you can trace the execution of the working & failing state, then view their differences to see at which point the code-path diverges.

The 'trace' module

This example shows how to use the trace Python module to trace script execution.

https://developer.blender.org/diffusion/B/browse/master/release/scripts/modules/bpy/__init__.py;711e3564b808ab802c503409e7740b0ca9b6ef65$68

The function call shows:

# Initializes Python classes.
# (good place to run a profiler or trace).
utils.load_scripts()

This example shows how a the function call can be traced.

import trace
tracer = trace.Trace(
        ignoredirs=[sys.prefix, sys.exec_prefix],
        trace=1,
        count=1,
        )
tracer.runctx('utils.load_scripts()', globals=globals(), locals=locals())

This traces all script execution on startup (addon registration, module imports... etc).

Heres an example of what the output may look like.

 --- modulename: __init__, funcname: <module>
<string>(1):  --- modulename: __init__, funcname: load_scripts
__init__.py(145):     use_time = _bpy.app.debug_python
__init__.py(147):     if use_time:
__init__.py(151):     loaded_modules = set()
__init__.py(153):     if refresh_scripts:
__init__.py(156):     if reload_scripts:
__init__.py(166):     def register_module_call(mod):
__init__.py(179):     def unregister_module_call(mod):
__init__.py(188):     def test_reload(mod):
__init__.py(202):     def test_register(mod):
__init__.py(215):     if reload_scripts:
__init__.py(231):     from bpy_restrict_state import RestrictBlend
 --- modulename: bpy_restrict_state, funcname: <module>
bpy_restrict_state.py(23): """
bpy_restrict_state.py(26):     "RestrictBlend",
bpy_restrict_state.py(29): import bpy as _bpy
bpy_restrict_state.py(32): class _RestrictContext:
 --- modulename: bpy_restrict_state, funcname: _RestrictContext
bpy_restrict_state.py(32): class _RestrictContext:
bpy_restrict_state.py(33):     __slots__ = ()
bpy_restrict_state.py(34):     _real_data = _bpy.data
bpy_restrict_state.py(36):     _real_pref = _bpy.context.user_preferences
bpy_restrict_state.py(38):     @property
bpy_restrict_state.py(42):     @property
bpy_restrict_state.py(47): class _RestrictData:
 --- modulename: bpy_restrict_state, funcname: _RestrictData
bpy_restrict_state.py(47): class _RestrictData:
bpy_restrict_state.py(48):     __slots__ = ()
bpy_restrict_state.py(51): _context_restrict = _RestrictContext()
bpy_restrict_state.py(52): _data_restrict = _RestrictData()
bpy_restrict_state.py(55): class RestrictBlend:
 --- modulename: bpy_restrict_state, funcname: RestrictBlend
bpy_restrict_state.py(55): class RestrictBlend:
bpy_restrict_state.py(56):     __slots__ = ("context", "data")
bpy_restrict_state.py(58):     def __enter__(self):
bpy_restrict_state.py(64):     def __exit__(self, type, value, traceback):
__init__.py(233):     with RestrictBlend():
 --- modulename: bpy_restrict_state, funcname: __enter__
bpy_restrict_state.py(59):         self.data = _bpy.data
bpy_restrict_state.py(60):         self.context = _bpy.context
bpy_restrict_state.py(61):         _bpy.data = _data_restrict
bpy_restrict_state.py(62):         _bpy.context = _context_restrict
__init__.py(234):         for base_path in script_paths():
 --- modulename: __init__, funcname: script_paths
__init__.py(306):     scripts = list(_scripts)
__init__.py(308):     if check_all:
__init__.py(314):         base_paths = _bpy_script_paths()
__init__.py(316):     for path in base_paths + (script_path_user(), script_path_pref()):
 --- modulename: __init__, funcname: script_path_user
__init__.py(282):     path = _user_resource('SCRIPTS')
__init__.py(283):     return _os.path.normpath(path) if path else None
 --- modulename: __init__, funcname: script_path_pref
__init__.py(288):     path = _user_preferences.filepaths.script_directory
__init__.py(289):     return _os.path.normpath(path) if path else None
__init__.py(317):         if path:
__init__.py(318):             path = _os.path.normpath(path)
__init__.py(319):             if path not in scripts and _os.path.isdir(path):
__init__.py(320):                 scripts.append(path)

-- snip (around 40k lines) --