pytypehint 1.2.1__tar.gz → 1.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. {pytypehint-1.2.1 → pytypehint-1.2.2}/CHANGELOG.md +29 -12
  2. pytypehint-1.2.2/PKG-INFO +66 -0
  3. pytypehint-1.2.2/README.md +42 -0
  4. {pytypehint-1.2.1 → pytypehint-1.2.2}/docs/build.md +1 -1
  5. {pytypehint-1.2.1 → pytypehint-1.2.2}/docs/contract.md +3 -3
  6. pytypehint-1.2.1/docs/philosophy.md → pytypehint-1.2.2/docs/design.md +11 -1
  7. pytypehint-1.2.1/docs/restrictions.md → pytypehint-1.2.2/docs/limits.md +8 -7
  8. pytypehint-1.2.2/docs/overview.md +105 -0
  9. {pytypehint-1.2.1 → pytypehint-1.2.2}/docs/vocabulary.md +6 -8
  10. {pytypehint-1.2.1 → pytypehint-1.2.2}/pyproject.toml +14 -0
  11. {pytypehint-1.2.1 → pytypehint-1.2.2}/src/pytypehint/__init__.py +1 -1
  12. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_hardening_a.py +1 -1
  13. pytypehint-1.2.1/PKG-INFO +0 -162
  14. pytypehint-1.2.1/README.md +0 -148
  15. pytypehint-1.2.1/docs/comparison.md +0 -18
  16. pytypehint-1.2.1/docs/guarantees.md +0 -24
  17. {pytypehint-1.2.1 → pytypehint-1.2.2}/.github/dependabot.yml +0 -0
  18. {pytypehint-1.2.1 → pytypehint-1.2.2}/.github/workflows/ci.yml +0 -0
  19. {pytypehint-1.2.1 → pytypehint-1.2.2}/.github/workflows/publish.yml +0 -0
  20. {pytypehint-1.2.1 → pytypehint-1.2.2}/.gitignore +0 -0
  21. {pytypehint-1.2.1 → pytypehint-1.2.2}/LICENSE +0 -0
  22. {pytypehint-1.2.1 → pytypehint-1.2.2}/docs/atoms.md +0 -0
  23. {pytypehint-1.2.1 → pytypehint-1.2.2}/docs/decode.md +0 -0
  24. {pytypehint-1.2.1 → pytypehint-1.2.2}/docs/defaults.md +0 -0
  25. {pytypehint-1.2.1 → pytypehint-1.2.2}/docs/immutable.md +0 -0
  26. {pytypehint-1.2.1 → pytypehint-1.2.2}/docs/resolve.md +0 -0
  27. {pytypehint-1.2.1 → pytypehint-1.2.2}/docs/tuples.md +0 -0
  28. {pytypehint-1.2.1 → pytypehint-1.2.2}/src/pytypehint/atoms.py +0 -0
  29. {pytypehint-1.2.1 → pytypehint-1.2.2}/src/pytypehint/bridge.py +0 -0
  30. {pytypehint-1.2.1 → pytypehint-1.2.2}/src/pytypehint/contract.py +0 -0
  31. {pytypehint-1.2.1 → pytypehint-1.2.2}/src/pytypehint/errors.py +0 -0
  32. {pytypehint-1.2.1 → pytypehint-1.2.2}/src/pytypehint/immutable.py +0 -0
  33. {pytypehint-1.2.1 → pytypehint-1.2.2}/src/pytypehint/py.typed +0 -0
  34. {pytypehint-1.2.1 → pytypehint-1.2.2}/src/pytypehint/shapes.py +0 -0
  35. {pytypehint-1.2.1 → pytypehint-1.2.2}/src/pytypehint/signature.py +0 -0
  36. {pytypehint-1.2.1 → pytypehint-1.2.2}/src/pytypehint/structure.py +0 -0
  37. {pytypehint-1.2.1 → pytypehint-1.2.2}/src/pytypehint/utils.py +0 -0
  38. {pytypehint-1.2.1 → pytypehint-1.2.2}/src/pytypehint/validation.py +0 -0
  39. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/conftest.py +0 -0
  40. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_annotated.py +0 -0
  41. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_annotated_hoisting_properties.py +0 -0
  42. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_atom_argument_validation.py +0 -0
  43. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_atom_table_reflection.py +0 -0
  44. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_atoms.py +0 -0
  45. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_bool.py +0 -0
  46. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_bridge.py +0 -0
  47. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_build.py +0 -0
  48. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_certification.py +0 -0
  49. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_collection_and_recursion_matrix.py +0 -0
  50. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_composition.py +0 -0
  51. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_contract.py +0 -0
  52. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_contract_graph.py +0 -0
  53. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_crossround_x.py +0 -0
  54. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_crossround_y.py +0 -0
  55. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_datetime.py +0 -0
  56. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_decode.py +0 -0
  57. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_decode_boundary.py +0 -0
  58. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_decode_routing.py +0 -0
  59. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_default_container_isolation.py +0 -0
  60. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_default_types.py +0 -0
  61. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_discriminated_wrapper.py +0 -0
  62. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_discriminator.py +0 -0
  63. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_documentation_contract.py +0 -0
  64. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_enum.py +0 -0
  65. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_equality.py +0 -0
  66. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_errors_pickle.py +0 -0
  67. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_extra.py +0 -0
  68. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_field_dataclass_surface.py +0 -0
  69. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_file_hint.py +0 -0
  70. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_final_restrictions.py +0 -0
  71. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_float.py +0 -0
  72. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_hardening_b.py +0 -0
  73. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_hardening_c.py +0 -0
  74. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_hardening_d.py +0 -0
  75. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_hardening_e.py +0 -0
  76. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_hardening_f.py +0 -0
  77. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_hardening_g.py +0 -0
  78. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_immutable.py +0 -0
  79. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_initvar_rejection.py +0 -0
  80. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_instance_validation_and_homonym_enums.py +0 -0
  81. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_int.py +0 -0
  82. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_list.py +0 -0
  83. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_literal.py +0 -0
  84. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_matches_no_option_notes.py +0 -0
  85. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_missing.py +0 -0
  86. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_none.py +0 -0
  87. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_none_transparency.py +0 -0
  88. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_numeric_constraint_validation.py +0 -0
  89. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_optional_toggle.py +0 -0
  90. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_portable_properties.py +0 -0
  91. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_presentation_atoms_surface.py +0 -0
  92. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_recursive.py +0 -0
  93. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_remat_runtime_failure.py +0 -0
  94. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_rematerialization.py +0 -0
  95. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_resolve.py +0 -0
  96. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_scalar_constraint_validation.py +0 -0
  97. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_scalar_option_identity.py +0 -0
  98. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_scalar_type_strictness.py +0 -0
  99. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_schema_model_invariants.py +0 -0
  100. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_shape_constraint_certification.py +0 -0
  101. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_shape_invariants.py +0 -0
  102. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_signature.py +0 -0
  103. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_signature_build.py +0 -0
  104. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_signature_field_rejection.py +0 -0
  105. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_single_pass_validation.py +0 -0
  106. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_str.py +0 -0
  107. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_string_and_literal_integration.py +0 -0
  108. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_struct.py +0 -0
  109. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_structured_errors.py +0 -0
  110. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_temporal_constraint_validation.py +0 -0
  111. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_time_second_precision.py +0 -0
  112. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_tuple.py +0 -0
  113. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_union_field_atoms.py +0 -0
  114. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_union_option_collisions.py +0 -0
  115. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_union_routing_matrix.py +0 -0
  116. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_unions.py +0 -0
  117. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_validate.py +0 -0
  118. {pytypehint-1.2.1 → pytypehint-1.2.2}/tests/test_wrapper_layer_composition.py +0 -0
