steer-core 0.1.16__py3-none-any.whl → 0.1.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.
@@ -0,0 +1,149 @@
1
+ import plotly.graph_objects as go
2
+ from typing import Dict, Any, Tuple, List, Union
3
+
4
+
5
+ class PlotterMixin:
6
+
7
+ @staticmethod
8
+ def plot_breakdown_sunburst(
9
+ breakdown_dict: Dict[str, Any],
10
+ title: str = "Breakdown",
11
+ root_label: str = "Total",
12
+ unit: str = "",
13
+ **kwargs,
14
+ ) -> go.Figure:
15
+ """
16
+ Create a sunburst plot for any generic nested breakdown dictionary.
17
+
18
+ Parameters
19
+ ----------
20
+ breakdown_dict : Dict[str, Any]
21
+ Nested dictionary where values can be either numbers or nested dictionaries.
22
+ Each nesting level becomes a ring in the sunburst plot.
23
+ title : str, optional
24
+ Title for the plot. Defaults to "Breakdown".
25
+ root_label : str, optional
26
+ Label for the root node. Defaults to "Total".
27
+ unit : str, optional
28
+ Unit string to display in hover text (e.g., "g", "kg", "%"). Defaults to "".
29
+
30
+ Returns
31
+ -------
32
+ go.Figure
33
+ Plotly sunburst figure
34
+ """
35
+
36
+ def _flatten_breakdown_values(data: Dict[str, Any]) -> List[float]:
37
+ """Recursively flatten all numeric values from nested breakdown dictionary"""
38
+ values = []
39
+ for value in data.values():
40
+ if isinstance(value, dict):
41
+ values.extend(_flatten_breakdown_values(value))
42
+ elif isinstance(value, (int, float)):
43
+ values.append(float(value))
44
+ return values
45
+
46
+ def _calculate_subtotal(data: Dict[str, Any]) -> float:
47
+ """Calculate the total value for a dictionary (sum of all nested numeric values)"""
48
+ total = 0.0
49
+ for value in data.values():
50
+ if isinstance(value, dict):
51
+ total += _calculate_subtotal(value)
52
+ elif isinstance(value, (int, float)):
53
+ total += float(value)
54
+ return total
55
+
56
+ def _prepare_sunburst_data(
57
+ data: Dict[str, Any], parent_id: str = "", current_path: str = ""
58
+ ) -> Tuple[List[str], List[str], List[str], List[float]]:
59
+ """Recursively prepare data for sunburst plot with proper hierarchy"""
60
+ ids = []
61
+ labels = []
62
+ parents = []
63
+ values = []
64
+
65
+ for key, value in data.items():
66
+ # Create unique ID for this node
67
+ node_id = f"{current_path}/{key}" if current_path else key
68
+
69
+ ids.append(node_id)
70
+ labels.append(key)
71
+ parents.append(parent_id)
72
+
73
+ if isinstance(value, dict):
74
+ # This is a nested dictionary - calculate its total value
75
+ subtotal = _calculate_subtotal(value)
76
+ values.append(subtotal)
77
+
78
+ # Recursively process nested dictionary
79
+ (
80
+ nested_ids,
81
+ nested_labels,
82
+ nested_parents,
83
+ nested_values,
84
+ ) = _prepare_sunburst_data(
85
+ value, parent_id=node_id, current_path=node_id
86
+ )
87
+
88
+ # Add nested data to our lists
89
+ ids.extend(nested_ids)
90
+ labels.extend(nested_labels)
91
+ parents.extend(nested_parents)
92
+ values.extend(nested_values)
93
+
94
+ elif isinstance(value, (int, float)):
95
+ # This is a leaf node with a numeric value
96
+ values.append(float(value))
97
+
98
+ return ids, labels, parents, values
99
+
100
+ # Calculate total value for root node
101
+ total_value = _calculate_subtotal(breakdown_dict)
102
+
103
+ # Prepare hierarchical data starting with root
104
+ ids, labels, parents, values = _prepare_sunburst_data(
105
+ breakdown_dict, parent_id=""
106
+ )
107
+
108
+ # Add root node at the beginning
109
+ ids.insert(0, root_label)
110
+ labels.insert(0, root_label)
111
+ parents.insert(0, "")
112
+ values.insert(0, total_value)
113
+
114
+ # Update parent references to point to root
115
+ for i in range(1, len(parents)):
116
+ if parents[i] == "":
117
+ parents[i] = root_label
118
+
119
+ # Create custom hover text with percentages
120
+ hover_text = []
121
+ for i, (label, value) in enumerate(zip(labels, values)):
122
+ if label == root_label:
123
+ unit_str = f" {unit}" if unit else ""
124
+ hover_text.append(f"<b>{root_label}</b><br>{value:.2f}{unit_str}")
125
+ else:
126
+ percentage = (value / total_value * 100) if total_value > 0 else 0
127
+ unit_str = f" {unit}" if unit else ""
128
+ hover_text.append(
129
+ f"<b>{label}</b><br>{value:.2f}{unit_str}<br>{percentage:.1f}% of total"
130
+ )
131
+
132
+ # Create the sunburst plot
133
+ fig = go.Figure(
134
+ go.Sunburst(
135
+ ids=ids,
136
+ labels=labels,
137
+ parents=parents,
138
+ values=values,
139
+ branchvalues="total",
140
+ hovertemplate="%{customdata}<extra></extra>",
141
+ customdata=hover_text,
142
+ )
143
+ )
144
+
145
+ fig.update_layout(
146
+ title=dict(text=title, x=0.5, font=dict(size=16)), font_size=12, **kwargs
147
+ )
148
+
149
+ return fig
@@ -5,24 +5,23 @@ from copy import deepcopy
5
5
 
6
6
 
7
7
  class SerializerMixin:
8
-
9
8
  def serialize(self) -> str:
10
9
  """
11
10
  Serialize an object to a string representation.
12
-
11
+
13
12
  Parameters
14
13
  ----------
15
14
  obj : Type
16
15
  The object to serialize.
17
-
16
+
18
17
  Returns
19
18
  -------
20
19
  str
21
20
  The serialized string representation of the object.
22
21
  """
23
22
  pickled = dumps(self)
24
- based = base64.b64encode(pickled).decode('utf-8')
25
- return based
23
+ based = base64.b64encode(pickled).decode("utf-8")
24
+ return based
26
25
 
27
26
  @staticmethod
28
27
  def deserialize(String: str) -> Type:
@@ -39,7 +38,6 @@ class SerializerMixin:
39
38
  SerializerMixin
40
39
  The deserialized object.
41
40
  """
42
- decoded = base64.b64decode(String.encode('utf-8'))
41
+ decoded = base64.b64decode(String.encode("utf-8"))
43
42
  obj = deepcopy(loads(decoded))
44
43
  return obj
45
-
@@ -3,14 +3,10 @@ import pandas as pd
3
3
  import numpy as np
4
4
 
5
5
 
6
- ALLOWED_REFERENCE = [
7
- 'Na/Na+',
8
- 'Li/Li+'
9
- ]
6
+ ALLOWED_REFERENCE = ["Na/Na+", "Li/Li+"]
10
7
 
11
8
 
12
9
  class ValidationMixin:
13
-
14
10
  @staticmethod
15
11
  def validate_type(value: Type, expected_type: Type, name: str) -> None:
16
12
  """
@@ -31,7 +27,9 @@ class ValidationMixin:
31
27
  If the value is not of the expected type.
32
28
  """
33
29
  if not isinstance(value, expected_type):
34
- raise TypeError(f"{name} must be of type {expected_type.__name__}. Provided: {type(value).__name__}.")
30
+ raise TypeError(
31
+ f"{name} must be of type {expected_type.__name__}. Provided: {type(value).__name__}."
32
+ )
35
33
 
36
34
  @staticmethod
37
35
  def validate_percentage(value: float, name: str) -> None:
@@ -54,7 +52,9 @@ class ValidationMixin:
54
52
  raise TypeError(f"{name} must be a number. Provided: {value}.")
55
53
 
56
54
  if not (0 <= value <= 100):
57
- raise ValueError(f"{name} must be a percentage between 0 and 100. Provided: {value}.")
55
+ raise ValueError(
56
+ f"{name} must be a percentage between 0 and 100. Provided: {value}."
57
+ )
58
58
 
59
59
  @staticmethod
60
60
  def validate_fraction(value: float, name: str) -> None:
@@ -74,13 +74,13 @@ class ValidationMixin:
74
74
  If the value is not a fraction.
75
75
  """
76
76
  if not (0 <= value <= 1):
77
- raise ValueError(f"{name} must be a fraction between 0 and 1. Provided: {value}.")
77
+ raise ValueError(
78
+ f"{name} must be a fraction between 0 and 1. Provided: {value}."
79
+ )
78
80
 
79
81
  @staticmethod
80
82
  def validate_pandas_dataframe(
81
- df: pd.DataFrame,
82
- name: str,
83
- column_names: list = None
83
+ df: pd.DataFrame, name: str, column_names: list = None
84
84
  ) -> None:
85
85
  """
86
86
  Validate that the input is a pandas DataFrame.
@@ -103,8 +103,10 @@ class ValidationMixin:
103
103
  if column_names is not None:
104
104
  missing_columns = [col for col in column_names if col not in df.columns]
105
105
  if missing_columns:
106
- raise ValueError(f"{name} is missing required columns: {missing_columns}. "
107
- f"Available columns: {df.columns.tolist()}.")
106
+ raise ValueError(
107
+ f"{name} is missing required columns: {missing_columns}. "
108
+ f"Available columns: {df.columns.tolist()}."
109
+ )
108
110
 
109
111
  @staticmethod
110
112
  def validate_electrochemical_reference(reference: str) -> None:
@@ -124,8 +126,10 @@ class ValidationMixin:
124
126
  ValidationMixin.validate_string(reference, "Electrochemical reference")
125
127
 
126
128
  if reference not in ALLOWED_REFERENCE:
127
- raise ValueError(f"Invalid electrochemical reference: {reference}. "
128
- f"Must be one of {ALLOWED_REFERENCE}.")
129
+ raise ValueError(
130
+ f"Invalid electrochemical reference: {reference}. "
131
+ f"Must be one of {ALLOWED_REFERENCE}."
132
+ )
129
133
 
130
134
  @staticmethod
131
135
  def validate_datum(datum: np.ndarray) -> None:
@@ -144,10 +148,10 @@ class ValidationMixin:
144
148
  """
145
149
  if type(datum) is not tuple and len(datum) != 3:
146
150
  raise ValueError("Datum must be a 3D point with exactly 3 coordinates.")
147
-
151
+
148
152
  if not all(isinstance(coord, (int, float)) for coord in datum):
149
153
  raise TypeError("All coordinates in datum must be numbers.")
150
-
154
+
151
155
  @staticmethod
152
156
  def validate_positive_float(value: float, name: str) -> None:
153
157
  """
@@ -167,7 +171,7 @@ class ValidationMixin:
167
171
  """
168
172
  if not isinstance(value, (int, float)):
169
173
  raise ValueError(f"{name} must be a positive float. Provided: {value}.")
170
-
174
+
171
175
  @staticmethod
172
176
  def validate_string(value: str, name: str) -> None:
173
177
  """
@@ -187,7 +191,7 @@ class ValidationMixin:
187
191
  """
188
192
  if not isinstance(value, str):
189
193
  raise TypeError(f"{name} must be a string. Provided: {value}.")
190
-
194
+
191
195
  @staticmethod
192
196
  def validate_two_iterable_of_floats(value: tuple, name: str) -> None:
193
197
  """
@@ -207,16 +211,22 @@ class ValidationMixin:
207
211
  """
208
212
  # Accept both tuples and lists
209
213
  if not isinstance(value, (tuple, list)) or len(value) != 2:
210
- raise TypeError(f"{name} must be a tuple or list of two numbers. Provided: {value}.")
211
-
214
+ raise TypeError(
215
+ f"{name} must be a tuple or list of two numbers. Provided: {value}."
216
+ )
217
+
212
218
  # Check if all values are numeric (int or float)
213
219
  if not all(isinstance(v, (int, float)) for v in value):
214
- raise TypeError(f"{name} must be a tuple or list of two numbers. Provided: {value}.")
215
-
220
+ raise TypeError(
221
+ f"{name} must be a tuple or list of two numbers. Provided: {value}."
222
+ )
223
+
216
224
  # Check if all values are non-negative
217
225
  if not all(v >= 0 for v in value):
218
- raise ValueError(f"{name} must be a tuple or list of two non-negative numbers. Provided: {value}.")
219
-
226
+ raise ValueError(
227
+ f"{name} must be a tuple or list of two non-negative numbers. Provided: {value}."
228
+ )
229
+
220
230
  @staticmethod
221
231
  def validate_positive_float_list(value: list, name: str) -> None:
222
232
  """
@@ -234,9 +244,12 @@ class ValidationMixin:
234
244
  TypeError
235
245
  If the value is not a list of positive floats.
236
246
  """
237
- if not isinstance(value, list) or not all(isinstance(v, (int, float)) and v > 0 for v in value):
238
- raise TypeError(f"{name} must be a list of positive floats. Provided: {value}.")
239
-
247
+ if not isinstance(value, list) or not all(
248
+ isinstance(v, (int, float)) and v > 0 for v in value
249
+ ):
250
+ raise TypeError(
251
+ f"{name} must be a list of positive floats. Provided: {value}."
252
+ )
253
+
240
254
  if len(value) == 0:
241
255
  raise ValueError(f"{name} must not be an empty list. Provided: {value}.")
242
-
steer_core/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.16"
1
+ __version__ = "0.1.17"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: steer-core
3
- Version: 0.1.16
3
+ Version: 0.1.17
4
4
  Summary: Modelling energy storage from cell to site - STEER OpenCell Design
5
5
  Home-page: https://github.com/nicholas9182/steer-core/
6
6
  Author: Nicholas Siemons
@@ -0,0 +1,34 @@
1
+ steer_core/DataManager.py,sha256=06TrnBa4SLGvLeH2DacCxwGZ4zjLZslwNcwIlmfhxtA,10943
2
+ steer_core/__init__.py,sha256=BzIjnki8Bz3evNWo6bjGxxpLhy_tN9MRYhtM0MnDiWs,23
3
+ steer_core/Apps/ContextManagers.py,sha256=-ImT0O8BdmPKOd_e7wS6AWJMMQme7nGDEUdxTi_wv8s,1870
4
+ steer_core/Apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ steer_core/Apps/Components/MaterialSelectors.py,sha256=LBf2PvHkyAXUoZgEhoJCfo5shEfaloa6l3PeOJAakFk,35707
6
+ steer_core/Apps/Components/RangeSliderComponents.py,sha256=tixdJSC--0OaWgI6OEpNSFZCzvW0iedXIfNVoIdt2XA,22071
7
+ steer_core/Apps/Components/SliderComponents.py,sha256=BGv_yzXhWV_VJ8LE5P7__tMukOxIFjcuBGHwl0oi3-Y,27600
8
+ steer_core/Apps/Components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ steer_core/Apps/Performance/CallbackTimer.py,sha256=Dh1dWvgX_LownO_UBmlBtUwl5XRb4sQ5kpzSqLXK2G8,387
10
+ steer_core/Apps/Performance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ steer_core/Apps/Utils/SliderControls.py,sha256=jSjYZBWE9A9uzFDJjHBjP0RND9DeKUKm0V3ovDoeezo,27008
12
+ steer_core/Apps/Utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ steer_core/Constants/Units.py,sha256=SPwPK13dHE3ua_e4F8yz-sLDOYgWalWRa-tPL7Yc-vQ,619
14
+ steer_core/Constants/Universal.py,sha256=5FWdrex5NiI2DResDmwO7GIvGN2B0DNtdlG1l-ysDh8,41
15
+ steer_core/Constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ steer_core/ContextManagers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ steer_core/Data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ steer_core/Data/database.db,sha256=lCRyt-d92hq_yWMLmPVNvyjknMCznxkAf54eDX2iz90,13615104
19
+ steer_core/Decorators/Coordinates.py,sha256=MxUWXQNrR9Q0_p4gGAywS4qnPAztajJzSay1Cu6lCRQ,1441
20
+ steer_core/Decorators/Electrochemical.py,sha256=YDXzYxrIpbMMViK2y56UHZHb6Y4bDSIeXSVeP8VtYr4,990
21
+ steer_core/Decorators/General.py,sha256=y1azWe4Ja9BP5vHn2gqwIpHVs11xQ1WKdqOc9v_uegs,969
22
+ steer_core/Decorators/Objects.py,sha256=aYaRQBFgdSE0IB4QgBVfb6GhEPagoU6TRNrW_pOaqQI,506
23
+ steer_core/Decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ steer_core/Mixins/Colors.py,sha256=vbo44Fr0oeziwHJ-tu7ojG-GzqFc2LBcT_hH4szvPFc,6796
25
+ steer_core/Mixins/Coordinates.py,sha256=irdrrXIm7lmjMqgXyRXmu-x5swNQHhR7S0EZTBhvV8U,12824
26
+ steer_core/Mixins/Data.py,sha256=2SXRIExCmd98N5JtNEFCQ9poi94fRF_GV5TNYjEGy6o,1363
27
+ steer_core/Mixins/Plotter.py,sha256=zYj-P9ryhSUe5mHoIyjasZSOnY5sDCFKx6u73E8rFZc,5424
28
+ steer_core/Mixins/Serializer.py,sha256=VC3sqfPMR8BxBC7WaDO6cCDpVAgLV8MKAVZtiX953gQ,1016
29
+ steer_core/Mixins/TypeChecker.py,sha256=YXvM3s0NIMGf8Dyk7xWgEMUak-tkuPxNK7ZgmefRUoE,7577
30
+ steer_core/Mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ steer_core-0.1.17.dist-info/METADATA,sha256=TARSguSAGdeKSpug0Dh5as4CxsD6vSgkla5r1gaebSA,704
32
+ steer_core-0.1.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
+ steer_core-0.1.17.dist-info/top_level.txt,sha256=6LFpGCSDE_SqRoT7raeM3Ax7KTBKQnyXLXxM9kXtw5M,11
34
+ steer_core-0.1.17.dist-info/RECORD,,
@@ -1,33 +0,0 @@
1
- steer_core/DataManager.py,sha256=KKpN8GiVHm8xfUmjHKgfLt_xRXT--dhNX8gxs022VHs,11156
2
- steer_core/__init__.py,sha256=yF88-8vL8keLe6gCTumymw0UoMkWkSrJnzLru4zBCLQ,23
3
- steer_core/Apps/ContextManagers.py,sha256=p3_m6cio2bobP0gg03Iu18XRPHTeIsoZasf5TnLsvZg,1810
4
- steer_core/Apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- steer_core/Apps/Components/MaterialSelectors.py,sha256=KVDhOK5c0LT-2z9_o_QYdk6wsDjPEZ0Wb4xHXOjZvNc,31715
6
- steer_core/Apps/Components/RangeSliderComponents.py,sha256=At-xmyIS9GEAO7MzWXc4vwwzY-zqwNKdGHYkXSUIDck,21732
7
- steer_core/Apps/Components/SliderComponents.py,sha256=SQRt8LQxNHCeif70CF4cgx-Cvwx_poUSweu86qYJBlA,27680
8
- steer_core/Apps/Components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- steer_core/Apps/Performance/CallbackTimer.py,sha256=wFbW2_nl6KdEKrtdviOh5y66ZQlbVf0ZDHm-SZBjbYg,390
10
- steer_core/Apps/Performance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- steer_core/Apps/Utils/SliderControls.py,sha256=NyX1BN4XJmeDD1MhfKfFyVjo8VvfRn68WRuFhXkTxS8,26971
12
- steer_core/Apps/Utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- steer_core/Constants/Units.py,sha256=Bdlv_APY2-kbKva3FW4jA0srTbavqAumrEaaQ6HNKuU,489
14
- steer_core/Constants/Universal.py,sha256=5FWdrex5NiI2DResDmwO7GIvGN2B0DNtdlG1l-ysDh8,41
15
- steer_core/Constants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- steer_core/ContextManagers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- steer_core/Data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- steer_core/Data/database.db,sha256=bcjSOuGjuWuCvWyZttRTIiz251hAvYs4xdScwpfwzy8,13615104
19
- steer_core/Decorators/Coordinates.py,sha256=qo79PlA8ZZ6QY-VvH9YGg27gqpVJ2-Xa3blyoQVCp7A,1436
20
- steer_core/Decorators/Electrochemical.py,sha256=fAy89aw3zspBu_8UPa5kEhUpvO-bYpM0xH1r6O6mSiA,985
21
- steer_core/Decorators/General.py,sha256=-Wu-kTC9JAokicgt_nvANR7zpbCBPNR1kDmY6jzHfy4,966
22
- steer_core/Decorators/Objects.py,sha256=xiQfFgyTY2k8MF4lWojHMWbUMzojpyt8fRGl5bTNze8,503
23
- steer_core/Decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
- steer_core/Mixins/Colors.py,sha256=rJnXyUb9hdy3SkzrPV9dXvnBFZ1funYRF8Q0EZr3vZA,1152
25
- steer_core/Mixins/Coordinates.py,sha256=lxToydRFDiRkHdA2sOJKZnu44ztbNfURV6aza5eMGtE,12969
26
- steer_core/Mixins/Data.py,sha256=wdNedZHS5Q7B-pCIoEbqTWMcxsC91CVn9pbQ2Zszg3w,1363
27
- steer_core/Mixins/Serializer.py,sha256=x-aX8BcFSh5egZdkKinYMmIHLqZymCnETNUld3hzgnk,1039
28
- steer_core/Mixins/TypeChecker.py,sha256=wmsDMYhjAynMQFN_7VixcyzKiin3WyklGT4JuJtxnm0,7400
29
- steer_core/Mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
- steer_core-0.1.16.dist-info/METADATA,sha256=qU1QQDw2n9OQGXHSBQ3XGSAtZJcW26OdsDHyiLTtU-0,704
31
- steer_core-0.1.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
- steer_core-0.1.16.dist-info/top_level.txt,sha256=6LFpGCSDE_SqRoT7raeM3Ax7KTBKQnyXLXxM9kXtw5M,11
33
- steer_core-0.1.16.dist-info/RECORD,,