process-bigraph 0.0.38__tar.gz → 0.0.41__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 (34) hide show
  1. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/.gitignore +2 -0
  2. {process-bigraph-0.0.38/process_bigraph.egg-info → process-bigraph-0.0.41}/PKG-INFO +1 -1
  3. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/__init__.py +6 -4
  4. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/composite.py +389 -4
  5. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/process_types.py +26 -0
  6. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/processes/__init__.py +5 -0
  7. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/tests.py +55 -3
  8. {process-bigraph-0.0.38 → process-bigraph-0.0.41/process_bigraph.egg-info}/PKG-INFO +1 -1
  9. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph.egg-info/SOURCES.txt +1 -0
  10. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph.egg-info/requires.txt +1 -3
  11. process-bigraph-0.0.41/pyproject.toml +19 -0
  12. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/setup.py +1 -1
  13. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/.github/workflows/notebook_to_html.yml +0 -0
  14. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/.github/workflows/pytest.yml +0 -0
  15. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/AUTHORS.md +0 -0
  16. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/CLA.md +0 -0
  17. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/CODE_OF_CONDUCT.md +0 -0
  18. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/CONTRIBUTING.md +0 -0
  19. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/LICENSE +0 -0
  20. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/README.md +0 -0
  21. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/doc/_static/process-bigraph.png +0 -0
  22. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/notebooks/process-bigraphs.ipynb +0 -0
  23. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/notebooks/visualize_processes.ipynb +0 -0
  24. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/emitter.py +0 -0
  25. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/experiments/__init__.py +0 -0
  26. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/experiments/minimal_gillespie.py +0 -0
  27. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/processes/growth_division.py +0 -0
  28. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/processes/parameter_scan.py +0 -0
  29. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph/protocols.py +0 -0
  30. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph.egg-info/dependency_links.txt +0 -0
  31. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/process_bigraph.egg-info/top_level.txt +0 -0
  32. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/pytest.ini +0 -0
  33. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/release.sh +0 -0
  34. {process-bigraph-0.0.38 → process-bigraph-0.0.41}/setup.cfg +0 -0
@@ -11,3 +11,5 @@ venv/
11
11
 
12
12
  process_bigraph.egg-info/
13
13
  out/
14
+ .devenv*
15
+ devenv.lock
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: process-bigraph
3
- Version: 0.0.38
3
+ Version: 0.0.41
4
4
  Home-page: https://github.com/vivarium-collective/process-bigraph
5
5
  Author: Ryan Spangler, Eran Agmon
6
6
  Author-email: ryan.spangler@gmail.com, agmon.eran@gmail.com
@@ -1,9 +1,8 @@
1
1
  import pprint
2
2
  from bigraph_schema.registry import deep_merge, default
3
3
  from process_bigraph.processes import register_processes
4
- from process_bigraph.composite import Process, Step, Composite, interval_time_precision
5
- from process_bigraph.process_types import ProcessTypes
6
- from process_bigraph.emitter import Emitter, gather_emitter_results, generate_emitter_state
4
+ from process_bigraph.composite import Process, Step, Composite, interval_time_precision, ProcessTypes
5
+ from process_bigraph.emitter import Emitter, gather_emitter_results, generate_emitter_state, BASE_EMITTERS
7
6
 
8
7
 
9
8
  pretty = pprint.PrettyPrinter(indent=2)
@@ -42,9 +41,12 @@ def register_types(core):
42
41
  'rates': 'map[float]',
43
42
  'species': 'map[float]'})
44
43
 
45
- core = register_processes(
44
+ register_processes(
46
45
  core)
47
46
 
48
47
  return core
49
48
 
50
49
 
50
+ def allocate_core():
51
+ core = ProcessTypes()
52
+ return register_types(core)
@@ -11,7 +11,7 @@ import collections
11
11
  from typing import Dict
12
12
 
13
13
  from bigraph_schema import (
14
- Edge, Registry,
14
+ Edge, Registry, TypeSystem, visit_method,
15
15
  get_path, set_path, resolve_path, hierarchy_depth, deep_merge,
16
16
  is_schema_key, strip_schema_keys)
17
17
 
@@ -22,6 +22,7 @@ from process_bigraph.protocols import local_lookup, local_lookup_module
22
22
  # Process Utility Functions
23
23
  # =========================
24
24
 
25
+
25
26
  def assert_interface(interface: Dict):
26
27
  """Ensure that an interface dict has the required keys"""
27
28
  required_keys = ['inputs', 'outputs']
@@ -379,6 +380,14 @@ class Defer:
379
380
  self.defer.get(),
380
381
  self.args)
