Serialization
The dynamic_expressions.serialization package covers two separate jobs:
| Role | Direction | Purpose |
|---|---|---|
| Parser | stored rule → Node tree | Load expressions from JSON or a string before evaluation |
| Serializer | Python value ↔ bytes |
Persist evaluation results in cache extensions |
Parsers are format-specific (no shared protocol). Serializers implement a common Serializer protocol. Every parser produces the same immutable Node trees evaluated by the dispatcher.
Parsers
Turn external rule formats into runtime nodes.
| Format | Parser | Module | Guide |
|---|---|---|---|
| JSON (discriminated schemas) | PydanticExpressionParser + NodeSchema.to_node() |
dynamic_expressions.serialization.pydantic |
Pydantic |
| Python-like string | ExpressionEvalParser.parse() |
dynamic_expressions.serialization.ast |
AST |
# Pydantic — JSON from an API or database
from dynamic_expressions.serialization.pydantic import BUILTIN_SCHEMAS, PydanticExpressionParser
parser = PydanticExpressionParser(BUILTIN_SCHEMAS)
schema = parser.type_adapter.validate_json(
'''{
"type": "binary",
"operator": "+",
"left": { "type": "literal", "value": 2 },
"right": { "type": "literal", "value": 2 }
}''')
node = schema.to_node()
# AST — human-readable rule string
from dynamic_expressions.serialization.ast import ExpressionEvalParser, get_builtin_handlers
node = ExpressionEvalParser(handlers=get_builtin_handlers()).parse("2 + 2")
Serializer protocol
Serializers encode cached evaluation results, not expression trees.
dynamic_expressions.serialization.Serializer
class Serializer[TResult](Protocol):
def serialize(self, value: TResult) -> bytes: ...
def deserialize(self, value: bytes) -> TResult: ...
| Implementation | Module | Typical use |
|---|---|---|
MsgSpecScalarSerializer |
dynamic_expressions.serialization.msgspec |
Default for Redis cache — JSON-compatible scalars |
MsgSpecSerializer |
dynamic_expressions.serialization.msgspec |
Typed msgspec structs in cache |
PydanticSerializer |
dynamic_expressions.serialization.pydantic |
Typed values with Pydantic validation on read |
The Pydantic module is the only one that provides both a parser and serializers; MsgSpec covers serializers only; AST covers parsers only.
Typical workflow
flowchart TB
subgraph rules ["Load rules"]
ruleStorage[(JSON or string storage)] --> parser[Parser]
parser --> nodes[Node tree]
end
nodes --> eval[dispatcher.visit]
eval --> result[Evaluated result]
subgraph cache ["Cache results optional"]
result --> serializer[Serializer]
serializer --> cacheStorage[(Redis or custom backend)]
end
- Parse — use a parser to build a
Nodetree from stored rules. - Evaluate — run
dispatcher.visit(node, context). - Serialize results — pass a
Serializerto a cache extension to persist evaluation outputs across requests.
Optional dependencies
pip install dynamic-expressions[serialization-pydantic] # parsers + PydanticSerializer
pip install dynamic-expressions[serialization-msgspec] # MsgSpec serializers
pip install dynamic-expressions[cache-redis,serialization-msgspec]
See individual format pages and the cookbook for end-to-end examples.