@@ -1,11 +1,28 @@
1
1
  # Changelog
2
2
 
3
- ## [1.2.1] — 2026-09-29
3
+ ## 1.2.2 - 2026-09-29
4
+
5
+ ### Changed
6
+
7
+ - Documentation only: the README becomes a short entrance to the documentation
8
+ site at https://offerrall.github.io/pytypehint/, and `docs/overview.md` holds
9
+ the introduction.
10
+ - Rename `docs/restrictions.md` to `docs/limits.md` ("Limits") and
11
+ `docs/philosophy.md` to `docs/design.md`. Merge
12
+ `docs/comparison.md` into Design and remove `docs/guarantees.md`, whose points
13
+ each live on their own page.
14
+ - Add `[project.urls]` (documentation, repository, changelog) and Python
15
+ classifiers to the package metadata.
16
+ - Fix the 1.1.0 release date in this changelog and date every entry.
17
+
18
+ The code is the same as 1.2.1.
19
+
20
+ ## 1.2.1 - 2026-09-29
4
21
 
5
22
  - Documentation only: the README title no longer carries the version, and the
6
23
  1.2.0 entry below has its release date. The code is the same as 1.2.0.
7
24
 
8
- ## [1.2.0] — 2026-09-20
25
+ ## 1.2.0 - 2026-09-20
9
26
 
10
27
  - Add `@immutable`: deeply immutable, slotted, keyword-only dataclasses with
11
28
  automatic validation on construction and `dataclasses.replace`.
@@ -18,7 +35,7 @@
18
35
  - Keep the implementation in `immutable.py`; existing schema operations retain
19
36
  their behavior. Add examples and the immutable model contract.
20
37
 
21
- ## [1.1.0] — 2026-20-09
38
+ ## 1.1.0 - 2026-09-20
22
39
 
23
40
  - Add fixed tuples (`tuple[X, Y]`), variadic tuples (`tuple[X, ...]`) and empty
24
41
  tuples (`tuple[()]`), including nested types, unions and per-position atoms.
@@ -31,7 +48,7 @@
31
48
  `v: 1`; consumers need tuple support to read the new shape type.
32
49
  - Shorten the README and move detailed guarantees and API reference into docs.
33
50
 
34
- ## [1.0.0] - 2026-08-10
51
+ ## 1.0.0 - 2026-08-10
35
52
 
36
53
  The core now owns the portable form of its own types. Until this release a
37
54
  compiled schema could only be read as Python objects, in the process that
@@ -98,7 +115,7 @@ then what validation and its errors guarantee.
98
115
  `date`, or one named `list[str]` beside a `list[str]` now fail at compilation
99
116
  with `Field 'x': duplicate discriminator name(s): str`. Each such pair left two
100
117
  options answering to one `$type`, with one of them unreachable — the rule
101
- [restrictions.md](docs/restrictions.md) already stated, now enforced where the
118
+ [limits.md](docs/limits.md) already stated, now enforced where the
102
119
  implementation had only covered options sharing a runtime type. A dataclass and
103
120
  an enum of the same class name use different discriminators and remain
104
121
  admissible.
@@ -331,7 +348,7 @@ then what validation and its errors guarantee.
331
348
  while filling does not; `restrictions.md` documents the discriminator-name rule
332
349
  and the union options a portable tree cannot spell bare.
333
350
 
334
- ## [0.0.7]
351
+ ## 0.0.7 - 2026-07-26
335
352
 
336
353
  - Breaking: `IsPathFile` now guarantees that the string names a real file at the
337
354
  moment of validation, not merely that its text ends in an accepted suffix. A
@@ -376,7 +393,7 @@ then what validation and its errors guarantee.
376
393
  exclusive to `Str`: no new shape, no `PathFile` type, and no compatibility
377
394
  switch (`exists=False`, `strict=False`) — the semantics are single and explicit.
