Add REPL effect detection and input handling to pipeline runner
- Detect REPL effect in pipeline and enable interactive mode - Enable raw terminal mode for REPL input capture - Add keyboard input loop for REPL commands (return, up/down arrows, backspace) - Process commands and handle pipeline mutations from REPL - Fix lint issues in graph and REPL modules (type annotations, imports)
This commit is contained in:
@@ -22,8 +22,8 @@ Usage:
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
|
||||
class NodeType(Enum):
|
||||
@@ -45,7 +45,7 @@ class Node:
|
||||
|
||||
name: str
|
||||
type: NodeType
|
||||
config: Dict[str, Any] = field(default_factory=dict)
|
||||
config: dict[str, Any] = field(default_factory=dict)
|
||||
enabled: bool = True
|
||||
optional: bool = False
|
||||
|
||||
@@ -59,17 +59,17 @@ class Connection:
|
||||
|
||||
source: str
|
||||
target: str
|
||||
data_type: Optional[str] = None # Optional data type constraint
|
||||
data_type: str | None = None # Optional data type constraint
|
||||
|
||||
|
||||
@dataclass
|
||||
class Graph:
|
||||
"""Pipeline graph representation."""
|
||||
|
||||
nodes: Dict[str, Node] = field(default_factory=dict)
|
||||
connections: List[Connection] = field(default_factory=list)
|
||||
nodes: dict[str, Node] = field(default_factory=dict)
|
||||
connections: list[Connection] = field(default_factory=list)
|
||||
|
||||
def node(self, name: str, node_type: Union[NodeType, str], **config) -> "Graph":
|
||||
def node(self, name: str, node_type: NodeType | str, **config) -> "Graph":
|
||||
"""Add a node to the graph."""
|
||||
if isinstance(node_type, str):
|
||||
# Try to parse as NodeType
|
||||
@@ -82,7 +82,7 @@ class Graph:
|
||||
return self
|
||||
|
||||
def connect(
|
||||
self, source: str, target: str, data_type: Optional[str] = None
|
||||
self, source: str, target: str, data_type: str | None = None
|
||||
) -> "Graph":
|
||||
"""Add a connection between nodes."""
|
||||
if source not in self.nodes:
|
||||
@@ -99,7 +99,7 @@ class Graph:
|
||||
self.connect(names[i], names[i + 1])
|
||||
return self
|
||||
|
||||
def from_dict(self, data: Dict[str, Any]) -> "Graph":
|
||||
def from_dict(self, data: dict[str, Any]) -> "Graph":
|
||||
"""Load graph from dictionary (TOML-compatible)."""
|
||||
# Parse nodes
|
||||
nodes_data = data.get("nodes", {})
|
||||
@@ -127,7 +127,7 @@ class Graph:
|
||||
|
||||
return self
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
"""Convert graph to dictionary."""
|
||||
return {
|
||||
"nodes": {
|
||||
@@ -140,7 +140,7 @@ class Graph:
|
||||
],
|
||||
}
|
||||
|
||||
def validate(self) -> List[str]:
|
||||
def validate(self) -> list[str]:
|
||||
"""Validate graph structure and return list of errors."""
|
||||
errors = []
|
||||
|
||||
@@ -166,9 +166,8 @@ class Graph:
|
||||
|
||||
temp.add(node_name)
|
||||
for conn in self.connections:
|
||||
if conn.source == node_name:
|
||||
if has_cycle(conn.target):
|
||||
return True
|
||||
if conn.source == node_name and has_cycle(conn.target):
|
||||
return True
|
||||
temp.remove(node_name)
|
||||
visited.add(node_name)
|
||||
return False
|
||||
|
||||
@@ -4,12 +4,12 @@ This module bridges the new graph-based abstraction with the existing
|
||||
Stage-based pipeline system for backward compatibility.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, List, Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
from engine.pipeline.graph import Graph, NodeType
|
||||
from engine.pipeline.controller import Pipeline, PipelineConfig
|
||||
from engine.pipeline.core import PipelineContext
|
||||
from engine.pipeline.params import PipelineParams
|
||||
from engine.camera import Camera
|
||||
from engine.data_sources.sources import EmptyDataSource, HeadlinesDataSource
|
||||
from engine.display import DisplayRegistry
|
||||
from engine.effects import get_registry
|
||||
from engine.pipeline.adapters import (
|
||||
CameraStage,
|
||||
DataSourceStage,
|
||||
@@ -18,15 +18,12 @@ from engine.pipeline.adapters import (
|
||||
FontStage,
|
||||
MessageOverlayStage,
|
||||
PositionStage,
|
||||
ViewportFilterStage,
|
||||
create_stage_from_display,
|
||||
create_stage_from_effect,
|
||||
)
|
||||
from engine.pipeline.adapters.positioning import PositioningMode
|
||||
from engine.display import DisplayRegistry
|
||||
from engine.effects import get_registry
|
||||
from engine.data_sources.sources import EmptyDataSource, HeadlinesDataSource
|
||||
from engine.camera import Camera
|
||||
from engine.pipeline.controller import Pipeline, PipelineConfig
|
||||
from engine.pipeline.core import PipelineContext
|
||||
from engine.pipeline.graph import Graph, NodeType
|
||||
from engine.pipeline.params import PipelineParams
|
||||
|
||||
|
||||
class GraphAdapter:
|
||||
@@ -34,8 +31,8 @@ class GraphAdapter:
|
||||
|
||||
def __init__(self, graph: Graph):
|
||||
self.graph = graph
|
||||
self.pipeline: Optional[Pipeline] = None
|
||||
self.context: Optional[PipelineContext] = None
|
||||
self.pipeline: Pipeline | None = None
|
||||
self.context: PipelineContext | None = None
|
||||
|
||||
def build_pipeline(
|
||||
self, viewport_width: int = 80, viewport_height: int = 24
|
||||
@@ -154,7 +151,7 @@ def graph_to_pipeline(
|
||||
|
||||
|
||||
def dict_to_pipeline(
|
||||
data: Dict[str, Any], viewport_width: int = 80, viewport_height: int = 24
|
||||
data: dict[str, Any], viewport_width: int = 80, viewport_height: int = 24
|
||||
) -> Pipeline:
|
||||
"""Convert a dictionary to a Pipeline."""
|
||||
graph = Graph().from_dict(data)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
"""TOML-based graph configuration loader."""
|
||||
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
from typing import Any
|
||||
|
||||
import tomllib
|
||||
|
||||
from engine.pipeline.graph import Graph, NodeType
|
||||
from engine.pipeline.graph_adapter import graph_to_pipeline
|
||||
@@ -23,7 +24,7 @@ def load_graph_from_toml(toml_path: str | Path) -> Graph:
|
||||
return graph_from_dict(data)
|
||||
|
||||
|
||||
def graph_from_dict(data: Dict[str, Any]) -> Graph:
|
||||
def graph_from_dict(data: dict[str, Any]) -> Graph:
|
||||
"""Create a graph from a dictionary (TOML-compatible structure).
|
||||
|
||||
Args:
|
||||
|
||||
@@ -18,8 +18,8 @@ providing the same flexibility.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict, List, Optional
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from engine.pipeline.graph import Graph, NodeType
|
||||
from engine.pipeline.graph_adapter import graph_to_pipeline
|
||||
@@ -32,7 +32,7 @@ class EffectConfig:
|
||||
name: str
|
||||
intensity: float = 1.0
|
||||
enabled: bool = True
|
||||
params: Dict[str, Any] = field(default_factory=dict)
|
||||
params: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -70,9 +70,9 @@ class PipelineConfig:
|
||||
"""
|
||||
|
||||
source: str = "headlines"
|
||||
camera: Optional[CameraConfig] = None
|
||||
effects: List[EffectConfig] = field(default_factory=list)
|
||||
display: Optional[DisplayConfig] = None
|
||||
camera: CameraConfig | None = None
|
||||
effects: list[EffectConfig] = field(default_factory=list)
|
||||
display: DisplayConfig | None = None
|
||||
viewport_width: int = 80
|
||||
viewport_height: int = 24
|
||||
|
||||
@@ -208,7 +208,7 @@ def load_hybrid_config(toml_path: str | Path) -> PipelineConfig:
|
||||
return parse_hybrid_config(data)
|
||||
|
||||
|
||||
def parse_hybrid_config(data: Dict[str, Any]) -> PipelineConfig:
|
||||
def parse_hybrid_config(data: dict[str, Any]) -> PipelineConfig:
|
||||
"""Parse hybrid configuration from dictionary.
|
||||
|
||||
Expected format:
|
||||
|
||||
Reference in New Issue
Block a user