| name | blender-core-api |
| description | Use when writing Blender Python scripts that access bpy module structure, RNA data, the context system, dependency graph, or operator invocation. Prevents the common mistake of accessing context attributes outside their valid scope or calling operators without checking poll(). Covers bpy.data, bpy.context, bpy.ops, depsgraph evaluation, and RNA property access patterns across Blender 3.x/4.x/5.x. Keywords: bpy, Blender Python, RNA, context, depsgraph, operator, bpy.data, bpy.ops, how to start scripting Blender, Blender Python basics, access objects in scene, get selected object.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires Blender 3.x/4.x/5.x with Python. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
blender-core-api
Quick Reference
bpy Module Hierarchy
| Module | Purpose | Example |
|---|
bpy.data | All blend-file data (ID data blocks) | bpy.data.objects["Cube"] |
bpy.context | Current state (active object, mode, selection) | bpy.context.active_object |
bpy.ops | Operators with undo support | bpy.ops.mesh.primitive_cube_add() |
bpy.types | Type definitions for all Blender structs | class MyOp(bpy.types.Operator): |
bpy.props | Property definitions for custom data | bpy.props.FloatProperty() |
bpy.utils | Utility functions (registration, paths) | bpy.utils.register_class(cls) |
bpy.app | Application info (version, handlers) | bpy.app.version |
bpy.path | Blender-aware path utilities | bpy.path.abspath("//file.png") |
bpy.msgbus | Message bus for property notifications | bpy.msgbus.subscribe_rna() |
bpy.data Collections (all versions)
bpy.data
├── .objects ├── .meshes ├── .materials ├── .scenes
├── .collections ├── .node_groups ├── .images ├── .textures
├── .lights ├── .cameras ├── .curves ├── .armatures
├── .worlds ├── .actions └── ... (30+ total collection types)
Critical Warnings
NEVER cache bpy.data object references across undo operations — undo invalidates all pointers.
NEVER call bpy.ops.* from a background thread — all bpy calls MUST run on the main thread.
NEVER use dict context overrides in Blender 4.0+ — use context.temp_override() instead.
NEVER modify scene data inside Panel.draw() — draw callbacks are read-only.
NEVER access mesh.vertices while in Edit Mode — the data is not synchronized. Use bmesh.from_edit_mesh() instead.
Essential Patterns
Pattern 1: Data Access vs. Operators
Use bpy.data for direct data manipulation (fast, no undo). Use bpy.ops only when undo support or user-facing actions are required.
obj = bpy.data.objects.get("Cube")
if obj:
obj.location = (1.0, 0.0, 0.0)
bpy.ops.object.location_clear()
Pattern 2: Context Overrides (version-critical)
override = bpy.context.copy()
override['active_object'] = obj
bpy.ops.object.modifier_apply(override, modifier="Subsurf")
with bpy.context.temp_override(object=obj, active_object=obj):
bpy.ops.object.modifier_apply(modifier="Subsurf")
for window in bpy.context.window_manager.windows:
for area in window.screen.areas:
if area.type == 'VIEW_3D':
with bpy.context.temp_override(window=window, area=area):
bpy.ops.view3d.snap_cursor_to_center()
break
Pattern 3: ID Data Block Lifecycle
mesh = bpy.data.meshes.new("MyMesh")
obj = bpy.data.objects.new("MyObject", mesh)
bpy.context.collection.objects.link(obj)
mesh.use_fake_user = True
bpy.data.meshes.remove(mesh)
Pattern 4: Dependency Graph
depsgraph = bpy.context.evaluated_depsgraph_get()
obj_eval = obj.evaluated_get(depsgraph)
mesh_eval = obj_eval.to_mesh()
obj_eval.to_mesh_clear()
for instance in depsgraph.object_instances:
obj = instance.object
matrix = instance.matrix_world
is_inst = instance.is_instance
Common Operations
Object Selection and Activation
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
RNA Introspection
obj = bpy.context.active_object
for prop in obj.bl_rna.properties:
print(f"{prop.identifier}: {prop.type}")
prop = obj.bl_rna.properties['location']
print(prop.array_length)
print(prop.subtype)
Application Handlers
from bpy.app.handlers import persistent
@persistent
def on_depsgraph_update(scene, depsgraph):
for update in depsgraph.updates:
if update.is_updated_geometry:
print(f"Geometry changed: {update.id.name}")
bpy.app.handlers.depsgraph_update_post.append(on_depsgraph_update)
bpy.app.handlers.depsgraph_update_post.remove(on_depsgraph_update)
Version Detection
major, minor, patch = bpy.app.version
if bpy.app.version >= (4, 0, 0):
pass
if bpy.app.version >= (5, 0, 0):
pass
Creating and Linking Objects
mesh = bpy.data.meshes.new("MyMesh")
verts = [(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0)]
faces = [(0, 1, 2, 3)]
mesh.from_pydata(verts, [], faces)
mesh.update()
obj = bpy.data.objects.new("MyObject", mesh)
bpy.context.collection.objects.link(obj)
Restricted Contexts
| Callback | Forbidden Operations |
|---|
Panel.draw() | bpy.ops.*, property modification |
depsgraph_update_post | Adding/removing objects, scene mutation |
render_pre/post | Most bpy.ops.* |
| Background mode | All viewport operators, OpenGL |
Version-Specific Migration Rules
| Feature | Blender 3.x | Blender 4.0+ |
|---|
| Context override | bpy.ops.foo(override_dict, ...) | context.temp_override(...) |
| Mesh bevel weight | edge.bevel_weight | mesh.attributes["bevel_weight_edge"] |
| Mesh crease | edge.crease | mesh.attributes["crease_edge"] |
| Node group sockets | node_group.inputs.new(...) | node_group.interface.new_socket(...) |
| Bone layers | bone.layers[i] | bone.collections |
| Feature | Blender 4.x | Blender 5.0+ |
|---|
| Drawing | bgl module (deprecated) | gpu module (REQUIRED) |
| Compositing | scene.node_tree | scene.compositing_node_group |
| EEVEE identifier | BLENDER_EEVEE or BLENDER_EEVEE_NEXT | BLENDER_EEVEE |
Reference Links
Official Sources