378
395
 
379
- ## [0.0.6]
396
+ ## 0.0.6 - 2026-07-24
380
397
 
381
398
  - Breaking: `datetime.time` values with non-zero microseconds are no longer
382
399
  accepted. Time precision is limited to whole seconds, so the effective range
@@ -393,7 +410,7 @@ then what validation and its errors guarantee.
393
410
  `exclusive bound at ... leaves no valid time`. A bound at `time.max` is instead
394
411
  rejected as sub-second precision.
395
412
 
396
- ## [0.0.5]
413
+ ## 0.0.5 - 2026-07-23
397
414
 
398
415
  - Compilation now rejects a union of two enums that share a class name, e.g.
399
416
  two Enum classes both named `Color`, with `Field '<name>': duplicate
@@ -405,7 +422,7 @@ then what validation and its errors guarantee.
405
422
  a dataclass of the same name never collide and stay admissible. Previously the
406
423
  core admitted the pair and only a wrapper could catch it.
407
424
 
408
- ## [0.0.4]
425
+ ## 0.0.4 - 2026-07-22
409
426
 
410
427
  - Enum fields now accept `Extra`, the same namespaced wrapper-notation channel
411
428
  the other leaf shapes already carry. `EnumShape` gains `_extras` and a
@@ -430,7 +447,7 @@ then what validation and its errors guarantee.
430
447
  degraded the whole line into the leaf and rendered `Field 'x': default <leaf>`.
431
448
  Only the message and its structure changed; no behaviour did.
432
449
 
433
- ## [0.0.3]
450
+ ## 0.0.3 - 2026-07-20
434
451
 
435
452
  - Unions whose options share one runtime input type now compile. `list[str] |
