bigraph-schema 1.0.0__py3-none-any.whl
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.
- bigraph_schema/__init__.py +112 -0
- bigraph_schema/core.py +759 -0
- bigraph_schema/edge.py +138 -0
- bigraph_schema/methods/__init__.py +12 -0
- bigraph_schema/methods/apply.py +276 -0
- bigraph_schema/methods/check.py +213 -0
- bigraph_schema/methods/default.py +204 -0
- bigraph_schema/methods/generalize.py +309 -0
- bigraph_schema/methods/handle_parameters.py +182 -0
- bigraph_schema/methods/infer.py +217 -0
- bigraph_schema/methods/jump.py +432 -0
- bigraph_schema/methods/merge.py +405 -0
- bigraph_schema/methods/realize.py +527 -0
- bigraph_schema/methods/resolve.py +692 -0
- bigraph_schema/methods/serialize.py +491 -0
- bigraph_schema/methods/validate.py +249 -0
- bigraph_schema/package/__init__.py +1 -0
- bigraph_schema/package/discover.py +122 -0
- bigraph_schema/parse.py +183 -0
- bigraph_schema/protocols.py +57 -0
- bigraph_schema/schema.py +370 -0
- bigraph_schema/units.py +133 -0
- bigraph_schema-1.0.0.dist-info/METADATA +66 -0
- bigraph_schema-1.0.0.dist-info/RECORD +28 -0
- bigraph_schema-1.0.0.dist-info/WHEEL +5 -0
- bigraph_schema-1.0.0.dist-info/licenses/AUTHORS.md +6 -0
- bigraph_schema-1.0.0.dist-info/licenses/LICENSE +201 -0
- bigraph_schema-1.0.0.dist-info/top_level.txt +1 -0
bigraph_schema/edge.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""
|
|
2
|
+
====
|
|
3
|
+
Edge
|
|
4
|
+
====
|
|
5
|
+
|
|
6
|
+
Base class for all edges in the bigraph schema.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
def default_wires(schema):
|
|
10
|
+
"""
|
|
11
|
+
Create default wiring for a schema by connecting each port to a store of the same name.
|
|
12
|
+
"""
|
|
13
|
+
return {
|
|
14
|
+
key: [key]
|
|
15
|
+
for key in schema}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Edge:
|
|
19
|
+
"""
|
|
20
|
+
Base class for all computational edges in the bigraph schema.
|
|
21
|
+
|
|
22
|
+
Edges define the interface between simulation processes and the global state,
|
|
23
|
+
specifying the structure of input and output ports using bigraph types
|
|
24
|
+
(e.g., 'float', 'map[float]', 'list[integer]', etc.).
|
|
25
|
+
|
|
26
|
+
Upon instantiation, each edge registers its port types with the core.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
config_schema = {}
|
|
30
|
+
|
|
31
|
+
def __init__(self, config=None, core=None):
|
|
32
|
+
"""
|
|
33
|
+
Initialize the edge with a config and simulation core.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
config (dict): Optional configuration dictionary. Defaults to empty dict.
|
|
37
|
+
core: The core simulation engine that manages this edge and its types.
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
Exception: If `core` is not provided.
|
|
41
|
+
"""
|
|
42
|
+
if core is None:
|
|
43
|
+
raise Exception('must provide a core')
|
|
44
|
+
self.core = core
|
|
45
|
+
|
|
46
|
+
if config is None:
|
|
47
|
+
config = {}
|
|
48
|
+
|
|
49
|
+
self._config = self.core.fill(self.config_schema, config)
|
|
50
|
+
self._composition = 'edge'
|
|
51
|
+
self._state = {}
|
|
52
|
+
|
|
53
|
+
self.initialize(
|
|
54
|
+
self._config)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def config(self):
|
|
59
|
+
return self._config
|
|
60
|
+
|
|
61
|
+
@config.setter
|
|
62
|
+
def config(self, config):
|
|
63
|
+
self._config = config
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def composition(self):
|
|
67
|
+
return self._composition
|
|
68
|
+
|
|
69
|
+
@composition.setter
|
|
70
|
+
def composition(self, composition):
|
|
71
|
+
self._composition = composition
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def state(self):
|
|
75
|
+
return self._state
|
|
76
|
+
|
|
77
|
+
@state.setter
|
|
78
|
+
def state(self, state):
|
|
79
|
+
self._state = state
|
|
80
|
+
|
|
81
|
+
def initialize(self, config):
|
|
82
|
+
"""Optional hook for subclass-specific initialization."""
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
def initial_state(self):
|
|
86
|
+
"""Return initial state values, if applicable."""
|
|
87
|
+
return {}
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def generate_state(config=None):
|
|
91
|
+
"""Generate static initial state for user configuration or inspection."""
|
|
92
|
+
return {}
|
|
93
|
+
|
|
94
|
+
def inputs(self):
|
|
95
|
+
"""
|
|
96
|
+
Return a dictionary mapping input port names to bigraph types.
|
|
97
|
+
|
|
98
|
+
Example:
|
|
99
|
+
{'glucose': 'float', 'biomass': 'map[float]'}
|
|
100
|
+
"""
|
|
101
|
+
return {}
|
|
102
|
+
|
|
103
|
+
def outputs(self):
|
|
104
|
+
"""
|
|
105
|
+
Return a dictionary mapping output port names to bigraph types.
|
|
106
|
+
|
|
107
|
+
Example:
|
|
108
|
+
{'growth_rate': 'float'}
|
|
109
|
+
"""
|
|
110
|
+
return {}
|
|
111
|
+
|
|
112
|
+
def default_config(self):
|
|
113
|
+
""" get the default of the config_schema for this edge """
|
|
114
|
+
return self.core.default(
|
|
115
|
+
self.config_schema)
|
|
116
|
+
|
|
117
|
+
def default_inputs(self):
|
|
118
|
+
"""Generate default wire paths for inputs: {port: [port]}"""
|
|
119
|
+
return default_wires(self.inputs())
|
|
120
|
+
|
|
121
|
+
def default_outputs(self):
|
|
122
|
+
"""Generate default wire paths for outputs: {port: [port]}"""
|
|
123
|
+
return default_wires(self.outputs())
|
|
124
|
+
|
|
125
|
+
def interface(self):
|
|
126
|
+
"""
|
|
127
|
+
Return combined interface schema as a dict:
|
|
128
|
+
{
|
|
129
|
+
'inputs': {port: type, ...},
|
|
130
|
+
'outputs': {port: type, ...}
|
|
131
|
+
}
|
|
132
|
+
"""
|
|
133
|
+
return {
|
|
134
|
+
'inputs': self.inputs(),
|
|
135
|
+
'outputs': self.outputs()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from bigraph_schema.methods.infer import infer, set_default
|
|
2
|
+
from bigraph_schema.methods.default import default, default_link
|
|
3
|
+
from bigraph_schema.methods.resolve import resolve
|
|
4
|
+
from bigraph_schema.methods.generalize import generalize
|
|
5
|
+
from bigraph_schema.methods.check import check
|
|
6
|
+
from bigraph_schema.methods.validate import validate
|
|
7
|
+
from bigraph_schema.methods.serialize import serialize, render, wrap_default
|
|
8
|
+
from bigraph_schema.methods.realize import realize, realize_link, load_protocol, load_local_protocol
|
|
9
|
+
from bigraph_schema.methods.merge import merge, merge_update
|
|
10
|
+
from bigraph_schema.methods.jump import jump, traverse
|
|
11
|
+
from bigraph_schema.methods.handle_parameters import schema_keys, align_parameters, reify_schema, handle_parameters
|
|
12
|
+
from bigraph_schema.methods.apply import apply
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
from plum import dispatch
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from bigraph_schema.schema import (
|
|
5
|
+
Node,
|
|
6
|
+
Atom,
|
|
7
|
+
Union,
|
|
8
|
+
Tuple,
|
|
9
|
+
Boolean,
|
|
10
|
+
Or,
|
|
11
|
+
And,
|
|
12
|
+
Xor,
|
|
13
|
+
Number,
|
|
14
|
+
Integer,
|
|
15
|
+
Float,
|
|
16
|
+
Delta,
|
|
17
|
+
Nonnegative,
|
|
18
|
+
String,
|
|
19
|
+
Enum,
|
|
20
|
+
Wrap,
|
|
21
|
+
Maybe,
|
|
22
|
+
Overwrite,
|
|
23
|
+
List,
|
|
24
|
+
Map,
|
|
25
|
+
Tree,
|
|
26
|
+
Array,
|
|
27
|
+
Key,
|
|
28
|
+
Path,
|
|
29
|
+
Wires,
|
|
30
|
+
Schema,
|
|
31
|
+
Link,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dispatch
|
|
36
|
+
def apply(schema: Maybe, state, update, path):
|
|
37
|
+
if state is None:
|
|
38
|
+
if update is not None:
|
|
39
|
+
return update, []
|
|
40
|
+
elif update is None:
|
|
41
|
+
return state, []
|
|
42
|
+
else:
|
|
43
|
+
return apply(schema._value, state, update, path)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dispatch
|
|
47
|
+
def apply(schema: Wrap, state, update, path):
|
|
48
|
+
return apply(schema._value, state, update, path)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dispatch
|
|
52
|
+
def apply(schema: Overwrite, state, update, path):
|
|
53
|
+
return update, []
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dispatch
|
|
57
|
+
def apply(schema: Union, state, update, path):
|
|
58
|
+
found = None
|
|
59
|
+
for option in schema._options:
|
|
60
|
+
if check(option, state) and check(option, update):
|
|
61
|
+
found = option
|
|
62
|
+
break
|
|
63
|
+
|
|
64
|
+
if found is not None:
|
|
65
|
+
return apply(found, state, update, path)
|
|
66
|
+
else:
|
|
67
|
+
return update, []
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dispatch
|
|
71
|
+
def apply(schema: Tuple, state, update, path):
|
|
72
|
+
merges = []
|
|
73
|
+
result = []
|
|
74
|
+
for index, value in enumerate(schema._values):
|
|
75
|
+
if index < len(state):
|
|
76
|
+
if update and index < len(update):
|
|
77
|
+
substate, submerges = apply(
|
|
78
|
+
value,
|
|
79
|
+
state[index],
|
|
80
|
+
update[index],
|
|
81
|
+
path+(index,))
|
|
82
|
+
result.append(substate)
|
|
83
|
+
merges += submerges
|
|
84
|
+
else:
|
|
85
|
+
result.append(state[index])
|
|
86
|
+
elif index < len(update):
|
|
87
|
+
result.append(update[index])
|
|
88
|
+
else:
|
|
89
|
+
result.append(default(value))
|
|
90
|
+
|
|
91
|
+
return tuple(result), merges
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@dispatch
|
|
95
|
+
def apply(schema: List, state, update, path):
|
|
96
|
+
merges = []
|
|
97
|
+
if isinstance(update, dict):
|
|
98
|
+
if '_remove' in update:
|
|
99
|
+
indexes = update['_remove']
|
|
100
|
+
if indexes == 'all':
|
|
101
|
+
result = []
|
|
102
|
+
else:
|
|
103
|
+
result = [
|
|
104
|
+
item
|
|
105
|
+
for index, item in enumerate(state)
|
|
106
|
+
if index not in indexes]
|
|
107
|
+
if '_add' in update:
|
|
108
|
+
result += update['_add']
|
|
109
|
+
else:
|
|
110
|
+
result = state + update
|
|
111
|
+
|
|
112
|
+
return result, merges
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@dispatch
|
|
116
|
+
def apply(schema: Map, state, update, path):
|
|
117
|
+
result = state.copy()
|
|
118
|
+
merges = []
|
|
119
|
+
|
|
120
|
+
if update is None:
|
|
121
|
+
return state, merges
|
|
122
|
+
|
|
123
|
+
if '_add' in update:
|
|
124
|
+
add_update = update['_add']
|
|
125
|
+
if isinstance(add_update, list):
|
|
126
|
+
for add_key, add_value in update['_add']:
|
|
127
|
+
result[add_key] = add_value
|
|
128
|
+
elif isinstance(add_update, dict):
|
|
129
|
+
for add_key, add_value in update['_add'].items():
|
|
130
|
+
result[add_key] = add_value
|
|
131
|
+
|
|
132
|
+
for key, value in result.items():
|
|
133
|
+
if key in update:
|
|
134
|
+
result[key], submerges = apply(
|
|
135
|
+
schema._value,
|
|
136
|
+
value,
|
|
137
|
+
update[key],
|
|
138
|
+
path+(key,))
|
|
139
|
+
merges += submerges
|
|
140
|
+
|
|
141
|
+
if '_remove' in update:
|
|
142
|
+
for remove_key in update['_remove']:
|
|
143
|
+
if remove_key in result:
|
|
144
|
+
del result[remove_key]
|
|
145
|
+
|
|
146
|
+
return result, merges
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@dispatch
|
|
150
|
+
def apply(schema: Tree, state, update, path):
|
|
151
|
+
if check(schema._leaf, state):
|
|
152
|
+
return apply(schema._leaf, state, update, path)
|
|
153
|
+
|
|
154
|
+
result = state.copy()
|
|
155
|
+
if '_remove' in update:
|
|
156
|
+
for remove_key in update['_remove']:
|
|
157
|
+
del result[remove_key]
|
|
158
|
+
|
|
159
|
+
if '_add' in update:
|
|
160
|
+
for add_key, add_value in update['_add']:
|
|
161
|
+
result[add_key] = add_value
|
|
162
|
+
|
|
163
|
+
for key, value in result:
|
|
164
|
+
if key in update:
|
|
165
|
+
result[key], submerges = apply(
|
|
166
|
+
schema,
|
|
167
|
+
value,
|
|
168
|
+
update[key],
|
|
169
|
+
path+(key,))
|
|
170
|
+
merges += submerges
|
|
171
|
+
|
|
172
|
+
return result, merges
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@dispatch
|
|
176
|
+
def apply(schema: Atom, state, update, path):
|
|
177
|
+
if update is None:
|
|
178
|
+
return state, []
|
|
179
|
+
if state is None:
|
|
180
|
+
return update, []
|
|
181
|
+
|
|
182
|
+
return (state + update), []
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@dispatch
|
|
186
|
+
def apply(schema: String, state, update, path):
|
|
187
|
+
return update, []
|
|
188
|
+
|
|
189
|
+
@dispatch
|
|
190
|
+
def apply(schema: Boolean, state, update, path):
|
|
191
|
+
return update, []
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@dispatch
|
|
195
|
+
def apply(schema: Or, state, update, path):
|
|
196
|
+
return state or update, []
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@dispatch
|
|
200
|
+
def apply(schema: And, state, update, path):
|
|
201
|
+
return state and update, []
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@dispatch
|
|
205
|
+
def apply(schema: Xor, state, update, path):
|
|
206
|
+
return (state or update) and not (state and update), []
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@dispatch
|
|
210
|
+
def apply(schema: Array, state, update, path):
|
|
211
|
+
index = tuple([
|
|
212
|
+
slice(0, dimension)
|
|
213
|
+
for dimension in update.shape])
|
|
214
|
+
state[index] += update
|
|
215
|
+
return state, []
|
|
216
|
+
|
|
217
|
+
@dispatch
|
|
218
|
+
def apply(schema: dict, state: np.ndarray, update, path):
|
|
219
|
+
merges = []
|
|
220
|
+
for key, subschema in schema.items():
|
|
221
|
+
if key in update:
|
|
222
|
+
substate = update[key]
|
|
223
|
+
state[key], submerges = apply(subschema, state[key], substate, path+(key,))
|
|
224
|
+
merges += submerges
|
|
225
|
+
return state, merges
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
@dispatch
|
|
229
|
+
def apply(schema: dict, state, update, path):
|
|
230
|
+
if update is None:
|
|
231
|
+
return state, []
|
|
232
|
+
if state is None:
|
|
233
|
+
return update, []
|
|
234
|
+
|
|
235
|
+
merges = []
|
|
236
|
+
result = {}
|
|
237
|
+
|
|
238
|
+
for key, subschema in schema.items():
|
|
239
|
+
if key in ('_inherit',):
|
|
240
|
+
continue
|
|
241
|
+
|
|
242
|
+
if key not in state:
|
|
243
|
+
continue
|
|
244
|
+
|
|
245
|
+
result[key], submerges = apply(
|
|
246
|
+
subschema,
|
|
247
|
+
state.get(key),
|
|
248
|
+
update.get(key),
|
|
249
|
+
path+(key,))
|
|
250
|
+
merges += submerges
|
|
251
|
+
|
|
252
|
+
for key in state.keys():
|
|
253
|
+
if not key in result and not key in schema:
|
|
254
|
+
result[key] = state[key]
|
|
255
|
+
|
|
256
|
+
return result, merges
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
@dispatch
|
|
260
|
+
def apply(schema: Node, state, update, path):
|
|
261
|
+
merges = []
|
|
262
|
+
if isinstance(state, dict) and isinstance(update, dict):
|
|
263
|
+
result = {}
|
|
264
|
+
for key in schema.__dataclass_fields__:
|
|
265
|
+
subschema = getattr(schema, key)
|
|
266
|
+
result[key], submerges = apply(
|
|
267
|
+
subschema,
|
|
268
|
+
state.get(key),
|
|
269
|
+
update.get(key),
|
|
270
|
+
path+(key,))
|
|
271
|
+
merges += submerges
|
|
272
|
+
|
|
273
|
+
else:
|
|
274
|
+
result = update
|
|
275
|
+
|
|
276
|
+
return result, merges
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
from plum import dispatch
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
from bigraph_schema.schema import (
|
|
5
|
+
Node,
|
|
6
|
+
Atom,
|
|
7
|
+
Empty,
|
|
8
|
+
Union,
|
|
9
|
+
Tuple,
|
|
10
|
+
Boolean,
|
|
11
|
+
Number,
|
|
12
|
+
Integer,
|
|
13
|
+
Float,
|
|
14
|
+
Delta,
|
|
15
|
+
Nonnegative,
|
|
16
|
+
String,
|
|
17
|
+
Enum,
|
|
18
|
+
Wrap,
|
|
19
|
+
Maybe,
|
|
20
|
+
Overwrite,
|
|
21
|
+
List,
|
|
22
|
+
Map,
|
|
23
|
+
Tree,
|
|
24
|
+
Array,
|
|
25
|
+
Key,
|
|
26
|
+
Path,
|
|
27
|
+
Wires,
|
|
28
|
+
Schema,
|
|
29
|
+
Link,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dispatch
|
|
34
|
+
def check(schema: Empty, state):
|
|
35
|
+
return state is None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dispatch
|
|
39
|
+
def check(schema: Maybe, state):
|
|
40
|
+
if state is None:
|
|
41
|
+
return True
|
|
42
|
+
else:
|
|
43
|
+
return check(schema._value, state)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dispatch
|
|
47
|
+
def check(schema: Wrap, state):
|
|
48
|
+
return check(schema._value, state)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dispatch
|
|
52
|
+
def check(schema: Union, state):
|
|
53
|
+
for option in schema._options:
|
|
54
|
+
if check(option, state):
|
|
55
|
+
return True
|
|
56
|
+
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dispatch
|
|
61
|
+
def check(schema: Tuple, state):
|
|
62
|
+
if not isinstance(state, (list, tuple)):
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
elif len(schema._values) == len(state):
|
|
66
|
+
return all([
|
|
67
|
+
check(subschema, value)
|
|
68
|
+
for subschema, value in zip(schema._values, state)])
|
|
69
|
+
|
|
70
|
+
else:
|
|
71
|
+
return False
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dispatch
|
|
75
|
+
def check(schema: Boolean, state):
|
|
76
|
+
return isinstance(state, bool)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dispatch
|
|
80
|
+
def check(schema: Integer, state):
|
|
81
|
+
return isinstance(state, int)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dispatch
|
|
85
|
+
def check(schema: Float, state):
|
|
86
|
+
return isinstance(state, float)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@dispatch
|
|
90
|
+
def check(schema: Nonnegative, state):
|
|
91
|
+
return state >= 0
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@dispatch
|
|
95
|
+
def check(schema: String, state):
|
|
96
|
+
return isinstance(state, str)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dispatch
|
|
100
|
+
def check(schema: Enum, state):
|
|
101
|
+
if not isinstance(state, str):
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
return state in schema._values
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@dispatch
|
|
108
|
+
def check(schema: List, state):
|
|
109
|
+
if not isinstance(state, (list, tuple)):
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
return all([
|
|
113
|
+
check(schema._element, element)
|
|
114
|
+
for element in state])
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@dispatch
|
|
118
|
+
def check(schema: Map, state):
|
|
119
|
+
if not isinstance(state, dict):
|
|
120
|
+
return False
|
|
121
|
+
|
|
122
|
+
all_values = all([
|
|
123
|
+
check(schema._value, value)
|
|
124
|
+
for value in state.values()])
|
|
125
|
+
|
|
126
|
+
if isinstance(schema._key, String):
|
|
127
|
+
return all_values
|
|
128
|
+
|
|
129
|
+
else:
|
|
130
|
+
# if the keys are not strings, we must realize
|
|
131
|
+
# them all to tell if they pass the check?
|
|
132
|
+
# - this seems expensive?
|
|
133
|
+
all_keys = all([
|
|
134
|
+
# TODO: if realize needs core this will fail
|
|
135
|
+
# does that matter?
|
|
136
|
+
check(schema._key, realize(None, schema._key, key))
|
|
137
|
+
for key in state.keys()])
|
|
138
|
+
|
|
139
|
+
return all_keys and all_values
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@dispatch
|
|
143
|
+
def check(schema: Tree, state):
|
|
144
|
+
if check(schema._leaf, state):
|
|
145
|
+
return True
|
|
146
|
+
|
|
147
|
+
elif isinstance(state, dict):
|
|
148
|
+
return all([
|
|
149
|
+
isinstance(key, str) and check(schema, branch)
|
|
150
|
+
for key, branch in state.items()])
|
|
151
|
+
else:
|
|
152
|
+
return False
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@dispatch
|
|
158
|
+
def check(schema: Array, state):
|
|
159
|
+
if not isinstance(state, np.ndarray):
|
|
160
|
+
return False
|
|
161
|
+
|
|
162
|
+
shape_match = tuple(schema._shape) == state.shape
|
|
163
|
+
data_match = schema._data == state.dtype
|
|
164
|
+
|
|
165
|
+
return shape_match and data_match
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@dispatch
|
|
169
|
+
def check(schema: Key, state):
|
|
170
|
+
return isinstance(state, int) or isinstance(state, str)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@dispatch
|
|
174
|
+
def check(schema: Node, state):
|
|
175
|
+
fields = [
|
|
176
|
+
field
|
|
177
|
+
for field in schema.__dataclass_fields__
|
|
178
|
+
if not field.startswith('_')]
|
|
179
|
+
|
|
180
|
+
if fields:
|
|
181
|
+
if isinstance(state, dict):
|
|
182
|
+
for key in schema.__dataclass_fields__:
|
|
183
|
+
if not key.startswith('_'):
|
|
184
|
+
if key not in state:
|
|
185
|
+
return False
|
|
186
|
+
else:
|
|
187
|
+
down = check(
|
|
188
|
+
getattr(schema, key),
|
|
189
|
+
state[key])
|
|
190
|
+
if down is False:
|
|
191
|
+
return False
|
|
192
|
+
return True
|
|
193
|
+
else:
|
|
194
|
+
return False
|
|
195
|
+
else:
|
|
196
|
+
return True
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@dispatch
|
|
200
|
+
def check(schema: dict, state):
|
|
201
|
+
for key, subschema in schema.items():
|
|
202
|
+
if key not in state:
|
|
203
|
+
continue
|
|
204
|
+
# return False
|
|
205
|
+
elif not check(subschema, state[key]):
|
|
206
|
+
return False
|
|
207
|
+
|
|
208
|
+
return True
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@dispatch
|
|
212
|
+
def check(schema, state):
|
|
213
|
+
raise Exception(f'not a valid schema: {schema}')
|