API Reference
zspec.Specification
Bases: ABC
Abstract specification that can be combined with &, |, ~, ^.
Source code in src/zspec/specification.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | |
__slots__ = ()
class-attribute
instance-attribute
registry = {}
class-attribute
__and__(other)
Combine with other via logical AND.
Source code in src/zspec/specification.py
__call__(candidate)
__eq__(other)
__hash__()
__init_subclass__(**kwargs)
__invert__()
__or__(other)
Combine with other via logical OR.
Source code in src/zspec/specification.py
__repr__()
Return ClassName(attr=value, ...) for all slots.
__str__()
__xor__(other)
Combine with other via logical XOR.
Source code in src/zspec/specification.py
all_of(*specs, default=None)
classmethod
Return a specification satisfied when all of specs are.
Accepts individual specs::
Specification.all_of(a, b, c)
Specification.all_of(*my_list)
Returns default when empty.
Source code in src/zspec/specification.py
any_of(*specs, default=None)
classmethod
Return a specification satisfied when any of specs are.
Accepts individual specs::
Specification.any_of(a, b, c)
Specification.any_of(*my_list)
Returns default when empty.
Source code in src/zspec/specification.py
count(candidates)
excluding(*predicates, **kwargs)
classmethod
Negated :meth:matching — exclude anything that matches.
::
spec = Specification[Product].excluding(price__gte=100)
# equivalent to ~Specification[Product].matching(price__gte=100)
Source code in src/zspec/specification.py
false()
classmethod
filter(candidates)
is_satisfied_by(candidate)
abstractmethod
matching(*predicates, **kwargs)
classmethod
Create a specification from field comparisons and/or predicates.
Positional args accept lambdas or field proxies from :func:fields::
F = fields(Product)
spec = Specification[Product].matching(
F.price >= 100,
lambda p: p.in_stock,
)
Keyword args use field__op syntax::
spec = Specification[Product].matching(price__gte=100, in_stock=True)
Supported keyword operators: eq, ne, gt, gte, lt, lte.
A plain field name without __op defaults to eq.
Source code in src/zspec/specification.py
of(fn)
classmethod
Create a specification from fn.
Usage::
adult = Specification.of(lambda u: u.age >= 18)
Source code in src/zspec/specification.py
partition(candidates)
Split into (passed, failed) lists.
Source code in src/zspec/specification.py
reject(candidates)
zspec.AndSpecification
Bases: Specification[T]
Conjunction of two specifications (produced by &).
Source code in src/zspec/specification.py
__slots__ = ('left', 'right')
class-attribute
instance-attribute
left = left
instance-attribute
right = right
instance-attribute
__init__(left, right)
__str__()
is_satisfied_by(candidate)
Check whether candidate satisfies both specifications.
zspec.OrSpecification
Bases: Specification[T]
Disjunction of two specifications (produced by |).
Source code in src/zspec/specification.py
__slots__ = ('left', 'right')
class-attribute
instance-attribute
left = left
instance-attribute
right = right
instance-attribute
__init__(left, right)
__str__()
is_satisfied_by(candidate)
Check whether candidate satisfies at least one specification.
zspec.NotSpecification
Bases: Specification[T]
Negation of a specification (produced by ~).
Source code in src/zspec/specification.py
__slots__ = ('spec',)
class-attribute
instance-attribute
spec = spec
instance-attribute
__init__(spec)
__invert__()
__str__()
is_satisfied_by(candidate)
zspec.Translator
Bases: ABC
Walk a specification tree and translate it into TResult.
Source code in src/zspec/translator.py
_and(left, right)
abstractmethod
_not(operand)
abstractmethod
_or(left, right)
abstractmethod
_translate(spec)
abstractmethod
_xor(left, right)
Combine with XOR — defaults to (A OR B) AND NOT (A AND B).
Override for backend-specific optimization.
Source code in src/zspec/translator.py
translate(spec)
Recursively translate spec into TResult.
Source code in src/zspec/translator.py
zspec.XorSpecification
Bases: Specification[T]
Exclusive disjunction of two specifications (produced by ^).
Source code in src/zspec/specification.py
__slots__ = ('left', 'right')
class-attribute
instance-attribute
left = left
instance-attribute
right = right
instance-attribute
__init__(left, right)
__str__()
is_satisfied_by(candidate)
zspec.TrueSpecification
Bases: Specification[T]
Internal: specification that is always satisfied.
Source code in src/zspec/specification.py
__slots__ = ()
class-attribute
instance-attribute
__invert__()
__str__()
zspec.FalseSpecification
Bases: Specification[T]
Internal: specification that is never satisfied.
Source code in src/zspec/specification.py
__slots__ = ()
class-attribute
instance-attribute
__invert__()
__str__()
zspec.FieldSpec
Bases: Specification[T]
Internal: attribute comparison created by matching.
Source code in src/zspec/specification.py
__slots__ = ('field', 'op', 'value')
class-attribute
instance-attribute
field = field
instance-attribute
op = op
instance-attribute
value = value
instance-attribute
__init__(field, op, value)
Initialize with field name, op code ("gte"), and value.
__str__()
zspec.explain
Explain and visualize specification trees.
AndSpecification
Bases: Specification[T]
Conjunction of two specifications (produced by &).
Source code in src/zspec/specification.py
__init__(left, right)
is_satisfied_by(candidate)
Check whether candidate satisfies both specifications.
ExplainNode
dataclass
Result of a specification check on a candidate.
The __str__ renders a tree with PASS / FAIL markers::
AND FAIL
├── InStock PASS
└── price >= 100 FAIL
Source code in src/zspec/explain.py
__str__()
Return an ASCII tree with PASS / FAIL for each node.
NotSpecification
Bases: Specification[T]
Negation of a specification (produced by ~).
Source code in src/zspec/specification.py
__init__(spec)
__invert__()
is_satisfied_by(candidate)
OrSpecification
Bases: Specification[T]
Disjunction of two specifications (produced by |).
Source code in src/zspec/specification.py
__init__(left, right)
is_satisfied_by(candidate)
Check whether candidate satisfies at least one specification.
Specification
Bases: ABC
Abstract specification that can be combined with &, |, ~, ^.
Source code in src/zspec/specification.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | |
__and__(other)
Combine with other via logical AND.
Source code in src/zspec/specification.py
__call__(candidate)
__init_subclass__(**kwargs)
__invert__()
__or__(other)
Combine with other via logical OR.
Source code in src/zspec/specification.py
__repr__()
Return ClassName(attr=value, ...) for all slots.
__str__()
__xor__(other)
Combine with other via logical XOR.
Source code in src/zspec/specification.py
all_of(*specs, default=None)
classmethod
Return a specification satisfied when all of specs are.
Accepts individual specs::
Specification.all_of(a, b, c)
Specification.all_of(*my_list)
Returns default when empty.
Source code in src/zspec/specification.py
any_of(*specs, default=None)
classmethod
Return a specification satisfied when any of specs are.
Accepts individual specs::
Specification.any_of(a, b, c)
Specification.any_of(*my_list)
Returns default when empty.
Source code in src/zspec/specification.py
count(candidates)
excluding(*predicates, **kwargs)
classmethod
Negated :meth:matching — exclude anything that matches.
::
spec = Specification[Product].excluding(price__gte=100)
# equivalent to ~Specification[Product].matching(price__gte=100)
Source code in src/zspec/specification.py
false()
classmethod
filter(candidates)
is_satisfied_by(candidate)
abstractmethod
matching(*predicates, **kwargs)
classmethod
Create a specification from field comparisons and/or predicates.
Positional args accept lambdas or field proxies from :func:fields::
F = fields(Product)
spec = Specification[Product].matching(
F.price >= 100,
lambda p: p.in_stock,
)
Keyword args use field__op syntax::
spec = Specification[Product].matching(price__gte=100, in_stock=True)
Supported keyword operators: eq, ne, gt, gte, lt, lte.
A plain field name without __op defaults to eq.
Source code in src/zspec/specification.py
of(fn)
classmethod
Create a specification from fn.
Usage::
adult = Specification.of(lambda u: u.age >= 18)
Source code in src/zspec/specification.py
partition(candidates)
Split into (passed, failed) lists.
Source code in src/zspec/specification.py
reject(candidates)
XorSpecification
Bases: Specification[T]
Exclusive disjunction of two specifications (produced by ^).
Source code in src/zspec/specification.py
__init__(left, right)
is_satisfied_by(candidate)
_render_tree(root, *, label, children)
Render root as an ASCII tree, one string per line.
Source code in src/zspec/explain.py
_spec_children(spec)
Source code in src/zspec/explain.py
explain(spec, candidate)
Evaluate spec against candidate and return a result tree.
Each leaf specification produces a node with no children. Composite specifications (AND, OR, NOT, XOR) produce nodes with children for each sub-specification.
Usage::
print(explain(eligible, product))
# AND FAIL
# ├── InStock PASS
# └── price >= 100 FAIL
Source code in src/zspec/explain.py
to_ascii(spec)
Return an ASCII tree visualization of spec.
Usage::
print(to_ascii(eligible))
# AND
# ├── price >= 100
# └── in_stock == True
Source code in src/zspec/explain.py
zspec.SqlTranslator
Bases: Translator[SqlFragment]
Translate specifications into parameterized SQL.
Subclass and override _translate for each leaf specification::
class MyTranslator(SqlTranslator):
def _translate(self, spec: Specification[Any]) -> SqlFragment:
match spec:
case InStock():
return SqlFragment("in_stock = %s", (True,))
case MinPrice(min_price=price):
return SqlFragment("price >= %s", (price,))
case _:
return super()._translate(spec)
Source code in src/zspec/translators.py
_and(left, right)
_not(operand)
zspec.MongoTranslator
Bases: Translator[dict[str, Any]]
Translate specifications into MongoDB filter documents.
Subclass and override _translate for each leaf specification::
class MyTranslator(MongoTranslator):
def _translate(self, spec: Specification[Any]) -> dict[str, Any]:
match spec:
case InStock():
return {"in_stock": True}
case MinPrice(min_price=price):
return {"price": {"$gte": price}}
case _:
return super()._translate(spec)
translator = MyTranslator()
results = collection.find(
translator.translate(InStock() & MinPrice(100)),
)
Source code in src/zspec/translators.py
_and(left, right)
_not(operand)
_or(left, right)
zspec.fields(_model)
Return a namespace for building field-comparison specifications.
Usage::
F = fields(Product)
spec = F.price >= 100 # Specification[Product]
Source code in src/zspec/specification.py
zspec.TRUE_SPEC = TrueSpecification()
module-attribute
zspec.FALSE_SPEC = FalseSpecification()
module-attribute
zspec.to_dict(spec)
Serialize spec to a plain dictionary.
Composite nodes are recursively serialized. Leaf specifications keep their class name and all slot values.
Usage::
data = to_dict(InStock() & MinPrice(100))
# {"type": "AndSpecification", "left": {...}, "right": {...}}
Specification.of() specs and unregistered user-defined types
will raise :exc:TypeError.
Source code in src/zspec/serialize.py
zspec.from_dict(data, registry=None)
Deserialize a specification tree from data.
registry maps class names to Specification subclasses.
Built-in types (composites, TRUE, FALSE, FieldSpec)
are always recognized.
Usage::
spec = from_dict({"type": "MinPrice", "threshold": 100})