Validation
Builders support two types of validation:
Structure Validation - Which children are allowed under which parents
Attribute Validation - Type checking, enums, required fields
Structure Validation
Defining Valid Children
Use the sub_tags parameter in @element to specify allowed child tags:
Wildcard: Accept Any Children
Use sub_tags='*' to create container elements that accept any child without validation:
Key points:
sub_tags='*'disables child validation entirelyUseful for generic container elements
validate()will not report errors for unknown childrenDifferent from
sub_tags=''which means no children allowed (leaf element)
Syntax |
Meaning |
|---|---|
|
Accept any children (no validation) |
|
Leaf element (no children allowed) |
|
Only |
Cardinality Constraints
Specify minimum and maximum occurrences with bracket syntax:
Syntax |
Meaning |
|---|---|
|
Any number (0..N) |
|
Exactly 1 |
|
Exactly 3 |
|
0 or more (same as |
|
At least 1 |
|
0 to 3 |
|
Between 2 and 5 |
Note:
tag[](empty brackets) is not valid syntax and raisesValueError. Usetagfor 0..N ortag[0:]explicitly.
The validate() Method
Use validate() to validate structure after building. It walks the bag and returns
a list of dicts (with keys path, tag, reasons) for every invalid node:
Invalid Children Detection
Attribute Validation
Attribute validation is handled automatically by the builder. Pass attributes as keyword arguments when calling elements:
Combining Structure and Attribute Validation
A complete example with structure constraints:
Best Practices
1. Define Constraints Early
Document your schema constraints clearly:
class ConfigBuilder(BagBuilderBase):
"""Builder for application config.
Structure:
config
├── database # Required, exactly one
├── cache[:1] # Optional, at most one
└── logging[:1] # Optional, at most one
"""
@element(sub_tags='database,cache[:1],logging[:1]')
def config(self): ...
2. Validate After Building
Always validate complete structures before use:
bag = BuilderBag(builder=MyBuilder)
# ... build the structure ...
errors = bag.builder.validate()
if errors:
for err in errors:
print(f"ERROR at {err['path']}: {err['reasons']}")
raise ValueError("Invalid structure")