PySimultan 0.5.9.5__py3-none-any.whl → 0.5.9.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.
PySimultan2/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ Version 0.5.9.7 (09.01.2024)
2
+ - Added default component support to Mapper: if a default component is not present in the datamodel, it is automatically added
3
+ - Fixed content naming bug: Content.name is now used for the name of the TaxonomyEntry in SIMULTAN
4
+ - Added typing for better code completion
5
+
1
6
  Version 0.5.9.4 (31.12.2024)
2
7
  - Fixed bug in DirectoryInfo where __dir__helper_file__ was not found if already existing
3
8
 
PySimultan2/__about__.py CHANGED
@@ -1 +1 @@
1
- version = '0.5.9.5'
1
+ version = '0.5.9.7'
PySimultan2/data_model.py CHANGED
@@ -587,18 +587,33 @@ class DataModel:
587
587
 
588
588
  del_copy = False
589
589
 
590
- existing_files = [x.Name for x in self.project_data_manager.AssetManager.Resources]
590
+ existing_files = [x.current_full_path for x in self.project_data_manager.AssetManager.Resources]
591
591
  try:
592
592
  act_filename = filename.replace('\\', os.sep)
593
593
  except TypeError:
594
594
  act_filename = filename
595
595
 
596
- if os.path.basename(act_filename) in existing_files:
596
+ if not act_filename.startswith(self.project.ProjectUnpackFolder.FullPath) and target_dir is None:
597
+ target_dir_str = self.project.ProjectUnpackFolder.FullPath
598
+ elif target_dir is not None:
599
+ if isinstance(target_dir, ResourceDirectoryEntry):
600
+ target_dir_str = target_dir.CurrentFullPath
601
+ elif isinstance(target_dir, SystemFileInfo):
602
+ target_dir_str = target_dir.FullPath
603
+ elif isinstance(target_dir, str):
604
+ target_dir_str = target_dir
605
+ elif isinstance(target_dir, DirectoryInfo):
606
+ target_dir_str = target_dir.FullPath
607
+
608
+ full_filename = os.path.join(target_dir_str, os.path.basename(act_filename))
609
+
610
+ if full_filename in existing_files:
597
611
  # create copy with running counter in temp dir and use this file:
598
612
  counter = 1
599
613
  while True:
600
614
  new_filename = os.path.basename(filename) + f'({str(counter)})'
601
- if new_filename not in existing_files and not os.path.exists(new_filename):
615
+ full_filename = os.path.join(target_dir_str, new_filename)
616
+ if full_filename not in existing_files and not os.path.exists(new_filename):
602
617
  break
603
618
  counter += 1
604
619
  shutil.copy(filename, os.path.join(os.path.dirname(filename), new_filename))
@@ -776,7 +791,10 @@ class DataModel:
776
791
  None)
777
792
  return model_to_work_with, resource_file
778
793
 
779
- def get_or_create_taxonomy(self, taxonomy_key: str, taxonomy_name: str = None, description='', create=True):
794
+ def get_or_create_taxonomy(self, taxonomy_key: str,
795
+ taxonomy_name: str = None,
796
+ description='',
797
+ create=True) -> SimTaxonomy:
780
798
  taxonomy = next((x for x in self.taxonomies if x.Key == taxonomy_key), None)
781
799
  if taxonomy is None:
782
800
  if create:
@@ -784,7 +802,11 @@ class DataModel:
784
802
  else:
785
803
  raise ValueError(f'Taxonomy {taxonomy_key} not found in project {self.project_path}')
786
804
 
787
- return next((x for x in self.taxonomies if x.Key == taxonomy_key), None)
805
+ taxonomy = next((x for x in self.taxonomies if x.Key == taxonomy_key), None)
806
+
807
+ if create and taxonomy is None:
808
+ raise ValueError(f'Could not create taxonomy {taxonomy_key} in project {self.project_path}')
809
+ return taxonomy
788
810
 