436
453
  list[int]` was rejected as a duplicate; both options are valid Python and
@@ -453,13 +470,13 @@ then what validation and its errors guarantee.
453
470
  - No breaking change: every hint accepted by 0.0.2 compiles and behaves as
454
471
  before.
455
472
 
456
- ## [0.0.2]
473
+ ## 0.0.2 - 2026-07-17
457
474
 
458
475
  - `Extra(value)` becomes `Extra(key, value)`, with a namespaced key
459
476
  (`"package.name"`) and any string value, empty included.
460
477
  - Shapes replace `extra` with `extras`, a read-only `dict[str, str]` merged from
461
478
  every `Extra` atom on the hint. Keys layer independently: the outer atom wins.
462
479
 
463
- ## [0.0.1] - 2026-07-15
480
+ ## 0.0.1 - 2026-07-15
464
481
 
465
482
  - Initial release.
@@ -0,0 +1,66 @@
1
+ Metadata-Version: 2.5
2
+ Name: pytypehint
3
+ Version: 1.2.2
4
+ Summary: Compiles Python type hints into strict, inspectable, portable contracts
5
+ Project-URL: Documentation, https://offerrall.github.io/pytypehint/
6
+ Project-URL: Repository, https://github.com/offerrall/pytypehint
7
+ Project-URL: Changelog, https://github.com/offerrall/pytypehint/blob/master/CHANGELOG.md
8
+ Author: Beltrán Offerrall
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.11
19
+ Provides-Extra: dev
20
+ Requires-Dist: hypothesis; extra == 'dev'
21
+ Requires-Dist: mypy; extra == 'dev'
22
+ Requires-Dist: pytest; extra == 'dev'
23
+ Description-Content-Type: text/markdown
24
+
25
+ # pytypehint
26
+
27
+ Define data once with ordinary Python type hints and dataclasses. pytypehint
28
+ compiles them into strict schemas that validate input with exact types and no
29
+ implicit coercion, build nested dataclasses, and export a portable description
30
+ another process can read.
31
+
32
+ Use `@immutable` for deeply immutable models that validate themselves and reuse
33
+ already validated children. pytypehint is the schema and validation core of
34
+ [func-to-web](https://offerrall.github.io/func-to-web/).
35
+
36
+ ```python
37
+ from dataclasses import dataclass
38
+ from typing import Annotated
39
+ from pytypehint import Min, struct_of
40
+
41
+ @dataclass
42
+ class Item:
43
+ name: str
44
+ quantity: Annotated[int, Min(1)] = 1
45
+
46
+ schema = struct_of(Item)
47
+ item = schema.build({"name": "Pen"}) # Item(name='Pen', quantity=1)
48
+ schema.build({"name": "Pen", "quantity": 0}) # SchemaValueError: quantity
49
+ ```
50
+
51
+ The full documentation is at https://offerrall.github.io/pytypehint/.
52
+
53
+ ## Documentation
54
+
55
+ - [Overview](docs/overview.md): immutable models, portable data, field metadata and the four operations.
56
+ - [Immutable models](docs/immutable.md): the `@immutable` contract, allowed fields, reuse and Python behavior.
57
+ - [Types and API](docs/vocabulary.md): which hints compile to which shapes, and the public API.
58
+ - [Atoms](docs/atoms.md): constraints and notation per shape, file names, layering and extras.
59
+ - [Build](docs/build.md): validating and constructing instances or keyword arguments, union selection and errors.
60
+ - [Resolve](docs/resolve.md): validated dictionaries with defaults filled at the current level.
61
+ - [Decode](docs/decode.md): restoring portable values such as dates, enums and tuples before validation.
62
+ - [Tuples](docs/tuples.md): fixed, variadic and empty tuples and the `Tuple` shape.
63
+ - [Defaults](docs/defaults.md): certification and rematerialization of default values.
64
+ - [Portable contract](docs/contract.md): the JSON-compatible schema document returned by `to_dict()`.
65
+ - [Limits](docs/limits.md): rejected definitions, option identity and runtime limits.
66
+ - [Design](docs/design.md): what the core owns, what consumers own, and why.
@@ -0,0 +1,42 @@
1
+ # pytypehint
2
+
3
+ Define data once with ordinary Python type hints and dataclasses. pytypehint
4
+ compiles them into strict schemas that validate input with exact types and no
5
+ implicit coercion, build nested dataclasses, and export a portable description
6
+ another process can read.
7
+
8
+ Use `@immutable` for deeply immutable models that validate themselves and reuse
9
+ already validated children. pytypehint is the schema and validation core of
10
+ [func-to-web](https://offerrall.github.io/func-to-web/).
11
+
12
+ ```python
13
+ from dataclasses import dataclass
14
+ from typing import Annotated
15
+ from pytypehint import Min, struct_of
16
+
17
+ @dataclass
18
+ class Item:
19
+ name: str
20
+ quantity: Annotated[int, Min(1)] = 1
21
+
22
+ schema = struct_of(Item)
23
+ item = schema.build({"name": "Pen"}) # Item(name='Pen', quantity=1)
24
+ schema.build({"name": "Pen", "quantity": 0}) # SchemaValueError: quantity
25
+ ```
26
+
27
+ The full documentation is at https://offerrall.github.io/pytypehint/.
28
+
29
+ ## Documentation
30
+
31
+ - [Overview](docs/overview.md): immutable models, portable data, field metadata and the four operations.
32
+ - [Immutable models](docs/immutable.md): the `@immutable` contract, allowed fields, reuse and Python behavior.
33
+ - [Types and API](docs/vocabulary.md): which hints compile to which shapes, and the public API.
34
+ - [Atoms](docs/atoms.md): constraints and notation per shape, file names, layering and extras.
35
+ - [Build](docs/build.md): validating and constructing instances or keyword arguments, union selection and errors.
36
+ - [Resolve](docs/resolve.md): validated dictionaries with defaults filled at the current level.
37
+ - [Decode](docs/decode.md): restoring portable values such as dates, enums and tuples before validation.
38
+ - [Tuples](docs/tuples.md): fixed, variadic and empty tuples and the `Tuple` shape.
39
+ - [Defaults](docs/defaults.md): certification and rematerialization of default values.
40
+ - [Portable contract](docs/contract.md): the JSON-compatible schema document returned by `to_dict()`.
41
+ - [Limits](docs/limits.md): rejected definitions, option identity and runtime limits.
42
+ - [Design](docs/design.md): what the core owns, what consumers own, and why.
@@ -42,7 +42,7 @@ Dataclass discriminators use the class name. Other wrappers use
42
42
  Discriminators are accepted only where needed, including inside sequence items.
43
43
  A lone dataclass rejects `$type` as an unexpected key. When dataclass and wrapped
44
44
  options coexist, `$value` distinguishes the wrapper from a dataclass dictionary.
45
- See [option identities](restrictions.md#option-identity).
45
+ See [option identities](limits.md#option-identity).
46
46
 
47
47
  `resolve` preserves validated discriminators; `build` removes them while
48
48
  constructing the selected values. Defaults are Python values and need no wrapper.
@@ -37,8 +37,8 @@ used in data discriminators; consumers must not substitute the definition ID.
37
37
 
38
38
  `v` versions the format, not the library. Removing a key or changing its meaning
39
39
  raises `v`; additive keys do not. Ignore unknown keys and reject unsupported shape
40
- types. Tuple nodes were added in library 1.1.0 while retaining format version 1;
41
- consumers need tuple support to read them.
40
+ types. Format version 1 includes `tuple` nodes; consumers need tuple support to
41
+ read them.
42
42
 
43
43
  ## Fields and nodes
44
44
 
@@ -51,7 +51,7 @@ There are no `optional`, `required` or `nullable` keys: inspect `default` and
51
51
  Each node has `type`. In a slot containing several options, each also has `id`,
52
52
  its `Shape.option_id()`. IDs are unique within the dataclass namespace and within
53
53
  the other-option namespace, not across both. Preserve option positions; use IDs
54
- for discriminators. See [option identities](restrictions.md#option-identity).
54
+ for discriminators. See [option identities](limits.md#option-identity).
55
55
 
56
56
  | `type` | Additional keys when applicable |
57
57
  |---|---|
@@ -5,7 +5,17 @@ into inspectable shapes, validate exact values, and construct ordinary objects.
5
5
 
6
6
  The core owns types, constraints, defaults and their portable representation.
7
7
  Consumers own input coercion, presentation, JSON text, function invocation and
8
- checks requiring files, networks or application state.
8
+ checks requiring files, networks or application state:
9
+
10
+ | Task | Responsible layer |
11
+ |---|---|
12
+ | Define ordinary models | Python dataclasses and type hints |
13
+ | Inspect/export schemas, validate values, restore portable types, construct models | pytypehint |
14
+ | Parse JSON, coerce form/CLI input, render controls, collect multiple errors | Consumer |
15
+ | Call functions, check files, manage persistence/authentication | Application |
16
+
17
+ Direct dataclass construction is simpler for trusted internal objects. Use
18
+ pytypehint when you need strict input validation or a shared inspectable contract.
9
19
 
10
20
  Keep union selection explicit when types or portable spellings collide. Keep
11
21
  missing values separate from `None`. Report the first error with its path.
@@ -1,4 +1,4 @@
1
- # Restrictions
1
+ # Limits
2
2
 
3
3
  Only the [documented types](vocabulary.md) and [atoms](atoms.md) are supported.
4
4
  Unsupported hints and invalid schemas fail during compilation.
@@ -25,7 +25,9 @@ def search(query: str):
25
25
  ```
26
26
 
27
27
  `datetime`, path objects, mappings, sets and arbitrary classes are outside the
