math-spec-mapping 0.3.15__py3-none-any.whl → 0.3.17__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.
@@ -69,7 +69,7 @@ class Block:
69
69
 
70
70
  self.find_all_spaces_used(data)
71
71
 
72
- def render_mermaid(self, i):
72
+ def render_mermaid(self, i, go_deep=True):
73
73
  i += 1
74
74
  out = 'X{}["{}"]'.format(i, self.name)
75
75
  if self.block_type == "Mechanism":
@@ -87,7 +87,7 @@ class Block:
87
87
  elif self.block_type in ["Parallel Block", "Stack Block", "Split Block"]:
88
88
  updates = self.all_updates
89
89
  else:
90
- return "\n", {}
90
+ return "\n", {}, 0
91
91
  updates = sorted(updates, key=lambda x: x[0].name + "-" + x[1].name)
92
92
 
93
93
  out = "\n"
@@ -115,18 +115,30 @@ class Block:
115
115
  out += "\n"
116
116
  out += "end\n"
117
117
  out += "\n"
118
- return out, entity_variable_mapping
118
+ return out, entity_variable_mapping, len(entities)
119
119
 
120
- def render_mermaid_root(self):
120
+ def render_mermaid_root(self, go_deep=True):
121
121
  out = """```mermaid\ngraph TB\n"""
122
- add, entity_variable_mapping = self.render_ending_entities()
122
+ add, entity_variable_mapping, n_entities = self.render_ending_entities()
123
123
  out += add
124
- out += self.render_mermaid(0)[0]
124
+ new, i = self.render_mermaid(0, go_deep=go_deep)
125
+ out += new
125
126
 
126
127
  for key in entity_variable_mapping:
127
128
  out = out.replace(key, entity_variable_mapping[key])
128
- out += "\n```"
129
+ out += "\n"
130
+ for x in range(1, i):
131
+ if (
132
+ "X{}[Domain]".format(x) not in out
133
+ and "X{}[Codomain]".format(x) not in out
134
+ and "subgraph X{}".format(x) not in out
135
+ ):
136
+ out += "class X{} internal-link;\n".format(x)
129
137
 
138
+ for x in range(n_entities):
139
+ out += "class EE{} internal-link;\n".format(x)
140
+
141
+ out += "\n```"
130
142
  return out
131
143
 
132
144
  def find_all_spaces_used(self, data):
@@ -223,7 +235,19 @@ class ParallelBlock(Block):
223
235
  self.metadata = data["metadata"]
224
236
  self.find_all_spaces_used(data)
225
237
 
226
- def render_mermaid(self, i):
238
+ def render_mermaid(self, i, go_deep=True):
239
+ if go_deep == "First":
240
+ go_deep = False
241
+ elif go_deep == False:
242
+ i += 1
243
+ out = 'X{}["{}"]'.format(i, self.name)
244
+ for u in self.all_updates:
245
+ out += "\n"
246
+ out += "X{} --> {}".format(
247
+ i,
248
+ (u[0].name + "-" + u[1].name).replace(" ", "-"),
249
+ )
250
+ return out, i
227
251
  multi = None
228
252
  if type(i) == list:
229
253
  multi = i
@@ -251,7 +275,7 @@ class ParallelBlock(Block):
251
275
  if x.name not in ["Empty Space", "Terminating Space"]
252
276
  ]
253
277
 
254
- component, i = component.render_mermaid(i)
278
+ component, i = component.render_mermaid(i, go_deep=go_deep)
255
279
  out += component
256
280
  out += "\n"
257
281
  domain_map[i] = domain
@@ -404,7 +428,19 @@ class StackBlock(Block):
404
428
  )
405
429
  return channels
406
430
 
407
- def render_mermaid(self, i):
431
+ def render_mermaid(self, i, go_deep=True):
432
+ if go_deep == "First":
433
+ go_deep = False
434
+ elif go_deep == False:
435
+ i += 1
436
+ out = 'X{}["{}"]'.format(i, self.name)
437
+ for u in self.all_updates:
438
+ out += "\n"
439
+ out += "X{} --> {}".format(
440
+ i,
441
+ (u[0].name + "-" + u[1].name).replace(" ", "-"),
442
+ )
443
+ return out, i
408
444
  multi = None
409
445
  if type(i) == list:
410
446
  multi = i
@@ -423,7 +459,7 @@ class StackBlock(Block):
423
459
  for x in domain
424
460
  if x.name not in ["Empty Space", "Terminating Space"]
425
461
  ]
426
- component, i = component.render_mermaid(i)
462
+ component, i = component.render_mermaid(i, go_deep=go_deep)
427
463
  domain_map[i] = domain
428
464
  out += component
429
465
  out += "\n"
@@ -535,7 +571,7 @@ class SplitBlock(Block):
535
571
  self.metadata = data["metadata"]
536
572
  self.find_all_spaces_used(data)
537
573
 
538
- def render_mermaid(self, i):
574
+ def render_mermaid(self, i, go_deep=True):
539
575
  multi = None
540
576
  if type(i) == list:
541
577
  multi = i
@@ -8,7 +8,8 @@ import os
8
8
  from copy import deepcopy
9
9
  import shutil
10
10
  import pandas as pd
11
- from inspect import signature, getsource
11
+ from inspect import signature, getsource, getfile
12
+ from IPython.display import display, Markdown
12
13
 
13
14
 
14
15
  class MathSpec:
@@ -1116,13 +1117,34 @@ class MathSpecImplementation:
1116
1117
 
1117
1118
  def load_source_files(self):
1118
1119
  self.source_files = {}
1119
- for key in self.components:
1120
+ self.file_names = {}
1121
+ for key in self.blocks:
1120
1122
  self.source_files[key] = getsource(self.components[key])
1123
+ self.file_names[key] = getfile(self.components[key])
1121
1124
 
1122
- def print_source_code_files(self, keys=None):
1125
+ def print_source_code_files(self, keys=None, markdown=True):
1123
1126
  if not keys:
1124
1127
  keys = list(self.source_files.keys())
1125
1128
  for key in keys:
1129
+ # Skip wirings
1130
+ if key not in self.ms.components:
1131
+ continue
1126
1132
  print("-" * 20 + key + "-" * 20)
1127
- print(self.source_files[key])
1133
+ if markdown:
1134
+ display(
1135
+ Markdown(
1136
+ """```python
1137
+ {}
1138
+ ```""".format(
1139
+ self.source_files[key]
1140
+ )
1141
+ )
1142
+ )
1143
+ else:
1144
+ print(self.source_files[key])
1145
+ print("\n")
1146
+ full_path = self.file_names[key]
1147
+ print("File path: {}".format(full_path))
1148
+ relative_path = "./" + os.path.relpath(full_path, os.getcwd())
1149
+ print("Relative file path: {}".format(relative_path))
1128
1150
  print("\n\n\n")
@@ -1,3 +1,8 @@
1
1
  # from .documentation import write_top_level_json_description
2
2
  from .starter import remove_dummy_repo_components
3
- from .github import write_scaffold_to_github_issues
3
+ from .github import (
4
+ write_scaffold_to_github_issues,
5
+ find_open_issues,
6
+ create_priority_label_matrix,
7
+ create_milestone_label_matrix,
8
+ )
@@ -1,5 +1,8 @@
1
1
  import os
2
2
  import requests
3
+ from github import Github, Auth
4
+ import pandas as pd
5
+ from dotenv import load_dotenv
3
6
 
4
7
 
5
8
  def write_scaffold_to_github_issues(
@@ -32,3 +35,74 @@ def write_scaffold_to_github_issues(
32
35
  headers=headers,
33
36
  json={"title": issue_name, "body": checklist},
34
37
  )
38
+
39
+
40
+ def find_open_issues():
41
+ load_dotenv()
42
+ g = Github(auth=Auth.Token(os.getenv("GITHUB_TOKEN")))
43
+ repo = g.get_repo("BlockScience/MSML")
44
+ open_issues = repo.get_issues(state="open")
45
+ open_issues = list(open_issues)
46
+
47
+ df = pd.DataFrame(
48
+ [[x.title, x.labels, x.html_url, x.milestone] for x in open_issues],
49
+ columns=["Name", "Labels", "URL", "Milestone"],
50
+ )
51
+ df["Milestone"] = df["Milestone"].apply(lambda x: x.title if x else None)
52
+ df = df.join(
53
+ df["Labels"]
54
+ .apply(lambda x: {y.name: True for y in x})
55
+ .apply(pd.Series)
56
+ .fillna(False)
57
+ )
58
+
59
+ empty = df[df["Labels"].apply(lambda x: len(x)) == 0]
60
+ empty = empty[~empty["URL"].str.contains("MSML/pull")]
61
+ assert len(empty) == 0, "Some issues do not have labels"
62
+
63
+ return df, open_issues
64
+
65
+
66
+ def create_priority_label_matrix(df, exclude_milestones=None):
67
+ if exclude_milestones:
68
+ df = df[~df["Milestone"].isin(exclude_milestones)]
69
+ priority_labels = ["High Priority", "Medium Priority", "Low Priority"]
70
+ labels = list(df.columns[4:])
71
+ labels = sorted([x for x in labels if x not in priority_labels])
72
+
73
+ table = []
74
+ for label in labels:
75
+ row = []
76
+ for priority in priority_labels:
77
+ row.append(df[(df[priority]) & (df[label])])
78
+ table.append(row)
79
+ table = pd.DataFrame(table, index=labels, columns=priority_labels)
80
+ table = table.applymap(
81
+ lambda y: "\n".join(
82
+ y.apply(lambda x: "[{}]({})".format(x["Name"], x["URL"]), axis=1).values
83
+ )
84
+ )
85
+ return table
86
+
87
+
88
+ def create_milestone_label_matrix(df, exclude_milestones=None):
89
+ if exclude_milestones:
90
+ df = df[~df["Milestone"].isin(exclude_milestones)]
91
+ priority_labels = ["High Priority", "Medium Priority", "Low Priority"]
92
+ labels = list(df.columns[4:])
93
+ labels = sorted([x for x in labels if x not in priority_labels])
94
+ milestones = sorted(list(df[~pd.isnull(df["Milestone"])]["Milestone"].unique()))
95
+
96
+ table = []
97
+ for label in labels:
98
+ row = []
99
+ for milestone in milestones:
100
+ row.append(df[(df["Milestone"] == milestone) & (df[label])])
101
+ table.append(row)
102
+ table = pd.DataFrame(table, index=labels, columns=milestones)
103
+ table = table.applymap(
104
+ lambda y: "\n".join(
105
+ y.apply(lambda x: "[{}]({})".format(x["Name"], x["URL"]), axis=1).values
106
+ )
107
+ )
108
+ return table
@@ -1,5 +1,19 @@
1
1
  import os
2
2
  from .state import write_state_section
3
+ from inspect import signature, getsource, getfile
4
+
5
+
6
+ def get_source_code(ms, component_type, implementation_name):
7
+ if implementation_name in ms.implementations["python"][component_type]:
8
+ code = ms.implementations["python"][component_type][implementation_name]
9
+ else:
10
+ return None
11
+ source_code = """```python
12
+ {}```""".format(
13
+ getsource(code)
14
+ )
15
+ file_path = getfile(code)
16
+ return source_code, file_path
3
17
 
4
18
 
5
19
  def write_entity_markdown_report(ms, path, entity, add_metadata=True):
@@ -179,7 +193,23 @@ def write_boundary_action_markdown_report(ms, path, boundary_action, add_metadat
179
193
 
180
194
  out += "#### Logic\n"
181
195
  out += x.logic
182
- out += "\n\n"
196
+ out += "\n"
197
+
198
+ temp = get_source_code(ms, "boundary_action_options", x.name)
199
+ if temp:
200
+ source_code, file_path = temp
201
+ file_path = os.path.relpath(
202
+ file_path, "{}/Boundary Actions".format(path)
203
+ )
204
+ out += "#### Python Implementation\n"
205
+ out += source_code
206
+ out += "\n"
207
+ out += "Implementation Path (only works if vault is opened at level including the src folder): [{}]({})".format(
208
+ file_path, file_path
209
+ )
210
+ out += "\n"
211
+
212
+ out += "\n"
183
213
 
184
214
  with open(
185
215
  "{}/Boundary Actions/{}.md".format(path, boundary_action.label), "w"
@@ -256,7 +286,21 @@ def write_policy_markdown_report(ms, path, policy, add_metadata=True):
256
286
 
257
287
  out += "#### Logic\n"
258
288
  out += x.logic
259
- out += "\n\n"
289
+ out += "\n"
290
+
291
+ temp = get_source_code(ms, "policies", x.name)
292
+ if temp:
293
+ source_code, file_path = temp
294
+ file_path = os.path.relpath(file_path, "{}/Policies".format(path))
295
+ out += "#### Python Implementation\n"
296
+ out += source_code
297
+ out += "\n"
298
+ out += "Implementation Path (only works if vault is opened at level including the src folder): [{}]({})".format(
299
+ file_path, file_path
300
+ )
301
+ out += "\n"
302
+
303
+ out += "\n"
260
304
 
261
305
  with open("{}/Policies/{}.md".format(path, policy.label), "w") as f:
262
306
  f.write(out)
@@ -323,6 +367,20 @@ def write_mechanism_markdown_report(ms, path, mechanism, add_metadata=True):
323
367
  )
324
368
  out += "\n"
325
369
 
370
+ temp = get_source_code(ms, "mechanisms", mechanism.name)
371
+ if temp:
372
+ source_code, file_path = temp
373
+ file_path = os.path.relpath(file_path, "{}/Mechanisms".format(path))
374
+ out += "## Python Implementation\n"
375
+ out += source_code
376
+ out += "\n"
377
+ out += "Implementation Path (only works if vault is opened at level including the src folder): [{}]({})".format(
378
+ file_path, file_path
379
+ )
380
+ out += "\n"
381
+
382
+ out += "\n"
383
+
326
384
  with open("{}/Mechanisms/{}.md".format(path, mechanism.label), "w") as f:
327
385
  f.write(out)
328
386
 
@@ -434,7 +492,23 @@ def write_control_action_markdown_report(ms, path, control_action, add_metadata=
434
492
 
435
493
  out += "#### Logic\n"
436
494
  out += x.logic
437
- out += "\n\n"
495
+ out += "\n"
496
+
497
+ temp = get_source_code(ms, "control_action_options", x.name)
498
+ if temp:
499
+ source_code, file_path = temp
500
+ file_path = os.path.relpath(
501
+ file_path, "{}/Control Actions".format(path)
502
+ )
503
+ out += "#### Python Implementation\n"
504
+ out += source_code
505
+ out += "\n"
506
+ out += "Implementation Path (only works if vault is opened at level including the src folder): [{}]({})".format(
507
+ file_path, file_path
508
+ )
509
+ out += "\n"
510
+
511
+ out += "\n"
438
512
 
439
513
  with open("{}/Control Actions/{}.md".format(path, control_action.label), "w") as f:
440
514
  f.write(out)
@@ -454,6 +528,13 @@ def write_wiring_markdown_report(ms, path, wiring, add_metadata=True):
454
528
  """.format(
455
529
  "\n".join(["{}: {}".format(x, metadata[x]) for x in metadata])
456
530
  )
531
+ out += "## Wiring Diagram (Zoomed Out)"
532
+ out += "\n"
533
+ out += "\n"
534
+ out += "- For display of only depth of 1 in the components/nested wirings\n"
535
+ out += wiring.render_mermaid_root(go_deep="First")
536
+ out += "\n"
537
+ out += "\n"
457
538
 
458
539
  out += "## Wiring Diagram"
459
540
  out += "\n"
@@ -707,6 +788,12 @@ def write_state_variables_markdown_reports(ms, path, state, add_metadata=True):
707
788
  out += variable.domain
708
789
  out += "\n\n"
709
790
 
791
+ out += "Updated By:\n"
792
+ for i, x in enumerate(sorted(variable.updated_by, key=lambda x: x.name)):
793
+ out += "{}. [[{}]]".format(i + 1, x.name)
794
+ out += "\n"
795
+ out += "\n"
796
+
710
797
  with open(
711
798
  "{}/State Variables/{}.md".format(
712
799
  path, "{}-{}".format(state.name, variable.name)
@@ -30,6 +30,12 @@ from .Reports import (
30
30
  write_parameter_table_markdown,
31
31
  )
32
32
  from .schema import schema
33
- from .Convenience import remove_dummy_repo_components, write_scaffold_to_github_issues
33
+ from .Convenience import (
34
+ remove_dummy_repo_components,
35
+ write_scaffold_to_github_issues,
36
+ find_open_issues,
37
+ create_priority_label_matrix,
38
+ create_milestone_label_matrix,
39
+ )
34
40
 
35
41
  # from .Convenience import write_top_level_json_description
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: math-spec-mapping
3
- Version: 0.3.15
3
+ Version: 0.3.17
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,12 +1,12 @@
1
- math_spec_mapping/__init__.py,sha256=LvuIbfILQf3UGyHympLJyncfnnpZpEyvN5UDOpi8bWw,1140
1
+ math_spec_mapping/__init__.py,sha256=uuz8qXGzsumq0W4-iAIw2w-xxyI10PhbNlGGQ9MxR60,1244
2
2
  math_spec_mapping/schema.py,sha256=6mrRqzEnTTSXjb19xJ63MBp0KjKH0s7i6TfT4MkAY9k,233
3
3
  math_spec_mapping/schema.schema.json,sha256=hJP2TcV5WPFPmx4u_A5U1xtnpkE1LeYaTeYOXadTot0,30916
4
4
  math_spec_mapping/Classes/ActionTransmissionChannel.py,sha256=zWMo5QsgPh5WGIWXl-xOrZNMXYJXmK6Vejw1dQvi0og,246
5
- math_spec_mapping/Classes/Block.py,sha256=geaH3cNPJ-BOSj1pqccexFl6FqmolAFbrb7wpQQqaUE,18215
5
+ math_spec_mapping/Classes/Block.py,sha256=x5eYzuWp6C_n1tUVMxECpdYi4w_Tv0NLyxg0m8pHjMo,19602
6
6
  math_spec_mapping/Classes/BoundaryAction.py,sha256=_rFvEZ4LNxmlM59js4SuQ9n5CgVmITw4YWKs0-q0r-4,560
7
7
  math_spec_mapping/Classes/ControlAction.py,sha256=4AzMSA8fbnUf-fGlvMJXHJFbz32G1h1QVWf2yzrXrLA,493
8
8
  math_spec_mapping/Classes/Entity.py,sha256=fA0-b128_OHHxfCg4pzqyQV083EYev1HlVpy86S5igg,1226
9
- math_spec_mapping/Classes/MathSpec.py,sha256=94cJsKpdcBj_jzlQhNYnNBJQyBVOI-RrNHuWHdbieUs,42637
9
+ math_spec_mapping/Classes/MathSpec.py,sha256=jOWfO5mx_7RjAy4SF9Faiw-tGEhL2HeyzV9lKk0pVDQ,43432
10
10
  math_spec_mapping/Classes/Mechanism.py,sha256=2sLm3wYBIeTQaMBcsJ9btqIWsbS895Ra8NY6Y9_G_Dg,379
11
11
  math_spec_mapping/Classes/Metric.py,sha256=iQhH4g8Z60QlM22nPX9ytGmidOsZSiSs0KjqwmsScwU,636
12
12
  math_spec_mapping/Classes/Parameter.py,sha256=ZuJ_w0sChvRElJ4sOnXZ2EV4Ell2xXFulKLjVOpgz2E,1237
@@ -17,9 +17,9 @@ math_spec_mapping/Classes/StateUpdateTransmissionChannel.py,sha256=3hBLvD1lE64Pk
17
17
  math_spec_mapping/Classes/StatefulMetric.py,sha256=plMFMAFEk1y2t4DR5lA2SRC9UrYArsx_W33l3mZSdgE,804
18
18
  math_spec_mapping/Classes/Type.py,sha256=2KFY8d3cv1PzJJ7SSMHJf1zcfQ3ZbqxotK2KgTaLZdM,289
19
19
  math_spec_mapping/Classes/__init__.py,sha256=0zxgOqns_9JybD74HKMVh6aw8ij8WVbfQ4Q_1uWzof0,761
20
- math_spec_mapping/Convenience/__init__.py,sha256=P8WgrbpJkH08GeyOdhF-ITfT4Yd4ny8QJEvZK0fSljc,164
20
+ math_spec_mapping/Convenience/__init__.py,sha256=BEZr1rXohKAknOa3wjNVx3EvSVxDcfftJsvtSw5mvmQ,264
21
21
  math_spec_mapping/Convenience/documentation.py,sha256=1ziWVJznbCUxeAAt03nAdEYtMlXNo5TeedHfgs0vSBU,1625
22
- math_spec_mapping/Convenience/github.py,sha256=mMOhIH3Nvh_91fNTOPjz1oQq1iDq2m5hNLMhtcrr5FU,1025
22
+ math_spec_mapping/Convenience/github.py,sha256=Wddr1FCxcIxaFeiKyvx3mvVDbzjcgTxs4rU8ulc4qXk,3539
23
23
  math_spec_mapping/Convenience/starter.py,sha256=9dBKU3EHscut2wA6Nx1XUmehrFIdr4dCjP9V1BbTF6s,12567
24
24
  math_spec_mapping/Load/__init__.py,sha256=_ga5nHi7U5rY5lCF36_XI9Qmybq4P8R4m5I5mmjLBk8,33
25
25
  math_spec_mapping/Load/action_transmission_channel.py,sha256=9Wer7g2s5SSOcUYuZ0PqSKUVVnW3EvGQJZNXJTwW__0,2561
@@ -45,7 +45,7 @@ math_spec_mapping/Reports/boundary_actions.py,sha256=45BPp4QjWdD-3E9ZWwqgj_nI2-Y
45
45
  math_spec_mapping/Reports/control_actions.py,sha256=NksekZKIPFSIkubttFstKFthc5AU9B9PWRLSl9j1wWs,1216
46
46
  math_spec_mapping/Reports/general.py,sha256=WOOn6Wlb8M4fsdN49FlKLwOka6vJPQ9aCUy88TL2ki0,1610
47
47
  math_spec_mapping/Reports/html.py,sha256=RpyQQON8pDnMmfcyxOsm8UAD5Ad8VKnnW-OyOarTmzA,9711
48
- math_spec_mapping/Reports/markdown.py,sha256=oLammMJMkWhZXmODKzCuZDdJpiJIs5P-84gVsYhs0Rw,24605
48
+ math_spec_mapping/Reports/markdown.py,sha256=DG0DmzE6Pas5dLLjbSnGa0xmWSFz0IGLa0sT_1MgYvI,27804
49
49
  math_spec_mapping/Reports/mechanisms.py,sha256=d2Rxt3JBYvqAOAYUynl0buYVoXEHrO8EGq7GK6hK8NA,1322
50
50
  math_spec_mapping/Reports/node_map.py,sha256=FdSMDQG16NX6n9sZcH-T5xwsvgjrV9OqBHc9J_VlNK0,3129
51
51
  math_spec_mapping/Reports/parameters.py,sha256=-ucL71lolqU0xvV7yb0sXl4pFMRl5tXNWdoBfUjLOaQ,1944
@@ -54,8 +54,8 @@ math_spec_mapping/Reports/spaces.py,sha256=-76hR5wQBv4lsG000ypBJ-OprjsNjI-rNRMYd
54
54
  math_spec_mapping/Reports/state.py,sha256=QYeCvX5cHeZBrbvMeDsTqJcUDTuDFJSLvPbasjLspk8,3643
55
55
  math_spec_mapping/Reports/tables.py,sha256=O0CNuqh3LMECq5uLjBOoxMUk5hUvkUK660FNnwWUxDY,1505
56
56
  math_spec_mapping/Reports/wiring.py,sha256=u9SvKWy6T-WJUEgFI6-zgZanoOaTTs_2YwmEceDLsV8,1618
57
- math_spec_mapping-0.3.15.dist-info/LICENSE,sha256=ObyEzSw8kgCaFbEfpu1zP4TrcAKLA0xhqHMZZfyh7N0,1069
58
- math_spec_mapping-0.3.15.dist-info/METADATA,sha256=H3FF0wDPZ2BUneG-JTOGfaGh8Z24tr2tgLlfOqe67Y4,6498
59
- math_spec_mapping-0.3.15.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
60
- math_spec_mapping-0.3.15.dist-info/top_level.txt,sha256=AImhn9wgazkdV0a9vfiphtQR8uGe2nq-ZIOp-6yUk9o,18
61
- math_spec_mapping-0.3.15.dist-info/RECORD,,
57
+ math_spec_mapping-0.3.17.dist-info/LICENSE,sha256=ObyEzSw8kgCaFbEfpu1zP4TrcAKLA0xhqHMZZfyh7N0,1069
58
+ math_spec_mapping-0.3.17.dist-info/METADATA,sha256=niURiLlRa8ejIvpDjiOcvg1jFeanlxz-76-Mb1joMsU,6498
59
+ math_spec_mapping-0.3.17.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
60
+ math_spec_mapping-0.3.17.dist-info/top_level.txt,sha256=AImhn9wgazkdV0a9vfiphtQR8uGe2nq-ZIOp-6yUk9o,18
61
+ math_spec_mapping-0.3.17.dist-info/RECORD,,