mrkeyoor.com_
Sat 08 Aug 17:41 UTC
PyPIUtilsupdated 08 Aug 2026

strictyaml

StrictYAML is a Python parser and schema validator for a deliberately restricted subset of YAML. Without a schema it loads scalars as strings, avoiding YAML's surprising implicit conversions; with a Python-defined schema it converts and validates integers, booleans, dates, sequences, mappings, enums, and more. It rejects features the project considers ambiguous or unsafe, including duplicate keys, explicit tags, anchors, and normal flow-style collections. Its distinctive feature is round-trip editing: parsed values retain comments and source positions, can be changed, and can be emitted as YAML again.

Verdict

Choose StrictYAML when rejecting clever YAML is a feature and configuration authors benefit from precise schema errors. Do not use it as a drop-in reader for YAML produced elsewhere, or when portable schemas and speed matter.

API stability4/5The core load, YAML.data, as_yaml, Map, Seq, scalar validator, and composition APIs have remained recognizable throughout the 1.x line. The restrictions are deliberate product decisions rather than accidental gaps, and dirty_load is clearly separated as an escape hatch. The package is still below 2.0 and its schema is executable Python, so uncommon validators and serialization behavior should be covered by tests before upgrading.
Docs5/5The documentation goes beyond an API list. It provides separate examples for compound and scalar validators, round-trip editing, line lookup, construction, merging, dirty loading, and schema alternatives. It also documents the controversial omissions one by one, including implicit typing, flow style, anchors, tags, duplicate keys, file inputs, and speed. That clarity makes it easy to decide against the library before writing integration code.
Maintenance2/5PyPI lists version 1.7.3 and GitHub shows the repository was last pushed on 2025-05-23, with 105 open issues and pull requests as of 2026-08-08. The repository is not archived, the package remains installable on Python 3.7 and later, and its mature scope limits churn. Still, more than a year without a push is a real maintenance warning for a parser handling untrusted configuration input.
Ecosystem3/5The package is widely downloaded and its validator catalog covers most configuration shapes, while python-dateutil supports date-related values. It interoperates with ordinary dicts and lists through .data, but the intentionally restricted syntax means many existing YAML documents cannot enter the system unchanged. Schemas are Python-only, and the community and integration surface are much smaller than PyYAML, ruamel.yaml, or Pydantic.

Use it if

  • You control a human-edited configuration format and want invalid keys or types rejected with line-aware messages
  • You want YAML scalars to stay strings unless a schema explicitly converts them
  • You need to edit and re-emit configuration while preserving comments
  • You prefer a small Python schema language over maintaining a separate JSON Schema file
Skip it if

Setup reality

pip install strictyaml installs a pure Python-facing package with python-dateutil as its declared runtime dependency, and release 1.7.3 supports Python 3.7 or newer. The real setup cost is defining the accepted document shape in Python. Map is closed by default, so an unexpected key raises an error; use Optional for optional keys, MapPattern for arbitrary names, or MapCombined when a few known keys coexist with patterned ones. Without a schema, every scalar stays a string. That prevents implicit values such as yes or no from silently becoming booleans, but it surprises code expecting numbers from load(...).data. Normal load intentionally rejects flow-style collections, anchors and aliases, explicit tags, and duplicate keys. dirty_load can admit flow style when allow_flow_style=True, but using it weakens the main reason to choose this package and still does not make StrictYAML a general YAML compatibility layer. The parser accepts YAML text, not a path or file object, so open with an explicit encoding and pass the resulting string. Keep the returned YAML object if you need comments, line numbers, or round-trip output; accessing .data gives ordinary Python structures and loses that editing context. Optional defaults appear in parsed data but are omitted when serializing if they equal the default, which can surprise snapshot tests. Assignments are revalidated, so updates can raise YAMLSerializationError. Catch YAMLError for user-facing parse and validation failures and print its marked snippet, but avoid exposing full configuration text if it can contain secrets.