28
- vocabulary. Use dataclasses to represent additional structure or policy.
28
+ vocabulary. Represent timestamp policy and other structure with a dataclass, and
29
+ file names with a `str` annotated with [`FileHint`](atoms.md#file-names), which
30
+ checks the suffix only.
29
31
 
30
32
  ## Option identity
31
33
 
@@ -66,8 +68,7 @@ contents never choose the variant.
66
68
  - Validation stops at the first error. Constructor exceptions propagate unchanged.
67
69
  - Cycles and excessive nesting may raise raw `RecursionError` in decode, resolve
68
70
  or build. Recursive schemas are supported; cyclic input values are not.
69
- - Factories must be pure, and input must not change during construction.
70
-
71
- `FileHint` checks the string's suffix only; existence, kind and size require
72
- consumer checks. Portable spelling collisions need [decode wrappers](decode.md#unions),
73
- even when their restored Python types would be distinct.
71
+ - [Default recipes](defaults.md) must be pure, and input must not change during
72
+ construction.
73
+ - Portable spelling collisions need [decode wrappers](decode.md#unions), even
74
+ when their restored Python types would be distinct.
@@ -0,0 +1,105 @@
1
+ # Overview
2
+
3
+ pytypehint turns a dataclass or a function signature into a compiled schema:
4
+ `struct_of(Item)` returns a `Struct`, `signature_of(fn)` a `Signature`. Compile
5
+ once and reuse. Validation is exact: `float` rejects `int`, `int` rejects `bool`,
6
+ and nothing is coerced. The first error raises `SchemaTypeError` or
7
+ `SchemaValueError` with the failing field or index in its `path`.
8
+
9
+ ## Immutable models
10
+
11
+ Declare constraints once. Normal construction and `dataclasses.replace` validate
12
+ automatically; nested instances keep their identity.
13
+
14
+ ```python
15
+ from dataclasses import replace
16
+ from typing import Annotated
17
+ from pytypehint import Max, Min, immutable
18
+
19
+ Positive = Annotated[int, Min(1)]
20
+ Channel = Annotated[float, Min(0.0), Max(1.0)]
21
+
22
+ @immutable
23
+ class Exposure:
24
+ stops: float = 0.0
25
+
26
+ @immutable
27
+ class Grayscale:
28
+ pass
29
+
30
+ @immutable
31
+ class Layer:
32
+ name: Annotated[str, Min(1)]
33
+ effect: Exposure | Grayscale
34
+ color: tuple[Channel, Channel, Channel, Channel] = (0.0, 0.0, 0.0, 1.0)
35
+
36
+ @immutable
37
+ class Document:
38
+ size: tuple[Positive, Positive]
39
+ layers: tuple[Layer, ...] = ()
40
+
41
+ photo = Layer(name="Photo", effect=Exposure(stops=1.5))
42
+ original = Document(size=(1920, 1080), layers=(photo,))
43
+ resized = replace(original, size=(3840, 2160))
44
+
45
+ assert resized.layers[0] is photo
46
+ assert original.size == (1920, 1080)
47
+ ```
48
+
49
+ The new document checks its size and layer references, without revisiting the
50
+ existing layer's fields. Tuples are checked; existing immutable children are reused.
51
+
52
+ ```python
53
+ replace(photo, color=(1.0, 0.0, 0.0, 2.0)) # SchemaValueError, path: ('color', 3)
54
+ Exposure(stops="1.5") # SchemaTypeError
55
+ original.size = (800, 600) # FrozenInstanceError
56
+ ```
57
+
58
+ Fields are restricted to immutable scalars, tuples and other `@immutable` models;
59
+ see [Immutable models](immutable.md) for the full contract, inheritance and defaults.
60
+
61
+ ## Portable data and inspection
62
+
63
+ The same models work with the schema API. `decode` restores portable values such
64
+ as JSON arrays and discriminated unions, and `to_dict` describes the schema for a
65
+ UI or another process:
66
+
67
+ ```python
68
+ from pytypehint import struct_of
69
+
70
+ schema = struct_of(Document)
71
+ loaded = schema.build(schema.decode({
72
+ "size": [1920, 1080],
73
+ "layers": [{
74
+ "name": "Photo",
75
+ "effect": {"$type": "Exposure", "stops": 1.5},
76
+ }],
77
+ }))
78
+
79
+ assert loaded == original
80
+ contract = schema.to_dict() # Portable description for a UI or another process
81
+ ```
82
+
83
+ Type constraints and interface metadata live on the same field:
84
+
85
+ ```python
86
+ from pytypehint import Label, Slider, Step
87
+
88
+ @immutable
89
+ class Brush:
90
+ size: Annotated[int, Min(1), Max(256), Label("Brush size"), Step(1), Slider()] = 32
91
+
92
+ size_field, = struct_of(Brush).fields
93
+ size_shape, = size_field.shape
94
+ assert size_field.label.value == "Brush size"
95
+ assert size_shape.max.value == 256
96
+ ```
97
+
98
+ ## The four operations
99
+
100
+ | Method | Result |
101
+ |---|---|
102
+ | [`build(data)`](build.md) | Dataclass instance; `signature_of(fn)` returns kwargs for `fn(**kwargs)` |
103
+ | [`resolve(data)`](resolve.md) | Validated dictionary with missing defaults filled at this level |
104
+ | [`decode(data)`](decode.md) | Portable values restored to Python types |
105
+ | [`to_dict()`](contract.md) | Portable schema description |
@@ -32,10 +32,7 @@ either: list[str] | list[int] # needs {"$type": "list[str]", "$value": ["a"]}
32
32
  Union options retain declaration order. Put type constraints on the option:
33
33
  `Annotated[int, Min(0)] | str`. Field notation such as `Label` belongs on the
34
34
  outer field. See [atoms](atoms.md), [tuples](tuples.md) and
35
- [restrictions](restrictions.md).
36
-
37
- There is no `datetime` or path shape. Represent timestamp policy with a dataclass;
38
- use a `str` annotated with `FileHint` for file names.
35
+ [limits](limits.md).
39
36
 
40
37
  ## Public API
41
38
 
@@ -51,10 +48,11 @@ Everything public is exported from `pytypehint`:
51
48
  `Extra`, `OptionalToggle`;
52
49
  - `MISSING`.
53
50
 
54
- `Struct` and `Signature` expose `.build(data)`, `.resolve(data)`, `.decode(data)`
55
- and `.to_dict()`. `Struct.fields` and `Signature.params` contain `Field` objects;
56
- `Field.shape` contains the available shapes, and `Field.default` is `MISSING`
57
- when no default exists. `Shape.option_id()` gives the discriminator identity.
51
+ `Struct` and `Signature` expose the [four operations](overview.md#the-four-operations):
52
+ `.build(data)`, `.resolve(data)`, `.decode(data)` and `.to_dict()`.
53
+ `Struct.fields` and `Signature.params` contain `Field` objects; `Field.shape`
54
+ contains the available shapes, and `Field.default` is `MISSING` when no default
55
+ exists. `Shape.option_id()` gives the discriminator identity.
58
56
  `Struct`, `Field` and `Signature` compare by identity; compile once and reuse.
59
57
 
60
58
  `@immutable` creates deeply immutable, automatically validated dataclasses with a
@@ -12,6 +12,20 @@ license = "MIT"
12
12
  license-files = ["LICENSE"]
13
13
  authors = [{ name = "Beltrán Offerrall" }]
14
14
  dependencies = []
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3 :: Only",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Operating System :: OS Independent",
22
+ "Typing :: Typed",
23
+ ]
24
+
25
+ [project.urls]
26
+ Documentation = "https://offerrall.github.io/pytypehint/"
27
+ Repository = "https://github.com/offerrall/pytypehint"
28
+ Changelog = "https://github.com/offerrall/pytypehint/blob/master/CHANGELOG.md"
15
29
 
16
30
  [project.optional-dependencies]
17
31
  dev = ["mypy", "pytest", "hypothesis"]
@@ -13,7 +13,7 @@ from pytypehint.shapes import (
13
13
  )
14
14
  from pytypehint.utils import MISSING
15
15
 
16
- __version__ = "1.2.1"
16
+ __version__ = "1.2.2"
17
17
 
18
18
  __all__ = [
19
19
  "immutable",
@@ -505,7 +505,7 @@ def test_no_module_level_name_escapes_all_by_accident():
505
505
 
506
506
 
507
507
  def test_the_version_is_the_one_this_release_claims():
508
- assert pytypehint.__version__ == "1.2.1"
508
+ assert pytypehint.__version__ == "1.2.2"
509
509
  assert "__version__" not in pytypehint.__all__
510
510
 
511
511
 
pytypehint-1.2.1/PKG-INFO DELETED
@@ -1,162 +0,0 @@
1
- Metadata-Version: 2.5
2
- Name: pytypehint
3
- Version: 1.2.1
4
- Summary: Compiles Python type hints into strict, inspectable, portable contracts
5
- Author: Beltrán Offerrall
6
- License-Expression: MIT
7
- License-File: LICENSE
8
- Requires-Python: >=3.11
9
- Provides-Extra: dev
10
- Requires-Dist: hypothesis; extra == 'dev'
11
- Requires-Dist: mypy; extra == 'dev'
12
- Requires-Dist: pytest; extra == 'dev'
13
- Description-Content-Type: text/markdown
14
-
15
- # pytypehint
16
-
17
- [![PyPI](https://img.shields.io/pypi/v/pytypehint.svg)](https://pypi.org/project/pytypehint/)
18
-
19
- Define data with Python type hints. Validate input, build nested dataclasses,
20
- inspect their fields or export a portable schema.
21
-
22
- Use **`@immutable`** for deeply immutable models that validate themselves and
23
- reuse validated children without checking their contents again.
24
-
25
- Exact types, no implicit coercion. Python 3.11+, standard library only.
26
- The schema and validation core of [FuncToWeb](https://github.com/offerrall/FuncToWeb).
27
-
28
- ```bash
29
- pip install pytypehint
30
- ```
31
-
32
- ## Validate input into ordinary dataclasses
33
-
34
- ```python
35
- from dataclasses import dataclass
36
- from typing import Annotated
37
- from pytypehint import Min, struct_of
38
-
39
- @dataclass
40
- class Item:
41
- name: str
42
- quantity: Annotated[int, Min(1)] = 1
43
-
44
- schema = struct_of(Item)
45
- item = schema.build({"name": "Pen"}) # Item(name='Pen', quantity=1)
46
- schema.build({"name": "Pen", "quantity": 0}) # SchemaValueError: quantity
47
- ```
48
-
49
- Compile once and reuse. Errors include the failing field or index in their `path`.
50
-
51
- ## Immutable models
52
-
53
- Declare constraints once. Normal construction and `dataclasses.replace` validate
54
- automatically; nested instances keep their identity.
55
-
56
- ```python
57
- from dataclasses import replace
58
- from typing import Annotated
59
- from pytypehint import Max, Min, immutable
60
-
61
- Positive = Annotated[int, Min(1)]
62
- Channel = Annotated[float, Min(0.0), Max(1.0)]
63
-
64
- @immutable
65
- class Exposure:
66
- stops: float = 0.0
67
-
68
- @immutable
69
- class Grayscale:
70
- pass
71
-
72
- @immutable
73
- class Layer:
74
- name: Annotated[str, Min(1)]
75
- effect: Exposure | Grayscale
76
- color: tuple[Channel, Channel, Channel, Channel] = (0.0, 0.0, 0.0, 1.0)
77
-
78
- @immutable
79
- class Document:
80
- size: tuple[Positive, Positive]
81
- layers: tuple[Layer, ...] = ()
82
-
83
- photo = Layer(name="Photo", effect=Exposure(stops=1.5))
84
- original = Document(size=(1920, 1080), layers=(photo,))
85
- resized = replace(original, size=(3840, 2160))
86
-
87
- assert resized.layers[0] is photo
88
- assert original.size == (1920, 1080)
89
- ```
90
-
91
- The new document checks its size and layer references, without revisiting the
92
- existing layer's fields. Tuples are checked; existing immutable children are reused.
93
-
94
- ```python
95
- replace(photo, color=(1.0, 0.0, 0.0, 2.0)) # SchemaValueError, path: ('color', 3)
96
- Exposure(stops="1.5") # SchemaTypeError
97
- original.size = (800, 600) # FrozenInstanceError
98
- ```
99
-
100
- Allowed fields are immutable scalars, tuples and other `@immutable` models.
101
- Mutable containers, ordinary dataclasses and enums are rejected. The guarantee
102
- covers declared fields through normal Python use; deliberate low-level mutation
103
- can bypass it. [Full contract, inheritance and defaults](docs/immutable.md).
104
-
105
- ## Load portable data and inspect the same definition
106
-
107
- The models above also work with the existing schema API:
108
-
109
- ```python
110
- from pytypehint import struct_of
111
-
112
- schema = struct_of(Document)
113
- loaded = schema.build(schema.decode({
114
- "size": [1920, 1080],
115
- "layers": [{
116
- "name": "Photo",
117
- "effect": {"$type": "Exposure", "stops": 1.5},
118
- }],
119
- }))
120
-
121
- assert loaded == original
122
- contract = schema.to_dict() # Portable description for a UI or another process
123
- ```
124
-
125
- Type constraints and interface metadata live on the same field:
126
-
127
- ```python
128
- from pytypehint import Label, Slider, Step
129
-
130
- @immutable
131
- class Brush:
132
- size: Annotated[int, Min(1), Max(256), Label("Brush size"), Step(1), Slider()] = 32
133
-
134
- size_field, = struct_of(Brush).fields
135
- size_shape, = size_field.shape
136
- assert size_field.label.value == "Brush size"
137
- assert size_shape.max.value == 256
138
- ```
139
-
140
- | Method | Result |
141
- |---|---|
142
- | `build(data)` | Dataclass instance; `signature_of(fn)` returns kwargs for `fn(**kwargs)` |
143
- | `resolve(data)` | Validated dictionary with missing defaults filled at this level |
144
- | `decode(data)` | Portable values restored to Python types |
145
- | `to_dict()` | Portable schema description |
146
-
147
- ## Documentation
148
-
149
- - [Immutable models](docs/immutable.md)
150
- - [Types and API](docs/vocabulary.md)
151
- - [Atoms](docs/atoms.md)
152
- - [Build](docs/build.md)
153
- - [Resolve](docs/resolve.md)
154
- - [Decode](docs/decode.md)
155
- - [Tuples](docs/tuples.md)
156
- - [Defaults](docs/defaults.md)
157
- - [Portable contract](docs/contract.md)
158
- - [Restrictions](docs/restrictions.md)
159
- - [Guarantees](docs/guarantees.md)
160
- - [Design](docs/philosophy.md)
161
- - [Comparison](docs/comparison.md)
162
- - [Changelog](CHANGELOG.md)
@@ -1,148 +0,0 @@
1
- # pytypehint
2
-
3
- [![PyPI](https://img.shields.io/pypi/v/pytypehint.svg)](https://pypi.org/project/pytypehint/)
4
-
5
- Define data with Python type hints. Validate input, build nested dataclasses,
6
- inspect their fields or export a portable schema.
7
-
8
- Use **`@immutable`** for deeply immutable models that validate themselves and
9
- reuse validated children without checking their contents again.
10
-
11
- Exact types, no implicit coercion. Python 3.11+, standard library only.
12
- The schema and validation core of [FuncToWeb](https://github.com/offerrall/FuncToWeb).
13
-
14
- ```bash
15
- pip install pytypehint
16
- ```
17
-
18
- ## Validate input into ordinary dataclasses
19
-
20
- ```python
21
- from dataclasses import dataclass
22
- from typing import Annotated
23
- from pytypehint import Min, struct_of
24
-
25
- @dataclass
26
- class Item:
27
- name: str
28
- quantity: Annotated[int, Min(1)] = 1
29
-
30
- schema = struct_of(Item)
31
- item = schema.build({"name": "Pen"}) # Item(name='Pen', quantity=1)
32
- schema.build({"name": "Pen", "quantity": 0}) # SchemaValueError: quantity
33
- ```
34
-
35
- Compile once and reuse. Errors include the failing field or index in their `path`.
36
-
37
- ## Immutable models
38
-
39
- Declare constraints once. Normal construction and `dataclasses.replace` validate
40
- automatically; nested instances keep their identity.
41
-
42
- ```python
43
- from dataclasses import replace
44
- from typing import Annotated
45
- from pytypehint import Max, Min, immutable
46
-
47
- Positive = Annotated[int, Min(1)]
48
- Channel = Annotated[float, Min(0.0), Max(1.0)]
49
-
50
- @immutable
51
- class Exposure:
52
- stops: float = 0.0
53
-
54
- @immutable
55
- class Grayscale:
56
- pass
57
-
58
- @immutable
59
- class Layer:
60
- name: Annotated[str, Min(1)]
61
- effect: Exposure | Grayscale
62
- color: tuple[Channel, Channel, Channel, Channel] = (0.0, 0.0, 0.0, 1.0)
63
-
64
- @immutable
65
- class Document:
66
- size: tuple[Positive, Positive]
67
- layers: tuple[Layer, ...] = ()
68
-
69
- photo = Layer(name="Photo", effect=Exposure(stops=1.5))
70
- original = Document(size=(1920, 1080), layers=(photo,))
71
- resized = replace(original, size=(3840, 2160))
72
-
73
- assert resized.layers[0] is photo
74
- assert original.size == (1920, 1080)
75
- ```
76
-
77
- The new document checks its size and layer references, without revisiting the
78
- existing layer's fields. Tuples are checked; existing immutable children are reused.
79
-
80
- ```python
81
- replace(photo, color=(1.0, 0.0, 0.0, 2.0)) # SchemaValueError, path: ('color', 3)
82
- Exposure(stops="1.5") # SchemaTypeError
83
- original.size = (800, 600) # FrozenInstanceError
84
- ```
85
-
86
- Allowed fields are immutable scalars, tuples and other `@immutable` models.
87
- Mutable containers, ordinary dataclasses and enums are rejected. The guarantee
88
- covers declared fields through normal Python use; deliberate low-level mutation
89
- can bypass it. [Full contract, inheritance and defaults](docs/immutable.md).
90
-
91
- ## Load portable data and inspect the same definition
92
-
93
- The models above also work with the existing schema API:
94
-
95
- ```python
96
- from pytypehint import struct_of
97
-
98
- schema = struct_of(Document)
99
- loaded = schema.build(schema.decode({
100
- "size": [1920, 1080],
101
- "layers": [{
102
- "name": "Photo",
103
- "effect": {"$type": "Exposure", "stops": 1.5},
104
- }],
105
- }))
106
-
107
- assert loaded == original
108
- contract = schema.to_dict() # Portable description for a UI or another process
109
- ```
110
-
111
- Type constraints and interface metadata live on the same field:
112
-
113
- ```python
114
- from pytypehint import Label, Slider, Step
115
-
116
- @immutable
117
- class Brush:
118
- size: Annotated[int, Min(1), Max(256), Label("Brush size"), Step(1), Slider()] = 32
119
-
120
- size_field, = struct_of(Brush).fields
121
- size_shape, = size_field.shape
122
- assert size_field.label.value == "Brush size"
123
- assert size_shape.max.value == 256
124
- ```
125
-
126
- | Method | Result |
127
- |---|---|
128
- | `build(data)` | Dataclass instance; `signature_of(fn)` returns kwargs for `fn(**kwargs)` |
129
- | `resolve(data)` | Validated dictionary with missing defaults filled at this level |
130
- | `decode(data)` | Portable values restored to Python types |
131
- | `to_dict()` | Portable schema description |
132
-
133
- ## Documentation
134
-
135
- - [Immutable models](docs/immutable.md)
136
- - [Types and API](docs/vocabulary.md)
137
- - [Atoms](docs/atoms.md)
138
- - [Build](docs/build.md)
139
- - [Resolve](docs/resolve.md)
140
- - [Decode](docs/decode.md)
141
- - [Tuples](docs/tuples.md)
142
- - [Defaults](docs/defaults.md)
143
- - [Portable contract](docs/contract.md)
144
- - [Restrictions](docs/restrictions.md)
145
- - [Guarantees](docs/guarantees.md)
146
- - [Design](docs/philosophy.md)
147
- - [Comparison](docs/comparison.md)
148
- - [Changelog](CHANGELOG.md)
@@ -1,18 +0,0 @@
1
- # Scope and ecosystem
2
-
3
- | Task | Responsible layer |
4
- |---|---|
5
- | Define ordinary models | Python dataclasses and type hints |
6
- | Inspect/export schemas, validate values, restore portable types, construct models | pytypehint |
7
- | Parse JSON, coerce form/CLI input, render controls, collect multiple errors | Consumer |
8
- | Call functions, check files, manage persistence/authentication | Application |
9
-
10
- Direct dataclass construction is simpler for trusted internal objects. Use
11
- pytypehint when you need strict input validation or a shared inspectable contract.
12
- Compile once and reuse schemas.
13
-
14
- Optional consumers, maintained separately:
15
-
16
- - [pytypehintweb](https://github.com/offerrall/pytypehintweb): browser forms.
17
- - [FuncToWeb](https://github.com/offerrall/FuncToWeb): web interfaces for functions.
18
- - [pytypehintstore](https://github.com/offerrall/pytypehintstore): validated storage.
@@ -1,24 +0,0 @@
1
- # Guarantees
2
-
3
- - Exact validation, with explicit selection for ambiguous unions; no guessing
4
- from contents or implicit coercion. See [build](build.md).
5
- - The first schema error includes its full field/index path in both its message
6
- and `path`, with the reason in `leaf`.
7
- - Defaults are certified at compilation and validated at every missing-key
8
- serving. Reconstructed contents are fresh; factories must honor the author's
9
- [purity requirements](defaults.md).
10
- - `resolve` validates recursively, preserves supplied values by reference and
11
- fills defaults only at the current level. `build` constructs nested instances.
12
- - `decode` does not mutate input, fill defaults or discard unknown keys. It
13
- rebuilds traversed plain containers; actual tuples and subclasses pass through.
14
- - `to_dict()` returns a fresh tree with deterministic ordering. Deterministic
15
- defaults and matching interpreter configuration are required for equal output.
16
- - The core's checks depend on the schema and value. File access and other external
17
- checks belong to the consumer; user factories and constructors remain user code.
18
- - `Signature.build` prepares kwargs and never calls the function.
19
-
20
- `@immutable` additionally validates construction and restricts fields to deeply
21
- immutable values, allowing already validated children to be reused without
22
- traversing them again. See [its contract and limits](immutable.md).
23
-
24
- For accepted definitions and runtime limits, see [restrictions](restrictions.md).
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes