math-spec-mapping 0.2.6.7__py3-none-any.whl → 0.2.7__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.
@@ -15,3 +15,4 @@ class ControlActionOption:
15
15
  self.name = data["name"]
16
16
  self.description = data["description"]
17
17
  self.logic = data["logic"]
18
+ self.implementations = data["implementations"]
@@ -4,6 +4,7 @@ from .Policy import Policy
4
4
  from .Mechanism import Mechanism
5
5
  from .ControlAction import ControlAction
6
6
  from .BoundaryAction import BoundaryAction
7
+ import os
7
8
 
8
9
 
9
10
  class MathSpec:
@@ -12,6 +13,7 @@ class MathSpec:
12
13
  self._ms_dict = ms_dict
13
14
  self._json = json
14
15
  self.type_keys = ms_dict["Type Keys"]
16
+ self.implementations = ms_dict["Implementations"]
15
17
  self.action_transmission_channels = ms_dict["Action Transmission Channels"]
16
18
  self.boundary_actions = ms_dict["Boundary Actions"]
17
19
  self.control_actions = ms_dict["Control Actions"]
@@ -349,3 +351,99 @@ class MathSpec:
349
351
  for metrics in self.stateful_metrics.values():
350
352
  sm.extend([x.name for x in metrics.metrics])
351
353
  return sm
354
+
355
+ def metaprogramming_python_types(self, model_directory, overwrite=False):
356
+ path = model_directory + "/types.py"
357
+ if not overwrite:
358
+ assert "types.py" not in os.listdir(
359
+ model_directory
360
+ ), "The types file is already written, either delete it or switch to overwrite mode"
361
+ out = "import typing\n\n"
362
+ for t in self.types:
363
+ t = self.types[t]
364
+ assert "python" in t.type, "No python type associated with {}".format(
365
+ t.name
366
+ )
367
+ x = t.type["python"]
368
+ type_desc = x.__name__ if hasattr(x, "__name__") else str(x)
369
+ out += "{} = {}".format(t.original_type_name, type_desc)
370
+ out += "\n"
371
+ with open(path, "w") as f:
372
+ f.write(out)
373
+
374
+ def metaprogramming_python_spaces(self, model_directory, overwrite=False):
375
+ path = model_directory + "/spaces.py"
376
+ if not overwrite:
377
+ assert "spaces.py" not in os.listdir(
378
+ model_directory
379
+ ), "The spaces file is already written, either delete it or switch to overwrite mode"
380
+ unique_spaces = set().union(
381
+ *[set(x.schema.values()) for x in self.spaces.values()]
382
+ )
383
+ unique_types = [x.original_type_name for x in unique_spaces]
384
+ out = ""
385
+ out += "from .types import {}".format(", ".join(unique_types))
386
+ out += "\n"
387
+ out += "from typing import TypedDict"
388
+ out += "\n"
389
+ out += "\n"
390
+
391
+ for space in self.spaces:
392
+ out += self.spaces[space].name_variable
393
+ out += " = "
394
+ d = self.spaces[space].schema
395
+ d = [(x, d[x].original_type_name) for x in d]
396
+ d = ["'{}': {}".format(x[0], x[1]) for x in d]
397
+ d = ", ".join(d)
398
+ d = "{" + d + "}"
399
+ out += "TypedDict('{}', {})".format(self.spaces[space].name, d)
400
+ out += "\n"
401
+
402
+ with open(path, "w") as f:
403
+ f.write(out)
404
+
405
+ def metaprogramming_python_states(
406
+ self, model_directory, overwrite=False, default_values=None
407
+ ):
408
+ path = model_directory + "/states.py"
409
+ if not overwrite:
410
+ assert "states.py" not in os.listdir(
411
+ model_directory
412
+ ), "The states file is already written, either delete it or switch to overwrite mode"
413
+ out = ""
414
+ unique_types = [x.variables for x in self.state.values()]
415
+ unique_types = [set(y.type.original_type_name for y in x) for x in unique_types]
416
+ unique_types = set().union(*unique_types)
417
+ out = ""
418
+ out += "from .types import {}".format(", ".join(unique_types))
419
+ out += "\n"
420
+ out += "from typing import TypedDict"
421
+ out += "\n"
422
+ out += "\n"
423
+
424
+ for state in self.state:
425
+ out += self.state[state].name_variable
426
+ out += " = "
427
+ d = self.state[state].variables
428
+ d = [(x.name, x.type.original_type_name) for x in d]
429
+ d = ["'{}': {}".format(x[0], x[1]) for x in d]
430
+ d = ", ".join(d)
431
+ d = "{" + d + "}"
432
+ out += "TypedDict('{}', {})".format(self.state[state].name, d)
433
+ out += "\n"
434
+ out += "\n"
435
+ out += "state: GlobalState = "
436
+ out += "{"
437
+ for x in self.state["Global State"].variables:
438
+ out += '"{}"'.format(x.name)
439
+ out += ": "
440
+ val = "None"
441
+ if default_values:
442
+ if x.name in default_values:
443
+ val = str(default_values[x.name])
444
+ out += val
445
+ out += ",\n"
446
+ out += "}"
447
+
448
+ with open(path, "w") as f:
449
+ f.write(out)
@@ -10,3 +10,4 @@ class Mechanism(Block):
10
10
  self.logic = data["logic"]
11
11
  self.updates = []
12
12
  self.block_type = "Mechanism"
13
+ self.implementations = data["implementations"]
@@ -7,6 +7,7 @@ class PolicyOption:
7
7
  self.name = data["name"]
8
8
  self.description = data["description"]
9
9
  self.logic = data["logic"]
10
+ self.implementations = data["implementations"]
10
11
 
11
12
 
12
13
  class Policy(Block):
@@ -6,6 +6,7 @@ class Space:
6
6
  self.name = data["name"]
7
7
  self.schema = data["schema"]
8
8
  self.metadata = data["metadata"]
9
+ self.name_variable = self.name.replace(" ", "").replace("-", "_")
9
10
 
10
11
  def __repr__(self):
11
12
  return self.name
@@ -15,6 +15,7 @@ class State:
15
15
  self._write_variable_map()
16
16
  self.updated_by = []
17
17
  self.metadata = data["metadata"]
18
+ self.name_variable = self.name.replace(" ", "").replace("-", "_")
18
19
 
19
20
  def _write_variable_map(self) -> None:
20
21
  """
@@ -6,3 +6,4 @@ class Type:
6
6
  self.type_name = data["type_name"]
7
7
  self.notes = data["notes"]
8
8
  self.metadata = data["metadata"]
9
+ self.original_type_name = data["original_type_name"]
@@ -35,6 +35,16 @@ def convert_control_action(data: Dict, ms: Dict) -> ControlAction:
35
35
  new_cao = []
36
36
  for ca in data["control_action_options"]:
37
37
  check_json_keys(ca, "Control Action Option")
38
+ ca["implementations"] = {}
39
+ if "python" in ms["Implementations"]:
40
+ if "control_action_options" in ms["Implementations"]["python"]:
41
+ if (
42
+ ca["name"]
43
+ in ms["Implementations"]["python"]["control_action_options"]
44
+ ):
45
+ ca["implementations"]["python"] = ms["Implementations"]["python"][
46
+ "control_action_options"
47
+ ][ca["name"]]
38
48
  new_cao.append(ControlActionOption(ca))
39
49
  data["control_action_options"] = new_cao
40
50
 
@@ -42,6 +42,14 @@ def convert_mechanism(data: Dict, ms: Dict) -> Mechanism:
42
42
  )
43
43
 
44
44
  data["domain"] = tuple(ms["Spaces"][x] for x in data["domain"])
45
+ data["implementations"] = {}
46
+
47
+ if "python" in ms["Implementations"]:
48
+ if "mechanisms" in ms["Implementations"]["python"]:
49
+ if data["name"] in ms["Implementations"]["python"]["mechanisms"]:
50
+ data["implementations"]["python"] = ms["Implementations"]["python"][
51
+ "mechanisms"
52
+ ][data["name"]]
45
53
 
46
54
  # Build the action transmission channel object
47
55
  return Mechanism(data), new_channels
@@ -5,7 +5,7 @@ from ..Classes import Policy, PolicyOption
5
5
  from .general import check_json_keys
6
6
 
7
7
 
8
- def convert_policy_options(data: Dict) -> PolicyOption:
8
+ def convert_policy_options(data: Dict, ms) -> PolicyOption:
9
9
  """Function to convert policy options
10
10
 
11
11
  Args:
@@ -21,6 +21,15 @@ def convert_policy_options(data: Dict) -> PolicyOption:
21
21
  # Copy
22
22
  data = data.copy()
23
23
 
24
+ data["implementations"] = {}
25
+
26
+ if "python" in ms["Implementations"]:
27
+ if "policies" in ms["Implementations"]["python"]:
28
+ if data["name"] in ms["Implementations"]["python"]["policies"]:
29
+ data["implementations"]["python"] = ms["Implementations"]["python"][
30
+ "policies"
31
+ ][data["name"]]
32
+
24
33
  # Build the policy object
25
34
  return PolicyOption(data)
26
35
 
@@ -62,7 +71,7 @@ def convert_policy(data: Dict, ms: Dict) -> Policy:
62
71
  # Convert policy options
63
72
  policy_options = []
64
73
  for po in data["policy_options"]:
65
- policy_options.append(convert_policy_options(po))
74
+ policy_options.append(convert_policy_options(po, ms))
66
75
  data["policy_options"] = policy_options
67
76
 
68
77
  data["codomain"] = tuple(ms["Spaces"][x] for x in data["codomain"])
@@ -18,6 +18,7 @@ def convert_type(data, ms):
18
18
  type_name = data["type"]
19
19
  data["type"] = {}
20
20
  data["type_name"] = {}
21
+ data["original_type_name"] = type_name
21
22
 
22
23
  if "python" in ms["Type Keys"]:
23
24
 
@@ -9,6 +9,7 @@ from .node_map import create_action_chains_graph
9
9
  from .parameters import write_out_params
10
10
  from .state import write_local_state_variable_tables, write_global_state_variable_table
11
11
  from typing import List
12
+ import os
12
13
 
13
14
 
14
15
  def write_basic_report_full(ms: MathSpec, directory: str, name: str) -> None:
@@ -128,6 +129,15 @@ def write_spec_tree(
128
129
  symbol3 = "│ │ ├──"
129
130
 
130
131
  out = ""
132
+
133
+ if linking:
134
+ out += """---
135
+ cssclasses:
136
+ - spec
137
+ ---
138
+
139
+ """
140
+
131
141
  out += symbol1 + "**Entities**\n"
132
142
  for name in ms.entities.keys():
133
143
  if linking:
@@ -214,7 +224,29 @@ def write_spec_tree(
214
224
  if path:
215
225
  with open("{}/Spec Tree.md".format(path), "w") as f:
216
226
  f.write(out)
217
- return out
227
+ try:
228
+ if ".obsidian" not in os.listdir(path):
229
+ path = path + "/" + ".obsidian"
230
+ os.mkdir(path)
231
+ else:
232
+ path = path + "/" + ".obsidian"
233
+ if "snippets" not in os.listdir(path):
234
+ path = path + "/" + "snippets"
235
+ os.mkdir(path)
236
+ else:
237
+ path = path + "/" + "snippets"
238
+
239
+ snippet = """.spec {
240
+ font-family: 'Consolas', Courier, monospace ;
241
+ line-height: 1;
242
+ }"""
243
+ with open("{}/spec.css".format(path), "w") as f:
244
+ f.write(snippet)
245
+
246
+ except:
247
+ print("Couldn't find .obsidian/snippets to put snippet in")
248
+ else:
249
+ return out
218
250
 
219
251
 
220
252
  def write_overview(ms: MathSpec, name: str, file_path: str, summary: str = None):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: math-spec-mapping
3
- Version: 0.2.6.7
3
+ Version: 0.2.7
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
@@ -4,18 +4,18 @@ math_spec_mapping/schema.schema.json,sha256=E8-TQIiv7AjIMXnAIB84z_O4cMLfGuDmDCFC
4
4
  math_spec_mapping/Classes/ActionTransmissionChannel.py,sha256=zWMo5QsgPh5WGIWXl-xOrZNMXYJXmK6Vejw1dQvi0og,246
5
5
  math_spec_mapping/Classes/Block.py,sha256=hXQO221IP-TqZm_TwFKfURpEEjZm7L1TPZDCYlaOdho,17302
6
6
  math_spec_mapping/Classes/BoundaryAction.py,sha256=AOENCqCEfpjotnHhzUj_F2SOP0SGpkN1tNPr8Mtl6Tc,476
7
- math_spec_mapping/Classes/ControlAction.py,sha256=xaU3_WVeWOoOFX3O86x30_9Eiirfe76KrO3M2kfjcmo,471
7
+ math_spec_mapping/Classes/ControlAction.py,sha256=ysqpgANwdizVdwqtgZmnxXMpCqrzmVEF_6YT0M3l4Ho,526
8
8
  math_spec_mapping/Classes/Entity.py,sha256=fA0-b128_OHHxfCg4pzqyQV083EYev1HlVpy86S5igg,1226
9
- math_spec_mapping/Classes/MathSpec.py,sha256=P4FPfv6tpbrY1ytmOQ61hXBey83YoCMgMKOpo6xikxU,13230
10
- math_spec_mapping/Classes/Mechanism.py,sha256=7jj6bcPI6H2iv1VZZTlpbG4G2k9s4MYkrH8Sfj9uGM4,324
9
+ math_spec_mapping/Classes/MathSpec.py,sha256=eweFUB8iuEI5Y-9VOULbAWbIeHd18Iw-I_VPUjvnn0E,16999
10
+ math_spec_mapping/Classes/Mechanism.py,sha256=2sLm3wYBIeTQaMBcsJ9btqIWsbS895Ra8NY6Y9_G_Dg,379
11
11
  math_spec_mapping/Classes/Metric.py,sha256=AhPgYppOP6q49xvR8S9STxQsXUKJlTWx7wI1LfZEtww,581
12
12
  math_spec_mapping/Classes/Parameter.py,sha256=ZuJ_w0sChvRElJ4sOnXZ2EV4Ell2xXFulKLjVOpgz2E,1237
13
- math_spec_mapping/Classes/Policy.py,sha256=HUEooO4Liy7olmHwegb6A-hcreNMNCevl9QKKwOjSik,475
14
- math_spec_mapping/Classes/Space.py,sha256=96Cdi8ERkfsgJnh5UyhecKiuU4hWwI6w-i1U1jtwX6A,398
15
- math_spec_mapping/Classes/State.py,sha256=Mdn0D21G198f6q13-2tVBYUbnzhRwoDivWpFtH4XJq0,1423
13
+ math_spec_mapping/Classes/Policy.py,sha256=fzV85tB3QScjiYGfhw_dyQt9L1BYYfTyTIQQcxeT8ac,530
14
+ math_spec_mapping/Classes/Space.py,sha256=QsahxoUfRsDWQLBL683KnGx72MAmRxv7CDE7TMgCG-E,472
15
+ math_spec_mapping/Classes/State.py,sha256=0gJHHTNjTrz1fL2K-yPu-dJlaCsU_NMxClw6neDv6gE,1497
16
16
  math_spec_mapping/Classes/StateUpdateTransmissionChannel.py,sha256=3hBLvD1lE64PkwqksBXAfFWv7foOZzGQLAFQWy42tOA,257
17
17
  math_spec_mapping/Classes/StatefulMetric.py,sha256=UCis1BJ7fsajHHxFF05ZiyDean2D4s4a95uYYW1Mjq4,749
18
- math_spec_mapping/Classes/Type.py,sha256=ZDHSiaDixHOxasOJlHbuBsMjZ29O2O5K_nmHOmlO-Ck,228
18
+ math_spec_mapping/Classes/Type.py,sha256=2KFY8d3cv1PzJJ7SSMHJf1zcfQ3ZbqxotK2KgTaLZdM,289
19
19
  math_spec_mapping/Classes/__init__.py,sha256=_hXyZMJanmIex_W6yCR2H7Jw8iU2JJIf3U7VcvBSOGU,737
20
20
  math_spec_mapping/Convenience/__init__.py,sha256=-hNZVoaNSgTmZTiyZoMfWyg14xonC3ppz-diQk1VlUY,60
21
21
  math_spec_mapping/Convenience/documentation.py,sha256=Jf7-JJIk_vZkNBIGV4bs5LM3B0RVaCCtuwJ164thGfY,1607
@@ -23,27 +23,27 @@ math_spec_mapping/Convenience/starter.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
23
23
  math_spec_mapping/Load/__init__.py,sha256=_ga5nHi7U5rY5lCF36_XI9Qmybq4P8R4m5I5mmjLBk8,33
24
24
  math_spec_mapping/Load/action_transmission_channel.py,sha256=9Wer7g2s5SSOcUYuZ0PqSKUVVnW3EvGQJZNXJTwW__0,2561
25
25
  math_spec_mapping/Load/boundary_actions.py,sha256=WvEj2tqN0pUZtE4EiKUuGzMdAcWsMlLslJJeFjIu6gk,2058
26
- math_spec_mapping/Load/control_actions.py,sha256=VmjezReijEqe9cdPHQubGZTGVPsYbMzWfLu5Dfm9WvY,1563
26
+ math_spec_mapping/Load/control_actions.py,sha256=4E57s730W4tX5SaKXKaAvet37r8Bwt-g8Kk6EanF4TU,2042
27
27
  math_spec_mapping/Load/displays.py,sha256=ooHWT_OryzEkp7F3LcGywwdLMRJLxuyPK82zJ3gcyN0,414
28
28
  math_spec_mapping/Load/entities.py,sha256=rMD_Pja-zqH1Z14rsO_Ia7dg3BIi5_HoQmqGAoEYofA,1208
29
29
  math_spec_mapping/Load/general.py,sha256=2q6aGKxXhebiHHTZhtACvM4nWIkTben0o5rXuvfv2Vw,4463
30
30
  math_spec_mapping/Load/implementations.py,sha256=SGKZ_YXeNpJUTnw5fajQTXji7S2bNQo8sh-7YcIO6pk,395
31
31
  math_spec_mapping/Load/load.py,sha256=CLprDhJpbwm9RAzKM2Ghwr8eqBu0a-wvGDOCMmc01YE,2484
32
- math_spec_mapping/Load/mechanism.py,sha256=aIpMzgQn8f1aywgOHxL5kHQUn1N8K9pmHOVs51bv3Hk,1673
32
+ math_spec_mapping/Load/mechanism.py,sha256=JBy-QpB4W0Z2OcNiakONjD4_RtEgxlFKtLXfDqfhR-0,2037
33
33
  math_spec_mapping/Load/metrics.py,sha256=gD68mt0Y5jSgofZUwscV8PFatOMV_LPwYyPrwV9SdtE,3273
34
34
  math_spec_mapping/Load/parameters.py,sha256=aid_vqYub9643s82NDtMAXLRdV9BPQkri5MadA0L0eQ,1334
35
- math_spec_mapping/Load/policy.py,sha256=fDBuOe1LWw-6C_xcYtvtx9dpjWoD9GNEumW7bK8QaT0,2077
35
+ math_spec_mapping/Load/policy.py,sha256=HvlhGHGJTweVs7DOI2HSL_2_diECr8ukDUmzoFLQELo,2444
36
36
  math_spec_mapping/Load/spaces.py,sha256=7zgGA57Te7T4hfuCCDElffiidWgn1lKm5E14e1yjt8M,1116
37
37
  math_spec_mapping/Load/state_update_transmission_channels.py,sha256=FJWp5n4HdtHAfof5BUQ6BnRakljatL2h8dWCapaVSc0,2238
38
38
  math_spec_mapping/Load/stateful_metrics.py,sha256=uGSTc6x6lld5xptgSUMHrO0Vg0QDRIL14C6zTg33S8o,1977
39
39
  math_spec_mapping/Load/states.py,sha256=cwo29SBAtj1FoQLEb8c0wkSCn038lIgM9RjNiZefUaE,1223
40
- math_spec_mapping/Load/type.py,sha256=R6d5t55TMMCKsOk8xXp_Cu5gvkt2DG4Yzvq6NREIefs,4174
40
+ math_spec_mapping/Load/type.py,sha256=Wq2EYTofuq4v8_jGGSr23IXJjwavLMjsqSEyhX9VoAM,4217
41
41
  math_spec_mapping/Load/wiring.py,sha256=1dR94U5N1W_WI5rL6lYBltH25ZvApB2pIpq9r5Opkug,3083
42
42
  math_spec_mapping/Reports/__init__.py,sha256=W27I6S9Ro1hWeHmnxIokCA06awB__eYey7PvKD4Hc1s,933
43
43
  math_spec_mapping/Reports/boundary_actions.py,sha256=45BPp4QjWdD-3E9ZWwqgj_nI2-YdcI2ZZ19_Qv_K7Qk,1410
44
44
  math_spec_mapping/Reports/control_actions.py,sha256=NksekZKIPFSIkubttFstKFthc5AU9B9PWRLSl9j1wWs,1216
45
45
  math_spec_mapping/Reports/general.py,sha256=WOOn6Wlb8M4fsdN49FlKLwOka6vJPQ9aCUy88TL2ki0,1610
46
- math_spec_mapping/Reports/html.py,sha256=rBnwvWeFgCfP7O8nsBL6hWE63Y1Qd24QyGD2Z7CnZ-8,8094
46
+ math_spec_mapping/Reports/html.py,sha256=xf5jk3DHWg4CfZHZuF2JK5iZ515ecjDShJJsahiqb4g,8882
47
47
  math_spec_mapping/Reports/markdown.py,sha256=pDGHYMdtZmeXHqvU9FB3BycyB4qflWXq0bf2m-wsXMU,21138
48
48
  math_spec_mapping/Reports/mechanisms.py,sha256=d2Rxt3JBYvqAOAYUynl0buYVoXEHrO8EGq7GK6hK8NA,1322
49
49
  math_spec_mapping/Reports/node_map.py,sha256=FdSMDQG16NX6n9sZcH-T5xwsvgjrV9OqBHc9J_VlNK0,3129
@@ -53,8 +53,8 @@ math_spec_mapping/Reports/spaces.py,sha256=-76hR5wQBv4lsG000ypBJ-OprjsNjI-rNRMYd
53
53
  math_spec_mapping/Reports/state.py,sha256=RSHDjzSiUj4ZjReWbkBW7k2njs3Ovp-q0rCC7GBfD-A,2203
54
54
  math_spec_mapping/Reports/tables.py,sha256=O0CNuqh3LMECq5uLjBOoxMUk5hUvkUK660FNnwWUxDY,1505
55
55
  math_spec_mapping/Reports/wiring.py,sha256=u9SvKWy6T-WJUEgFI6-zgZanoOaTTs_2YwmEceDLsV8,1618
56
- math_spec_mapping-0.2.6.7.dist-info/LICENSE,sha256=ObyEzSw8kgCaFbEfpu1zP4TrcAKLA0xhqHMZZfyh7N0,1069
57
- math_spec_mapping-0.2.6.7.dist-info/METADATA,sha256=RCtYITudw1OBgnI8de20W_3kdhG9LUNxZWmCc6A25nY,6014
58
- math_spec_mapping-0.2.6.7.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
59
- math_spec_mapping-0.2.6.7.dist-info/top_level.txt,sha256=AImhn9wgazkdV0a9vfiphtQR8uGe2nq-ZIOp-6yUk9o,18
60
- math_spec_mapping-0.2.6.7.dist-info/RECORD,,
56
+ math_spec_mapping-0.2.7.dist-info/LICENSE,sha256=ObyEzSw8kgCaFbEfpu1zP4TrcAKLA0xhqHMZZfyh7N0,1069
57
+ math_spec_mapping-0.2.7.dist-info/METADATA,sha256=H3plPQQrT7sss_57Z2341oAlBkMpW7_QHihqFoZcgUM,6012
58
+ math_spec_mapping-0.2.7.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
59
+ math_spec_mapping-0.2.7.dist-info/top_level.txt,sha256=AImhn9wgazkdV0a9vfiphtQR8uGe2nq-ZIOp-6yUk9o,18
60
+ math_spec_mapping-0.2.7.dist-info/RECORD,,