PME code is most useful when it removes a specific piece of Blender workflow friction. Start with a goal below; use the syntax collection when you need to understand or adapt the command itself.
The archive often uses compact names such as C, L, E, and U. PME Terms You Will Meet explains where each name is available before you copy a snippet into a different slot type.
Choose what you want to build
Focused recipes
Use these after you know which kind of behavior or interface you are building.
Context and availability
- Keep an action disabled until its option is enabled
- Use one hotkey for different Node Editor menus
- Guard a Custom layout against object type and no selection
Calling and integrating automation
Custom-layout details
- Draw only X, Y, or Z from a vector property
- Draw an Object, Bone, or Scene custom property
- Draw Blender header menus with header_menu()
- Add a Blender template widget to a Popup Dialog
- Give enum buttons explicit labels
Essential syntax collection
The compact patterns below are retained because PME’s standard Command, Custom, and Poll authoring fields are single-line controls. Use semicolons and expressions for short commands; use an external script when the logic deserves normal multiline Python.
Standard PME command fields use one line
Keep short commands in the field; move longer or reusable logic into a Python file.
- Use
;(semicolon) to separate statements- Use ternary expressions
a if condition else binstead ofif/elseblocks- Use list comprehensions
[x for x in items]instead offorloops- Use
and/orfor short-circuit evaluation instead of conditionalsThe multi-line examples in this guide are for readability only. Convert them to a single line before entering them into a standard PME command field.
Converting Multi-Line to Single-Line
Readable format (for documentation):
if bpy.context.mode == 'EDIT_MESH':
bpy.ops.mesh.select_all(action='SELECT')
else:
bpy.ops.object.select_all(action='SELECT')Actual PME format (what you must type):
bpy.ops.mesh.select_all(action='SELECT') if C.mode == 'EDIT_MESH' else bpy.ops.object.select_all(action='SELECT')Multi-statement example (requires an active object):
# Readable:
obj = C.active_object
obj.show_wire = True
obj.show_all_edges = True
# PME format:
obj = C.active_object; obj.show_wire = True; obj.show_all_edges = TrueUnderstanding PME Code Slots
PME has several places where you can write Python code:
| Location | Purpose | Example |
|---|---|---|
| Command slot | Execute operators or short code | bpy.ops.mesh.subdivide() |
| Custom slot | Draw UI with UILayout | Labels, properties, operators |
| Poll tab | Gate menu or item visibility | return C.mode == 'EDIT_MESH' |
| Property editor | Expose a reusable value | Scene/object settings |
PME Global Variables
PME provides shorthand variables for common Blender modules:
| Variable | Equivalent | Description |
|---|---|---|
C | bpy.context | Current context |
D | bpy.data | Blender data |
O | bpy.ops | Operators |
T | bpy.types | Type definitions |
L | UILayout | Current layout (Custom slot) |
E | Event | Current scoped event, when available |
U | UserData | Session-scoped scratch data |
Basic Patterns
Simple Operator Call
O.mesh.subdivide(number_cuts=2)Multiple Operations (Macro-style)
# Readable:
bpy.ops.object.duplicate()
bpy.ops.transform.translate(value=(1, 0, 0))
# PME format:
O.object.duplicate(); O.transform.translate(value=(1, 0, 0))Conditional Execution (Ternary)
# Instead of if/else blocks, use ternary:
O.mesh.select_all(action='SELECT') if C.mode == 'EDIT_MESH' else O.object.select_all(action='SELECT')Short-Circuit Evaluation
Use and/or for conditional execution:
# Execute only in a valid object context:
C.mode == 'OBJECT' and C.active_object and O.object.shade_smooth()
# Execute with fallback:
C.selected_objects or message_box("No objects selected!")Common Recipes
Toggle Selection Mode
# Readable version:
ts = C.tool_settings
mode = tuple(ts.mesh_select_mode)
if mode == (True, False, False):
ts.mesh_select_mode = (False, True, False)
elif mode == (False, True, False):
ts.mesh_select_mode = (False, False, True)
else:
ts.mesh_select_mode = (True, False, False)
# PME format (using nested ternary):
ts = C.tool_settings; m = tuple(ts.mesh_select_mode); ts.mesh_select_mode = (False, True, False) if m == (True, False, False) else ((False, False, True) if m == (False, True, False) else (True, False, False))Access Active Object Properties
# Readable:
obj = C.active_object
if obj is not None:
obj.show_wire = not obj.show_wire
# PME format:
obj = C.active_object; obj is not None and setattr(obj, "show_wire", not obj.show_wire)Undo Boundaries for Multi-Step Actions
Undo behavior varies by operator, mode, and Blender version. Test the sequence before adding a manual undo push; Plan undo boundaries for multi-step PME actions explains the historical observation and test procedure.
Running External Python Files
Call External Script
If you need to run a
.pyfile, use theexecute_script()function. This is essential for complex scripts that cannot fit in a single line.
execute_script() Function
execute_script(path, **kwargs)- path: A
scripts/...path checks the user scripts directory first and then PME’s bundled scripts; other relative paths use the add-on directory, and absolute paths are accepted - kwargs: Additional keyword arguments passed to the script
- Returns: Value of
return_valuevariable in script, orTrueby default
Usage Examples
Basic execution:
execute_script("scripts/my_script.py")With parameters:
execute_script("scripts/my_script.py", msg="Hello World!", count=5)Inside your script (my_script.py):
# Access passed parameters via kwargs
msg = kwargs.get("msg", "Default")
count = kwargs.get("count", 1)
# PME globals are available (C, D, O, L, etc.)
for i in range(count):
print(msg)
# Return a value
return_value = "Success!"Available in script:
- PME globals for the current execution context (
C,D,O,L,U, andEwhen a scoped event exists) kwargs- Passed keyword arguments__file__- Script file pathreturn_value- Set this to return a value
Poll Function Examples
Poll functions determine when a menu or slot is visible. They must return a boolean.
Only in Edit Mode
return C.mode == 'EDIT_MESH'Only When Object Selected
return C.active_object is not NoneOnly for Mesh Objects
return C.active_object and C.active_object.type == 'MESH'Multiple Conditions
obj = C.active_object; return obj and obj.type == 'MESH' and C.mode == 'EDIT_MESH'Advanced Patterns
Using the Layout API (Custom Slots)
# Each line separated by ; in actual PME:
L.label(text="My Custom Tool"); L.prop(C.active_object, "name"); L.operator("mesh.subdivide"); L.separator(); L.prop(C.scene.render, "engine")Generate UI Rows with a List Comprehension
# Draw one row for each selected object:
[L.label(text=obj.name, icon='OBJECT_DATA') for obj in C.selected_objects]Accessing Addon Preferences
prefs = C.preferences.addons['my_addon'].preferences; value = prefs.my_propertyUsing UserData (U) for Session-Scoped Scratch State
U is a scratch container shared by PME commands during one registered session. Disabling PME or restarting Blender recreates it. Use a PME Property or Blender data when the value must persist.
# Store data for the current PME session:
U.my_value = 42; U.update(foo="bar", count=10)
# Retrieve data:
value = U.get("my_value", 0)Debugging Tips
Print to Console
print("Debug:", C.active_object)Message Box for User Feedback
message_box("Operation completed!", icon='INFO')Check Available Properties
In Blender’s Python Console:
dir(bpy.context.active_object)Find Operator ID
- Open
Edit → Preferences → Interface - Enable “Developer Extras”
- Right-click any button → “Edit Source” or hover to see operator ID
Quick Reference Card
| Pattern | PME Syntax |
|---|---|
| Multiple statements | stmt1; stmt2; stmt3 |
| If/else | a if cond else b |
| If only | cond and action |
| Loop | [action for x in items] |
| Get with default | obj.get("key", default) |
| Safe attribute | getattr(obj, "attr", None) |
| External script | execute_script("path.py", **kwargs) |