Add modular primitive libraries and fix Symbol class compatibility
- Add primitive_libs/ with modular primitive loading (core, math, image, color, color_ops, filters, geometry, drawing, blending, arrays, ascii) - Effects now explicitly declare dependencies via (require-primitives "...") - Convert ascii-fx-zone from hardcoded special form to loadable primitive - Add _is_symbol/_is_keyword helpers for duck typing to support both sexp_effects.parser.Symbol and artdag.sexp.parser.Symbol classes - Auto-inject _interp and _env for primitives that need them - Remove silent error swallowing in cell_effect evaluation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
17
execute.py
17
execute.py
@@ -348,9 +348,9 @@ def get_encoding(recipe_encoding: dict, step_config: dict) -> dict:
|
||||
class SexpEffectModule:
|
||||
"""Wrapper for S-expression effects to provide process_frame interface."""
|
||||
|
||||
def __init__(self, effect_path: Path, effects_registry: dict = None, recipe_dir: Path = None):
|
||||
def __init__(self, effect_path: Path, effects_registry: dict = None, recipe_dir: Path = None, minimal_primitives: bool = False):
|
||||
from sexp_effects import get_interpreter
|
||||
self.interp = get_interpreter()
|
||||
self.interp = get_interpreter(minimal_primitives=minimal_primitives)
|
||||
|
||||
# Load only explicitly declared effects from the recipe's registry
|
||||
# No auto-loading from directory - everything must be explicit
|
||||
@@ -371,10 +371,10 @@ class SexpEffectModule:
|
||||
return self.interp.run_effect(self.effect_name, frame, params, state or {})
|
||||
|
||||
|
||||
def load_effect(effect_path: Path, effects_registry: dict = None, recipe_dir: Path = None):
|
||||
def load_effect(effect_path: Path, effects_registry: dict = None, recipe_dir: Path = None, minimal_primitives: bool = False):
|
||||
"""Load an effect module from a local path (.py or .sexp)."""
|
||||
if effect_path.suffix == ".sexp":
|
||||
return SexpEffectModule(effect_path, effects_registry, recipe_dir)
|
||||
return SexpEffectModule(effect_path, effects_registry, recipe_dir, minimal_primitives)
|
||||
|
||||
spec = importlib.util.spec_from_file_location("effect", effect_path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
@@ -981,6 +981,11 @@ def execute_plan(plan_path: Path = None, output_path: Path = None, recipe_dir: P
|
||||
if effects_registry:
|
||||
print(f"Effects registry: {list(effects_registry.keys())}", file=sys.stderr)
|
||||
|
||||
# Check for minimal primitives mode
|
||||
minimal_primitives = plan.get("minimal_primitives", False)
|
||||
if minimal_primitives:
|
||||
print(f"Minimal primitives mode: enabled", file=sys.stderr)
|
||||
|
||||
# Execute steps
|
||||
results = {} # step_id -> output_path
|
||||
work_dir = Path(tempfile.mkdtemp(prefix="artdag_exec_"))
|
||||
@@ -1124,7 +1129,7 @@ def execute_plan(plan_path: Path = None, output_path: Path = None, recipe_dir: P
|
||||
|
||||
if effect_path:
|
||||
full_path = recipe_dir / effect_path
|
||||
effect_module = load_effect(full_path, effects_registry, recipe_dir)
|
||||
effect_module = load_effect(full_path, effects_registry, recipe_dir, minimal_primitives)
|
||||
params = {k: v for k, v in config.items()
|
||||
if k not in ("effect", "effect_path", "cid", "encoding", "multi_input")}
|
||||
print(f" Effect: {effect_name}", file=sys.stderr)
|
||||
@@ -1420,7 +1425,7 @@ def execute_plan(plan_path: Path = None, output_path: Path = None, recipe_dir: P
|
||||
|
||||
if effect_path:
|
||||
full_path = recipe_dir / effect_path
|
||||
effect_module = load_effect(full_path, effects_registry, recipe_dir)
|
||||
effect_module = load_effect(full_path, effects_registry, recipe_dir, minimal_primitives)
|
||||
params = {k: v for k, v in effect_config.items()
|
||||
if k not in ("effect", "effect_path", "cid", "encoding", "type")}
|
||||
print(f" COMPOUND [{i+1}/{len(effects)}]: {effect_name} (Python)", file=sys.stderr)
|
||||
|
||||
Reference in New Issue
Block a user