didactic 0.7.2__tar.gz → 0.7.3__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.
- {didactic-0.7.2 → didactic-0.7.3}/PKG-INFO +3 -3
- {didactic-0.7.2 → didactic-0.7.3}/README.md +1 -1
- {didactic-0.7.2 → didactic-0.7.3}/pyproject.toml +2 -2
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/api.py +9 -1
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/codegen/source.py +5 -2
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/lenses/__init__.py +8 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/lenses/_dependent_lens.py +5 -3
- didactic-0.7.3/src/didactic/lenses/_morphisms.py +200 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/theory/_theory.py +34 -5
- {didactic-0.7.2 → didactic-0.7.3}/.gitignore +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/_self_describing.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/axioms/__init__.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/axioms/_axiom_enforcement.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/axioms/_axioms.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/cli/__init__.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/cli/_cli.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/codegen/__init__.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/codegen/_emitter.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/codegen/_json_schema.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/codegen/_write.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/codegen/io.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/fields/__init__.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/fields/_computed.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/fields/_derived.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/fields/_fields.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/fields/_refs.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/fields/_unions.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/fields/_validators.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/lenses/_lens.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/lenses/_testing.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/migrations/__init__.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/migrations/_diff.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/migrations/_fingerprint.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/migrations/_migrations.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/migrations/_synthesis.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/models/__init__.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/models/_config.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/models/_meta.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/models/_model.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/models/_root.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/models/_storage.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/py.typed +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/theory/__init__.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/types/__init__.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/types/_types.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/types/_types_lib.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/types/_typing.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/vcs/__init__.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/vcs/_backref.py +0 -0
- {didactic-0.7.2 → didactic-0.7.3}/src/didactic/vcs/_repo.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: didactic
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.3
|
|
4
4
|
Summary: Pydantic-class API on top of panproto: GATs, lenses, and VCS.
|
|
5
5
|
Project-URL: Homepage, https://github.com/panproto/didactic
|
|
6
6
|
Project-URL: Repository, https://github.com/panproto/didactic
|
|
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
15
15
|
Classifier: Typing :: Typed
|
|
16
16
|
Requires-Python: >=3.14
|
|
17
17
|
Requires-Dist: annotated-types>=0.7
|
|
18
|
-
Requires-Dist: panproto>=0.
|
|
18
|
+
Requires-Dist: panproto>=0.52.0
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
|
|
21
21
|
# didactic
|
|
@@ -39,7 +39,7 @@ contribute submodules under `didactic.<name>`.
|
|
|
39
39
|
|
|
40
40
|
## Install
|
|
41
41
|
|
|
42
|
-
didactic targets Python 3.14 and panproto 0.
|
|
42
|
+
didactic targets Python 3.14 and panproto 0.52+.
|
|
43
43
|
|
|
44
44
|
```sh
|
|
45
45
|
pip install didactic
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "didactic"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.3"
|
|
8
8
|
description = "Pydantic-class API on top of panproto: GATs, lenses, and VCS."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.14"
|
|
@@ -22,7 +22,7 @@ classifiers = [
|
|
|
22
22
|
"Typing :: Typed",
|
|
23
23
|
]
|
|
24
24
|
dependencies = [
|
|
25
|
-
"panproto>=0.
|
|
25
|
+
"panproto>=0.52.0",
|
|
26
26
|
"annotated-types>=0.7",
|
|
27
27
|
]
|
|
28
28
|
|
|
@@ -54,6 +54,11 @@ from didactic.fields._validators import (
|
|
|
54
54
|
from didactic.lenses import _testing as testing
|
|
55
55
|
from didactic.lenses._dependent_lens import DependentLens
|
|
56
56
|
from didactic.lenses._lens import Iso, Lens, Mapping, lens
|
|
57
|
+
from didactic.lenses._morphisms import (
|
|
58
|
+
Correspondence,
|
|
59
|
+
best_correspondence,
|
|
60
|
+
find_correspondences,
|
|
61
|
+
)
|
|
57
62
|
from didactic.migrations._diff import classify_change, diff, is_breaking_change
|
|
58
63
|
from didactic.migrations._migrations import (
|
|
59
64
|
load_registry,
|
|
@@ -69,7 +74,7 @@ from didactic.types import _types_lib as types
|
|
|
69
74
|
from didactic.vcs._backref import ModelPool, resolve_backrefs
|
|
70
75
|
from didactic.vcs._repo import Repository
|
|
71
76
|
|
|
72
|
-
__version__ = "0.7.
|
|
77
|
+
__version__ = "0.7.3"
|
|
73
78
|
|
|
74
79
|
#: Conventional namespace for lens utilities (`dx.lens.identity(...)`,
|
|
75
80
|
#: `dx.lens.Lens`, etc.). The ``lens`` name doubles as a decorator
|
|
@@ -81,6 +86,7 @@ __all__ = [
|
|
|
81
86
|
"Axiom",
|
|
82
87
|
"Backref",
|
|
83
88
|
"BaseModel",
|
|
89
|
+
"Correspondence",
|
|
84
90
|
"DependentLens",
|
|
85
91
|
"Embed",
|
|
86
92
|
"ExtraPolicy",
|
|
@@ -103,6 +109,7 @@ __all__ = [
|
|
|
103
109
|
"ValidationErrorEntry",
|
|
104
110
|
"__version__",
|
|
105
111
|
"axiom",
|
|
112
|
+
"best_correspondence",
|
|
106
113
|
"classify_change",
|
|
107
114
|
"codegen",
|
|
108
115
|
"computed",
|
|
@@ -110,6 +117,7 @@ __all__ = [
|
|
|
110
117
|
"diff",
|
|
111
118
|
"embed_schema_uri",
|
|
112
119
|
"field",
|
|
120
|
+
"find_correspondences",
|
|
113
121
|
"is_breaking_change",
|
|
114
122
|
"lens",
|
|
115
123
|
"load_registry",
|
|
@@ -4,8 +4,11 @@ For every tree-sitter grammar panproto bundles, didactic can:
|
|
|
4
4
|
|
|
5
5
|
- **De-novo emit** a [Model][didactic.api.Model] class as fresh source via
|
|
6
6
|
[emit_pretty][didactic.codegen.source.emit_pretty]. Walks the
|
|
7
|
-
grammar's production rules;
|
|
8
|
-
grammar
|
|
7
|
+
grammar's production rules; spacing and indentation derive from
|
|
8
|
+
grammar-classified token roles. Emit round-trips are checked
|
|
9
|
+
against each grammar's upstream corpus in panproto's test suite.
|
|
10
|
+
Use [available_targets][didactic.codegen.source.available_targets]
|
|
11
|
+
to enumerate what the running build supports.
|
|
9
12
|
- **Edit-pipeline emit**: parse real source, transform the schema,
|
|
10
13
|
re-emit the bytes. Uses [emit][didactic.codegen.source.emit].
|
|
11
14
|
- **Parse** source bytes into a panproto Schema for inspection.
|
|
@@ -4,12 +4,20 @@ from didactic.lenses import _testing as testing
|
|
|
4
4
|
from didactic.lenses._dependent_lens import DependentLens
|
|
5
5
|
from didactic.lenses._lens import Iso, Lens, Mapping, identity
|
|
6
6
|
from didactic.lenses._lens import lens as lens
|
|
7
|
+
from didactic.lenses._morphisms import (
|
|
8
|
+
Correspondence,
|
|
9
|
+
best_correspondence,
|
|
10
|
+
find_correspondences,
|
|
11
|
+
)
|
|
7
12
|
|
|
8
13
|
__all__ = [
|
|
14
|
+
"Correspondence",
|
|
9
15
|
"DependentLens",
|
|
10
16
|
"Iso",
|
|
11
17
|
"Lens",
|
|
12
18
|
"Mapping",
|
|
19
|
+
"best_correspondence",
|
|
20
|
+
"find_correspondences",
|
|
13
21
|
"identity",
|
|
14
22
|
"lens",
|
|
15
23
|
"testing",
|
|
@@ -146,7 +146,7 @@ class DependentLens:
|
|
|
146
146
|
src_schema: panproto.Schema,
|
|
147
147
|
tgt_schema: panproto.Schema,
|
|
148
148
|
protocol: panproto.Protocol,
|
|
149
|
-
hints:
|
|
149
|
+
hints: dict[str, str],
|
|
150
150
|
*,
|
|
151
151
|
stringency: str | None = None,
|
|
152
152
|
) -> DependentLens:
|
|
@@ -161,8 +161,10 @@ class DependentLens:
|
|
|
161
161
|
protocol
|
|
162
162
|
The panproto protocol both schemas conform to.
|
|
163
163
|
hints
|
|
164
|
-
Vertex-correspondence hints
|
|
165
|
-
|
|
164
|
+
Vertex-correspondence hints mapping source-schema vertex
|
|
165
|
+
IDs to target-schema vertex IDs. A discovered
|
|
166
|
+
[Correspondence][didactic.api.Correspondence] supplies this
|
|
167
|
+
shape via its ``vertex_map``.
|
|
166
168
|
stringency
|
|
167
169
|
Optional stringency hint. ``None`` uses panproto's default.
|
|
168
170
|
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""Vertex-correspondence discovery via panproto's hom search.
|
|
2
|
+
|
|
3
|
+
Given two panproto Schemas, panproto can enumerate the structure-
|
|
4
|
+
preserving maps (schema morphisms) between them and score each one.
|
|
5
|
+
didactic wraps that search as
|
|
6
|
+
[find_correspondences][didactic.api.find_correspondences] and
|
|
7
|
+
[best_correspondence][didactic.api.best_correspondence], returning
|
|
8
|
+
plain [Correspondence][didactic.api.Correspondence] records.
|
|
9
|
+
|
|
10
|
+
The discovered ``vertex_map`` has exactly the shape that
|
|
11
|
+
[DependentLens.auto_generate_with_hints][didactic.api.DependentLens.auto_generate_with_hints]
|
|
12
|
+
takes as ``hints``, so the two compose into a discover-then-derive
|
|
13
|
+
pipeline: search for the best correspondence, then derive a chain
|
|
14
|
+
that respects it.
|
|
15
|
+
|
|
16
|
+
Examples
|
|
17
|
+
--------
|
|
18
|
+
>>> import didactic.api as dx
|
|
19
|
+
>>> import panproto
|
|
20
|
+
>>>
|
|
21
|
+
>>> proto = panproto.get_builtin_protocol("openapi")
|
|
22
|
+
>>> # ... build src_schema and tgt_schema via proto.schema() ...
|
|
23
|
+
>>>
|
|
24
|
+
>>> best = dx.best_correspondence(src_schema, tgt_schema) # doctest: +SKIP
|
|
25
|
+
>>> best.vertex_map # doctest: +SKIP
|
|
26
|
+
{'post:body.text': 'post:body.content', ...}
|
|
27
|
+
>>> chain = dx.DependentLens.auto_generate_with_hints( # doctest: +SKIP
|
|
28
|
+
... src_schema,
|
|
29
|
+
... tgt_schema,
|
|
30
|
+
... proto,
|
|
31
|
+
... best.vertex_map,
|
|
32
|
+
... )
|
|
33
|
+
|
|
34
|
+
See Also
|
|
35
|
+
--------
|
|
36
|
+
didactic.lenses._dependent_lens : the hint-consuming chain derivation.
|
|
37
|
+
panproto.find_morphisms : the runtime search.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
from __future__ import annotations
|
|
41
|
+
|
|
42
|
+
from dataclasses import dataclass
|
|
43
|
+
from typing import TYPE_CHECKING
|
|
44
|
+
|
|
45
|
+
if TYPE_CHECKING:
|
|
46
|
+
import panproto
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass(frozen=True, slots=True)
|
|
50
|
+
class Correspondence:
|
|
51
|
+
"""One discovered schema morphism, scored.
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
vertex_map
|
|
56
|
+
Mapping from source-schema vertex IDs to target-schema vertex
|
|
57
|
+
IDs. Feed directly as the ``hints`` argument of
|
|
58
|
+
[DependentLens.auto_generate_with_hints][didactic.api.DependentLens.auto_generate_with_hints].
|
|
59
|
+
quality
|
|
60
|
+
Alignment quality in ``[0.0, 1.0]``. Higher is better.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
vertex_map: dict[str, str]
|
|
64
|
+
quality: float
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def find_correspondences(
|
|
68
|
+
src_schema: panproto.Schema,
|
|
69
|
+
tgt_schema: panproto.Schema,
|
|
70
|
+
*,
|
|
71
|
+
anchors: dict[str, str] | None = None,
|
|
72
|
+
monic: bool = False,
|
|
73
|
+
epic: bool = False,
|
|
74
|
+
iso: bool = False,
|
|
75
|
+
max_results: int = 0,
|
|
76
|
+
relax_edge_name_pruning: bool = False,
|
|
77
|
+
) -> list[Correspondence]:
|
|
78
|
+
"""Enumerate scored vertex correspondences between two schemas.
|
|
79
|
+
|
|
80
|
+
Parameters
|
|
81
|
+
----------
|
|
82
|
+
src_schema
|
|
83
|
+
Source schema.
|
|
84
|
+
tgt_schema
|
|
85
|
+
Target schema.
|
|
86
|
+
anchors
|
|
87
|
+
Vertex pairs (source ID to target ID) the search must respect.
|
|
88
|
+
Use to pin known correspondences and let the search fill in
|
|
89
|
+
the rest.
|
|
90
|
+
monic
|
|
91
|
+
Require the morphism to be injective on vertices (no two
|
|
92
|
+
source vertices map to the same target vertex).
|
|
93
|
+
epic
|
|
94
|
+
Require the morphism to be surjective on vertices (every
|
|
95
|
+
target vertex is hit).
|
|
96
|
+
iso
|
|
97
|
+
Require a bijection. Implies ``monic`` and ``epic``.
|
|
98
|
+
max_results
|
|
99
|
+
Upper bound on the number of morphisms returned. ``0`` means
|
|
100
|
+
unbounded.
|
|
101
|
+
relax_edge_name_pruning
|
|
102
|
+
Keep kind-compatible candidate targets that share no outgoing
|
|
103
|
+
edge name with the source vertex. By default the search prunes
|
|
104
|
+
such candidates for object vertices with large candidate
|
|
105
|
+
domains, which can discard a correct pairing when every child
|
|
106
|
+
was renamed. Naturality is still enforced.
|
|
107
|
+
|
|
108
|
+
Returns
|
|
109
|
+
-------
|
|
110
|
+
list of Correspondence
|
|
111
|
+
Discovered correspondences. Empty when no structure-preserving
|
|
112
|
+
map exists under the given constraints.
|
|
113
|
+
|
|
114
|
+
Notes
|
|
115
|
+
-----
|
|
116
|
+
The schemas didactic builds from Model classes are single-vertex
|
|
117
|
+
(the structure lives in the Theory), so searching between two
|
|
118
|
+
Models degenerates to the root pairing. The search is informative
|
|
119
|
+
on multi-vertex schemas: protocol schemas built by hand and
|
|
120
|
+
schemas recovered by [didactic.codegen.source.parse][].
|
|
121
|
+
"""
|
|
122
|
+
import panproto # noqa: PLC0415
|
|
123
|
+
|
|
124
|
+
found = panproto.find_morphisms(
|
|
125
|
+
src_schema,
|
|
126
|
+
tgt_schema,
|
|
127
|
+
anchors=anchors,
|
|
128
|
+
monic=monic,
|
|
129
|
+
epic=epic,
|
|
130
|
+
iso=iso,
|
|
131
|
+
max_results=max_results,
|
|
132
|
+
relax_edge_name_pruning=relax_edge_name_pruning,
|
|
133
|
+
)
|
|
134
|
+
return [
|
|
135
|
+
Correspondence(vertex_map=m.vertex_map, quality=float(m.quality)) for m in found
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def best_correspondence(
|
|
140
|
+
src_schema: panproto.Schema,
|
|
141
|
+
tgt_schema: panproto.Schema,
|
|
142
|
+
*,
|
|
143
|
+
anchors: dict[str, str] | None = None,
|
|
144
|
+
monic: bool = False,
|
|
145
|
+
epic: bool = False,
|
|
146
|
+
iso: bool = False,
|
|
147
|
+
relax_edge_name_pruning: bool = False,
|
|
148
|
+
) -> Correspondence | None:
|
|
149
|
+
"""Return the highest-quality correspondence, or ``None``.
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
src_schema
|
|
154
|
+
Source schema.
|
|
155
|
+
tgt_schema
|
|
156
|
+
Target schema.
|
|
157
|
+
anchors
|
|
158
|
+
Vertex pairs (source ID to target ID) the search must respect.
|
|
159
|
+
monic
|
|
160
|
+
Require injectivity on vertices.
|
|
161
|
+
epic
|
|
162
|
+
Require surjectivity on vertices.
|
|
163
|
+
iso
|
|
164
|
+
Require a bijection. Implies ``monic`` and ``epic``.
|
|
165
|
+
relax_edge_name_pruning
|
|
166
|
+
Keep kind-compatible candidate targets that share no outgoing
|
|
167
|
+
edge name with the source vertex. See
|
|
168
|
+
[find_correspondences][didactic.api.find_correspondences].
|
|
169
|
+
|
|
170
|
+
Returns
|
|
171
|
+
-------
|
|
172
|
+
Correspondence or None
|
|
173
|
+
The best-scoring correspondence, or ``None`` when no
|
|
174
|
+
structure-preserving map exists under the given constraints.
|
|
175
|
+
|
|
176
|
+
See Also
|
|
177
|
+
--------
|
|
178
|
+
find_correspondences : the full enumeration.
|
|
179
|
+
"""
|
|
180
|
+
import panproto # noqa: PLC0415
|
|
181
|
+
|
|
182
|
+
found = panproto.find_best_morphism(
|
|
183
|
+
src_schema,
|
|
184
|
+
tgt_schema,
|
|
185
|
+
anchors=anchors,
|
|
186
|
+
monic=monic,
|
|
187
|
+
epic=epic,
|
|
188
|
+
iso=iso,
|
|
189
|
+
relax_edge_name_pruning=relax_edge_name_pruning,
|
|
190
|
+
)
|
|
191
|
+
if found is None:
|
|
192
|
+
return None
|
|
193
|
+
return Correspondence(vertex_map=found.vertex_map, quality=float(found.quality))
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
__all__ = [
|
|
197
|
+
"Correspondence",
|
|
198
|
+
"best_correspondence",
|
|
199
|
+
"find_correspondences",
|
|
200
|
+
]
|
|
@@ -34,6 +34,8 @@ from __future__ import annotations
|
|
|
34
34
|
from typing import TYPE_CHECKING, TypedDict, cast
|
|
35
35
|
|
|
36
36
|
if TYPE_CHECKING:
|
|
37
|
+
from collections.abc import Mapping
|
|
38
|
+
|
|
37
39
|
import panproto
|
|
38
40
|
|
|
39
41
|
from didactic.fields._fields import FieldSpec
|
|
@@ -58,6 +60,31 @@ class TheorySpec(TypedDict):
|
|
|
58
60
|
policies: list[dict[str, JsonValue]]
|
|
59
61
|
|
|
60
62
|
|
|
63
|
+
def _spec_payload(spec: TheorySpec) -> Mapping[str, JsonValue]:
|
|
64
|
+
"""Narrow a ``TheorySpec`` to the mapping shape ``create_theory`` takes.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
spec
|
|
69
|
+
A spec dict from ``build_theory_spec``.
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
Mapping
|
|
74
|
+
The same dict, typed as ``Mapping[str, JsonValue]``.
|
|
75
|
+
|
|
76
|
+
Notes
|
|
77
|
+
-----
|
|
78
|
+
The typing spec makes a ``TypedDict`` assignable to
|
|
79
|
+
``Mapping[str, object]`` and to no mapping with a narrower value
|
|
80
|
+
type, so handing a ``TheorySpec`` to ``panproto.create_theory``
|
|
81
|
+
(whose parameter is ``Mapping[str, JsonValue]``) needs a cast at
|
|
82
|
+
the boundary. Every ``TheorySpec`` field type is a ``JsonValue``,
|
|
83
|
+
so the cast is sound.
|
|
84
|
+
"""
|
|
85
|
+
return cast("Mapping[str, JsonValue]", spec)
|
|
86
|
+
|
|
87
|
+
|
|
61
88
|
# ---------------------------------------------------------------------------
|
|
62
89
|
# Spec construction (no panproto runtime required)
|
|
63
90
|
# ---------------------------------------------------------------------------
|
|
@@ -347,7 +374,7 @@ def build_theory(cls: type) -> panproto.Theory:
|
|
|
347
374
|
if len(parents) <= 1:
|
|
348
375
|
# single (or no) Model inheritance: the flat spec is correct
|
|
349
376
|
spec = build_theory_spec(cls)
|
|
350
|
-
return panproto.create_theory(spec)
|
|
377
|
+
return panproto.create_theory(_spec_payload(spec))
|
|
351
378
|
|
|
352
379
|
# multiple Model inheritance: compute the colimit of the parent
|
|
353
380
|
# theories over their lowest common ancestor in the Model lineage
|
|
@@ -432,13 +459,15 @@ def _build_colimit_theory(cls: type, parents: list[type]) -> panproto.Theory:
|
|
|
432
459
|
"""
|
|
433
460
|
import panproto # noqa: PLC0415
|
|
434
461
|
|
|
435
|
-
accumulator = panproto.create_theory(build_theory_spec(parents[0]))
|
|
462
|
+
accumulator = panproto.create_theory(_spec_payload(build_theory_spec(parents[0])))
|
|
436
463
|
accumulator_cls: type = parents[0]
|
|
437
464
|
|
|
438
465
|
for parent in parents[1:]:
|
|
439
466
|
ancestor = _lowest_common_model_ancestor([accumulator_cls, parent])
|
|
440
|
-
ancestor_theory = panproto.create_theory(
|
|
441
|
-
|
|
467
|
+
ancestor_theory = panproto.create_theory(
|
|
468
|
+
_spec_payload(build_theory_spec(ancestor))
|
|
469
|
+
)
|
|
470
|
+
next_theory = panproto.create_theory(_spec_payload(build_theory_spec(parent)))
|
|
442
471
|
accumulator = panproto.colimit_theories(
|
|
443
472
|
accumulator, next_theory, ancestor_theory
|
|
444
473
|
)
|
|
@@ -447,7 +476,7 @@ def _build_colimit_theory(cls: type, parents: list[type]) -> panproto.Theory:
|
|
|
447
476
|
# finally fold in any cls-only fields by colimiting against the
|
|
448
477
|
# immediate spec of cls; the shared ancestor is the accumulated
|
|
449
478
|
# theory we just built
|
|
450
|
-
cls_theory = panproto.create_theory(build_theory_spec(cls))
|
|
479
|
+
cls_theory = panproto.create_theory(_spec_payload(build_theory_spec(cls)))
|
|
451
480
|
return panproto.colimit_theories(accumulator, cls_theory, accumulator)
|
|
452
481
|
|
|
453
482
|
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|