Skip to main content

An extension of StrictYAML that adds more expressive schema tools for validation.

Project description

strictyamlx

An extension of StrictYAML that adds more expressive schema tools for validation.

Installation

pip install strictyamlx

Features

DMap (Dynamic Map)

DMap allows you to validate YAML where the schema of a map depends on the value of one or more of its keys. It evaluates a "control" schema first, and uses its values to determine which Case schema applies. The final parsed object safely merges the validated control and case values.

from strictyamlx import Map, Str, Int, load, Control, Case, DMap

# Control schema evaluates the "action" key to route the document
ctrl = Control(Map({"action": Str()}))

# Blocks conditionally apply a schema based on the evaluated control value
blocks = [
    Case(
        when=lambda raw, ctrl: ctrl["action"] == "message", 
        schema=Map({"text": Str()})
    ),
    Case(
        when=lambda raw, ctrl: ctrl["action"] == "transfer", 
        schema=Map({"amount": Int(), "to": Str()})
    ),
]

# Create the schema 
schema = DMap(ctrl, blocks)

# Validation merges the control ("action") and case schema values ("text")
yaml_str = """
action: message
text: Hello!
"""
doc = load(yaml_str, schema)
assert doc.data == {"action": "message", "text": "Hello!"}

Using source in Control

Sometimes the values needed to determine the schema aren't placed at the root of the document, but nested inside another key (like "metadata"). You can use source to define where the Control values should be drawn from:

from strictyamlx import Map, Str, Int, load, Control, Case, DMap

# Evaluates the control values from the `meta` key
ctrl = Control(Map({"type": Str()}), source="meta")

blocks = [
    Case(
        when=lambda raw, ctrl: ctrl["type"] == "number", 
        schema=Map({"value": Int()})
    )
]

schema = DMap(ctrl, blocks)

yaml_str = """
meta:
  type: number
value: 42
"""
doc = load(yaml_str, schema)
assert doc.data == {"meta": {"type": "number"}, "value": 42}

Constraints

You can append constraints to Case blocks or globally on the DMap. Constraints are callables that validate the incoming data.

Case(
    when=lambda raw, ctrl: ctrl["action"] == "transfer",
    schema=Map({"amount": Int(), "from": Str(), "to": Str()}),
    constraints=[
        lambda raw, ctrl, validated: validated["amount"] > 0,
        lambda raw, ctrl, validated: validated["from"] != validated["to"]
    ]
)

Nesting DMaps

DMaps can nested to create complex state graphs. A Case block can even have another DMap as its schema!

from strictyamlx import Map, Str, Int, Control, Case, DMap

inner_schema = DMap(
    Control(Map({"subkind": Str()})),
    [
        Case(when=lambda raw, ctrl: ctrl["subkind"] == "V1", schema=Map({"v1": Int()})),
        Case(when=lambda raw, ctrl: ctrl["subkind"] == "V2", schema=Map({"v2": Str()})),
    ]
)

schema = DMap(
    Control(Map({"kind": Str()})),
    [
        Case(when=lambda raw, ctrl: ctrl["kind"] == "complex", schema=inner_schema),
        Case(when=lambda raw, ctrl: ctrl["kind"] == "simple", schema=Map({"value": Str()})),
    ]
)

ForwardRef

ForwardRef defines recursive or mutually dependent schemas, letting you use a schema component before it is fully defined.

from strictyamlx import Map, Str, Optional, Seq, load, ForwardRef

# 1. Create the reference
tree = ForwardRef()

# 2. Define the schema recursively and assign it using .set()
tree.set(Map({"name": Str(), Optional("children"): Seq(tree)}))

# 3. Validation handles recursive resolution automatically
yaml_str = """
name: root
children:
  - name: child
    children:
      - name: grandchild
"""
doc = load(yaml_str, tree)

DMaps with ForwardRef

You can use a ForwardRef inside DMap case schemas to easily build deep recursive dynamic behavior:

from strictyamlx import Map, Str, Int, load, Control, Case, DMap, ForwardRef

ref = ForwardRef()

schema = DMap(
    Control(Map({"type": Str()})),
    [
        Case(
            when=lambda raw, ctrl: ctrl["type"] == "node", 
            schema=Map({"value": Int(), "child": ref})
        ),
        Case(
            when=lambda raw, ctrl: ctrl["type"] == "leaf", 
            schema=Map({"value": Int()})
        ),
    ]
)

# Reference points to the DMap itself, allowing infinite nesting!
ref.set(schema)

yaml_str = """
type: node
value: 1
child:
  type: leaf
  value: 2
"""
doc = load(yaml_str, schema)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

strictyamlx-0.1.1.tar.gz (5.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

strictyamlx-0.1.1-py3-none-any.whl (8.1 kB view details)

Uploaded Python 3

File details

Details for the file strictyamlx-0.1.1.tar.gz.

File metadata

  • Download URL: strictyamlx-0.1.1.tar.gz
  • Upload date:
  • Size: 5.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.2 CPython/3.12.10 Windows/11

File hashes

Hashes for strictyamlx-0.1.1.tar.gz
Algorithm Hash digest
SHA256 80cf5db7bddba8fc611fcdaf594026688fe9ebd0702f7d103461af8c99a38acb
MD5 582f07f4bbad8f81312b93957351dcf1
BLAKE2b-256 599c4bfed425fdd105c2b410d02cf0a3cfcb1478940a3e1163b0c65fc5f432a8

See more details on using hashes here.

File details

Details for the file strictyamlx-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: strictyamlx-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 8.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.2 CPython/3.12.10 Windows/11

File hashes

Hashes for strictyamlx-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c6f4d4211ba63fa51861f61360f139d1444912ada1f04693597ec69bff14541c
MD5 6dfaef98188a5bcf9fb80056a7ccd3cd
BLAKE2b-256 0ddbc07d3ff831405feb0dceae1307165d480344b87f27d67e2d79ac27dde374

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page