PME Code Examples

Python snippets and patterns for advanced PME customization.


⚠️ Critical: PME’s One-Line Constraint

All PME code must be a single line

In PME, all code is stored in Blender’s string properties, which means your entire command must be completely on a single line.

  • Use ; (semicolon) to separate statements
  • Use ternary expressions a if condition else b instead of if/else blocks
  • Use list comprehensions [x for x in items] instead of for loops
  • Use and/or for short-circuit evaluation instead of conditionals

The multi-line examples in this guide are for readability only. You must convert them to single-line format before using in PME.

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:

# Readable:
obj = C.active_object
obj.data.use_auto_smooth = True
obj.data.auto_smooth_angle = 0.523599
 
# PME format:
obj = C.active_object; obj.data.use_auto_smooth = True; obj.data.auto_smooth_angle = 0.523599

Understanding PME Code Slots

PME has several places where you can write Python code:

LocationPurposeExample
Command slotExecute operators or codebpy.ops.mesh.subdivide()
Custom slotComplex scripts with UIMulti-step tools
Poll tabConditional menu displayreturn C.mode == 'EDIT_MESH'
Property slotExpose Blender propertiesScene/object settings

PME Global Variables

PME provides shorthand variables for common Blender modules:

VariableEquivalentDescription
Cbpy.contextCurrent context
Dbpy.dataBlender data
Obpy.opsOperators
Tbpy.typesType definitions
LUILayoutCurrent layout (Custom slot)
EEventCurrent event
UUserDataPersistent user data storage

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 if condition is true:
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 and obj.type == 'MESH':
    obj.data.use_auto_smooth = True
 
# PME format:
obj = C.active_object; obj and obj.type == 'MESH' and setattr(obj.data, 'use_auto_smooth', True)

Execute with Undo Push

From [[../Posts/2025/post_05648|Post #5648]] - important for macro reliability:

O.paint.visibility_invert("EXEC_DEFAULT"); O.ed.undo_push(message="visibility_invert")

Running External Python Files

Call External Script

If you need to run a .py file, use the execute_script() function. This is essential for complex scripts that cannot fit in a single line.

execute_script() Function

execute_script(path, **kwargs)
  • path: Script file path relative to pie_menu_editor folder (recommended) or absolute path
  • kwargs: Additional keyword arguments passed to the script
  • Returns: Value of return_value variable in script, or True by 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:

  • All PME global variables (C, D, O, L, E, U)
  • kwargs - Passed keyword arguments
  • __file__ - Script file path
  • return_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 None

Only 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")

Dynamic Menu Items with List Comprehension

# Instead of for loops, use list comprehension:
[L.operator("object.select_all", text=obj.name).action for obj in C.selected_objects]

Accessing Addon Preferences

prefs = C.preferences.addons['my_addon'].preferences; value = prefs.my_property

Using UserData (U) for Persistent State

# Store data:
U.my_value = 42; U.update(foo="bar", count=10)
 
# Retrieve data:
value = U.get("my_value", 0)

Debugging Tips

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

  1. Open Edit → Preferences → Interface
  2. Enable “Developer Extras”
  3. Right-click any button → “Edit Source” or hover to see operator ID

Quick Reference Card

PatternPME Syntax
Multiple statementsstmt1; stmt2; stmt3
If/elsea if cond else b
If onlycond and action
Loop[action for x in items]
Get with defaultobj.get("key", default)
Safe attributegetattr(obj, "attr", None)
External scriptexecute_script("path.py", **kwargs)

Browse code-related discussions in the archive:


External Resources