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.
@@ -0,0 +1,527 @@
1
+ from ast import literal_eval
2
+ from pprint import pformat as pf
3
+ from plum import dispatch
4
+ import numpy as np
5
+ from numpy.random.mtrand import RandomState
6
+ from dataclasses import replace
7
+
8
+ from bigraph_schema.protocols import local_lookup
9
+
10
+
11
+ from bigraph_schema.schema import (
12
+ Node,
13
+ Empty,
14
+ NONE_SYMBOL,
15
+ Union,
16
+ Tuple,
17
+ Boolean,
18
+ Number,
19
+ Integer,
20
+ Float,
21
+ Delta,
22
+ Nonnegative,
23
+ NPRandom,
24
+ String,
25
+ Enum,
26
+ Wrap,
27
+ Maybe,
28
+ Overwrite,
29
+ List,
30
+ Map,
31
+ Tree,
32
+ Array,
33
+ Key,
34
+ Path,
35
+ Wires,
36
+ Protocol,
37
+ LocalProtocol,
38
+ Schema,
39
+ Link,
40
+ )
41
+
42
+
43
+ from bigraph_schema.methods.serialize import render
44
+ from bigraph_schema.methods.default import default
45
+
46
+
47
+ @dispatch
48
+ def realize(core, schema: Empty, encode, path=()):
49
+ return schema, encode, []
50
+
51
+ @dispatch
52
+ def realize(core, schema: Maybe, encode, path=()):
53
+ if encode is not None and encode != NONE_SYMBOL:
54
+ return realize(core, schema._value, encode)
55
+ else:
56
+ return schema, encode, []
57
+
58
+ @dispatch
59
+ def realize(core, schema: Wrap, encode, path=()):
60
+ return realize(core, schema._value, encode)
61
+
62
+ @dispatch
63
+ def realize(core, schema: Union, encode, path=()):
64
+ for option in schema._options:
65
+ decode_schema, decode_state, merges = realize(core, option, encode)
66
+ if decode_state is not None:
67
+ return decode_schema, decode_state, merges
68
+ return schema, None, []
69
+
70
+ @dispatch
71
+ def realize(core, schema: Tuple, encode, path=()):
72
+ merges = []
73
+
74
+ if isinstance(encode, str):
75
+ encode = literal_eval(encode)
76
+
77
+ if isinstance(encode, (list, tuple)):
78
+ subvalues = []
79
+ subtuple = []
80
+ for value, code, index in zip(schema._values, encode, range(len(encode))):
81
+ subvalue, subcode, submerges = realize(core, value, code, path+(index,))
82
+ subvalues.append(subvalue)
83
+ subtuple.append(subcode)
84
+ merges += submerges
85
+
86
+ result_schema = replace(schema, **{'_values': subvalues})
87
+ result_state = tuple(subtuple)
88
+
89
+ return result_schema, result_state, merges
90
+
91
+ else:
92
+ default_schema, default_state, merges = core.default_merges(schema, path=path)
93
+ return default_schema, default_state, merges
94
+
95
+
96
+ def realize_default(core, schema, encode: dict, path=()):
97
+ default_state = encode.get('_default', default(schema))
98
+ return realize(core, schema, default_state, path=path)
99
+
100
+
101
+ @dispatch
102
+ def realize(core, schema: Boolean, encode, path=()):
103
+ if encode is None:
104
+ schema, state = core.default(schema, path=path)
105
+ return schema, state, []
106
+ elif isinstance(encode, dict):
107
+ return realize_default(core, schema, encode, path=path)
108
+ elif encode == 'true':
109
+ return schema, True, []
110
+ elif encode == 'false':
111
+ return schema, False, []
112
+ else:
113
+ return schema, encode, []
114
+
115
+ @dispatch
116
+ def realize(core, schema: Integer, encode, path=()):
117
+ if encode is None:
118
+ schema, state = core.default(schema, path=path)
119
+ return schema, state, []
120
+ if isinstance(encode, dict):
121
+ return realize_default(core, schema, encode, path=path)
122
+
123
+ try:
124
+ result = int(encode)
125
+ return schema, result, []
126
+ except Exception:
127
+ return schema, None, []
128
+
129
+ @dispatch
130
+ def realize(core, schema: Float, encode, path=()):
131
+ if encode is None:
132
+ schema, state = core.default(schema, path=path)
133
+ return schema, state, []
134
+ elif isinstance(encode, dict):
135
+ return realize_default(core, schema, encode, path=path)
136
+ else:
137
+ try:
138
+ result = float(encode)
139
+ return schema, result, []
140
+ except Exception:
141
+ return schema, None, []
142
+
143
+ @dispatch
144
+ def realize(core, schema: String, encode, path=()):
145
+ if isinstance(encode, dict):
146
+ return realize_default(core, schema, encode, path=path)
147
+
148
+ return schema, encode, []
149
+
150
+ @dispatch
151
+ def realize(core, schema: NPRandom, encode, path=()):
152
+ if isinstance(encode, RandomState):
153
+ return schema, encode, []
154
+ else:
155
+ state = realize(core, schema.state, encode)
156
+ random = RandomState()
157
+ random.set_state(state)
158
+
159
+ return schema, random, []
160
+
161
+ @dispatch
162
+ def realize(core, schema: List, encode, path=()):
163
+ decode = []
164
+ merges = []
165
+
166
+ if isinstance(encode, str):
167
+ encode = literal_eval(encode)
168
+
169
+ if isinstance(encode, (list, tuple)):
170
+ for index, element in enumerate(encode):
171
+ subschema, substate, submerges = realize(core, schema._element, element, path+(index,))
172
+ element_schema = core.resolve(schema._element, subschema)
173
+ schema = replace(schema, **{'_element': element_schema})
174
+ decode.append(substate)
175
+ merges += submerges
176
+
177
+ return schema, decode, merges
178
+
179
+ else:
180
+ return schema, None, []
181
+
182
+ @dispatch
183
+ def realize(core, schema: Map, encode, path=()):
184
+ if isinstance(encode, str):
185
+ encode = literal_eval(encode)
186
+
187
+ if isinstance(encode, dict):
188
+ decode = {}
189
+ merges = []
190
+ schema = replace(schema, **{'_default': encode})
191
+ value_schemas = []
192
+
193
+ for key, value in encode.items():
194
+ if key.startswith('_'):
195
+ continue
196
+ else:
197
+ subschema, substate, submerges = realize(core, schema._value, value, path+(key,))
198
+ value_schemas.append(subschema)
199
+ decode[key] = substate
200
+ merges += submerges
201
+
202
+ if value_schemas:
203
+ value_schema = core.resolve_schemas(
204
+ value_schemas)
205
+ value_schema = core.resolve(schema._value, value_schema)
206
+
207
+ schema = replace(schema, **{
208
+ '_value': value_schema})
209
+
210
+ return schema, decode, merges
211
+
212
+ else:
213
+ return schema, None, []
214
+
215
+ @dispatch
216
+ def realize(core, schema: Tree, encode, path=()):
217
+ decode = {}
218
+
219
+ if isinstance(encode, str):
220
+ try:
221
+ encode = literal_eval(encode)
222
+ except:
223
+ pass
224
+
225
+ leaf_schema, leaf_state, merges = realize(core, schema._leaf, encode)
226
+ if leaf_state is not None:
227
+ return leaf_schema, leaf_state, merges
228
+
229
+ elif isinstance(encode, dict):
230
+ decode = {}
231
+ for key, value in encode.items():
232
+ subschema, substate, submerges = realize(core, schema, value, path+(key,))
233
+ schema = core.resolve(schema, subschema)
234
+ decode[key] = substate
235
+ merges += submerges
236
+
237
+ return schema, decode, merges
238
+
239
+ else:
240
+ return schema, None, []
241
+
242
+ def dict_values(d):
243
+ result = []
244
+ for key, value in d.items():
245
+ if isinstance(value, dict):
246
+ value = dict_values(value)
247
+ result.append(value)
248
+ return result
249
+
250
+ @dispatch
251
+ def realize(core, schema: Array, encode, path=()):
252
+ if isinstance(encode, np.ndarray):
253
+ return schema, encode, []
254
+ elif isinstance(encode, dict):
255
+ encode = dict_values(encode)
256
+
257
+ state = np.array(
258
+ encode,
259
+ dtype=schema._data)
260
+
261
+ if state.shape != schema._shape:
262
+ state.reshape(schema._shape)
263
+
264
+ return schema, state, []
265
+
266
+
267
+ def load_local_protocol(core, protocol, data):
268
+ if isinstance(data, str):
269
+ return local_lookup(core, data)
270
+ else:
271
+ raise Exception(f'address must be str, not {data}')
272
+
273
+
274
+ @dispatch
275
+ def load_protocol(core, protocol: LocalProtocol, data):
276
+ return load_local_protocol(core, protocol, data)
277
+
278
+
279
+ @dispatch
280
+ def load_protocol(core, protocol: Protocol, data):
281
+ raise Exception(f'protocol {protocol} with data {data} not implemented (!)')
282
+
283
+
284
+ @dispatch
285
+ def load_protocol(core, protocol, data):
286
+ raise Exception(f'value is not a protocol: {protocol}')
287
+
288
+
289
+ def port_merges(core, port_schema, wires, path):
290
+ if isinstance(wires, (list, tuple)):
291
+ subpath = path[:-1] + tuple(wires)
292
+ return [(subpath, port_schema)]
293
+
294
+ else:
295
+ merges = []
296
+ for key, subwires in wires.items():
297
+ down_schema, _ = core.jump(
298
+ port_schema,
299
+ {},
300
+ key)
301
+
302
+ submerges = port_merges(
303
+ core,
304
+ down_schema,
305
+ subwires,
306
+ path)
307
+ merges += submerges
308
+
309
+ return merges
310
+
311
+
312
+ def default_wires(schema):
313
+ return {
314
+ key: [key]
315
+ for key in schema}
316
+
317
+
318
+ def realize_link(core, schema: Link, encode, path=()):
319
+ if 'instance' in encode:
320
+ return schema, encode, []
321
+
322
+ address = encode.get('address', 'local:edge')
323
+ if isinstance(address, str):
324
+ if ':' not in address:
325
+ protocol = 'local'
326
+ data = address
327
+ else:
328
+ protocol, data = address.split(':', 1)
329
+
330
+ address = {
331
+ 'protocol': protocol,
332
+ 'data': data}
333
+
334
+ protocol = address.get('protocol', 'local')
335
+ protocol_schema = core.access(protocol)
336
+ edge_class = load_protocol(core, protocol_schema, address['data'])
337
+
338
+ if edge_class is None:
339
+ raise Exception(f'no link found at address: {address}')
340
+
341
+ config_schema = edge_class.config_schema
342
+ encode_config = encode.get('config', {})
343
+ _, decode_config = core.realize(config_schema, encode_config)
344
+ config = core.fill(config_schema, decode_config)
345
+
346
+ # validate the config against the config_schema
347
+ message = f'config provided to {address} does not match the config_schema!\n\nconfig_schema: {pf(render(config_schema))}\n\nconfig: {pf(config)}\n\n'
348
+ core.validate(config_schema, config, message)
349
+
350
+ edge_instance = encode.get('instance', edge_class(config, core))
351
+ interface = edge_instance.interface()
352
+
353
+ decode = {
354
+ 'address': address,
355
+ 'config': config,
356
+ 'instance': edge_instance}
357
+ merges = []
358
+
359
+ for port in ['inputs', 'outputs']:
360
+ port_key = f'_{port}'
361
+ port_schema = getattr(schema, port_key)
362
+
363
+ port_schema = core.resolve(
364
+ port_schema,
365
+ interface[port])
366
+ if port_key in encode and encode[port_key]:
367
+ port_schema = core.resolve(
368
+ port_schema,
369
+ encode[port_key])
370
+
371
+ decode[port_key] = port_schema
372
+ schema = replace(schema, **{port_key: port_schema})
373
+
374
+ if port_schema is None:
375
+ continue
376
+
377
+ if port not in encode or encode[port] is None:
378
+ decode[port] = default_wires(port_schema)
379
+ else:
380
+ subschema = getattr(schema, port)
381
+
382
+ subschema._default = encode[port]
383
+ wires_schema, wires_state, submerges = realize(core, subschema, encode[port], path+(port,))
384
+ if wires_state is None:
385
+ decode[port] = default_wires(port_schema)
386
+ else:
387
+ decode[port] = wires_state
388
+ merges += submerges
389
+
390
+ submerges = port_merges(
391
+ core,
392
+ port_schema,
393
+ decode[port],
394
+ path)
395
+
396
+ merges += submerges
397
+
398
+ # if 'shared' in encode and encode['shared'] is not None:
399
+ # decode['shared'] = {}
400
+ # for shared_name, shared_state in encode['shared'].items():
401
+ # link_schema, link_state, submerges = realize_link(core, schema, shared_state, path+('shared',))
402
+ # merges += submerges
403
+
404
+ # link_state['instance'].register_shared(edge_instance)
405
+ # decode['shared'][shared_name] = link_state
406
+
407
+ for key, value in encode.items():
408
+ if not key.startswith('_'):
409
+ if hasattr(schema, key):
410
+ getattr(schema, key)._default = value
411
+ else:
412
+ attr, decode[key], submerges = realize(
413
+ core, {}, value, path+(key,))
414
+ setattr(schema, key, attr)
415
+ merges += submerges
416
+
417
+ return schema, decode, merges
418
+
419
+ @dispatch
420
+ def realize(core, schema: Link, encode, path=()):
421
+ return realize_link(core, schema, encode, path=path)
422
+
423
+ @dispatch
424
+ def realize(core, schema: Node, encode, path=()):
425
+ if isinstance(encode, str):
426
+ try:
427
+ encode = literal_eval(encode)
428
+ except Exception as e:
429
+ return schema, encode, []
430
+
431
+ result = {}
432
+ merges = []
433
+
434
+ if isinstance(encode, dict):
435
+ for key in schema.__dataclass_fields__:
436
+ if key in encode:
437
+ attr = getattr(schema, key)
438
+ subschema, substate, submerges = realize(
439
+ core,
440
+ attr,
441
+ encode.get(key),
442
+ path+(key,))
443
+ schema = replace(schema, **{
444
+ key: core.resolve(attr, subschema)})
445
+ result[key] = substate
446
+ merges += submerges
447
+
448
+ if result:
449
+ return schema, result, merges
450
+ else:
451
+ return schema, encode, []
452
+
453
+ @dispatch
454
+ def realize(core, schema: None, encode, path=()):
455
+ if isinstance(encode, dict):
456
+ if '_type' in encode:
457
+ schema_keys = {
458
+ key: value
459
+ for key, value in encode.items()
460
+ if key.startswith('_')}
461
+ schema = core.access_type(schema_keys)
462
+ result_schema, result_state, merges = realize(
463
+ core, schema, encode, path=path)
464
+
465
+ return result_schema, result_state, merges
466
+ else:
467
+ merges = []
468
+ schema = {}
469
+ state = {}
470
+ for key, value in encode.items():
471
+ schema[key], state[key], submerges = realize(
472
+ core,
473
+ None,
474
+ value,
475
+ path+(key,))
476
+ merges += submerges
477
+ return schema, state, merges
478
+ else:
479
+ infer_schema, merges = core.infer_merges(
480
+ encode, path=path)
481
+ return infer_schema, encode, merges
482
+
483
+ @dispatch
484
+ def realize(core, schema: dict, encode, path=()):
485
+ if isinstance(encode, str):
486
+ try:
487
+ encode = literal_eval(encode)
488
+ except Exception as e:
489
+ return schema, encode, []
490
+
491
+ result_schema = {}
492
+ result_state = {}
493
+ merges = []
494
+
495
+ if isinstance(encode, dict):
496
+ for key, subschema in schema.items():
497
+ if key in encode:
498
+ outcome_schema, outcome_state, submerges = realize(
499
+ core,
500
+ subschema,
501
+ encode[key],
502
+ path+(key,))
503
+
504
+ if outcome_state is not None:
505
+ result_schema[key] = core.resolve(subschema, outcome_schema)
506
+ result_state[key] = outcome_state
507
+ merges += submerges
508
+ else:
509
+ if key != '_default':
510
+ result_schema[key], result_state[key], submerges = core.default_merges(
511
+ subschema,
512
+ path=path+(key,))
513
+ merges += submerges
514
+
515
+ for key in encode.keys():
516
+ if (isinstance(key, str) and not key.startswith('_')) and not key in schema:
517
+ result_schema[key], result_state[key], submerges = realize(
518
+ core, None, encode[key], path+(key,))
519
+ merges += submerges
520
+
521
+ if result_state:
522
+ return result_schema, result_state, merges
523
+
524
+ return schema, encode, merges
525
+
526
+
527
+