This is all about overriding operators and improving the debugging experience for script authors when calling operators whose functionality isn’t exposed to the Python API. Also much of the credit/authorship of this design goes to @ideasman42
Design Task: #144746 - Python - Improve Documentation or Feedback of `temp_override` - blender - Blender Projects
The Problem
Let’s say you’re a script author, running headless operations on a server farm or just an artist learning how to script in Python.
You come across an operation like mesh data transfer that is only exposed with the operator bpy.ops.object.data_transfer and with context.temp_override, you can easily integrate this into a script. This issue is you aren’t sure which context members to override.
RuntimeError: Operator bpy.ops.object.data_transfer() failed, context is incorrect
Your operator doesn’t work! So you visit the gotchas page on operators and learn that poll messages are not widely used. Now this turns into a guessing game of keywords and reading source code. This also makes it harder to identify what is a bug, as the expected inputs are unknown.
This is the situation that several TDs and Pipeline architects expressed as a major pain point. We also ran into this issue on the development of the Blender Studio’s Asset Pipeline Add-On.
The Solution
Improving the poll messages/documentation is a lot of work, and adds an increased maintenance burden, and not everything can be directly exposed as Python functions.
The actual solution was a balance between effort and complexity; improve the context logging system and expose that to the PyAPI. This allows for the possibility of debugging what context members are being accessed.
How does it work?
To use the new logging functions called ./blender --log "context" but taking this a step further, the same information was exposed to the Python API.
Here is an example of the typical use case that most script authors have. They are overriding the context of an operator but not that they should be providing a certain item. In this example script we are transferring a seam from Cube1 to Cube2.
import bpy
source_obj = bpy.data.objects["Cube1"]
target_obj = bpy.data.objects["Cube2"]
# missing argument selected_editable_objects=[source_obj, target_obj],
with bpy.context.temp_override(object=source_obj) as temp_override_handle:
temp_override_handle.logging_set(True) # Use this to enable logging!
bpy.ops.object.data_transfer(
data_type="SEAM",
edge_mapping="NEAREST",
mix_mode="REPLACE",
use_object_transform=False,
)
With logging enabled here are the relevant outputs in the console. The user can infer that because selected_editable_objects is appearing in the logs, it should be included in the overrides.
04:11.238 context | /path/my_script.py:109: object=<Object("Cube1") at 0x7623ed594620>
04:11.238 context | /path/my_script.py:109: selected_editable_objects=[1 item(s)]
Warning: Failed to transfer mesh data to 1 objects
Feedback
I would love to hear any and all thoughts related to this problem and how this solution impacts you if you are a developer or artist. Currently the logging implemented in 5.0 is a full log of everything accessed (including lots of duplicate UI calls.)
So your feedback would be extremely useful on the additional logging arguments that are being added in an upcoming PR. Which included an option to de-duplicate the logs, for a more human-readable output.
Python: Add additional logging options for Context.temp_override #146416
Limitations
During an unrelated project I needed to override the USD Exporter. When doing so I was reminded of the unfortunate fact that not every operator actually accesses context. Now this new feature still saved me lots of time, as I was able to quickly determine no context members were being accessed, and I have added a line to the documentation to indicate this fact.
NOTE! Not every operator can be overridden, this feature assist in the debugging of these operators and what context member keywords can be passed, but it is not guaranteed that you can override the operator due to limitations of context.temp_override