Patterns

Load conservative string dataload-without-schema

from strictyaml import load

config = load("port: 8080\nenabled: yes\n")
assert config.data == {"port": "8080", "enabled": "yes"}

Without a schema, scalars remain strings. This is intentional protection against YAML implicit typing, not a failed conversion.

Validate and convert a fixed mappingvalidate-mapping

from strictyaml import Bool, Int, Map, Str, load

schema = Map({
    "host": Str(),
    "port": Int(),
    "debug": Bool(),
})
config = load(yaml_text, schema).data

Map rejects missing required keys and unexpected keys. Add Optional or choose MapCombined when the shape is not fully closed.

Add an optional key with a defaultset-optional-default

from strictyaml import Bool, Int, Map, Optional, load

schema = Map({
    "port": Int(),
    Optional("debug", default=False): Bool(),
})
config = load("port: 8080\n", schema).data
assert config["debug"] is False

A value equal to its Optional default is dropped from serialized YAML even though it is present in parsed .data.

Validate a sequence of mappingsvalidate-sequence

from strictyaml import Int, Map, Seq, Str, load

schema = Seq(Map({"name": Str(), "port": Int()}))
services = load("- name: api\n  port: 8080\n", schema).data

Seq applies one validator to every item. Use FixedSeq when positions intentionally have different types.

Require unique sequence valuesreject-duplicates

from strictyaml import Str, UniqueSeq, load

schema = UniqueSeq(Str())
tags = load("- stable\n- internal\n", schema).data

UniqueSeq raises YAMLValidationError for duplicate input and YAMLSerializationError if code tries to serialize duplicate values.

Validate arbitrary mapping keysallow-patterned-keys

from strictyaml import Int, MapPattern, Regex, load

schema = MapPattern(Regex(r"^[a-z][a-z0-9-]+$"), Int())
ports = load("api: 8080\nadmin: 8081\n", schema).data

MapPattern is the right fit for user-defined key names; a plain Map is for a known closed set.

Allow one of two scalar typesaccept-either-type

from strictyaml import Bool, Int, Map, load

schema = Map({"workers": Int() | Bool()})
config = load("workers: 4\n", schema).data

The | operator composes validators. Keep alternatives distinguishable or error messages and resulting types can become harder to reason about.

Edit while preserving commentsround-trip-comments

from strictyaml import Int, Map, Str, load

schema = Map({"name": Str(), "port": Int()})
doc = load("# public listener\nname: api\nport: 8080\n", schema)
doc["port"] = 8081
print(doc.as_yaml())

Keep the YAML document object for round trips. Converting to .data and rebuilding a document does not preserve the original comments.

Locate a value in the sourcereport-source-line

doc = load(yaml_text, schema)
print("port came from line", doc["port"].start_line)

Line metadata belongs to YAML nodes, not the ordinary objects returned by .data.

Admit flow style as a migration escape hatchload-flow-style

from strictyaml import Int, Map, dirty_load

schema = Map({"x": Int(), "y": Int()})
doc = dirty_load("{x: 1, y: 2}", schema, allow_flow_style=True)

Normal load rejects flow-style YAML. dirty_load is explicitly the less-strict path and should not become the default unnoticed.

Create YAML from Python databuild-document

from strictyaml import Int, Map, Str, as_document

schema = Map({"name": Str(), "port": Int()})
doc = as_document({"name": "api", "port": 8080}, schema)
print(doc.as_yaml())

as_document validates during serialization, so incompatible Python values raise YAMLSerializationError rather than producing invalid output.

Alternatives

PackageRegistryPick it when
PyYAMLPyPIYou need broad YAML compatibility and familiar safe_load behavior without a built-in schema system
ruamel.yamlPyPIYou need YAML 1.2 features plus detailed comment-preserving round trips
pydanticPyPIYou want rich typed validation after loading YAML, JSON, environment variables, or other input sources