comparison docs/schema.txt @ 5:84dfd1a94926

Add the existing implementation. All tests work. The documentation as text file is included also.
author Franz Glasner <fzglas.hg@dom66.de>
date Thu, 06 Jul 2023 23:41:41 +0200
parents
children c3a0fe8d4587
comparison
equal deleted inserted replaced
4:d715f0c13c60 5:84dfd1a94926
1 .. -*- coding: utf-8; mode: rst; indent-tabs-mode: nil -*-
2
3 ========
4 Schema
5 ========
6
7 Grundideen
8 ==========
9
10 - Angelehnt an JSON Schema
11 - Deklarativ in YAML
12 - Verwendung von erweiterten YAML-Features:
13
14 + laden von (beliebigen) Python-Objekten
15 + Benutzung von YAML-Referenzen
16
17 - Möglichkeit der direkten Verwendung von Python-Callables
18 Diese müssen Iteratoren sein und jedes Problem `yield`en.
19 - Rückgabe einer Liste von Problemen: Versuch möglichst viele Probleme auf
20 einen Schlag zu melden (soweit möglich und sinnvoll)
21
22 .. seealso:: - https://json-schema.org/understanding-json-schema/index.html
23 - http://rx.codesimply.com/coretypes.html
24
25
26 Extra Keywords für :py:func:`validate`
27 ======================================
28
29 - ``skip_keys``
30
31 Eine Liste Strings oder von compilierten REs
32
33 Ein String-Item wird auf Gleichheit getestet, die RE per :py:meth:`search`
34 -- und zwar auf den Dict-key
35
36 Bei Treffer wird dieser Key komplett ignoriert. Das ist also eine globale
37 Ignore-Liste für Dict-Keys.
38
39
40 Typen
41 =====
42
43 Durch ``type`` (required) gekennzeichnet
44
45
46 Alle Schemata außer den `Schema-Kombinatoren`_ haben auch ein optionales
47 Attribut ``index-constraint``.
48
49 Dessen Wert ist eine Liste von Indizes, an denen das Element in
50 seinem Parent-Container (Liste, sorted dict) vorkommen darf.
51
52
53 dict / map / object
54 -------------------
55
56 - ``nullable``
57
58 bool (Default: False): instead of an empty dict allow also a None/null/nil
59
60 - ``keys``
61
62 `dict` mit Keys und den Values als zugeordnete Schemata für die Values
63 des Dicts
64
65 - ``keyNames``
66
67 Wenn vorhanden: ein Schema, dem die *Keys* -- auch die `additionalKeys` --
68 folgen müssen.
69
70 Default: entspricht ``{"type": "string"}``
71
72 - ``additionalKeys``
73
74 * bool
75
76 `False`
77 nicht erlaubt (default)
78
79 Globales ``skip_keys`` wird aber zusätzlich noch in Betracht
80 gezogen.
81
82 `True`
83 erlaubt -- keine weitergehende Schema-Prüfung der Inhalte
84
85 Globales ``skip_keys`` ist offensichtlich irrelevant.
86
87 * Schema
88
89 Prüfung erfolgt nach gegebenem Schema
90
91 Globales ``skip_keys`` wird aber zusätzlich noch in Betracht gezogen.
92
93 - ``required``
94
95 Liste von Strings mit Key-Namen, die vorkommen müssen
96
97 - ``maxLength``
98 - ``minLength``
99
100
101 list / array
102 ------------
103
104 - ``nullable``
105
106 bool (Default: False): instead of an empty list allow also a None/null/nil
107
108 - ``items``
109
110 Ein Schema für *alle* Items.
111
112 - ``maxLength``
113 - ``minLength``
114
115
116 set / frozenset
117 ---------------
118
119 - ``nullable``
120
121 bool (Default: False): instead of an empty set allow also a None/null/nil
122
123 - ``items``
124
125 Ein Schema für *alle* Items
126
127 - ``maxLength``
128 - ``minLength``
129
130
131 tuple / record
132 --------------
133
134 - ``nullable``
135
136 bool (Default: False): instead of an empty list or tuple allow also
137 a None/null/nil
138
139 - ``items``
140
141 Eine Liste: je ein spezielles Schema *pro Item*
142
143 - ``additionalItems``
144
145 * bool
146
147 `False`
148 nicht erlaubt (default)
149
150 `True`
151 erlaubt -- keine weitergehende Schema-Prüfung der Inhalte
152
153 * Schema
154
155 Prüfung der "zusätzlichen" Items erfolgt nach gegebenem Schema
156
157 - ``maxLength``
158 - ``minLength``
159
160
161 string / str
162 ------------
163
164 - ``nullable``
165
166 bool (Default: False): instead of an empty string allow also a None/null/nil
167
168 - ``enum``
169
170 Eine Liste von Strings, von denen genau einer dem String entspricht
171
172 Achtung: Alle anderen Prüfungen (siehe unten) werden trotzdem auch
173 durchgeführt.
174
175 - ``is-contained-in-ref``
176
177 The string's value must be contained in (Python ``in``) in the referenced
178 object (see `Referenzen`_).
179
180 - ``maxLength``
181 - ``minLength``
182 - ``pattern``
183
184 * string
185
186 RE of the accepted pattern
187
188 * compiled RE
189
190 compiled RE of the accepted pattern
191
192 * Callable
193
194
195 binary
196 ------
197
198 - ``maxLength``
199 - ``minLength``
200 - ``pattern``
201
202 * string
203
204 RE of the accepted pattern. The YAML unicode string value will be
205 converted to a byte-string with :func:`ast.literal_eval` as if it
206 is surrounded by ``b'''<re>'''`` or ``b"""<re>"""``. If the pattern
207 contains both a ``'''`` or ``"""`` substring the conversion will fail.
208
209 * bytes, bytearray
210
211 RE of the accepted pattern
212
213 * compiled RE
214
215 compiled RE of the accepted pattern
216
217 * Callable
218
219
220 bool / boolean
221 --------------
222
223 Only **real** boolean values: ``true`` and ``false``
224
225 - ``value``
226
227 The accepted value or a validating callable
228
229 - ``nullable``
230
231 bool (Default: False): instead of a boolean allow also a None/null/nil
232
233
234 timestamp / datetime
235 --------------------
236
237 Only :py:class:`datetime.datetime` allowed
238
239 - ``value``
240
241 Callable that validates the value of a timestamp
242
243
244 Callable
245 --------
246
247 Iterator (e.g. ``yield``) mit Signatur: :py:func:`callable(object, schema, context)`
248
249
250 accept
251 ------
252
253 Validates successfully always: accept everything
254
255
256 deny
257 ----
258
259 Does not validate successfully: always yield the error code 10010
260
261
262 :py:obj:`None` / none / null / nil
263 ----------------------------------
264
265 Only the `None` object validates
266
267
268 empty
269 -----
270
271 Erlaubt sind: None, leeres Dict, leere Liste, leeres Set/Frozenset
272
273 .. note:: Leere Strings sind **nicht** erlaubt.
274
275
276 integer / int
277 -------------
278
279 - ``nullable``
280
281 bool (Default: False): allow also a None/null/nil
282
283 - ``minValue``
284 - ``maxValue``
285 - ``value``
286
287 A callable to validate the integer value
288
289 - ``enum``
290
291 Eine Liste von ganzen Zahlen, von denen genau einer dem vorhandenen
292 Wert entsprechen muß.
293
294 Achtung: Alle anderen Prüfungen (`minValue`, `maxValue`, `value`)
295 werden trotzdem auch durchgeführt.
296
297
298 real / double / float
299 ---------------------
300
301 - ``nullable``
302
303 bool (Default: False): allow also a None/null/nil
304
305 - ``minValue``
306 - ``maxValue``
307 - ``value``
308
309 A callable to validate the float value
310
311
312 number / num
313 ------------
314
315 - ``nullable``
316
317 bool (Default: False): allow also a None/null/nil
318
319 Any numeric value (int or float)
320
321 - ``minValue``
322 - ``maxValue``
323 - ``value``
324
325 A callable to validate the number
326
327 - ``enum``
328
329 Eine Liste von Zahlen, von denen genau einer dem vorhandenen
330 Wert entsprechen muß.
331
332 Achtung: Alle anderen Prüfungen (`minValue`, `maxValue`, `value`)
333 werden trotzdem auch durchgeführt.
334
335
336 scalar
337 ------
338
339 Any scalar value: no `None`, no `dict`, no `tuple`, no `list`, no `set`,
340 no `frozenset`.
341
342 But if
343
344 - ``nullable``
345
346 bool (Default: False): None/null/nil is allowed also
347
348
349 Schema-Kombinatoren
350 -------------------
351
352 - ``all-of``
353
354 alle in der gegebenen Liste müssen validieren
355
356 - ``any-of``
357
358 mindestens einer muß validieren
359
360 Nach den ersten erfolgreichen Test werden alle weiteren Sub-Tests
361 abgebrochen (aka. short-circuit Verhalten).
362
363 - ``one-of``
364
365 **genau einer** aus der Liste muß validieren (aka. xor)
366
367 - ``not``
368
369 das folgende Schema darf nicht successful validieren
370
371
372 Bedingungen
373 ===========
374
375 ``cond``-Key im Schema:
376
377 Lisp-like `cond`:
378
379 - eine Liste von Wenn-Dann-Paaren
380
381 Bedingung: ``when``, ``when-ref-true``, ``when-ref-exists``
382
383 Dann: ``then``, ``then-merge``
384
385 Für ``when``:
386
387 Logische Operatoren:
388
389 ``not``
390
391 ``all-of`` (aka `and`)
392
393 ``any-of`` (aka `or`)
394
395 ``one-of`` (aka `xor`)
396
397 Prädikate:
398
399 ``ref-true``, ``ref-exists``, ein Objekt im boolschen Kontext
400
401 Vergleichs-Operator:
402
403 ``equals`` gefolgt von einer Liste der Länge zwei als Gleichheits-
404 Operator:
405
406 Mögliche Keys:
407
408 ``ref``: eine Referenz
409
410 ``value`` oder ``val`` ein Wert
411
412 z.B. in YAML::
413
414 equals:
415 - ref: object:#my.key
416 - value: "a string value"
417
418 ``when-ref-true`` und ``when-ref-exists`` sind einfache Abkürzungen für::
419
420 when:
421 ref-true: ...
422
423 bzw::
424
425 when:
426 ref-exists: ...
427
428 - die *erste* zutreffende Bedingung bestimmt via seinem "Dann" ein Schema
429
430 ``then``
431
432 Keys im Then-Schema *ersetzen* korrespondierende Keys im Parent-Schema
433
434 ``then-merge``
435
436 Then-Merge-Schema wird in das Parent-Schema *eingemischt*
437
438 - das ganze erfolgt rekursiv
439
440 - falls keine der Bedingungen zutrifft wird nichts ausgeführt/geändert
441
442 - ``when`` -- direkt gefolgt von einer Liste -- ist eine Abkürzung für
443 ``all-of` und eben dieser Liste::
444
445 cond:
446 when:
447 - test1
448 - test2
449 - test3
450
451 ist äquivalent zu::
452
453 cond:
454 when:
455 all-of:
456 - test1
457 - test2
458 - test3
459
460 .. important:: Schema-Referenzen werden **vor** dem Replace/Merge jeweils
461 aufgelöst!
462
463 ``match`` entspricht ``cond`` -- mit dem Unterschied, daß statt der *ersten*
464 wahren Bedingung **alle** wahren Bedingungen ausgeführt werden;
465
466 erst werden alle Schemata, die aus wahren Bedingungen kommen gesammelt,
467 danach werden die Schemata ersetzt bzw. gemerged.
468
469 Beispiel::
470
471 required:
472 - a
473 - b
474 cond:
475 - when:
476 all-of:
477 - not:
478 ref-true: 'object:#p1.p2.p3'
479 - ref-exists: '#p4.p5'
480 then:
481 required: ["foo", "bar"] # replace existing `required'
482 - when:
483 ref-true: 'object:#p6.p7'
484 then:
485 new-key: "new-val" # a new key to the containing dict
486 then-merge:
487 required: ["c", "d"] # add `c' and `d' to `a' and `b'
488 - when: true # als letzer Fall: "else"
489 then-replace:
490 required: ["something", "else"] # replace existing `required'
491
492
493 Referenzen
494 ==========
495
496 URI-Syntax
497
498 Angepaßte und simplifizierte JSON-Pointer-Syntax (:rfc:`6901`)
499
500 Beispiele:
501
502 - ``object:#wsgi.china_detector.enabled``
503
504 ist (weil `object` das Default-URI-Schema ist) äquivalent zu:
505
506 ``#wsgi.china_detector.enabled``
507
508 Das ist eine **absolute** Referenz.
509
510 ``.`` ist also -- wie in :py:mod:`configmix` -- der Hierarchie-Separator
511 für URI-Fragmente in Objekt-Referenzen
512
513 - ``object:#`` ist das Root-Objekt
514
515 - ``object:#.`` ist das current Kontext-Object (aka "Base")
516
517 - ``object:`` ist *ungültig*
518
519 Ein Fragment **muß** also formal vorhanden sein -- auch wenn es leer ist.
520
521 - Relative Referenzen *starten* mit einen Punkt (analog Python-Imports)
522
523 Mehrere führende Punkte sind -- wie bei Python-Imports -- relative
524 Referenzen zu Parent-Objekten. Der Versuch, den Parent des Root-Objektes
525 anzusprechen, liefert einen :py:exc:`TypeError`.
526
527 Wo ein Schema erlaubt ist, ist auch ein dict mit dem einzigen Key ``$ref``
528 erlaubt. Dies ist eine Referenz auf ein anderes Schema mit dem URI-Schema
529 ``schema:``. Dieses andere Schema kann auch aus einer anderen Datei kommen:
530
531 - ``schema:$root#/``
532
533 Das Root-Element des Root-Schemas
534
535 - ``schema:$self#/``
536
537 Das Root-Element des gerade aktiven Schemas.
538
539 - ``schema:data:schemalib:file.schema.yml#/foo``
540
541 Das ``foo``-Element des via Packagedata von `schemalib` geladenen Schemas
542 `file.schema.yml`. Das ist dann auch das neue aktive Schema.