789
811
  def get_or_create_taxonomy_entry(self,
790
812
  name: str,
@@ -860,7 +882,18 @@ class DataModel:
860
882
 
861
883
  @lru_cache()
862
884
  def get_file_infos(self) -> list[PythonFileInfo]:
863
- return [PythonFileInfo(resource_entry=asset) for asset in self.assets]
885
+ file_infos = []
886
+ for asset in self.assets:
887
+ if isinstance(asset, ResourceFileEntry):
888
+ file_infos.append(PythonFileInfo(resource_entry=asset))
889
+ return file_infos
890
+
891
+ def get_directory_infos(self) -> list[PythonDirectoryInfo]:
892
+ dir_infos = []
893
+ for asset in self.assets:
894
+ if isinstance(asset, ResourceDirectoryEntry):
895
+ dir_infos.append(PythonDirectoryInfo(resource_entry=asset, data_model=self))
896
+ return dir_infos
864
897
 
865
898
  def get_file_info_by_key(self,
866
899
  key: int) -> Optional[PythonFileInfo]:
@@ -17,6 +17,9 @@ from SIMULTAN.Data.Components import (ComponentWalker, SimComponent, SimBoolPara
17
17
  SimEnumParameter, SimIntegerParameter, SimStringParameter, ComponentMapping,
18
18
  SimSlot, SimComponentVisibility, SimChildComponentEntry, SimDefaultSlots,
19
19
  SimParameterOperations, SimComponentReference)
20
+
21
+ from SIMULTAN.Data.Assets import DocumentAsset
22
+
20
23
  from .files import FileInfo
21
24
 
22
25
  from . import config
@@ -562,9 +565,14 @@ class ComponentDictionary(SimultanObject):
562
565
  for ref_asset in self._wrapped_obj.ReferencedAssets.Items:
563
566
  for tag in ref_asset.Resource.Tags:
564
567
  key = tag.Target.Key.replace('__dict_key__', '')
565
- comp_dict[key] = get_obj_value(ref_asset.Target,
566
- data_model=self._data_model,
567
- object_mapper=self._object_mapper)
568
+ if isinstance(ref_asset, DocumentAsset):
569
+ comp_dict[key] = get_obj_value(ref_asset.Resource,
570
+ data_model=self._data_model,
571
+ object_mapper=self._object_mapper)
572
+ else:
573
+ comp_dict[key] = get_obj_value(ref_asset.Target,
574
+ data_model=self._data_model,
575
+ object_mapper=self._object_mapper)
568
576
 
569
577
  object.__setattr__(self, '_dict', comp_dict)
570
578
 
@@ -1,4 +1,4 @@
1
- from typing import Optional, Type, TYPE_CHECKING, Union, Any
1
+ from typing import Optional, Type, TYPE_CHECKING, Union, Any, Dict, List
2
2
  from copy import copy
3
3
  from collections import UserList
4
4
  from colorlog import getLogger
@@ -74,6 +74,8 @@ class PythonMapper(object):
74
74
  self.re_register = False
75
75
  self.load_undefined = False
76
76
 
77
+ self.default_components: List[Any] = []
78
+
77
79
  @property
78
80
  def module(self):
79
81
  return self._module
@@ -147,7 +149,9 @@ class PythonMapper(object):
147
149
  self.taxonomy_maps.update(submodule.taxonomy_maps)
148
150
  self.registered_geometry_classes.update(submodule.registered_geometry_classes)
149
151
 
150
- def create_mapped_class(self, taxonomy, cls):
152
+ def create_mapped_class(self,
153
+ taxonomy: str,
154
+ cls: Any):
151
155
 
152
156
  if any([issubclass(cls, x) for x in (SimultanObject, UserList)]):
153
157
  bases = (cls,)
@@ -179,7 +183,10 @@ class PythonMapper(object):
179
183
 
180
184
  return self.mapped_classes.get(taxonomy, None)
181
185
 
182
- def get_typed_data(self, data_model=None, component_list=None, create_all=False):
186
+ def get_typed_data(self,
187
+ data_model: 'DataModel' = None,
188
+ component_list: List[SimComponent] = None,
189
+ create_all: bool = False):
183
190
 
184
191
  typed_data = []
185
192
 
@@ -229,8 +236,27 @@ class PythonMapper(object):
229
236
  typed_object = self.create_python_object(component, data_model=data_model)
230
237
  if typed_object is not None:
231
238
  typed_data.append(typed_object)
239
+
240
+ if create_all:
241
+ self.create_default_components(data_model)
242
+
232
243
  return typed_data
233
244
 
245
+ def create_default_components(self, data_model: 'DataModel'):
246
+ for instance in self.default_components:
247
+ key = list(filter(lambda x: self.registered_classes[x] == type(instance),
248
+ self.registered_classes)
249
+ )[0]
250
+ cls = self.get_mapped_class(key)
251
+ if not cls.cls_instances:
252
+ self.create_mapped_python_object(obj=instance,
253
+ data_model=data_model)
254
+ else:
255
+ # check if default instance is already in data model
256
+ if not any([x.name == instance.name for x in cls.cls_instances]):
257
+ self.create_mapped_python_object(obj=instance,
258
+ data_model=data_model)
259
+
234
260
  def create_python_geometry_object(self,
235
261
  component: Union[Layer, Vertex, Edge, PEdge, Face, Volume, EdgeLoop],
236
262
  data_model: 'DataModel' = None,
@@ -3,12 +3,12 @@ from functools import cache
3
3
  from ruamel.yaml import YAML, yaml_object, add_representer
4
4
  from . import yaml
5
5
 
6
- from typing import TYPE_CHECKING, Optional, Union, Literal
6
+ from typing import TYPE_CHECKING, Optional, Union, Literal, Any, Dict
7
7
 
8
8
  if TYPE_CHECKING:
9
9
  from .data_model import DataModel
10
10
 
11
- from SIMULTAN.Data.Taxonomy import SimTaxonomyEntryReference
11
+ from SIMULTAN.Data.Taxonomy import SimTaxonomyEntryReference, SimTaxonomyEntry, SimTaxonomyEntryReference, SimTaxonomy
12
12
 
13
13
 
14
14
  @yaml_object(yaml)
@@ -17,6 +17,14 @@ class Content(object):
17
17
  yaml_tag = u'!Content'
18
18
 
19
19
  def __init__(self,
20
+ text_or_key: str,
21
+ name: Optional[str] = None,
22
+ property_name: Optional[str] = None,
23
+ slot_extension: Optional[str] = None,
24
+ type: Optional[Any] = None,
25
+ unit: Optional[str] = None,
26
+ documentation: Optional[str] = None,
27
+ component_policy: Optional[Literal['reference', 'subcomponent']] = 'subcomponent',
20
28
  *args,
21
29
  **kwargs):
22
30
  """
@@ -24,6 +32,7 @@ class Content(object):
24
32
 
25
33
  :param args:
26
34
  :Keyword Arguments
35
+ * *name* (``str``) -- name of the Taxonomy Entry in SIMULTAN
27
36
  * *text_or_key* (``str``) -- text or key of the content/parameter/property
28
37
  * *property_name* (``str``) -- name of the generated property
29
38
  * *slot_extension* (``str``) -- slot extension of the content/parameter/property
@@ -33,20 +42,20 @@ class Content(object):
33
42
  * *component_policy* (``str``) -- component add policy of the content/parameter/property, 'reference' or 'subcomponent'
34
43
  """
35
44
 
36
- self.name: str = kwargs.get('name', kwargs.get('text_or_key'))
37
- self.text_or_key: str = kwargs.get('text_or_key') # text or key of the content/parameter/property
38
- self.property_name: str = kwargs.get('property_name') # name of the generated property
39
- self.slot_extension: str = kwargs.get('slot_extension') # slot extension of the content/parameter/property
40
- self.type = kwargs.get('type', None) # type of the content/parameter/property
41
- self.unit: Optional[str] = kwargs.get('unit', None) # unit of the content/parameter/property
42
- self.documentation: Optional[str] = kwargs.get('documentation', None) # documentation of the content/parameter/property
43
- self.component_policy: Literal['reference', 'subcomponent'] = kwargs.get('component_policy', 'reference') # component add policy of the content/parameter/property, 'reference' or 'subcomponent'
45
+ self.name: str = name if name is not None else text_or_key # name of the Taxonomy Entry in SIMULTAN
46
+ self.text_or_key: str = text_or_key # text or key of the content/parameter/property
47
+ self.property_name: str = property_name if property_name is not None else text_or_key # name of the generated property in the python class
48
+ self.slot_extension: str = slot_extension # slot extension of the content/parameter/property
49
+ self.type: Optional[Any] = type # type of the content/parameter/property
50
+ self.unit: Optional[str] = unit # unit of the content/parameter/property
51
+ self.documentation: Optional[str] = documentation # documentation of the content/parameter/property
52
+ self.component_policy: Literal['reference', 'subcomponent'] = component_policy # component add policy of the content/parameter/property, 'reference' or 'subcomponent'
44
53
 
45
54
  self._taxonomies = {}
46
55
  self._taxonomy_entries = {}
47
- self._taxonomy_map = kwargs.get('taxonomy_map', None)
56
+ self._taxonomy_map: Optional['TaxonomyMap'] = kwargs.get('taxonomy_map', None)
48
57
 
49
- self.taxonomy_key = kwargs.get('taxonomy_key')
58
+ self.taxonomy_key: Optional[SimTaxonomy] = kwargs.get('taxonomy_key')
50
59
 
51
60
  add_kwargs = kwargs.copy()
52
61
  _ = [add_kwargs.pop(key, None) for key in ['taxonomy_name', 'taxonomy_key', 'taxonomy_entry_name',
@@ -54,10 +63,10 @@ class Content(object):
54
63
  'mapped_class', 'unit', 'type', 'component_policy',
55
64
  'text_or_key', 'property_name', 'slot_extension']]
56
65
 
57
- self.additional_attributes = add_kwargs
66
+ self.additional_attributes: dict[Any, Any] = add_kwargs
58
67
 
59
- self.taxonomy_key = kwargs.get('taxonomy_key')
60
- self.taxonomy_name = kwargs.get('taxonomy_name')
68
+ self.taxonomy_key: Optional[SimTaxonomy] = kwargs.get('taxonomy_key')
69
+ self.taxonomy_name: str = kwargs.get('taxonomy_name')
61
70
 
62
71
 
63
72
  def get_taxonomie_entry(self, data_model: 'DataModel'):
@@ -70,7 +79,7 @@ class Content(object):
70
79
  taxonomy_key=self.taxonomy_key,
71
80
  create=True)
72
81
 
73
- self._taxonomy_entries[data_model] = data_model.get_or_create_taxonomy_entry(name=self.text_or_key,
82
+ self._taxonomy_entries[data_model] = data_model.get_or_create_taxonomy_entry(name=self.name,
74
83
  key=self.text_or_key,
75
84
  description=self.documentation,
76
85
  sim_taxonomy=taxonomy)
@@ -97,29 +106,38 @@ class TaxonomyMap(object):
97
106
  taxonomie_map = yaml.load(f)
98
107
  return taxonomie_map[0]
99
108
 
100
- def __init__(self, *args, **kwargs):
109
+ def __init__(self,
110
+ taxonomy_key: str,
111
+ taxonomy_entry_key: str,
112
+ taxonomy_name: Optional[str] = None,
113
+ taxonomy_entry_name: Optional[str] = None,
114
+ content: Optional[list[Content]] = None,
115
+ documentation: Optional[str] = None,
116
+ *args,
117
+ **kwargs):
101
118
 
102
119
  self._content = []
103
120
  self._content_dict = {}
104
121
  self._parameter_taxonomy_entry_dict = {}
105
122
 
106
- self.taxonomy_name = kwargs.get('taxonomy_name', kwargs.get('taxonomy_key'))
107
- self.taxonomy_key = kwargs.get('taxonomy_key')
123
+ self.taxonomy_key = taxonomy_key
124
+ self.taxonomy_name = taxonomy_name if taxonomy_name is not None else taxonomy_key
108
125
 
109
- if self.taxonomy_key == kwargs.get('taxonomy_entry_key'):
126
+
127
+ if self.taxonomy_key == taxonomy_entry_key:
110
128
  raise ValueError('taxonomy_key and taxonomy_entry_key must be different')
111
129
 
112
- self.taxonomy_entry_name = kwargs.get('taxonomy_entry_name', kwargs.get('taxonomy_entry_key'))
113
- self.taxonomy_entry_key = kwargs.get('taxonomy_entry_key')
130
+ self.taxonomy_entry_key = taxonomy_entry_key
131
+ self.taxonomy_entry_name = taxonomy_entry_name if taxonomy_entry_name is not None else taxonomy_entry_key
114
132
 
115
- self.content = kwargs.get('content', [])
116
- self.documentation = kwargs.get('documentation', '')
133
+ self.content = content if content is not None else []
134
+ self.documentation = documentation
117
135
 
118
136
  self.python_mapper = kwargs.get('python_mapper', None)
119
137
  self.mapped_class = kwargs.get('mapped_class', None)
120
138
 
121
- self._taxonomies = {}
122
- self._taxonomy_entries = {}
139
+ self._taxonomies: Dict[DataModel, SimTaxonomy] = {}
140
+ self._taxonomy_entries: Dict[DataModel, SimTaxonomyEntry] = {}
123
141
 
124
142
  @property
125
143
  def content(self):
@@ -187,7 +205,7 @@ class TaxonomyMap(object):
187
205
 
188
206
  def get_or_create_simultan_taxonomy(self,
189
207
  data_model: 'DataModel',
190
- create=True):
208
+ create=True) -> SimTaxonomy:
191
209
  if self._taxonomies.get(data_model, None) is None:
192
210
  self._taxonomies[data_model] = data_model.get_or_create_taxonomy(
193
211
  taxonomy_name=self.taxonomy_name,
PySimultan2/utils.py CHANGED
@@ -151,7 +151,7 @@ def create_taxonomy(name, key, description='', data_model=None) -> SimTaxonomy:
151
151
  :param data_model: data model; if not None, the taxonomy will be added to the data model
152
152
  :return: SimTaxonomy
153
153
  """
154
- new_taxonomy = SimTaxonomy(key, name, description)
154
+ new_taxonomy = SimTaxonomy(key, name, description, None)
155
155
  if data_model is not None:
156
156
  data_model.taxonomies.Add(new_taxonomy)
157
157
  return new_taxonomy
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySimultan
3
- Version: 0.5.9.5
3
+ Version: 0.5.9.7
4
4
  Project-URL: Documentation, https://github.com/Bühler Maximilian/PySimultan2#readme
5
5
  Project-URL: Issues, https://github.com/Bühler Maximilian/PySimultan2/issues
6
6
  Project-URL: Source, https://github.com/Bühler Maximilian/PySimultan2
@@ -166,6 +166,10 @@ print(instances[0].param_1)
166
166
 
167
167
 
168
168
  # Change Log
169
+ ## [0.5.9.7] - 2025-01-09
170
+ - Added default component support to Mapper: if a default component is not present in the datamodel, it is automatically added
171
+ - Fixed content naming bug: Content.name is now used for the name of the TaxonomyEntry in SIMULTAN
172
+ - Added typing for better code completion
169
173
 
170
174
  ## [0.5.9.4] - 2024-12-31
171
175
  - Fixed bug in DirectoryInfo where \_\_dir_helper_file__ was not found if already existing
@@ -1,15 +1,15 @@
1
- PySimultan2/CHANGELOG.md,sha256=oibgN_OC1p98_zVtpae5CtPZNLLnpQYd3XGIN0ztniU,484
2
- PySimultan2/__about__.py,sha256=MeQdhI4ntQ60lTPRhDyMx9nuGAA9YdviWq3YIh1IWyA,21
1
+ PySimultan2/CHANGELOG.md,sha256=bRHCRr8oAxy4wd1ZUSztPYmx7_F40KkO3Qm9_H5jCGg,787
2
+ PySimultan2/__about__.py,sha256=AzMoyWtva5vCDZ8GestG4ORgLbm33B3AaD-c_QZaxCI,21
3
3
  PySimultan2/__init__.py,sha256=PGVR1uhY01dF5tHyad-znURUZ_LVB95vsjId2BT0aJM,3245
4
- PySimultan2/data_model.py,sha256=x1fvcPt9iC3Qy8uUkE59KRZCdh-paze8hDtDOzpf3YI,36278
5
- PySimultan2/default_types.py,sha256=K-Eka5BCKk8DT3HU5761Ym_-ZFmu1_Dro0zW0LVGoHA,27157
4
+ PySimultan2/data_model.py,sha256=3PJdz-coAa69Zct9PmGEB_CeMp-r-s4DQFFdTCwsn6o,37878
5
+ PySimultan2/default_types.py,sha256=P43xVs8ItrxONRwq902-InUmCVXiTYerD0i-PME3KeM,27542
6
6
  PySimultan2/files.py,sha256=4wuTfjgOMz6BEEwUDgNmUjfHZj0PYvcuE5-LWz2UEb0,28763
7
7
  PySimultan2/multi_values.py,sha256=ZFXlTLuZo32x7_7diYAp2XEjp5uwgHLgNOzN7v74-5I,13650
8
- PySimultan2/object_mapper.py,sha256=_SQye38NmIr4m_-X9CuvUJnVDBmjmUDdPH2bnaxpzKY,18546
8
+ PySimultan2/object_mapper.py,sha256=BJ4GZvRSZz0KU3ibjBQWnQbgiAzVWsf1b8tLaYrYtpQ,19708
9
9
  PySimultan2/simultan_object.py,sha256=akaSUZZWIVfwx1wT5EdOgRR2UeShUthX-LE2Uk6w8CQ,19058
10
- PySimultan2/taxonomy_maps.py,sha256=K8lwiBkEnQkx40YZxqSJAHdqwuo6ssvkXLL_GBxVYO0,9271
10
+ PySimultan2/taxonomy_maps.py,sha256=hhgXhRXIPTD2briG_yYZssJ9musOnzs0LC4e8e78e40,10323
11
11
  PySimultan2/type_setter_lookup.py,sha256=PGa5_EtV7SM15w3uxy0fA3LiQ0TaS4Ys0LYR5zs8aNk,3748
12
- PySimultan2/utils.py,sha256=0c49o3p4kTpL70ouI31Rjn1Lzu6XPK_YaX2ZHA8cqMg,66829
12
+ PySimultan2/utils.py,sha256=5IPhrmbh72gWa9YxCCJkdaU_vtpA5QNogDYDnduj2uM,66835
13
13
  PySimultan2/geometry/__init__.py,sha256=nJolTD1i5J8qUkOQa-r3D20aq3Co3sN31Xc0n4wJpJo,248
14
14
  PySimultan2/geometry/geometry_base.py,sha256=TwABfQEsqxAIGLqwvqVXEV-GA5sYGBJSJm7e58QmNzM,24015
15
15
  PySimultan2/geometry/utils.py,sha256=J25YsK8sso_UL7xRusItQZvyjtvxdOsSPelBQYFABhY,8519
@@ -75,7 +75,7 @@ PySimultan2/resources/assimp.dll,sha256=HwfDwXqoPDTFRyoQpA3qmgZoUdFtziJkV5fNtktE
75
75
  PySimultan2/resources/componentmanager.user,sha256=hrzr1US4pqkFnLHXcvPkvrgGd7QvlxaV8mhS6fuikEs,760
76
76
  PySimultan2/resources/defaultsettings.xml,sha256=s6Tk1tubLz5UYqXZWpD42EDHzedemRY1nEneoIVcUfg,392
77
77
  PySimultan2/resources/setup.bat,sha256=fjvvYfVM6TalS-QTSiKAbAId5nTsk8kGGo06ba-wWaY,32
78
- pysimultan-0.5.9.5.dist-info/METADATA,sha256=0eJZRacdVEhpQah_9YRazQnhF_mD2rVJk0UEQvKXe8Y,6256
79
- pysimultan-0.5.9.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
80
- pysimultan-0.5.9.5.dist-info/licenses/LICENSE.txt,sha256=pmSr98k6N005KMojnZxzLGRuRlDjDx3PUrK1lFj53HA,1126
81
- pysimultan-0.5.9.5.dist-info/RECORD,,
78
+ pysimultan-0.5.9.7.dist-info/METADATA,sha256=5K3Hf8oJBzmjVOorHvWa4r7lyD-RNT_tfA0_DQ6m9Fo,6550
79
+ pysimultan-0.5.9.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
80
+ pysimultan-0.5.9.7.dist-info/licenses/LICENSE.txt,sha256=pmSr98k6N005KMojnZxzLGRuRlDjDx3PUrK1lFj53HA,1126
81
+ pysimultan-0.5.9.7.dist-info/RECORD,,