math-spec-mapping 0.3.18__tar.gz → 0.3.20__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. {math_spec_mapping-0.3.18/src/math_spec_mapping.egg-info → math_spec_mapping-0.3.20}/PKG-INFO +1 -1
  2. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/pyproject.toml +1 -1
  3. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/Block.py +3 -0
  4. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/MathSpec.py +109 -7
  5. math_spec_mapping-0.3.20/src/math_spec_mapping/Classes/Space.py +33 -0
  6. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/Type.py +3 -0
  7. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/action_transmission_channel.py +8 -2
  8. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/boundary_actions.py +3 -1
  9. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/control_actions.py +3 -1
  10. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/general.py +9 -0
  11. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/mechanism.py +3 -1
  12. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/policy.py +2 -1
  13. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/spaces.py +3 -0
  14. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/spec_tree.py +28 -7
  15. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/stateful_metrics.py +6 -0
  16. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/html.py +13 -0
  17. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/markdown.py +19 -4
  18. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/schema.schema.json +3 -0
  19. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20/src/math_spec_mapping.egg-info}/PKG-INFO +1 -1
  20. math_spec_mapping-0.3.18/src/math_spec_mapping/Classes/Space.py +0 -18
  21. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/LICENSE +0 -0
  22. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/README.md +0 -0
  23. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/setup.cfg +0 -0
  24. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/ActionTransmissionChannel.py +0 -0
  25. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/BoundaryAction.py +0 -0
  26. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/ControlAction.py +0 -0
  27. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/Entity.py +0 -0
  28. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/Mechanism.py +0 -0
  29. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/Metric.py +0 -0
  30. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/Parameter.py +0 -0
  31. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/Policy.py +0 -0
  32. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/State.py +0 -0
  33. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/StateUpdateTransmissionChannel.py +0 -0
  34. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/StatefulMetric.py +0 -0
  35. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Classes/__init__.py +0 -0
  36. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Convenience/__init__.py +0 -0
  37. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Convenience/documentation.py +0 -0
  38. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Convenience/github.py +0 -0
  39. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Convenience/starter.py +0 -0
  40. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/__init__.py +0 -0
  41. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/displays.py +0 -0
  42. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/entities.py +0 -0
  43. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/implementations.py +0 -0
  44. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/load.py +0 -0
  45. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/metrics.py +0 -0
  46. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/parameters.py +0 -0
  47. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/state_update_transmission_channels.py +0 -0
  48. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/states.py +0 -0
  49. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/type.py +0 -0
  50. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Load/wiring.py +0 -0
  51. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/__init__.py +0 -0
  52. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/boundary_actions.py +0 -0
  53. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/control_actions.py +0 -0
  54. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/general.py +0 -0
  55. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/mechanisms.py +0 -0
  56. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/node_map.py +0 -0
  57. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/parameters.py +0 -0
  58. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/policies.py +0 -0
  59. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/spaces.py +0 -0
  60. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/state.py +0 -0
  61. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/tables.py +0 -0
  62. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/Reports/wiring.py +0 -0
  63. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/__init__.py +0 -0
  64. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping/schema.py +0 -0
  65. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping.egg-info/SOURCES.txt +0 -0
  66. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping.egg-info/dependency_links.txt +0 -0
  67. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping.egg-info/requires.txt +0 -0
  68. {math_spec_mapping-0.3.18 → math_spec_mapping-0.3.20}/src/math_spec_mapping.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: math-spec-mapping
3
- Version: 0.3.18
3
+ Version: 0.3.20
4
4
  Summary: A library for easy mapping of mathematical specifications.
5
5
  Author-email: Sean McOwen <Sean@Block.Science>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -3,7 +3,7 @@ requires = ["setuptools>=61.0"]
3
3
  build-backend = "setuptools.build_meta"
4
4
  [project]
5
5
  name = "math-spec-mapping"
6
- version = "0.3.18"
6
+ version = "0.3.20"
7
7
  authors = [
8
8
  { name="Sean McOwen", email="Sean@Block.Science" },
9
9
  ]
@@ -172,6 +172,9 @@ class Block:
172
172
  out = list(set(out))
173
173
  return out
174
174
 
175
+ def __repr__(self):
176
+ return "<{}>".format(self.name)
177
+
175
178
 
176
179
  class ParallelBlock(Block):
