Mercurial > hgrepos > Python > libs > data-schema
view docs/schema.txt @ 14:cfb97c7c9e5b
Simplify ctor of ValidationProblem somewhat
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Fri, 07 Jul 2023 02:13:16 +0200 |
| parents | 84dfd1a94926 |
| children | c3a0fe8d4587 |
line wrap: on
line source
.. -*- coding: utf-8; mode: rst; indent-tabs-mode: nil -*- ======== Schema ======== Grundideen ========== - Angelehnt an JSON Schema - Deklarativ in YAML - Verwendung von erweiterten YAML-Features: + laden von (beliebigen) Python-Objekten + Benutzung von YAML-Referenzen - Möglichkeit der direkten Verwendung von Python-Callables Diese müssen Iteratoren sein und jedes Problem `yield`en. - Rückgabe einer Liste von Problemen: Versuch möglichst viele Probleme auf einen Schlag zu melden (soweit möglich und sinnvoll) .. seealso:: - https://json-schema.org/understanding-json-schema/index.html - http://rx.codesimply.com/coretypes.html Extra Keywords für :py:func:`validate` ====================================== - ``skip_keys`` Eine Liste Strings oder von compilierten REs Ein String-Item wird auf Gleichheit getestet, die RE per :py:meth:`search` -- und zwar auf den Dict-key Bei Treffer wird dieser Key komplett ignoriert. Das ist also eine globale Ignore-Liste für Dict-Keys. Typen ===== Durch ``type`` (required) gekennzeichnet Alle Schemata außer den `Schema-Kombinatoren`_ haben auch ein optionales Attribut ``index-constraint``. Dessen Wert ist eine Liste von Indizes, an denen das Element in seinem Parent-Container (Liste, sorted dict) vorkommen darf. dict / map / object ------------------- - ``nullable`` bool (Default: False): instead of an empty dict allow also a None/null/nil - ``keys`` `dict` mit Keys und den Values als zugeordnete Schemata für die Values des Dicts - ``keyNames`` Wenn vorhanden: ein Schema, dem die *Keys* -- auch die `additionalKeys` -- folgen müssen. Default: entspricht ``{"type": "string"}`` - ``additionalKeys`` * bool `False` nicht erlaubt (default) Globales ``skip_keys`` wird aber zusätzlich noch in Betracht gezogen. `True` erlaubt -- keine weitergehende Schema-Prüfung der Inhalte Globales ``skip_keys`` ist offensichtlich irrelevant. * Schema Prüfung erfolgt nach gegebenem Schema Globales ``skip_keys`` wird aber zusätzlich noch in Betracht gezogen. - ``required`` Liste von Strings mit Key-Namen, die vorkommen müssen - ``maxLength`` - ``minLength`` list / array ------------ - ``nullable`` bool (Default: False): instead of an empty list allow also a None/null/nil - ``items`` Ein Schema für *alle* Items. - ``maxLength`` - ``minLength`` set / frozenset --------------- - ``nullable`` bool (Default: False): instead of an empty set allow also a None/null/nil - ``items`` Ein Schema für *alle* Items - ``maxLength`` - ``minLength`` tuple / record -------------- - ``nullable`` bool (Default: False): instead of an empty list or tuple allow also a None/null/nil - ``items`` Eine Liste: je ein spezielles Schema *pro Item* - ``additionalItems`` * bool `False` nicht erlaubt (default) `True` erlaubt -- keine weitergehende Schema-Prüfung der Inhalte * Schema Prüfung der "zusätzlichen" Items erfolgt nach gegebenem Schema - ``maxLength`` - ``minLength`` string / str ------------ - ``nullable`` bool (Default: False): instead of an empty string allow also a None/null/nil - ``enum`` Eine Liste von Strings, von denen genau einer dem String entspricht Achtung: Alle anderen Prüfungen (siehe unten) werden trotzdem auch durchgeführt. - ``is-contained-in-ref`` The string's value must be contained in (Python ``in``) in the referenced object (see `Referenzen`_). - ``maxLength`` - ``minLength`` - ``pattern`` * string RE of the accepted pattern * compiled RE compiled RE of the accepted pattern * Callable binary ------ - ``maxLength`` - ``minLength`` - ``pattern`` * string RE of the accepted pattern. The YAML unicode string value will be converted to a byte-string with :func:`ast.literal_eval` as if it is surrounded by ``b'''<re>'''`` or ``b"""<re>"""``. If the pattern contains both a ``'''`` or ``"""`` substring the conversion will fail. * bytes, bytearray RE of the accepted pattern * compiled RE compiled RE of the accepted pattern * Callable bool / boolean -------------- Only **real** boolean values: ``true`` and ``false`` - ``value`` The accepted value or a validating callable - ``nullable`` bool (Default: False): instead of a boolean allow also a None/null/nil timestamp / datetime -------------------- Only :py:class:`datetime.datetime` allowed - ``value`` Callable that validates the value of a timestamp Callable -------- Iterator (e.g. ``yield``) mit Signatur: :py:func:`callable(object, schema, context)` accept ------ Validates successfully always: accept everything deny ---- Does not validate successfully: always yield the error code 10010 :py:obj:`None` / none / null / nil ---------------------------------- Only the `None` object validates empty ----- Erlaubt sind: None, leeres Dict, leere Liste, leeres Set/Frozenset .. note:: Leere Strings sind **nicht** erlaubt. integer / int ------------- - ``nullable`` bool (Default: False): allow also a None/null/nil - ``minValue`` - ``maxValue`` - ``value`` A callable to validate the integer value - ``enum`` Eine Liste von ganzen Zahlen, von denen genau einer dem vorhandenen Wert entsprechen muß. Achtung: Alle anderen Prüfungen (`minValue`, `maxValue`, `value`) werden trotzdem auch durchgeführt. real / double / float --------------------- - ``nullable`` bool (Default: False): allow also a None/null/nil - ``minValue`` - ``maxValue`` - ``value`` A callable to validate the float value number / num ------------ - ``nullable`` bool (Default: False): allow also a None/null/nil Any numeric value (int or float) - ``minValue`` - ``maxValue`` - ``value`` A callable to validate the number - ``enum`` Eine Liste von Zahlen, von denen genau einer dem vorhandenen Wert entsprechen muß. Achtung: Alle anderen Prüfungen (`minValue`, `maxValue`, `value`) werden trotzdem auch durchgeführt. scalar ------ Any scalar value: no `None`, no `dict`, no `tuple`, no `list`, no `set`, no `frozenset`. But if - ``nullable`` bool (Default: False): None/null/nil is allowed also Schema-Kombinatoren ------------------- - ``all-of`` alle in der gegebenen Liste müssen validieren - ``any-of`` mindestens einer muß validieren Nach den ersten erfolgreichen Test werden alle weiteren Sub-Tests abgebrochen (aka. short-circuit Verhalten). - ``one-of`` **genau einer** aus der Liste muß validieren (aka. xor) - ``not`` das folgende Schema darf nicht successful validieren Bedingungen =========== ``cond``-Key im Schema: Lisp-like `cond`: - eine Liste von Wenn-Dann-Paaren Bedingung: ``when``, ``when-ref-true``, ``when-ref-exists`` Dann: ``then``, ``then-merge`` Für ``when``: Logische Operatoren: ``not`` ``all-of`` (aka `and`) ``any-of`` (aka `or`) ``one-of`` (aka `xor`) Prädikate: ``ref-true``, ``ref-exists``, ein Objekt im boolschen Kontext Vergleichs-Operator: ``equals`` gefolgt von einer Liste der Länge zwei als Gleichheits- Operator: Mögliche Keys: ``ref``: eine Referenz ``value`` oder ``val`` ein Wert z.B. in YAML:: equals: - ref: object:#my.key - value: "a string value" ``when-ref-true`` und ``when-ref-exists`` sind einfache Abkürzungen für:: when: ref-true: ... bzw:: when: ref-exists: ... - die *erste* zutreffende Bedingung bestimmt via seinem "Dann" ein Schema ``then`` Keys im Then-Schema *ersetzen* korrespondierende Keys im Parent-Schema ``then-merge`` Then-Merge-Schema wird in das Parent-Schema *eingemischt* - das ganze erfolgt rekursiv - falls keine der Bedingungen zutrifft wird nichts ausgeführt/geändert - ``when`` -- direkt gefolgt von einer Liste -- ist eine Abkürzung für ``all-of` und eben dieser Liste:: cond: when: - test1 - test2 - test3 ist äquivalent zu:: cond: when: all-of: - test1 - test2 - test3 .. important:: Schema-Referenzen werden **vor** dem Replace/Merge jeweils aufgelöst! ``match`` entspricht ``cond`` -- mit dem Unterschied, daß statt der *ersten* wahren Bedingung **alle** wahren Bedingungen ausgeführt werden; erst werden alle Schemata, die aus wahren Bedingungen kommen gesammelt, danach werden die Schemata ersetzt bzw. gemerged. Beispiel:: required: - a - b cond: - when: all-of: - not: ref-true: 'object:#p1.p2.p3' - ref-exists: '#p4.p5' then: required: ["foo", "bar"] # replace existing `required' - when: ref-true: 'object:#p6.p7' then: new-key: "new-val" # a new key to the containing dict then-merge: required: ["c", "d"] # add `c' and `d' to `a' and `b' - when: true # als letzer Fall: "else" then-replace: required: ["something", "else"] # replace existing `required' Referenzen ========== URI-Syntax Angepaßte und simplifizierte JSON-Pointer-Syntax (:rfc:`6901`) Beispiele: - ``object:#wsgi.china_detector.enabled`` ist (weil `object` das Default-URI-Schema ist) äquivalent zu: ``#wsgi.china_detector.enabled`` Das ist eine **absolute** Referenz. ``.`` ist also -- wie in :py:mod:`configmix` -- der Hierarchie-Separator für URI-Fragmente in Objekt-Referenzen - ``object:#`` ist das Root-Objekt - ``object:#.`` ist das current Kontext-Object (aka "Base") - ``object:`` ist *ungültig* Ein Fragment **muß** also formal vorhanden sein -- auch wenn es leer ist. - Relative Referenzen *starten* mit einen Punkt (analog Python-Imports) Mehrere führende Punkte sind -- wie bei Python-Imports -- relative Referenzen zu Parent-Objekten. Der Versuch, den Parent des Root-Objektes anzusprechen, liefert einen :py:exc:`TypeError`. Wo ein Schema erlaubt ist, ist auch ein dict mit dem einzigen Key ``$ref`` erlaubt. Dies ist eine Referenz auf ein anderes Schema mit dem URI-Schema ``schema:``. Dieses andere Schema kann auch aus einer anderen Datei kommen: - ``schema:$root#/`` Das Root-Element des Root-Schemas - ``schema:$self#/`` Das Root-Element des gerade aktiven Schemas. - ``schema:data:schemalib:file.schema.yml#/foo`` Das ``foo``-Element des via Packagedata von `schemalib` geladenen Schemas `file.schema.yml`. Das ist dann auch das neue aktive Schema.
