Coverage for src/lexigram/web/pipes/pipeline.py: 34%
29 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 04:37 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 04:37 +0800
1"""PipeProtocol pipeline for running pipes on parameters.
3The pipeline runs pipes in order, transforming each parameter value.
4"""
6from __future__ import annotations
8from typing import TYPE_CHECKING, Any
10if TYPE_CHECKING:
11 from lexigram.web.protocols import ParamMetadata, PipeProtocol
14class PipePipeline:
15 """Pipeline that runs pipes on handler parameters.
17 Processes parameters through registered pipes in order, transforming
18 and validating values before they reach the handler.
19 """
21 def __init__(self, pipes: dict[str, list[PipeProtocol]] | None = None):
22 """Initialize the pipe pipeline.
24 Args:
25 pipes: Optional dict mapping parameter names to lists of pipes.
26 """
27 self._pipes: dict[str, list[PipeProtocol]] = pipes or {}
29 def add_pipe(self, param_name: str, pipe: PipeProtocol) -> None:
30 """Add a pipe for a parameter.
32 Args:
33 param_name: The name of the parameter.
34 pipe: The pipe to add.
35 """
36 if param_name not in self._pipes:
37 self._pipes[param_name] = []
38 if pipe not in self._pipes[param_name]:
39 self._pipes[param_name].append(pipe)
41 def remove_pipe(self, param_name: str, pipe: PipeProtocol) -> None:
42 """Remove a pipe for a parameter.
44 Args:
45 param_name: The name of the parameter.
46 pipe: The pipe to remove.
47 """
48 if param_name in self._pipes:
49 if pipe in self._pipes[param_name]:
50 self._pipes[param_name].remove(pipe)
51 if not self._pipes[param_name]:
52 del self._pipes[param_name]
54 def get_pipes(self, param_name: str) -> list[PipeProtocol]:
55 """Get pipes for a parameter.
57 Args:
58 param_name: The name of the parameter.
60 Returns:
61 List of pipes for the parameter.
62 """
63 return list(self._pipes.get(param_name, []))
65 async def transform(
66 self,
67 param_name: str,
68 value: Any,
69 metadata: ParamMetadata,
70 ) -> Any:
71 """Transform a parameter value through its pipes.
73 Args:
74 param_name: The name of the parameter.
75 value: The value to transform.
76 metadata: Metadata about the parameter.
78 Returns:
79 Transformed value.
80 """
81 pipes = self.get_pipes(param_name)
83 if not pipes:
84 return value
86 result = value
87 for pipe in pipes:
88 result = await pipe.transform(result, metadata)
90 return result
92 def __len__(self) -> int:
93 """Return total number of pipes."""
94 return sum(len(p) for p in self._pipes.values())
97__all__ = ["PipePipeline"]