177
180
  def __init__(self, data: Dict):
@@ -8,7 +8,7 @@ import os
8
8
  from copy import deepcopy
9
9
  import shutil
10
10
  import pandas as pd
11
- from inspect import signature, getsource, getfile
11
+ from inspect import signature, getsource, getfile, getsourcelines
12
12
  from IPython.display import display, Markdown
13
13
 
14
14
 
@@ -439,7 +439,14 @@ class MathSpec:
439
439
 
440
440
  self._used_spaces = list(set().union(*self._used_spaces))
441
441
  us_names = [y.name for y in self._used_spaces]
442
- self._unused_spaces = [self.spaces[x] for x in self.spaces if x not in us_names]
442
+ self._unused_spaces = [
443
+ self.spaces[x]
444
+ for x in self.spaces
445
+ if x not in us_names and x not in ["Terminating Space", "Empty Space"]
446
+ ]
447
+
448
+ if len(self._unused_spaces) > 0:
449
+ print("The following spaces are not used: {}".format(self._unused_spaces))
443
450
 
444
451
  def _add_spec_tree(self, tree):
445
452
  self.tree = tree
@@ -535,8 +542,17 @@ class MathSpec:
535
542
  component
536
543
  ]
537
544
  elif folder == "Displays":
538
- print("Displays not implemented")
539
- # keys = [x["name"] for x in ms.displays["Wiring"]]
545
+
546
+ for component in self.displays["Wiring"]:
547
+ if component["name"] not in tree:
548
+ print(
549
+ "Can't find component code source in {} for {}".format(
550
+ folder, component["name"]
551
+ )
552
+ )
553
+ component["Source Code Location"] = None
554
+ else:
555
+ component["Source Code Location"] = tree[component["name"]]
540
556
  elif folder == "Spaces":
541
557
  for component in self.spaces:
542
558
  if component in ["Terminating Space", "Empty Space"]:
@@ -955,23 +971,31 @@ using .Spaces: generate_space_type
955
971
  with open(path, "w") as f:
956
972
  f.write(out)
957
973
 
958
- def build_implementation(self, params):
959
- return MathSpecImplementation(self, params)
974
+ def build_implementation(self, params, domain_codomain_checking=False):
975
+ return MathSpecImplementation(
976
+ self, params, domain_codomain_checking=domain_codomain_checking
977
+ )
960
978
 
961
979
  def _set_source_code(self):
962
980
  if "python" not in self.implementations:
963
981
  self.source_code = None
964
982
  return
965
983
  self.source_code = deepcopy(self.implementations["python"])
984
+ self.source_code_lines = {}
966
985
  for x in self.source_code:
986
+ self.source_code_lines[x] = {}
967
987
  for y in self.source_code[x]:
988
+ self.source_code_lines[x][y] = "#L{}".format(
989
+ getsourcelines(self.source_code[x][y])[1]
990
+ )
968
991
  self.source_code[x][y] = getsource(self.source_code[x][y])
969
992
 
970
993
 
971
994
  class MathSpecImplementation:
972
- def __init__(self, ms: MathSpec, params):
995
+ def __init__(self, ms: MathSpec, params, domain_codomain_checking):
973
996
  self.ms = deepcopy(ms)
974
997
  self.params = params
998
+ self.domain_codomain_checking = domain_codomain_checking
975
999
  self.control_actions = self.load_control_actions()
976
1000
  self.boundary_actions = self.load_boundary_actions()
977
1001
  self.policies = self.load_policies()
@@ -1010,6 +1034,14 @@ class MathSpecImplementation:
1010
1034
  )
1011
1035
  else:
1012
1036
  control_actions[ca.name] = opt.implementations["python"]
1037
+
1038
+ for opt_i in [x for x in ca.control_action_options if x != opt]:
1039
+ if "python" not in opt_i.implementations:
1040
+ print(
1041
+ "No python implementation for {} / {}. To fix this, go to Implementations/Python/ControlActions and add {}".format(
1042
+ ca.name, opt_i.name, opt_i.name
1043
+ )
1044
+ )
1013
1045
  return control_actions
1014
1046
 
1015
1047
  def load_boundary_actions(self):
@@ -1041,6 +1073,14 @@ class MathSpecImplementation:
1041
1073
  )
1042
1074
  else:
1043
1075
  boundary_actions[ba.name] = opt.implementations["python"]
1076
+
1077
+ for opt_i in [x for x in ba.boundary_action_options if x != opt]:
1078
+ if "python" not in opt_i.implementations:
1079
+ print(
1080
+ "No python implementation for {} / {}. To fix this, go to Implementations/Python/BoundaryActions and add {}".format(
1081
+ ba.name, opt_i.name, opt_i.name
1082
+ )
1083
+ )
1044
1084
  return boundary_actions
1045
1085
 
1046
1086
  def load_mechanisms(self):
@@ -1137,6 +1177,14 @@ class MathSpecImplementation:
1137
1177
  )
1138
1178
  else:
1139
1179
  policies[p.name] = opt.implementations["python"]
1180
+ for opt_i in [x for x in p.policy_options if x != opt]:
1181
+ if "python" not in opt_i.implementations:
1182
+ print(
1183
+ "No python implementation for {} / {}. To fix this, go to Implementations/Python/Policies and add {}".format(
1184
+ p.name, opt_i.name, opt_i.name
1185
+ )
1186
+ )
1187
+
1140
1188
  return policies
1141
1189
 
1142
1190
  def load_stateful_metrics(self):
@@ -1283,6 +1331,60 @@ class MathSpecImplementation:
1283
1331
  self.components.update(self.mechanisms)
1284
1332
  self.components.update(self.wiring)
1285
1333
 
1334
+ self.components_enhanced = {}
1335
+
1336
+ def create_wrapper(component, domain_codomain_checking):
1337
+ def wrapper(
1338
+ state,
1339
+ params,
1340
+ spaces,
1341
+ domain_codomain_checking=self.domain_codomain_checking,
1342
+ ):
1343
+ domain = spaces
1344
+
1345
+ # Domain Checking
1346
+ if domain_codomain_checking:
1347
+ prototype_spaces = self.ms.blocks[component].domain
1348
+ prototype_spaces = [
1349
+ x.schema for x in prototype_spaces if x.name != "Empty Space"
1350
+ ]
1351
+ assert len(prototype_spaces) == len(
1352
+ domain
1353
+ ), "Length of domain incorrect for {}".format(component)
1354
+ for space1, space2 in zip(domain, prototype_spaces):
1355
+ assert set(space1.keys()) == set(
1356
+ space2.keys()
1357
+ ), "Keys for domain schema of {} is not matched by {} in {} component".format(
1358
+ set(space2.keys()), set(space1.keys()), component
1359
+ )
1360
+
1361
+ codomain = self.components[component](state, params, spaces)
1362
+
1363
+ # Codomain Checking
1364
+ if domain_codomain_checking and codomain:
1365
+ prototype_spaces = self.ms.blocks[component].codomain
1366
+ prototype_spaces = [
1367
+ x.schema for x in prototype_spaces if x.name != "Empty Space"
1368
+ ]
1369
+ assert len(prototype_spaces) == len(
1370
+ codomain
1371
+ ), "Length of codomain incorrect for {}".format(component)
1372
+ for space1, space2 in zip(codomain, prototype_spaces):
1373
+ assert set(space1.keys()) == set(
1374
+ space2.keys()
1375
+ ), "Keys for codomain schema of {} is not matched by {} in {} component".format(
1376
+ set(space2.keys()), set(space1.keys()), component
1377
+ )
1378
+ return codomain
1379
+
1380
+ return wrapper
1381
+
1382
+ for component in self.components:
1383
+
1384
+ self.components_enhanced[component] = create_wrapper(
1385
+ component, self.domain_codomain_checking
1386
+ )
1387
+
1286
1388
  def execute_blocks(self, state, params, blocks):
1287
1389
  for block in blocks:
1288
1390
  self.components[block](state, params, [])
@@ -0,0 +1,33 @@
1
+ from typing import Dict
2
+
3
+
4
+ class Space:
5
+ def __init__(self, data: Dict):
6
+ self.name = data["name"]
7
+ self.schema = data["schema"]
8
+ self.metadata = data["metadata"]
9
+ self.description = data["description"]
10
+ self.name_variable = self.name.replace(" ", "").replace("-", "_")
11
+ self.domain_blocks = []
12
+ self.codomain_blocks = []
13
+
14
+ def __repr__(self):
15
+ return self.name
16
+
17
+
18
+ TerminatingSpace = Space(
19
+ {
20
+ "name": "Terminating Space",
21
+ "schema": {},
22
+ "metadata": {},
23
+ "description": "Built-in space for denoting termination of block",
24
+ }
25
+ )
26
+ EmptySpace = Space(
27
+ {
28
+ "name": "Empty Space",
29
+ "schema": {},
30
+ "metadata": {},
31
+ "description": "Built-in space for denoting returning no data",
32
+ }
33
+ )
@@ -7,3 +7,6 @@ class Type:
7
7
  self.notes = data["notes"]
8
8
  self.metadata = data["metadata"]
9
9
  self.original_type_name = data["original_type_name"]
10
+
11
+ def __repr__(self):
12
+ return self.name
@@ -50,8 +50,14 @@ def convert_action_transmission_channel(
50
50
  data["target"] = ms["Mechanisms"][target]
51
51
 
52
52
  # Add in called by and called here with origin and target
53
- data["origin"].calls.append((data["target"], data["optional"], data["space"]))
54
- data["target"].called_by.append((data["origin"], data["optional"], data["space"]))
53
+ if (data["target"], data["optional"], data["space"]) not in data["origin"].calls:
54
+ data["origin"].calls.append((data["target"], data["optional"], data["space"]))
55
+ if (data["origin"], data["optional"], data["space"]) not in data[
56
+ "target"
57
+ ].called_by:
58
+ data["target"].called_by.append(
59
+ (data["origin"], data["optional"], data["space"])
60
+ )
55
61
 
56
62
  # Build the action transmission channel object
57
63
  return ActionTransmissionChannel(data)
@@ -1,6 +1,6 @@
1
1
  from typing import Dict
2
2
  from ..Classes import BoundaryAction, BoundaryActionOption
3
- from .general import check_json_keys
3
+ from .general import check_json_keys, check_domain_codomain_spaces
4
4
 
5
5
 
6
6
  def convert_boundary_action(data: Dict, ms: Dict) -> BoundaryAction:
@@ -24,6 +24,8 @@ def convert_boundary_action(data: Dict, ms: Dict) -> BoundaryAction:
24
24
  data["name"]
25
25
  )
26
26
 
27
+ check_domain_codomain_spaces(data, ms)
28
+
27
29
  if len(data["codomain"]) == 0:
28
30
  data["codomain"] = ("Empty Space",)
29
31
 
@@ -1,6 +1,6 @@
1
1
  from typing import Dict
2
2
  from ..Classes import ControlAction, ControlActionOption
3
- from .general import check_json_keys
3
+ from .general import check_json_keys, check_domain_codomain_spaces
4
4
 
5
5
 
6
6
  def convert_control_action(data: Dict, ms: Dict) -> ControlAction:
@@ -25,6 +25,8 @@ def convert_control_action(data: Dict, ms: Dict) -> ControlAction:
25
25
  data["name"]
26
26
  )
27
27
 
28
+ check_domain_codomain_spaces(data, ms)
29
+
28
30
  if len(data["codomain"]) == 0:
29
31
  data["codomain"] = ("Empty Space",)
30
32
 
@@ -159,3 +159,12 @@ def check_json_keys(json: Dict, check_set_key: str) -> None:
159
159
 
160
160
  def validate_json_schema(json):
161
161
  validate(json, schema)
162
+
163
+
164
+ def check_domain_codomain_spaces(json: Dict, ms) -> None:
165
+ if "domain" in json:
166
+ for key in json["domain"]:
167
+ assert key in ms["Spaces"], "{} not in spaces".format(key)
168
+ if "codomain" in json:
169
+ for key in json["codomain"]:
170
+ assert key in ms["Spaces"], "{} not in spaces".format(key)
@@ -1,6 +1,6 @@
1
1
  from typing import Dict
2
2
  from ..Classes import Mechanism
3
- from .general import check_json_keys
3
+ from .general import check_json_keys, check_domain_codomain_spaces
4
4
 
5
5
 
6
6
  def convert_mechanism(data: Dict, ms: Dict) -> Mechanism:
@@ -26,6 +26,8 @@ def convert_mechanism(data: Dict, ms: Dict) -> Mechanism:
26
26
  if len(data["domain"]) == 0:
27
27
  data["domain"] = ("Empty Space",)
28
28
 
29
+ check_domain_codomain_spaces(data, ms)
30
+
29
31
  # Copy
30
32
  data = data.copy()
31
33
 
@@ -2,7 +2,7 @@ from typing import Dict
2
2
  from ..Classes import Policy, PolicyOption
3
3
 
4
4
 
5
- from .general import check_json_keys
5
+ from .general import check_json_keys, check_domain_codomain_spaces
6
6
 
7
7
 
8
8
  def convert_policy_options(data: Dict, ms) -> PolicyOption:
@@ -58,6 +58,7 @@ def convert_policy(data: Dict, ms: Dict) -> Policy:
58
58
  assert type(data["domain"]) == tuple, "{} domain is not a tuple".format(
59
59
  data["name"]
60
60
  )
61
+ check_domain_codomain_spaces(data, ms)
61
62
 
62
63
  if len(data["codomain"]) == 0:
63
64
  data["codomain"] = ("Empty Space",)
@@ -20,6 +20,9 @@ def convert_space(ms, data: Dict) -> Space:
20
20
  )
21
21
  data["schema"][x] = ms["Types"][data["schema"][x]]
22
22
 
23
+ if "description" not in data:
24
+ data["description"] = None
25
+
23
26
  # Build the space object
24
27
  return Space(data)
25
28
 
@@ -2,6 +2,18 @@ import ast
2
2
  import os
3
3
 
4
4
 
5
+ def index_to_line_and_column(lines, index):
6
+ cumulative_length = 0
7
+ for line_number, line in enumerate(lines):
8
+ line_length = len(line) + 1 # +1 for the newline character
9
+ if cumulative_length + line_length > index:
10
+ column = index - cumulative_length
11
+ return line_number, column
12
+ cumulative_length += line_length
13
+
14
+ raise ValueError("Index out of range")
15
+
16
+
5
17
  def load_spec_tree(path, ms):
6
18
  tree = {}
7
19
  for folder in [
@@ -61,11 +73,20 @@ def load_spec_tree(path, ms):
61
73
  assert False, "Not implemented for imports that are not import from"
62
74
  elif isinstance(node, ast.ImportFrom):
63
75
  if node.module:
64
- for name in node.names:
65
- file_path = "{}/{}/{}.py".format(path, folder, node.module)
66
- with open(file_path, "r") as file2:
67
- contents = file2.read()
68
- for key in keys:
69
- if key in contents:
70
- tree[folder][key] = os.path.abspath(file_path)
76
+ file_path = "{}/{}/{}.py".format(path, folder, node.module)
77
+
78
+ with open(file_path, "r") as file2:
79
+ contents = file2.read()
80
+ split = contents.split("\n")
81
+ for key in keys:
82
+ if key in contents:
83
+ line_number = (
84
+ index_to_line_and_column(
85
+ split, contents.index(key)
86
+ )[0]
87
+ + 1
88
+ )
89
+ tree[folder][key] = os.path.abspath(
90
+ file_path
91
+ ) + "#L{}".format(line_number)
71
92
  return tree
@@ -40,6 +40,12 @@ def convert_stateful_metric(ms, data: Dict) -> StatefulMetricSet:
40
40
  x[1]
41
41
  )
42
42
 
43
+ assert (
44
+ var["type"] in ms["Types"] or var["type"] in ms["Spaces"]
45
+ ), "{} type/space referenced by {} is not present in math spec".format(
46
+ var["type"], var["name"]
47
+ )
48
+
43
49
  var["implementations"] = {}
44
50
  if "python" in ms["Implementations"]:
45
51
  if "stateful_metrics" in ms["Implementations"]["python"]:
@@ -169,6 +169,13 @@ cssclasses:
169
169
  else:
170
170
  out += symbol3 + "{}".format(var.name) + "\n"
171
171
 
172
+ out += symbol1 + "**Metrics**\n"
173
+ for name in ms.metrics.keys():
174
+ if linking:
175
+ out += symbol2 + "[[{}]]".format(name) + "\n"
176
+ else:
177
+ out += symbol2 + "{}".format(name) + "\n"
178
+
172
179
  out += symbol1 + "**Types**\n"
173
180
  for name in ms.types.keys():
174
181
  if linking:
@@ -221,6 +228,12 @@ cssclasses:
221
228
  out += symbol2 + "[[{}]]".format(name) + "\n"
222
229
  else:
223
230
  out += symbol2 + name + "\n"
231
+ out += symbol1 + "**Wirings**\n"
232
+ for name in ms.wiring.keys():
233
+ if linking:
234
+ out += symbol2 + "[[{}]]".format(name) + "\n"
235
+ else:
236
+ out += symbol2 + name + "\n"
224
237
 
225
238
  if add_tabbing:
226
239
  out = out.split("\n")
@@ -1,6 +1,6 @@
1
1
  import os
2
2
  from .state import write_state_section
3
- from inspect import signature, getsource, getfile
3
+ from inspect import signature, getsource, getfile, getsourcelines
4
4
 
5
5
 
6
6
  def get_source_code(
@@ -16,7 +16,7 @@ def get_source_code(
16
16
  {}```""".format(
17
17
  getsource(code)
18
18
  )
19
- file_path = getfile(code)
19
+ file_path = getfile(code) + "#L{}".format(getsourcelines(code)[1])
20
20
  return source_code, file_path
21
21
 
22
22
 
@@ -67,7 +67,10 @@ def write_entity_markdown_report(ms, path, entity, add_metadata=True):
67
67
 
68
68
 
69
69
  def write_source_code_block(component, text, path):
70
- file_path = component.source_code_location
70
+ if hasattr(component, "source_code_location"):
71
+ file_path = component.source_code_location
72
+ else:
73
+ file_path = component["Source Code Location"]
71
74
  if file_path:
72
75
  file_path = os.path.relpath(file_path, path)
73
76
  text += "## Spec Source Code Location\n\n"
@@ -434,6 +437,13 @@ def write_space_markdown_report(ms, path, space, add_metadata=True):
434
437
  "\n".join(["{}: {}".format(x, metadata[x]) for x in metadata])
435
438
  )
436
439
 
440
+ if space.description:
441
+ out += "## Description"
442
+ out += "\n"
443
+ out += space.description
444
+ out += "\n"
445
+ out += "\n"
446
+
437
447
  out += "## Schema"
438
448
  out += "\n"
439
449
  out += "\n"
@@ -855,6 +865,8 @@ def write_state_variables_markdown_reports(ms, path, state, add_metadata=True):
855
865
  out += "Description: "
856
866
  out += variable.description
857
867
  out += "\n\n"
868
+ out += "Underlying state: [[{}]]".format(state.name)
869
+ out += "\n\n"
858
870
  out += "Type: [["
859
871
  out += variable.type.name
860
872
  out += "]]\n\n"
@@ -939,7 +951,10 @@ def write_wiring_display_markdown_report(ms, path, wiring, add_metadata=True):
939
951
  out += "\n"
940
952
  out += "\n"
941
953
 
942
- with open("{}/Displays/Wiring/{}.md".format(path, wiring["name"]), "w") as f:
954
+ path = "{}/Displays/Wiring/{}.md".format(path, wiring["name"])
955
+ out = write_source_code_block(wiring, out, path)
956
+
957
+ with open(path, "w") as f:
943
958
  f.write(out)
944
959
 
945
960
 
@@ -441,6 +441,9 @@
441
441
  "name": {
442
442
  "type": "string"
443
443
  },
444
+ "description": {
445
+ "type": "string"
446
+ },
444
447
  "schema": {
445
448
  "$ref": "./schema.schema.json/#/definitions/Schema"
446
449
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: math-spec-mapping
3
- Version: 0.3.18
3
+ Version: 0.3.20
4
4
  Summary: A library for easy mapping of mathematical specifications.
5
5
  Author-email: Sean McOwen <Sean@Block.Science>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,18 +0,0 @@
1
- from typing import Dict
2
-
3
-
4
- class Space:
5
- def __init__(self, data: Dict):
6
- self.name = data["name"]
7
- self.schema = data["schema"]
8
- self.metadata = data["metadata"]
9
- self.name_variable = self.name.replace(" ", "").replace("-", "_")
10
- self.domain_blocks = []
11
- self.codomain_blocks = []
12
-
13
- def __repr__(self):
14
- return self.name
15
-
16
-
17
- TerminatingSpace = Space({"name": "Terminating Space", "schema": {}, "metadata": {}})
18
- EmptySpace = Space({"name": "Empty Space", "schema": {}, "metadata": {}})