381
382
 
383
+ def match_star_path(path, star_path):
384
+ compare = zip(path, star_path)
385
+ for element, star_element in compare:
386
+ if element != star_element:
387
+ if star_element != "*":
388
+ return False
389
+ return True
390
+
382
391
 
383
392
  class Composite(Process):
384
393
  """
@@ -487,13 +496,16 @@ class Composite(Process):
487
496
 
488
497
  def build_step_network(self):
489
498
  self.step_triggers = {}
499
+ self.star_triggers = {}
490
500
  for step_path, step in self.step_paths.items():
491
501
  step_triggers = find_step_triggers(
492
502
  step_path, step)
493
503
  self.step_triggers = merge_collections(
494
504
  self.step_triggers,
495
505
  step_triggers)
496
-
506
+ for trigger in self.step_triggers:
507
+ if "*" in trigger:
508
+ self.star_triggers[trigger] = self.step_triggers[trigger]
497
509
  self.steps_run = set([])
498
510
 
499
511
  self.step_dependencies, self.node_dependencies = build_step_network(
@@ -571,6 +583,12 @@ class Composite(Process):
571
583
  'process_bigraph.composite.Step')
572
584
 
573
585
 
586
+ def clean_front(self, state):
587
+ self.find_instance_paths(state)
588
+
589
+ # import ipdb; ipdb.set_trace()
590
+
591
+
574
592
  def inputs(self):
575
593
  return self.process_schema.get('inputs', {})
576
594
 
@@ -756,8 +774,7 @@ class Composite(Process):
756
774
  self.bridge_updates.append(
757
775
  bridge_update)
758
776
 
759
- self.find_instance_paths(
760
- self.state)
777
+ self.clean_front(self.state)
761
778
 
762
779
  return update_paths
763
780
 
@@ -896,6 +913,10 @@ class Composite(Process):
896
913
  paths = explode_path(update_path)
897
914
  for path in paths:
898
915
  step_paths = self.step_triggers.get(path, [])
916
+ if self.star_triggers:
917
+ for star_trigger, star_steps in self.star_triggers.items():
918
+ if match_star_path(path, star_trigger):
919
+ step_paths.extend(star_steps)
899
920
  for step_path in step_paths:
900
921
  if step_path is not None and step_path not in self.steps_run:
901
922
  steps_to_run.append(step_path)
@@ -933,3 +954,367 @@ class Composite(Process):
933
954
  return updates
934
955
 
935
956
 
957
+ # ======================
958
+ # Process Type Functions
959
+ # ======================
960
+
961
+
962
+ def apply_process(schema, current, update, top_schema, top_state, path, core):
963
+ """Apply an update to a process."""
964
+ process_schema = schema.copy()
965
+ process_schema.pop('_apply')
966
+ return core.apply_update(
967
+ process_schema,
968
+ current,
969
+ update,
970
+ top_schema=top_schema,
971
+ top_state=top_state,
972
+ path=path)
973
+
974
+
975
+ def check_process(schema, state, core):
976
+ """Check if this is a process."""
977
+ return 'instance' in state and isinstance(
978
+ state['instance'],
979
+ Edge)
980
+
981
+
982
+ def fold_visit(schema, state, method, values, core):
983
+ visit = visit_method(
984
+ schema,
985
+ state,
986
+ method,
987
+ values,
988
+ core)
989
+
990
+ return visit
991
+
992
+
993
+ def divide_process(schema, state, values, core):
994
+ # daughter_configs must have a config per daughter
995
+
996
+ daughter_configs = values.get(
997
+ 'daughter_configs',
998
+ [{} for index in range(values['divisions'])])
999
+
1000
+ if 'config' not in state:
1001
+ return daughter_configs
1002
+
1003
+ existing_config = state['config']
1004
+
1005
+ divisions = []
1006
+ for index in range(values['divisions']):
1007
+ daughter_config = copy.deepcopy(
1008
+ existing_config)
1009
+ daughter_config = deep_merge(
1010
+ daughter_config,
1011
+ daughter_configs[index])
1012
+
1013
+ # TODO: provide a way to override inputs and outputs
1014
+ daughter_state = {
1015
+ 'address': state['address'],
1016
+ 'config': daughter_config,
1017
+ 'inputs': copy.deepcopy(state['inputs']),
1018
+ 'outputs': copy.deepcopy(state['outputs'])}
1019
+
1020
+ if 'interval' in state:
1021
+ daughter_state['interval'] = state['interval']
1022
+
1023
+ divisions.append(daughter_state)
1024
+
1025
+ return divisions
1026
+
1027
+
1028
+ def serialize_process(schema, value, core):
1029
+ """Serialize a process to a JSON-safe representation."""
1030
+ # TODO -- need to get back the protocol: address and the config
1031
+ process = value.copy()
1032
+ process['config'] = core.serialize(
1033
+ process['instance'].config_schema,
1034
+ process['config'])
1035
+ del process['instance']
1036
+ return process
1037
+
1038
+
1039
+ def deserialize_process(schema, encoded, core):
1040
+ """Deserialize a process from a serialized state.
1041
+
1042
+ This function is used by the type system to deserialize a process.
1043
+
1044
+ :param encoded: A JSON-safe representation of the process.
1045
+ :param bindings: The bindings to use for deserialization.
1046
+ :param core: The type system to use for deserialization.
1047
+
1048
+ :returns: The deserialized state with an instantiated process.
1049
+ """
1050
+ encoded = encoded or {}
1051
+ schema = schema or {}
1052
+
1053
+ default = core.default(schema)
1054
+ deserialized = deep_merge(default, encoded)
1055
+
1056
+ if not deserialized.get('address'):
1057
+ return deserialized
1058
+
1059
+ protocol, address = deserialized['address'].split(':', 1)
1060
+
1061
+ existing_instance = 'instance' in deserialized and deserialized['instance']
1062
+ if existing_instance:
1063
+ instantiate = type(deserialized['instance'])
1064
+ else:
1065
+ process_lookup = core.protocol_registry.access(protocol)
1066
+ if not process_lookup:
1067
+ raise Exception(f'protocol "{protocol}" not implemented')
1068
+
1069
+ instantiate = process_lookup(core, address)
1070
+ if not instantiate:
1071
+ raise Exception(f'process "{address}" not found')
1072
+
1073
+ config = core.deserialize(
1074
+ instantiate.config_schema,
1075
+ deserialized.get('config', {}))
1076
+
1077
+ interval = core.deserialize(
1078
+ 'interval',
1079
+ deserialized.get('interval'))
1080
+
1081
+ if interval is None:
1082
+ interval = core.default(
1083
+ schema.get(
1084
+ 'interval',
1085
+ 'interval'))
1086
+
1087
+ if existing_instance:
1088
+ process = deserialized['instance']
1089
+ else:
1090
+ process = instantiate(
1091
+ config,
1092
+ core=core)
1093
+
1094
+ deserialized['instance'] = process
1095
+
1096
+ # TODO: this mutating the original value directly into
1097
+ # the return value is weird (?)
1098
+ shared = deserialized.get('shared', {})
1099
+ deserialized['shared'] = {}
1100
+ if shared:
1101
+ for step_id, step_config in shared.items():
1102
+ step = deserialize_step(
1103
+ 'step',
1104
+ step_config,
1105
+ core)
1106
+
1107
+ step['instance'].register_shared(
1108
+ process)
1109
+
1110
+ deserialized['shared'][step_id] = step
1111
+
1112
+ deserialized['config'] = config
1113
+ deserialized['interval'] = interval
1114
+ deserialized['_inputs'] = copy.deepcopy(
1115
+ deserialized['instance'].inputs())
1116
+ deserialized['_outputs'] = copy.deepcopy(
1117
+ deserialized['instance'].outputs())
1118
+
1119
+ return deserialized
1120
+
1121
+
1122
+ def deserialize_step(schema, encoded, core):
1123
+ default = core.default(schema)
1124
+ deserialized = deep_merge(default, encoded)
1125
+
1126
+ if not deserialized['address']:
1127
+ return deserialized
1128
+
1129
+ protocol, address = deserialized['address'].split(':', 1)
1130
+
1131
+ existing_instance = 'instance' in deserialized and deserialized['instance']
1132
+ if existing_instance:
1133
+ instantiate = type(deserialized['instance'])
1134
+ else:
1135
+ process_lookup = core.protocol_registry.access(protocol)
1136
+ if not process_lookup:
1137
+ raise Exception(f'protocol "{protocol}" not implemented')
1138
+
1139
+ instantiate = process_lookup(core, address)
1140
+ if not instantiate:
1141
+ raise Exception(f'process "{address}" not found')
1142
+
1143
+ config = core.deserialize(
1144
+ instantiate.config_schema,
1145
+ deserialized.get('config', {}))
1146
+
1147
+ if not existing_instance:
1148
+ process = instantiate(config, core=core)
1149
+ deserialized['instance'] = process
1150
+
1151
+ deserialized['config'] = config
1152
+ deserialized['_inputs'] = copy.deepcopy(
1153
+ deserialized['instance'].inputs())
1154
+ deserialized['_outputs'] = copy.deepcopy(
1155
+ deserialized['instance'].outputs())
1156
+
1157
+ return deserialized
1158
+
1159
+
1160
+ # ===================
1161
+ # Process Type System
1162
+ # ===================
1163
+
1164
+ class ProcessTypes(TypeSystem):
1165
+ """
1166
+ ProcessTypes class extends the TypeSystem class to include process types.
1167
+ It maintains a registry of process types and provides methods to register
1168
+ new process types, protocols, and emitters.
1169
+ """
1170
+
1171
+ def __init__(self):
1172
+ super().__init__()
1173
+ self.process_registry = Registry()
1174
+ self.protocol_registry = Registry()
1175
+
1176
+ self.update_types(PROCESS_TYPES)
1177
+ self.register_protocols(BASE_PROTOCOLS)
1178
+
1179
+ self.register_process('composite', Composite)
1180
+
1181
+
1182
+ def register_protocols(self, protocols):
1183
+ """Register protocols with the core"""
1184
+ self.protocol_registry.register_multiple(protocols)
1185
+
1186
+
1187
+ def register_process(
1188
+ self,
1189
+ name,
1190
+ process_data
1191
+ ):
1192
+ """
1193
+ Registers a new process type in the process registry.
1194
+
1195
+ Args:
1196
+ name (str): The name of the process type.
1197
+ process_data: The data associated with the process type.
1198
+ """
1199
+ self.process_registry.register(name, process_data)
1200
+
1201
+
1202
+ def register_processes(self, processes):
1203
+ for process_key, process_data in processes.items():
1204
+ self.register_process(
1205
+ process_key,
1206
+ process_data)
1207
+
1208
+
1209
+ def initialize_edge_state(self, schema, path, edge):
1210
+ """
1211
+ Initialize the state for an edge based on the schema and the edge.
1212
+ """
1213
+ initial_state = edge['instance'].initial_state()
1214
+ if not initial_state:
1215
+ return initial_state
1216
+
1217
+ input_ports = copy.deepcopy(get_path(schema, path + ('_inputs',)))
1218
+ output_ports = copy.deepcopy(get_path(schema, path + ('_outputs',)))
1219
+ ports = {
1220
+ '_inputs': input_ports,
1221
+ '_outputs': output_ports}
1222
+
1223
+ input_state = {}
1224
+ if input_ports:
1225
+ input_state = self.project_edge(
1226
+ ports,
1227
+ edge,
1228
+ path[:-1],
1229
+ initial_state,
1230
+ ports_key='inputs')
1231
+
1232
+ output_state = {}
1233
+ if output_ports:
1234
+ output_state = self.project_edge(
1235
+ ports,
1236
+ edge,
1237
+ path[:-1],
1238
+ initial_state,
1239
+ ports_key='outputs')
1240
+
1241
+ state = deep_merge(input_state, output_state)
1242
+
1243
+ return state
1244
+
1245
+
1246
+ def default_state(self, process_class, initial_state=None):
1247
+ default_config = self.default(
1248
+ process_class.config_schema)
1249
+
1250
+ instance = process_class(
1251
+ default_config,
1252
+ core=self)
1253
+
1254
+ state = {
1255
+ '_type': 'process',
1256
+ 'address': f'local:!{process_class.__module__}.{process_class.__name__}',
1257
+ 'config': default_config,
1258
+ 'inputs': instance.default_inputs(),
1259
+ 'outputs': instance.default_outputs()}
1260
+
1261
+ if issubclass(process_class, Process):
1262
+ state['interval'] = 1.0
1263
+
1264
+ if initial_state:
1265
+ state = deep_merge(
1266
+ state,
1267
+ initial_state)
1268
+
1269
+ return state
1270
+
1271
+
1272
+ PROCESS_TYPES = {
1273
+ 'protocol': {
1274
+ '_type': 'protocol',
1275
+ '_inherit': 'string'},
1276
+
1277
+ 'emitter_mode': 'enum[none,all,stores,bridge,paths,ports]',
1278
+
1279
+ 'interval': {
1280
+ '_type': 'interval',
1281
+ '_inherit': 'float',
1282
+ '_apply': 'set',
1283
+ '_default': '1.0'},
1284
+
1285
+ 'step': {
1286
+ '_type': 'step',
1287
+ '_inherit': 'edge',
1288
+ '_apply': apply_process,
1289
+ '_serialize': serialize_process,
1290
+ '_deserialize': deserialize_step,
1291
+ '_check': check_process,
1292
+ '_fold': fold_visit,
1293
+ '_divide': divide_process,
1294
+ '_description': '',
1295
+ # TODO: support reference to type parameters from other states
1296
+ 'address': 'protocol',
1297
+ 'config': 'quote'},
1298
+
1299
+ # TODO: slice process to allow for navigating through a port
1300
+ 'process': {
1301
+ '_type': 'process',
1302
+ '_inherit': 'edge',
1303
+ '_apply': apply_process,
1304
+ '_serialize': serialize_process,
1305
+ '_deserialize': deserialize_process,
1306
+ '_check': check_process,
1307
+ '_fold': fold_visit,
1308
+ '_divide': divide_process,
1309
+ '_description': '',
1310
+ # TODO: support reference to type parameters from other states
1311
+ 'interval': 'interval',
1312
+ 'address': 'protocol',
1313
+ 'config': 'quote',
1314
+ 'shared': 'map[step]'},
1315
+ }
1316
+
1317
+
1318
+ BASE_PROTOCOLS = {
1319
+ 'local': local_lookup}
1320
+
@@ -306,6 +306,32 @@ class ProcessTypes(TypeSystem):
306
306
  return state
307
307
 
308
308
 
309
+ def default_state(self, process_class, initial_state=None):
310
+ default_config = self.default(
311
+ process_class.config_schema)
312
+
313
+ instance = process_class(
314
+ default_config,
315
+ core=self)
316
+
317
+ state = {
318
+ '_type': 'process',
319
+ 'address': f'local:!{process_class.__module__}.{process_class.__name__}',
320
+ 'config': default_config,
321
+ 'inputs': instance.default_inputs(),
322
+ 'outputs': instance.default_outputs()}
323
+
324
+ if issubclass(process_class, Process):
325
+ state['interval'] = 1.0
326
+
327
+ if initial_state:
328
+ state = deep_merge(
329
+ state,
330
+ initial_state)
331
+
332
+ return state
333
+
334
+
309
335
  PROCESS_TYPES = {
310
336
  'protocol': {
311
337
  '_type': 'protocol',
@@ -1,5 +1,6 @@
1
1
  from process_bigraph.processes.parameter_scan import ToySystem, ODE, RunProcess, ParameterScan
2
2
  from process_bigraph.processes.growth_division import Grow, Divide
3
+ from process_bigraph.emitter import BASE_EMITTERS
3
4
  # from process_bigraph.experiments.minimal_gillespie import GillespieInterval, GillespieEvent
4
5
 
5
6
 
@@ -18,4 +19,8 @@ TOY_PROCESSES = {
18
19
  def register_processes(core):
19
20
  for name, process in TOY_PROCESSES.items():
20
21
  core.register_process(name, process)
22
+
23
+ core = core.register_processes(
24
+ BASE_EMITTERS)
25
+
21
26
  return core
@@ -7,10 +7,9 @@ import random
7
7
  from bigraph_schema import default
8
8
  from process_bigraph import register_types
9
9
 
10
- from process_bigraph.composite import Process, Step, Composite, merge_collections
10
+ from process_bigraph.composite import Process, Step, Composite, merge_collections, match_star_path, ProcessTypes
11
11
 
12
- from process_bigraph.processes.growth_division import grow_divide_agent
13
- from process_bigraph.process_types import ProcessTypes
12
+ from process_bigraph.processes.growth_division import grow_divide_agent, Grow, Divide
14
13
  from process_bigraph.emitter import emitter_from_wires, gather_emitter_results
15
14
 
16
15
 
@@ -871,16 +870,68 @@ def test_star_update(core):
871
870
  assert star.state['Compartments']['2']['Shared Environment']['counts']['biomass'] == 2899
872
871
 
873
872
 
873
+ class GlobalProcess(Process):
874
+ config_schema = {}
875
+
876
+
877
+ def initialize(self, config):
878
+ pass
879
+
880
+
881
+
882
+
883
+
884
+ def test_default_process_state(core):
885
+ # provide some initial values
886
+ default_rate = {
887
+ 'config': {
888
+ 'rate': 0.001}}
889
+
890
+ # generate a default state for the Grow process
891
+ default_grow = core.default_state(
892
+ Grow,
893
+ default_rate)
894
+
895
+ # create a composite from the default process state
896
+ composite = Composite({
897
+ 'state': {
898
+ 'grow': default_grow,
899
+ 'mass': 1.0}},
900
+ core=core)
901
+
902
+ # run the composite
903
+ composite.run(10.0)
904
+
905
+ # assert the process ran and the mass increased
906
+ assert composite.state['mass'] > 1.0
907
+
908
+ default_divide = core.default_state(
909
+ Divide)
910
+
911
+ assert 'interval' not in default_divide
912
+
913
+
914
+ def test_update_removal(core):
915
+ return {}
916
+
917
+
874
918
  def test_stochastic_deterministic_composite(core):
875
919
  # TODO make the demo for a hybrid stochastic/deterministic simulator
876
920
  pass
877
921
 
878
922
 
923
+ def test_match_star_path(core):
924
+ assert match_star_path(["first", "list", "test"], ["first", "*", "test"])
925
+ assert not match_star_path(["first", "list", "tent"], ["first", "*", "test"])
926
+ assert match_star_path(["first", "list", "test"], ["first", "list", "test"])
927
+
928
+
879
929
  if __name__ == '__main__':
880
930
  core = ProcessTypes()
881
931
  core = register_types(core)
882
932
 
883
933
  test_default_config(core)
934
+ test_default_process_state(core)
884
935
  test_merge_collections(core)
885
936
  test_process(core)
886
937
  test_composite(core)
@@ -900,3 +951,4 @@ if __name__ == '__main__':
900
951
  test_merge_schema(core)
901
952
  test_grow_divide(core)
902
953
  test_star_update(core)
954
+ test_match_star_path(core)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: process-bigraph
3
- Version: 0.0.38
3
+ Version: 0.0.41
4
4
  Home-page: https://github.com/vivarium-collective/process-bigraph
5
5
  Author: Ryan Spangler, Eran Agmon
6
6
  Author-email: ryan.spangler@gmail.com, agmon.eran@gmail.com
@@ -5,6 +5,7 @@ CODE_OF_CONDUCT.md
5
5
  CONTRIBUTING.md
6
6
  LICENSE
7
7
  README.md
8
+ pyproject.toml
8
9
  pytest.ini
9
10
  release.sh
10
11
  setup.py
@@ -1,5 +1,3 @@
1
1
  bigraph-schema
2
- numpy
3
- pytest
4
- orjson
5
2
  matplotlib
3
+ pytest
@@ -0,0 +1,19 @@
1
+ [project]
2
+ name = "process-bigraph"
3
+ version = "0.0.41"
4
+ description = ""
5
+ readme = "README.md"
6
+ requires-python = "==3.12.9"
7
+ dependencies = [
8
+ "bigraph-schema",
9
+ "matplotlib",
10
+ "pytest"
11
+ ]
12
+
13
+ [tool.setuptools]
14
+ packages = [
15
+ "process_bigraph"
16
+ ]
17
+
18
+ [tool.uv.sources]
19
+ bigraph-schema = { path = "../bigraph-schema", editable = true }
@@ -2,7 +2,7 @@ import re
2
2
  from setuptools import setup, find_packages
3
3
 
4
4
 
5
- VERSION = '0.0.38'
5
+ VERSION = '0.0.41'
6
6
 
7
7
 
8
8
  with open("README.md", "r") as readme: