leap-model-parser 0.1.199.dev2__py3-none-any.whl → 0.1.228__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.
- leap_model_parser/contract/graph.py +1 -0
- leap_model_parser/keras_json_model_import.py +10 -4
- leap_model_parser/leap_graph_editor.py +29 -3
- leap_model_parser/model_parser.py +52 -8
- {leap_model_parser-0.1.199.dev2.dist-info → leap_model_parser-0.1.228.dist-info}/METADATA +5 -4
- {leap_model_parser-0.1.199.dev2.dist-info → leap_model_parser-0.1.228.dist-info}/RECORD +9 -9
- {leap_model_parser-0.1.199.dev2.dist-info → leap_model_parser-0.1.228.dist-info}/WHEEL +1 -1
- {leap_model_parser-0.1.199.dev2.dist-info → leap_model_parser-0.1.228.dist-info}/entry_points.txt +0 -0
- {leap_model_parser-0.1.199.dev2.dist-info → leap_model_parser-0.1.228.dist-info/licenses}/LICENSE +0 -0
|
@@ -5,7 +5,6 @@ from typing import Set, Dict, Any, List, Type, Optional, Tuple
|
|
|
5
5
|
|
|
6
6
|
import tensorflow as tf # type: ignore
|
|
7
7
|
from keras.engine.keras_tensor import KerasTensor # type: ignore
|
|
8
|
-
from keras.engine.node import Node # type: ignore
|
|
9
8
|
from keras.engine.node import Node as keras_node # type: ignore
|
|
10
9
|
from keras.layers import Layer # type: ignore
|
|
11
10
|
from keras.layers.convolutional.base_conv import Conv # type: ignore
|
|
@@ -206,7 +205,7 @@ class KerasJsonModelImport:
|
|
|
206
205
|
'serialized_call_kwargs': serialized_call_kwargs})
|
|
207
206
|
|
|
208
207
|
def generate_regular_node(self, layer: Dict[str, Any], layer_metadata: Dict[str, Any], node_key: str,
|
|
209
|
-
layer_name_to_inbound_nodes: Dict[str, List[
|
|
208
|
+
layer_name_to_inbound_nodes: Dict[str, List[keras_node]]):
|
|
210
209
|
data = layer['config']
|
|
211
210
|
if layer['class_name'] in ('TFOpLambda', 'SlicingOpLambda') or layer['class_name'] in self.custom_layers:
|
|
212
211
|
call_args = layer_name_to_inbound_nodes[layer['config']
|
|
@@ -221,11 +220,17 @@ class KerasJsonModelImport:
|
|
|
221
220
|
|
|
222
221
|
self.layer_data_adjustments(data, layer_metadata)
|
|
223
222
|
node = Node(id=str(self.id), name=layer_metadata.get(
|
|
224
|
-
"class_name", layer["class_name"]), data=data, position=[0, 0]
|
|
223
|
+
"class_name", layer["class_name"]), data=data, position=[0, 0],
|
|
224
|
+
shape=self._convert_layer_shape_to_string(layer['output_shape']))
|
|
225
225
|
if 'wrapper' in layer:
|
|
226
226
|
node.wrapper = layer['wrapper']
|
|
227
227
|
self.nodes_cache[node_key] = node
|
|
228
228
|
|
|
229
|
+
@staticmethod
|
|
230
|
+
def _convert_layer_shape_to_string(s: List[Optional[int]]) -> List[str]:
|
|
231
|
+
return [str(dim) if dim is not None else 'dynamic_shape' for dim in s]
|
|
232
|
+
|
|
233
|
+
|
|
229
234
|
@classmethod
|
|
230
235
|
def handle_wrapper_layer(cls, layer):
|
|
231
236
|
wrapped_layer = layer['config']['layer']
|
|
@@ -332,7 +337,8 @@ class KerasJsonModelImport:
|
|
|
332
337
|
self.connected_inputs.append(input_info)
|
|
333
338
|
input_copy = {
|
|
334
339
|
'type': 'Input',
|
|
335
|
-
'output_name': input_name
|
|
340
|
+
'output_name': input_name,
|
|
341
|
+
'batch_input_shape_origin': shape
|
|
336
342
|
}
|
|
337
343
|
inputNode = Node(
|
|
338
344
|
id=str(self.id), name='Input', data=input_copy, position=[0, 0])
|
|
@@ -31,7 +31,9 @@ class LeapGraphEditor:
|
|
|
31
31
|
f"Prediction node with name {prediction_node.name} not found in model graph"
|
|
32
32
|
prediction_node_id = prediction_mapping_node.id
|
|
33
33
|
self.model_graph[prediction_node_id].data['prediction_type'] = prediction_labels_name
|
|
34
|
-
|
|
34
|
+
elif 'Input' in node_connection.node.type.value:
|
|
35
|
+
self._find_or_add_input_node(node_connection.node)
|
|
36
|
+
elif node_connection.node.type == NodeMappingType.Visualizer:
|
|
35
37
|
new_visualizer_node_id = self._add_visualizer_node(
|
|
36
38
|
node_connection.node.name, node_connection.node.sub_type,
|
|
37
39
|
node_connection.node.user_unique_name, node_connection.node.arg_names)
|
|
@@ -47,6 +49,7 @@ class LeapGraphEditor:
|
|
|
47
49
|
self._add_connection_to_node(new_metric_node_id, input_name, input_node_id)
|
|
48
50
|
elif node_connection.node.type in (NodeMappingType.Loss, NodeMappingType.CustomLoss):
|
|
49
51
|
new_loss_node_id = self._add_loss_node(node_connection.node.name,
|
|
52
|
+
node_connection.node.user_unique_name,
|
|
50
53
|
node_connection.node.type == NodeMappingType.CustomLoss,
|
|
51
54
|
node_connection.node.arg_names)
|
|
52
55
|
for input_name, node in node_connection.node_inputs.items():
|
|
@@ -71,6 +74,8 @@ class LeapGraphEditor:
|
|
|
71
74
|
|
|
72
75
|
def _find_input_node_by_origin_name(self, origin_name: str) -> Optional[Node]:
|
|
73
76
|
for node in self.model_graph.values():
|
|
77
|
+
if node.data.get('original_output_name') == origin_name:
|
|
78
|
+
return node
|
|
74
79
|
if node.data.get('output_name') == origin_name:
|
|
75
80
|
return node
|
|
76
81
|
return None
|
|
@@ -122,6 +127,22 @@ class LeapGraphEditor:
|
|
|
122
127
|
self.model_graph[new_node_id] = ground_truth_node
|
|
123
128
|
return new_node_id
|
|
124
129
|
|
|
130
|
+
def _add_input_encoder_not_connected_to_the_model_node(self, input_name: str) -> str:
|
|
131
|
+
new_node_id = self._generate_new_node_id()
|
|
132
|
+
ground_truth_node = Node(
|
|
133
|
+
new_node_id,
|
|
134
|
+
'Input',
|
|
135
|
+
position=[0, 0],
|
|
136
|
+
data={'name': input_name, 'output_name': input_name,
|
|
137
|
+
'type': 'Input', "selected": input_name},
|
|
138
|
+
inputs={},
|
|
139
|
+
outputs={
|
|
140
|
+
f'{new_node_id}-{input_name}': ConnectionOutput([])
|
|
141
|
+
}
|
|
142
|
+
)
|
|
143
|
+
self.model_graph[new_node_id] = ground_truth_node
|
|
144
|
+
return new_node_id
|
|
145
|
+
|
|
125
146
|
def _add_visualizer_node(self, visualizer_name: str, visualizer_type: str,
|
|
126
147
|
user_unique_name: str, arg_names: List[str]) -> str:
|
|
127
148
|
new_node_id = self._generate_new_node_id()
|
|
@@ -155,7 +176,7 @@ class LeapGraphEditor:
|
|
|
155
176
|
self.model_graph[new_node_id] = metric_node
|
|
156
177
|
return new_node_id
|
|
157
178
|
|
|
158
|
-
def _add_loss_node(self, loss_name: str, is_custom_loss: bool, arg_names: Optional[List[str]]=None) -> str:
|
|
179
|
+
def _add_loss_node(self, loss_name: str, user_unique_name:str, is_custom_loss: bool, arg_names: Optional[List[str]]=None) -> str:
|
|
159
180
|
new_node_id = self._generate_new_node_id()
|
|
160
181
|
|
|
161
182
|
loss_type = 'CustomLoss' if is_custom_loss else 'Loss'
|
|
@@ -165,7 +186,7 @@ class LeapGraphEditor:
|
|
|
165
186
|
new_node_id,
|
|
166
187
|
loss_node_name,
|
|
167
188
|
position=[0, 0],
|
|
168
|
-
data={'type': loss_type, 'selected': loss_name, 'name': loss_name},
|
|
189
|
+
data={'type': loss_type, 'selected': loss_name, 'name': loss_name, 'user_unique_name': user_unique_name},
|
|
169
190
|
inputs={},
|
|
170
191
|
outputs={
|
|
171
192
|
f'{new_node_id}-loss': ConnectionOutput([])
|
|
@@ -210,7 +231,10 @@ class LeapGraphEditor:
|
|
|
210
231
|
input_node_by_origin = self._find_input_node_by_origin_name(origin_name)
|
|
211
232
|
assert input_node_by_origin is not None, f"Input node with origin name {origin_name} not found in model graph"
|
|
212
233
|
input_node_id = input_node_by_origin.id
|
|
234
|
+
if 'original_output_name' not in self.model_graph[input_node_id].data:
|
|
235
|
+
self.model_graph[input_node_id].data['original_output_name'] = self.model_graph[input_node_id].data['output_name']
|
|
213
236
|
self.model_graph[input_node_id].data['output_name'] = input_node.name
|
|
237
|
+
|
|
214
238
|
output_keys = list(self.model_graph[input_node_id].outputs.keys())
|
|
215
239
|
for output_key in output_keys:
|
|
216
240
|
new_output_key = f'{input_node_id}-{input_node.name}'
|
|
@@ -232,6 +256,8 @@ class LeapGraphEditor:
|
|
|
232
256
|
if input_node_id is None:
|
|
233
257
|
if input_node.type == NodeMappingType.GroundTruth:
|
|
234
258
|
input_node_id = self._add_ground_truth_node(input_node.name)
|
|
259
|
+
elif input_node.type == NodeMappingType.Input:
|
|
260
|
+
input_node_id = self._add_input_encoder_not_connected_to_the_model_node(input_node.name)
|
|
235
261
|
else:
|
|
236
262
|
raise Exception(f'Couldnt find input node name {input_node.name}')
|
|
237
263
|
elif 'Input' in input_node.type.value:
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# mypy: ignore-errors
|
|
2
|
+
|
|
1
3
|
import glob
|
|
2
4
|
import json
|
|
3
5
|
import ntpath
|
|
@@ -6,9 +8,8 @@ import tempfile
|
|
|
6
8
|
from importlib.util import find_spec
|
|
7
9
|
from pathlib import Path
|
|
8
10
|
|
|
9
|
-
|
|
10
11
|
import tensorflow as tf # type: ignore
|
|
11
|
-
from code_loader.contract.mapping import NodeConnection # type: ignore
|
|
12
|
+
from code_loader.contract.mapping import NodeConnection, NodeMapping # type: ignore
|
|
12
13
|
from keras import Model # type: ignore
|
|
13
14
|
from keras_data_format_converter import convert_channels_first_to_last # type: ignore
|
|
14
15
|
from leap_model_rebuilder import rebuild_model # type: ignore
|
|
@@ -33,6 +34,7 @@ if spec is not None:
|
|
|
33
34
|
|
|
34
35
|
onnx_imported = True
|
|
35
36
|
|
|
37
|
+
|
|
36
38
|
class ModelParser:
|
|
37
39
|
def __init__(self, should_transform_inputs_and_outputs=False,
|
|
38
40
|
custom_layers=None,
|
|
@@ -53,8 +55,14 @@ class ModelParser:
|
|
|
53
55
|
ImportModelTypeEnum.PB_TF2.value: self.convert_pb_model,
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
@staticmethod
|
|
59
|
+
def _add_output_node_shape_to_model_schema(model_schema: Dict, keras_model: Model):
|
|
60
|
+
for i, layer in enumerate(keras_model.layers):
|
|
61
|
+
model_schema['config']['layers'][i]['output_shape'] = list(layer.output_shape)
|
|
62
|
+
|
|
56
63
|
def get_keras_model_and_model_graph(
|
|
57
|
-
self, model_path: Path, model_type: ImportModelTypeEnum) -> Tuple[
|
|
64
|
+
self, model_path: Path, model_type: ImportModelTypeEnum) -> Tuple[
|
|
65
|
+
Dict[str, Node], List[InputInfo], Optional[Model], Optional[str]]:
|
|
58
66
|
model_to_keras_converter: Optional[Callable[[str], Tuple[Dict[str, Node], Model, Optional[str]]]] = \
|
|
59
67
|
self._model_types_converter.get(model_type.value)
|
|
60
68
|
if model_to_keras_converter is None:
|
|
@@ -63,6 +71,9 @@ class ModelParser:
|
|
|
63
71
|
|
|
64
72
|
file_path = str(model_path)
|
|
65
73
|
model_schema, keras_model_with_weights, error_info = model_to_keras_converter(file_path)
|
|
74
|
+
|
|
75
|
+
self._add_output_node_shape_to_model_schema(model_schema, keras_model_with_weights)
|
|
76
|
+
|
|
66
77
|
model_generator = KerasJsonModelImport(self.custom_layers)
|
|
67
78
|
|
|
68
79
|
keras_model = keras_model_with_weights
|
|
@@ -82,7 +93,6 @@ class ModelParser:
|
|
|
82
93
|
|
|
83
94
|
return graph, connected_inputs, keras_model_with_weights, error_info
|
|
84
95
|
|
|
85
|
-
|
|
86
96
|
def _get_k_model_from_pb_path(self, file_path: str):
|
|
87
97
|
tar_file = tarfile.open(file_path)
|
|
88
98
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
@@ -97,7 +107,8 @@ class ModelParser:
|
|
|
97
107
|
k_model = self._load_keras_model_with_custom_layers(pb_folder_path)
|
|
98
108
|
return k_model
|
|
99
109
|
|
|
100
|
-
def generate_model_graph(self, model_path: Path, model_type: ImportModelTypeEnum) -> Tuple[
|
|
110
|
+
def generate_model_graph(self, model_path: Path, model_type: ImportModelTypeEnum) -> Tuple[
|
|
111
|
+
Dict[str, Node], List[InputInfo]]:
|
|
101
112
|
model_graph, connected_inputs, _, error_info = self.get_keras_model_and_model_graph(
|
|
102
113
|
model_path, model_type)
|
|
103
114
|
return model_graph, connected_inputs
|
|
@@ -122,23 +133,56 @@ class ModelParser:
|
|
|
122
133
|
node.name for node in onnx_model.graph.initializer]
|
|
123
134
|
input_names = list(set(input_all) - set(input_initializer))
|
|
124
135
|
converted_response: ConvertedResponse = onnx_to_keras(onnx_model, input_names=input_names,
|
|
125
|
-
|
|
136
|
+
name_policy='attach_weights_name',
|
|
137
|
+
allow_partial_compilation=False)
|
|
126
138
|
return self.convert_to_keras_model(converted_response.converted_model, converted_response.error_info)
|
|
127
139
|
|
|
128
140
|
def _load_keras_model_with_custom_layers(self, file_path: str):
|
|
129
141
|
custom_objects = {}
|
|
130
142
|
if self.custom_layers is not None:
|
|
131
143
|
custom_objects = self.custom_layers
|
|
132
|
-
|
|
144
|
+
|
|
145
|
+
try:
|
|
146
|
+
return load_model(file_path, custom_objects=custom_objects, compile=False)
|
|
147
|
+
except OSError as e:
|
|
148
|
+
if 'signature' in str(e):
|
|
149
|
+
raise Exception('Unable to open model file. The model might be corrupted or not a valid.')
|
|
150
|
+
else:
|
|
151
|
+
raise e
|
|
152
|
+
|
|
133
153
|
|
|
134
154
|
def convert_h5_model(self, file_path: str) -> Tuple[Dict[str, Node], Model, Optional[str]]:
|
|
135
155
|
imported_model = self._load_keras_model_with_custom_layers(file_path)
|
|
136
156
|
return self.convert_to_keras_model(imported_model)
|
|
137
157
|
|
|
138
|
-
def convert_to_keras_model(self, k_model, error_info: Optional[str] = None) -> Tuple[
|
|
158
|
+
def convert_to_keras_model(self, k_model, error_info: Optional[str] = None) -> Tuple[
|
|
159
|
+
Dict[str, Node], Model, Optional[str]]:
|
|
139
160
|
converted_k_model = convert_channels_first_to_last(
|
|
140
161
|
k_model, self._should_transform_inputs_and_outputs, self.custom_layers)
|
|
141
162
|
|
|
163
|
+
from keras.saving.legacy.saved_model import json_utils # type: ignore
|
|
164
|
+
import numpy as np
|
|
165
|
+
|
|
166
|
+
_orig_get_json_type = json_utils.get_json_type
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _patched_get_json_type(obj): # type: ignore
|
|
170
|
+
# Handle numpy dtype explicitly
|
|
171
|
+
if isinstance(obj, np.dtype):
|
|
172
|
+
return obj.name # e.g. "int64"
|
|
173
|
+
# Make sure common numpy scalars/containers are handled robustly
|
|
174
|
+
if isinstance(obj, np.integer):
|
|
175
|
+
return int(obj)
|
|
176
|
+
if isinstance(obj, np.floating):
|
|
177
|
+
return float(obj)
|
|
178
|
+
if isinstance(obj, np.bool_):
|
|
179
|
+
return bool(obj)
|
|
180
|
+
if isinstance(obj, np.ndarray):
|
|
181
|
+
return obj.tolist()
|
|
182
|
+
return _orig_get_json_type(obj)
|
|
183
|
+
|
|
184
|
+
json_utils.get_json_type = _patched_get_json_type
|
|
185
|
+
|
|
142
186
|
model_schema = json.loads(converted_k_model.to_json())
|
|
143
187
|
|
|
144
188
|
return model_schema, converted_k_model, error_info
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: leap-model-parser
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.228
|
|
4
4
|
Summary:
|
|
5
5
|
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
6
7
|
Author: idan
|
|
7
8
|
Author-email: idan.yogev@tensorleap.ai
|
|
8
9
|
Requires-Python: >=3.8,<3.11
|
|
@@ -11,12 +12,12 @@ Classifier: Programming Language :: Python :: 3
|
|
|
11
12
|
Classifier: Programming Language :: Python :: 3.8
|
|
12
13
|
Classifier: Programming Language :: Python :: 3.9
|
|
13
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
-
Requires-Dist: code-loader (
|
|
15
|
+
Requires-Dist: code-loader (>=1.0.127)
|
|
15
16
|
Requires-Dist: keras-data-format-converter (==0.1.22)
|
|
16
17
|
Requires-Dist: leap-model-rebuilder (==0.1.7)
|
|
17
18
|
Requires-Dist: numpy (>=1.22.3,<2.0.0)
|
|
18
19
|
Requires-Dist: onnx (==1.13.0)
|
|
19
|
-
Requires-Dist: onnx2kerastl (==0.0.
|
|
20
|
+
Requires-Dist: onnx2kerastl (==0.0.177)
|
|
20
21
|
Requires-Dist: tensorflow (==2.12.0) ; platform_machine == "x86_64"
|
|
21
22
|
Requires-Dist: tensorflow-io-gcs-filesystem (==0.34.0)
|
|
22
23
|
Requires-Dist: tensorflow-macos (==2.12.0) ; platform_machine == "arm64"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
leap_model_parser/__init__.py,sha256=OAU7rFHAVVWUM-cDtQ4Ohum567KN8M-YTkHZp5KiYbo,132
|
|
2
2
|
leap_model_parser/contract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
leap_model_parser/contract/graph.py,sha256=
|
|
3
|
+
leap_model_parser/contract/graph.py,sha256=lbs_IUnlkvoVjiARBMJee-aNbqeNXNPsUeOEwQliKgU,1170
|
|
4
4
|
leap_model_parser/contract/importmodelresponse.py,sha256=GlvnKS8xrebU2Sj0dxqtEhAOOo3DlOtT7AMJ2BlzH9E,145
|
|
5
5
|
leap_model_parser/contract/nodedata.py,sha256=1_ML0nzp3QUZ0_9mGSLhfO4_hqjYMwi0DWLwymUnWEs,43326
|
|
6
6
|
leap_model_parser/contract/ui_components.json,sha256=0lsxwOLElW1E-imCcdh3zKPWgzFuQ_bApG6aHvYfTvo,410591
|
|
7
|
-
leap_model_parser/keras_json_model_import.py,sha256=
|
|
8
|
-
leap_model_parser/leap_graph_editor.py,sha256=
|
|
9
|
-
leap_model_parser/model_parser.py,sha256=
|
|
7
|
+
leap_model_parser/keras_json_model_import.py,sha256=h9-eb41W67goutRV5c3VkStxvntgb6EmPFdPeshhtsY,17058
|
|
8
|
+
leap_model_parser/leap_graph_editor.py,sha256=s6iVO06xM6LJ8ZjSxkr1srYxsHhGl2KnQjQoc9g4_iE,14329
|
|
9
|
+
leap_model_parser/model_parser.py,sha256=W8FGKCBOBClIl0sdBlTdoSRT8sIdVrlbO8veNMouJ7o,8169
|
|
10
10
|
leap_model_parser/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
leap_model_parser/utils/layerpedia/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
12
|
leap_model_parser/utils/layerpedia/layerpedia.py,sha256=1syubfXBTB630TVkgcQ-Ge7Qe9Zbr6EtZRreuqCJnQ8,9292
|
|
@@ -17,8 +17,8 @@ leap_model_parser/utils/uicomponents/generatenodedata.py,sha256=LRaPlO5jJ9pUtkvL
|
|
|
17
17
|
leap_model_parser/utils/uicomponents/tensorflowinscpection.py,sha256=ym613z9iQKPDBpr0RYD35bTABdm1L-Ez86G47BYT7qw,6775
|
|
18
18
|
leap_model_parser/utils/uicomponents/ui_components.json,sha256=0lsxwOLElW1E-imCcdh3zKPWgzFuQ_bApG6aHvYfTvo,410591
|
|
19
19
|
leap_model_parser/utils/uicomponents/ui_components_config.yaml,sha256=cRH8T-c3TAL0nfefRvt9pFsjbTWNEg38NRyHR7RpJsk,19534
|
|
20
|
-
leap_model_parser-0.1.
|
|
21
|
-
leap_model_parser-0.1.
|
|
22
|
-
leap_model_parser-0.1.
|
|
23
|
-
leap_model_parser-0.1.
|
|
24
|
-
leap_model_parser-0.1.
|
|
20
|
+
leap_model_parser-0.1.228.dist-info/METADATA,sha256=4mXS089Qn_kVo07OcvrVsHvQnbu6clRRnJXircAOEG0,1138
|
|
21
|
+
leap_model_parser-0.1.228.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
22
|
+
leap_model_parser-0.1.228.dist-info/entry_points.txt,sha256=ZvV6EuQt1uAqwapNg5Lo2qjJM9ZG5g2wfzZoLh_Ztyk,77
|
|
23
|
+
leap_model_parser-0.1.228.dist-info/licenses/LICENSE,sha256=qIwWjdspQeSMTtnFZBC8MuT-95L02FPvzRUdWFxrwJY,1067
|
|
24
|
+
leap_model_parser-0.1.228.dist-info/RECORD,,
|
{leap_model_parser-0.1.199.dev2.dist-info → leap_model_parser-0.1.228.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{leap_model_parser-0.1.199.dev2.dist-info → leap_model_parser-0.1.228.dist-info/licenses}/LICENSE
RENAMED
|
File without changes
|