PySimultan 0.4.22__py3-none-any.whl → 0.5.2.5__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. PySimultan2/CHANGELOG.md +4 -0
  2. PySimultan2/__about__.py +1 -1
  3. PySimultan2/__init__.py +1 -0
  4. PySimultan2/data_model.py +185 -80
  5. PySimultan2/default_types.py +125 -23
  6. PySimultan2/files.py +55 -5
  7. PySimultan2/object_mapper.py +146 -9
  8. PySimultan2/resources/ComponentBuilder.dll +0 -0
  9. PySimultan2/resources/ComponentBuilder.runtimeconfig.json +2 -1
  10. PySimultan2/resources/ComponentBuilder.xml +47 -1
  11. PySimultan2/resources/SIMULTAN.AutoUpdate.Client.dll +0 -0
  12. PySimultan2/resources/SIMULTAN.AutoUpdate.DataTransferLibrary.dll +0 -0
  13. PySimultan2/resources/SIMULTAN.Lang.dll +0 -0
  14. PySimultan2/resources/SIMULTAN.Lang.xml +94 -7
  15. PySimultan2/resources/SIMULTAN.Plugins.dll +0 -0
  16. PySimultan2/resources/SIMULTAN.UI.dll +0 -0
  17. PySimultan2/resources/SIMULTAN.UI.xml +136 -43
  18. PySimultan2/resources/SIMULTAN.dll +0 -0
  19. PySimultan2/resources/SIMULTAN.xml +364 -97
  20. PySimultan2/resources/System.Collections.Immutable.dll +0 -0
  21. PySimultan2/resources/System.Reflection.Metadata.dll +0 -0
  22. PySimultan2/resources/System.Reflection.MetadataLoadContext.dll +0 -0
  23. PySimultan2/resources/componentmanager.user +0 -0
  24. PySimultan2/simultan_object.py +64 -15
  25. PySimultan2/taxonomy_maps.py +20 -12
  26. PySimultan2/type_setter_lookup.py +46 -33
  27. PySimultan2/utils.py +79 -14
  28. {pysimultan-0.4.22.dist-info → pysimultan-0.5.2.5.dist-info}/METADATA +2 -3
  29. {pysimultan-0.4.22.dist-info → pysimultan-0.5.2.5.dist-info}/RECORD +31 -32
  30. {pysimultan-0.4.22.dist-info → pysimultan-0.5.2.5.dist-info}/WHEEL +1 -1
  31. PySimultan2/resources/GeometryViewer.dll +0 -0
  32. PySimultan2/resources/GeometryViewer.dll.config +0 -42
  33. PySimultan2/resources/GeometryViewer.xml +0 -6425
  34. PySimultan2/resources/SitePlanner.dll +0 -0
  35. PySimultan2/resources/SitePlanner.dll.config +0 -11
  36. PySimultan2/resources/SitePlanner.xml +0 -2736
  37. {pysimultan-0.4.22.dist-info → pysimultan-0.5.2.5.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,9 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- import xxsubtype
4
3
  from collections.abc import Iterable
5
4
  import numpy as np
6
- import pandas as pd
7
5
  import colorlog
8
6
  from typing import Union, List, Type, Set, Tuple, Any, Optional
9
7
 
@@ -139,11 +137,19 @@ class ComponentList(SimultanObject):
139
137
 
140
138
  def append(self, values: Union[SimultanObject, List]):
141
139
 
140
+ return_val = []
141
+
142
+ as_list = True
142
143
  if not isinstance(values, Iterable):
144
+ as_list = False
143
145
  values = [values]
144
146
 
145
147
  for i, value in enumerate(values, start=len(self.data)):
146
- self._set_value(value, i)
148
+ return_val.append(self._set_value(value, i))
149
+
150
+ if not as_list:
151
+ return return_val[0]
152
+ return return_val
147
153
 
148
154
  def _update_slot_extensions(self, index: int):
149
155
 
@@ -160,6 +166,9 @@ class ComponentList(SimultanObject):
160
166
 
161
167
  def _set_value(self, value, i):
162
168
 
169
+ if isinstance(value, FileInfo):
170
+ raise ValueError(f'FileInfos cannot be added to ComponentLists')
171
+
163
172
  if isinstance(value, SimultanObject):
164
173
  slot = value._wrapped_obj.Slots.Items[0]
165
174
 
@@ -171,6 +180,9 @@ class ComponentList(SimultanObject):
171
180
  self.add_referenced_component(value._wrapped_obj,
172
181
  slot_extension=str(i),
173
182
  slot=slot)
183
+
184
+ return value
185
+
174
186
  else:
175
187
  new_val = create_mapped_python_object(value,
176
188
  data_model=self._data_model,
@@ -193,6 +205,8 @@ class ComponentList(SimultanObject):
193
205
  slot_extension=str(i),
194
206
  slot=taxonomy_entry)
195
207
 
208
+ return new_val
209
+
196
210
  def __setitem__(self, i, value):
197
211
  if isinstance(i, slice):
198
212
  for j, val in enumerate(value):
@@ -210,7 +224,7 @@ class ComponentList(SimultanObject):
210
224
  self._set_value(value, i)
211
225
 
212
226
  def extend(self, values: List):
213
- self.append(values)
227
+ return self.append(values)
214
228
 
215
229
  def remove(self, value: SimultanObject):
216
230
  self.discard(value)
@@ -292,6 +306,41 @@ class ComponentList(SimultanObject):
292
306
  self._wrapped_obj.Components.Clear()
293
307
  self._wrapped_obj.ReferencedComponents.Clear()
294
308
 
309
+ def to_json(self) -> dict[Any: Any]:
310
+
311
+ return_val = [None] * len(self.data)
312
+
313
+ for i, val in enumerate(self.data):
314
+
315
+ if hasattr(val, 'json_ref'):
316
+ return_val[i] = val.json_ref()
317
+ elif isinstance(val, list):
318
+ return_val[i] = [v.json_ref() if hasattr(v, 'json_ref') else v for v in val]
319
+ elif isinstance(val, dict):
320
+ return_val[i] = {k: v.json_ref() if hasattr(v, 'json_ref') else v for k, v in val.items()}
321
+ elif isinstance(val, np.ndarray):
322
+ return_val[i] = val.tolist()
323
+ else:
324
+ return_val[i] = val
325
+
326
+ return {
327
+ str(self.id): {
328
+ 'name': self.name,
329
+ 'taxonomies': self.taxonomy_keys,
330
+ 'items': return_val
331
+ }
332
+ }
333
+
334
+ def json_ref(self):
335
+ return {"$ref": {
336
+ "$type": 'ComponentList',
337
+ "$taxonomies": self.taxonomy_keys,
338
+ "$id": {'local_id': self.id.LocalId,
339
+ 'global_id': str(self.id.GlobalId)
340
+ },
341
+ "length": len(self)
342
+ }
343
+ }
295
344
 
296
345
  component_list_map = TaxonomyMap(taxonomy_name='PySimultan',
297
346
  taxonomy_key='PySimultan',
@@ -319,9 +368,11 @@ class ComponentDictionary(SimultanObject):
319
368
  self._dict = {}
320
369
  super().__init__(*args, **kwargs)
321
370
  self.component_policy = kwargs.get('component_policy', 'subcomponent') # component add policy of the content/parameter/property, 'reference' or 'subcomponent'
371
+ self._generate_internal_dict()
322
372
 
323
373
  def __load_init__(self, *args, **kwargs):
324
374
  self._dict = {}
375
+ self._generate_internal_dict()
325
376
 
326
377
  @classmethod
327
378
  def create_from_values(cls,
@@ -348,15 +399,20 @@ class ComponentDictionary(SimultanObject):
348
399
  for key, value in values.items():
349
400
  new_component_dict[key] = value
350
401
 
402
+ new_component_dict._generate_internal_dict()
403
+
351
404
  return new_component_dict
352
405
 
353
406
  def __getitem__(self, key, *args, **kwargs):
354
407
 
355
408
  comp_dict = object.__getattribute__(self, '_dict')
356
409
 
357
- if kwargs.get('check_dict', True) and comp_dict is not None and key in object.__getattribute__(self,
358
- '_dict').keys():
359
- return object.__getattribute__(self, '_dict').get(key, None)
410
+ if (kwargs.get('check_dict', False) and comp_dict is not None and
411
+ (key in comp_dict.keys() or '__dict_key__' + key in comp_dict.keys())):
412
+ if key in comp_dict.keys():
413
+ return comp_dict.get(key, None)
414
+ else:
415
+ return comp_dict.get('__dict_key__' + key, None)
360
416
  else:
361
417
  # data_model = config.default_data_model
362
418
  # obj = get_component_taxonomy_entry(self._wrapped_obj, key)
@@ -406,6 +462,8 @@ class ComponentDictionary(SimultanObject):
406
462
  object_mapper=object_mapper)
407
463
 
408
464
  if val is not None:
465
+ if key.startswith('__dict_key__'):
466
+ key = key.replace('__dict_key__', '')
409
467
  self._dict[key] = val
410
468
 
411
469
  return self._dict.get(key, None)
@@ -454,27 +512,32 @@ class ComponentDictionary(SimultanObject):
454
512
  return
455
513
 
456
514
  from .type_setter_lookup import type_setter_fcn_lookup_dict
457
- setter_fcn = type_setter_fcn_lookup_dict.get(type(value), set_property_to_unknown_type)
515
+ setter_fcn = type_setter_fcn_lookup_dict.get(value, set_property_to_unknown_type)
458
516
 
459
517
  setter_fcn(*fcn_arg_list)
460
518
  item = self.__getitem__(key, check_dict=False)
461
519
 
462
- self._dict[key] = item
520
+ if key.startswith('__dict_key__'):
521
+ self._dict[key.replace('__dict_key__', '')] = item
522
+ else:
523
+ self._dict[key] = item
463
524
 
464
525
  def __delitem__(self, key):
465
526
  self[key] = None
466
527
  del self._dict[key]
467
528
 
468
529
  def items(self):
530
+ if self._dict is None or not self._dict:
531
+ self._generate_internal_dict()
469
532
  return self._dict.items()
470
533
 
471
534
  def keys(self):
472
- if not self._dict:
535
+ if not self._dict or not self._dict:
473
536
  self._generate_internal_dict()
474
537
  return self._dict.keys()
475
538
 
476
539
  def values(self):
477
- if not self._dict:
540
+ if not self._dict or not self._dict:
478
541
  self._generate_internal_dict()
479
542
  return self._dict.values()
480
543
 
@@ -482,22 +545,26 @@ class ComponentDictionary(SimultanObject):
482
545
  comp_dict = {}
483
546
 
484
547
  for parameter in self._wrapped_obj.Parameters.Items:
485
- comp_dict[parameter.NameTaxonomyEntry.TextOrKey] = get_obj_value(parameter,
486
- data_model=self._data_model,
487
- object_mapper=self._object_mapper)
548
+ key = parameter.NameTaxonomyEntry.TextOrKey.replace('__dict_key__', '')
549
+ comp_dict[key] = get_obj_value(parameter,
550
+ data_model=self._data_model,
551
+ object_mapper=self._object_mapper)
488
552
  for component in self._wrapped_obj.Components.Items:
489
- comp_dict[component.Slot.SlotBase.Target.Key] = get_obj_value(component.Component,
490
- data_model=self._data_model,
491
- object_mapper=self._object_mapper)
553
+ key = component.Slot.SlotBase.Target.Key.replace('__dict_key__', '')
554
+ comp_dict[key] = get_obj_value(component.Component,
555
+ data_model=self._data_model,
556
+ object_mapper=self._object_mapper)
492
557
  for ref_component in self._wrapped_obj.ReferencedComponents.Items:
493
- comp_dict[ref_component.Slot.SlotBase.Target.Key] = get_obj_value(ref_component.Target,
494
- data_model=self._data_model,
495
- object_mapper=self._object_mapper)
558
+ key = ref_component.Slot.SlotBase.Target.Key.replace('__dict_key__', '')
559
+ comp_dict[key] = get_obj_value(ref_component.Target,
560
+ data_model=self._data_model,
561
+ object_mapper=self._object_mapper)
496
562
  for ref_asset in self._wrapped_obj.ReferencedAssets.Items:
497
563
  for tag in ref_asset.Resource.Tags:
498
- comp_dict[tag.Target.Key] = get_obj_value(ref_asset.Target,
499
- data_model=self._data_model,
500
- object_mapper=self._object_mapper)
564
+ 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)
501
568
 
502
569
  object.__setattr__(self, '_dict', comp_dict)
503
570
 
@@ -529,5 +596,40 @@ class ComponentDictionary(SimultanObject):
529
596
  for key, value in other.items():
530
597
  self[key] = value
531
598
 
599
+ def to_json(self) -> dict:
600
+
601
+ return_value = {}
602
+
603
+ for key, value in self.items():
604
+ if isinstance(value, SimultanObject):
605
+ return_value[key] = value.to_json()
606
+ elif isinstance(value, list):
607
+ return_value[key] = [v.json_ref() if hasattr(v, 'json_ref') else v for v in value]
608
+ elif isinstance(value, dict):
609
+ return_value[key] = {k: v.json_ref() if hasattr(v, 'json_ref') else v for k, v in value.items()}
610
+ elif isinstance(value, np.ndarray):
611
+ return_value[key] = value.tolist()
612
+ else:
613
+ return_value[key] = value
614
+
615
+ return {
616
+ str(self.id): {
617
+ 'name': self.name,
618
+ 'taxonomies': self.taxonomy_keys,
619
+ 'items': return_value
620
+ }
621
+ }
622
+
623
+ def json_ref(self):
624
+ return {"$ref": {
625
+ "$type": 'ComponentDictionary',
626
+ "$taxonomies": self.taxonomy_keys,
627
+ "$id": {'local_id': self.id.LocalId,
628
+ 'global_id': str(self.id.GlobalId)
629
+ },
630
+ "length": len(self)
631
+ }
632
+ }
633
+
532
634
 
533
635
  component_dict_map = ComponentDictionary._taxonomy_map
PySimultan2/files.py CHANGED
@@ -81,9 +81,17 @@ def add_asset_to_component(comp: [SimComponent, SimultanObject],
81
81
  wrapped_obj = comp if isinstance(comp, SimComponent) else comp._wrapped_obj
82
82
 
83
83
  if tag is not None:
84
- add_tag_to_resource(asset, tag)
84
+ try:
85
+ add_tag_to_resource(asset, tag)
86
+ except Exception as e:
87
+ logger.error(f'Error adding tag to asset {asset}: {e} ')
88
+ raise e
85
89
 
86
- return ComponentMapping.AddAsset(wrapped_obj, asset, content_id)
90
+ try:
91
+ return ComponentMapping.AddAsset(wrapped_obj, asset, content_id)
92
+ except Exception as e:
93
+ logger.error(f'Error adding asset {asset} to component: {e}')
94
+ raise e
87
95
 
88
96
 
89
97
  def remove_asset_from_component(comp: Union[SimComponent, SimultanObject],
@@ -187,7 +195,9 @@ class FileInfo(object, metaclass=MetaMock):
187
195
  _cls_instances = {}
188
196
 
189
197
  @classmethod
190
- def from_string(cls, filename: str, content: str, *args, **kwargs) -> FileInfo:
198
+ def from_string(cls,
199
+ filename: str,
200
+ content: str, *args, **kwargs) -> FileInfo:
191
201
  """
192
202
  Create a file info object from a string.
193
203
  :param filename: Name of the file to be created. E.g. 'new_file.txt'
@@ -237,6 +247,13 @@ class FileInfo(object, metaclass=MetaMock):
237
247
  self.args = args
238
248
  self.kwargs = kwargs
239
249
 
250
+ @property
251
+ def key(self) -> int:
252
+ try:
253
+ return self.resource_entry.Key
254
+ except Exception as e:
255
+ return None
256
+
240
257
  @property
241
258
  def resource_entry(self) -> Union[ResourceFileEntry, ContainedResourceFileEntry, None]:
242
259
  if self._resource_entry is None:
@@ -258,8 +275,13 @@ class FileInfo(object, metaclass=MetaMock):
258
275
  self._resource_entry = value
259
276
 
260
277
  @property
261
- def file_size(self) -> int:
262
- return os.path.getsize(self.file_path)
278
+ def file_size(self) -> Optional[int]:
279
+ try:
280
+ return os.path.getsize(self.file_path)
281
+ except FileNotFoundError:
282
+ raise FileNotFoundError(f'File not found: {self.file_path}')
283
+ except Exception as e:
284
+ raise e
263
285
 
264
286
  @property
265
287
  def last_modified(self) -> datetime:
@@ -269,6 +291,10 @@ class FileInfo(object, metaclass=MetaMock):
269
291
  def resource_entry(self, value):
270
292
  self._resource_entry = value
271
293
 
294
+ @property
295
+ def filename(self) -> str:
296
+ return self.resource_entry.File.Name
297
+
272
298
  @property
273
299
  def name(self) -> str:
274
300
  return os.path.basename(self.file_path)
@@ -317,6 +343,9 @@ class FileInfo(object, metaclass=MetaMock):
317
343
  def __exit__(self, *args):
318
344
  self.file_obj.close()
319
345
 
346
+ def __repr__(self):
347
+ return f'FileInfo({self.file_path})'
348
+
320
349
  def get_content(self, encoding='utf-8') -> Optional[Union[str, dict[str, str]]]:
321
350
  """
322
351
  Get the content of the file.
@@ -373,3 +402,24 @@ class FileInfo(object, metaclass=MetaMock):
373
402
  if self.resource_entry is not None:
374
403
  self.data_model.delete_resource(self.resource_entry)
375
404
  os.remove(self.file_path)
405
+
406
+ def to_json(self) -> dict:
407
+
408
+ obj_dict = {
409
+ 'key': self.key,
410
+ 'name': self.name,
411
+ 'file_path': self.file_path,
412
+ 'file_size': self.file_size,
413
+ 'last_modified': self.last_modified,
414
+ 'encoding': self.encoding,
415
+ 'is_zip': self.is_zip,
416
+ }
417
+
418
+ return obj_dict
419
+
420
+ def json_ref(self):
421
+ return {"$ref": {
422
+ "$type": 'FileInfo',
423
+ "$key": str(self.key)
424
+ }
425
+ }
@@ -1,4 +1,4 @@
1
- from typing import Optional, Type, TYPE_CHECKING, Union
1
+ from typing import Optional, Type, TYPE_CHECKING, Union, Any
2
2
  from copy import copy
3
3
  from collections import UserList
4
4
  from colorlog import getLogger
@@ -32,9 +32,21 @@ default_taxonomy_maps = {'ComponentList': component_list_map,
32
32
 
33
33
  class PythonMapper(object):
34
34
 
35
+ mappers = {}
36
+
35
37
  def __new__(cls, *args, **kwargs):
36
38
  instance = super(PythonMapper, cls).__new__(cls)
37
39
  config.set_default_mapper(instance)
40
+
41
+ if kwargs.get('add_to_mappers', True):
42
+ initial_module_name = kwargs.get('module', 'unknown_module')
43
+ module_name = initial_module_name
44
+ i = 0
45
+ while module_name in cls.mappers.keys():
46
+ module_name = f'{initial_module_name}_{i}'
47
+ i+=1
48
+ cls.mappers[module_name] = instance
49
+
38
50
  return instance
39
51
 
40
52
  def __init__(self, *args, **kwargs):
@@ -42,6 +54,9 @@ class PythonMapper(object):
42
54
  self._mapped_classes = {}
43
55
 
44
56
  self.name = kwargs.get('name', 'PythonMapper')
57
+ self._module = kwargs.get('module', 'unknown_module')
58
+ self.submodules = kwargs.get('submodules', {})
59
+
45
60
  self.registered_classes: dict[str: SimultanObject] = copy(default_registered_classes) # dict with all registered classes: {taxonomy: class}
46
61
 
47
62
  self.undefined_registered_classes: dict[str: SimultanObject] = {} # dict with all registered classes: {taxonomy: class}
@@ -59,6 +74,18 @@ class PythonMapper(object):
59
74
  self.re_register = False
60
75
  self.load_undefined = False
61
76
 
77
+ @property
78
+ def module(self):
79
+ return self._module
80
+
81
+ @module.setter
82
+ def module(self, value):
83
+ if self._module != value:
84
+ del self.mappers[self._module]
85
+
86
+ self._module = value
87
+ self.mappers[value] = self
88
+
62
89
  @property
63
90
  def mapped_classes(self):
64
91
  if len(self.registered_classes) > len(self._mapped_classes):
@@ -72,10 +99,24 @@ class PythonMapper(object):
72
99
  def mapped_classes(self, value):
73
100
  self._mapped_classes = value
74
101
 
75
- def register(self, taxonomy, cls, taxonomy_map=None):
76
- if not self.re_register and taxonomy in self.registered_classes.keys():
102
+ def register(self,
103
+ taxonomy: str,
104
+ cls: Type[Any],
105
+ re_register=True,
106
+ update_in_other_mappers=False,
107
+ taxonomy_map=None):
108
+
109
+ # print(f'Registering {taxonomy} with {cls} {hash(cls)}')
110
+
111
+ if not (self.re_register or re_register) and taxonomy in self.registered_classes.keys():
77
112
  return
78
113
 
114
+ if taxonomy in self.mapped_classes.keys():
115
+ try:
116
+ del self.mapped_classes[taxonomy]
117
+ except KeyError:
118
+ pass
119
+
79
120
  if taxonomy_map is None:
80
121
  taxonomy_map = TaxonomyMap(taxonomy_name='PySimultan',
81
122
  taxonomy_key='PySimultan',
@@ -85,8 +126,28 @@ class PythonMapper(object):
85
126
  self.registered_classes[taxonomy] = cls
86
127
  self.taxonomy_maps[taxonomy] = taxonomy_map
87
128
 
129
+ if update_in_other_mappers:
130
+ self.update_from_other_mappers()
131
+
88
132
  return self.get_mapped_class(taxonomy)
89
133
 
134
+ def update_from_other_mappers(self):
135
+ for mapper in self.mappers.values():
136
+ if mapper is not self:
137
+ for cls, taxonomy in mapper.registered_classes.items():
138
+ if cls in self.registered_classes.values():
139
+ key = list(filter(lambda x: mapper.registered_classes[x] == cls,
140
+ mapper.registered_classes)
141
+ )[0]
142
+ mapper.registered_classes[key] = cls
143
+ print(f'Updated {cls} in {mapper.module} with {taxonomy}')
144
+
145
+ def update_from_submodules(self):
146
+ for submodule in self.submodules.values():
147
+ self.registered_classes.update(submodule.registered_classes)
148
+ self.taxonomy_maps.update(submodule.taxonomy_maps)
149
+ self.registered_geometry_classes.update(submodule.registered_geometry_classes)
150
+
90
151
  def create_mapped_class(self, taxonomy, cls):
91
152
 
92
153
  if any([issubclass(cls, x) for x in (SimultanObject, UserList)]):
@@ -171,7 +232,11 @@ class PythonMapper(object):
171
232
  typed_data.append(typed_object)
172
233
  return typed_data
173
234
 
174
- def create_python_geometry_object(self, component, data_model=None, *args, **kwargs):
235
+ def create_python_geometry_object(self,
236
+ component: Union[Layer, Vertex, Edge, PEdge, Face, Volume, EdgeLoop],
237
+ data_model: 'DataModel' = None,
238
+ *args,
239
+ **kwargs):
175
240
 
176
241
  if component is None:
177
242
  return None
@@ -191,7 +256,7 @@ class PythonMapper(object):
191
256
  self.create_python_object(component, data_model, *args, **kwargs)
192
257
 
193
258
  def get_mapped_class_from_component(self,
194
- component,
259
+ component: Union[SimComponent, Layer, Vertex, Edge, PEdge, Face, Volume, EdgeLoop],
195
260
  data_model: Optional['DataModel'] = None,
196
261
  *args,
197
262
  **kwargs) -> Optional[Type[SimultanObject]]:
@@ -205,7 +270,10 @@ class PythonMapper(object):
205
270
  if isinstance(component,
206
271
  (Layer, Vertex, Edge, PEdge, Face, Volume, EdgeLoop)
207
272
  ):
208
- self.create_python_geometry_object(component, data_model, *args, **kwargs)
273
+ self.create_python_geometry_object(component,
274
+ data_model,
275
+ *args,
276
+ **kwargs)
209
277
 
210
278
  c_slots = [x.Target.Key for x in component.Slots.Items]
211
279
  c_slot = list(set(c_slots) & set(self.registered_classes.keys()))
@@ -266,6 +334,21 @@ class PythonMapper(object):
266
334
  *args,
267
335
  **kwargs)
268
336
 
337
+ def create_mapped_python_object(self,
338
+ obj: Any,
339
+ data_model=None,
340
+ add_to_data_model=True,
341
+ *args,
342
+ **kwargs) -> Optional[SimultanObject]:
343
+
344
+ from .utils import create_mapped_python_object
345
+ return create_mapped_python_object(obj,
346
+ object_mapper=self,
347
+ data_model=data_model,
348
+ add_to_data_model=add_to_data_model,
349
+ *args,
350
+ **kwargs)
351
+
269
352
  def get_typed_data_with_taxonomy(self, taxonomy: str, data_model=None, first=False):
270
353
 
271
354
  tax_components = data_model.find_components_with_taxonomy(taxonomy=taxonomy, first=first)
@@ -307,14 +390,68 @@ class PythonMapper(object):
307
390
  new_val = create_mapped_python_object(obj, self, data_model)
308
391
  return new_val
309
392
 
310
- def copy(self):
311
- new_mapper = PythonMapper()
393
+ def copy(self,
394
+ *args,
395
+ **kwargs) -> 'PythonMapper':
396
+
397
+ orig_new_module_name = kwargs.get('module', self.module)
398
+ new_module_name = orig_new_module_name
399
+ i = 0
400
+ while new_module_name in self.mappers.keys():
401
+ new_module_name = f'copy_{i}_of_{new_module_name}'
402
+ i+=1
403
+
404
+ new_mapper = PythonMapper(add_to_mappers=kwargs.get('add_to_mappers', True),
405
+ module=new_module_name)
312
406
  new_mapper.registered_classes = self.registered_classes
313
407
  new_mapper.taxonomy_maps = self.taxonomy_maps
314
408
  new_mapper.registered_geometry_classes = self.registered_geometry_classes
315
409
  new_mapper.load_undefined = self.load_undefined
410
+
316
411
  return new_mapper
317
412
 
413
+ def __add__(self, other: 'PythonMapper') -> 'PythonMapper':
414
+ # new_mapper = self.copy(add_to_mappers=True)
415
+ self.submodules[other.module] = other
416
+ self.submodules.update(other.submodules)
417
+ self.registered_classes.update(other.registered_classes)
418
+ self.taxonomy_maps.update(other.taxonomy_maps)
419
+ self.registered_geometry_classes.update(other.registered_geometry_classes)
420
+ return self
421
+
422
+ def get_mapped_class_for_python_type(self, python_type: type) -> Optional[Type[SimultanObject]]:
423
+ try:
424
+ key = list(filter(lambda x: self.registered_classes[x] == python_type,
425
+ self.registered_classes)
426
+ )[0]
427
+ mapped_cls = self.get_mapped_class(key)
428
+ return mapped_cls
429
+ except IndexError:
430
+ return None
431
+
432
+ def __repr__(self):
433
+ return f'PythonMapper(module={self.module}, {len(self.registered_classes)} registered classes)'
434
+
318
435
 
319
436
  if config.get_default_mapper() is None:
320
- config.set_default_mapper(PythonMapper())
437
+ config.set_default_mapper(PythonMapper(module='default'))
438
+
439
+
440
+ def register(taxonomy: str,
441
+ taxonomy_map: TaxonomyMap,
442
+ re_register=True,
443
+ module: str = 'unknown_module') -> Any:
444
+
445
+ if module not in PythonMapper.mappers.keys():
446
+ PythonMapper(module=module)
447
+
448
+ mapper = PythonMapper.mappers[module]
449
+
450
+ def decorator(cls):
451
+ mapper.register(taxonomy,
452
+ cls,
453
+ re_register=re_register,
454
+ taxonomy_map=taxonomy_map)
455
+ return cls
456
+
457
+ return decorator
Binary file
@@ -12,7 +12,8 @@
12
12
  }
13
13
  ],
14
14
  "configProperties": {
15
- "System.Reflection.Metadata.MetadataUpdater.IsSupported": false
15
+ "System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
16
+ "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": true
16
17
  }
17
18
  }
18
19
  }