PySimultan 0.4.22__py3-none-any.whl → 0.5.0__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.
Files changed (36) hide show
  1. PySimultan2/__about__.py +1 -1
  2. PySimultan2/__init__.py +1 -0
  3. PySimultan2/data_model.py +185 -80
  4. PySimultan2/default_types.py +127 -21
  5. PySimultan2/files.py +55 -5
  6. PySimultan2/object_mapper.py +58 -7
  7. PySimultan2/resources/ComponentBuilder.dll +0 -0
  8. PySimultan2/resources/ComponentBuilder.runtimeconfig.json +2 -1
  9. PySimultan2/resources/ComponentBuilder.xml +47 -1
  10. PySimultan2/resources/SIMULTAN.AutoUpdate.Client.dll +0 -0
  11. PySimultan2/resources/SIMULTAN.AutoUpdate.DataTransferLibrary.dll +0 -0
  12. PySimultan2/resources/SIMULTAN.Lang.dll +0 -0
  13. PySimultan2/resources/SIMULTAN.Lang.xml +94 -7
  14. PySimultan2/resources/SIMULTAN.Plugins.dll +0 -0
  15. PySimultan2/resources/SIMULTAN.UI.dll +0 -0
  16. PySimultan2/resources/SIMULTAN.UI.xml +136 -43
  17. PySimultan2/resources/SIMULTAN.dll +0 -0
  18. PySimultan2/resources/SIMULTAN.xml +364 -97
  19. PySimultan2/resources/System.Collections.Immutable.dll +0 -0
  20. PySimultan2/resources/System.Reflection.Metadata.dll +0 -0
  21. PySimultan2/resources/System.Reflection.MetadataLoadContext.dll +0 -0
  22. PySimultan2/resources/componentmanager.user +0 -0
  23. PySimultan2/simultan_object.py +64 -15
  24. PySimultan2/taxonomy_maps.py +20 -12
  25. PySimultan2/type_setter_lookup.py +46 -33
  26. PySimultan2/utils.py +49 -14
  27. {pysimultan-0.4.22.dist-info → pysimultan-0.5.0.dist-info}/METADATA +2 -3
  28. {pysimultan-0.4.22.dist-info → pysimultan-0.5.0.dist-info}/RECORD +30 -32
  29. {pysimultan-0.4.22.dist-info → pysimultan-0.5.0.dist-info}/WHEEL +1 -1
  30. PySimultan2/resources/GeometryViewer.dll +0 -0
  31. PySimultan2/resources/GeometryViewer.dll.config +0 -42
  32. PySimultan2/resources/GeometryViewer.xml +0 -6425
  33. PySimultan2/resources/SitePlanner.dll +0 -0
  34. PySimultan2/resources/SitePlanner.dll.config +0 -11
  35. PySimultan2/resources/SitePlanner.xml +0 -2736
  36. {pysimultan-0.4.22.dist-info → pysimultan-0.5.0.dist-info}/licenses/LICENSE.txt +0 -0
PySimultan2/__about__.py CHANGED
@@ -1 +1 @@
1
- version = '0.4.22'
1
+ version = '0.5.0'
PySimultan2/__init__.py CHANGED
@@ -48,6 +48,7 @@ def setup():
48
48
  logger.setLevel('DEBUG')
49
49
 
50
50
  dll_path = os.environ.get('SIMULTAN_SDK_DIR', None)
51
+ dll_path = None
51
52
  if dll_path is None:
52
53
  with pkg_resources.path(resources, 'SIMULTAN.dll') as r_path:
53
54
  dll_path = str(r_path)
PySimultan2/data_model.py CHANGED
@@ -2,6 +2,8 @@ import atexit
2
2
  import os
3
3
  import shutil
4
4
  from uuid import uuid4
5
+ from functools import lru_cache
6
+ from time import sleep
5
7
  from colorlog import getLogger
6
8
  from . import config
7
9
  from .utils import *
@@ -11,7 +13,7 @@ from typing import Union, Tuple, TYPE_CHECKING
11
13
 
12
14
  # from SIMULTAN import Projects
13
15
  # noinspection PyUnresolvedReferences
14
- from SIMULTAN.Projects import ExtendedProjectData
16
+ from SIMULTAN.Projects import ExtendedProjectData, CompactProject
15
17
  # noinspection PyUnresolvedReferences
16
18
  from SIMULTAN import Utils
17
19
  # noinspection PyUnresolvedReferences
@@ -19,7 +21,7 @@ from SIMULTAN.Data import Users as SimultanUsers
19
21
  # from SIMULTAN.Serializer import Projects
20
22
  from SIMULTAN.Serializer.SimGeo import *
21
23
  from SIMULTAN.Serializer.Projects import *
22
- from SIMULTAN.Data.Components import SimComponent
24
+ from SIMULTAN.Data.Components import SimComponent, SimComponentCollection
23
25
  from SIMULTAN.Data.MultiValues import SimMultiValueBigTable, SimMultiValueField3D
24
26
  from SIMULTAN.Data.Assets import ResourceEntry
25
27
  from SIMULTAN.Data.Geometry import OffsetAlgorithm
@@ -33,13 +35,14 @@ from SIMULTAN.Data.Geometry import GeometryModel as NetGeometryModel
33
35
  from SIMULTAN.Data.Geometry import Layer, Vertex, Edge, PEdge, Face, Volume, EdgeLoop
34
36
 
35
37
  from System.Security import SecureString
38
+ from SIMULTAN.Data import SimId
36
39
  from System import Guid
37
40
  from System.IO import *
38
41
  from System.Security import *
39
42
  from System.Security.Cryptography import *
40
43
  from System.Text import *
41
44
 
42
- from .files import add_tag_to_resource
45
+ from .files import add_tag_to_resource, FileInfo as PythonFileInfo
43
46
 
44
47
 
45
48
  if TYPE_CHECKING:
@@ -72,19 +75,6 @@ class IAuthenticationServiceNew(SimultanUsers.IAuthenticationService):
72
75
  return user.Item1
73
76
 
74
77
 
75
- # data_models = WeakSet()
76
- # data_models_dict = WeakValueDictionary()
77
-
78
-
79
- # def get_default_data_model():
80
- # return data_models[0]
81
- #
82
- #
83
- # def add_data_model(data_model):
84
- # data_models.add(data_model)
85
-
86
-
87
- # noinspection PyUnresolvedReferences
88
78
  class DataModel:
89
79
 
90
80
  @classmethod
@@ -143,17 +133,17 @@ class DataModel:
143
133
  atexit.register(self.cleanup)
144
134
 
145
135
  self.id = uuid4()
146
- self.data = None
147
- self._project_data_manager = None
136
+ self.data: Optional[SimComponentCollection] = None
137
+ self._project_data_manager: Optional[ExtendedProjectData] = None
148
138
  self._user = None
149
- self._project = None
139
+ self._project: Optional[CompactProject] = None
150
140
  self._zip_loader = None
151
141
 
152
- self.project_data_manager = kwargs.get('project_data_manager', None)
142
+ self.project_data_manager: Optional[ExtendedProjectData] = kwargs.get('project_data_manager', None)
153
143
 
154
- self.project_path = kwargs.get('project_path', None)
144
+ self.project_path: Optional[str] = kwargs.get('project_path', None)
155
145
 
156
- self.service_provider = Utils.ServicesProvider()
146
+ self.service_provider: Utils.ServicesProvider = Utils.ServicesProvider()
157
147
 
158
148
  self.i_aut_service = IAuthenticationServiceNew
159
149
  self.i_aut_service.user_name = self.user_name
@@ -168,6 +158,8 @@ class DataModel:
168
158
 
169
159
  self.__mongo_instance = None
170
160
 
161
+ self.component_dict: dict[SimId, SimComponent] = {}
162
+
171
163
  @property
172
164
  def assets(self):
173
165
  return self.project_data_manager.AssetManager.Resources
@@ -282,6 +274,10 @@ class DataModel:
282
274
 
283
275
  def import_data_model(self):
284
276
  self.data = self.project_data_manager.Components
277
+
278
+ self.create_component_dict.cache_clear()
279
+ self.get_component_by_id.cache_clear()
280
+
285
281
  return self.data
286
282
 
287
283
  def add_field(self, field: SimMultiValueField3D):
@@ -313,6 +309,7 @@ class DataModel:
313
309
  return
314
310
 
315
311
  self.data.Add(component)
312
+ self.create_component_dict.cache_clear()
316
313
  # logger.info(
317
314
  # f'Added component {component.Id} {component.Name} {type(component)} to project {self.project_path}')
318
315
 
@@ -351,6 +348,32 @@ class DataModel:
351
348
  elif index is not None:
352
349
  self.data.RemoveItem(index)
353
350
 
351
+ self.create_component_dict.cache_clear()
352
+ self.get_component_by_id.cache_clear()
353
+
354
+ def remove_component(self,
355
+ component: Union[SimComponent, SimultanObject] = None,
356
+ index: int = None):
357
+ """
358
+ Remove a component from the project
359
+ :param component:
360
+ :param index:
361
+ :return:
362
+ """
363
+ if hasattr(component, '_wrapped_obj'):
364
+ component = component._wrapped_obj
365
+
366
+ if component.Parent is not None:
367
+ scce = next((x for x in component.Parent.Components if component.Id.Equals(x.Component.Id)), None)
368
+ if scce is not None:
369
+ component.Parent.Components.Remove(scce)
370
+ else:
371
+ index = self.data.Items.IndexOf(component)
372
+ self.data.RemoveItem(index)
373
+
374
+ self.create_component_dict.cache_clear()
375
+ self.get_component_by_id.cache_clear()
376
+
354
377
  def save(self):
355
378
  """
356
379
  Save the project
@@ -423,6 +446,7 @@ class DataModel:
423
446
  slot = SimSlot(slot_name, str(slot_extension))
424
447
  ComponentManagement.AddReferencedComponentSlot(comp, slot, self.user)
425
448
  ComponentManagement.AddReferencedComponent(comp, slot, ref_comp, self.user)
449
+ self.create_component_dict.cache_clear()
426
450
 
427
451
  def remove_referenced_component(self, comp: SimComponent, index: int):
428
452
  if index is not None:
@@ -431,6 +455,9 @@ class DataModel:
431
455
  index = self.data.Items.IndexOf(comp)
432
456
  self.data.RemoveItem(index)
433
457
 
458
+ self.create_component_dict.cache_clear()
459
+ self.get_component_by_id.cache_clear()
460
+
434
461
  def add_new_geometry_model(self, file_name: str, model_name: str = None, return_resource=False):
435
462
  """
436
463
  Create and add a new fc_geometry model
@@ -439,6 +466,7 @@ class DataModel:
439
466
  :param return_resource: return the resource
440
467
  :return: GeometryViewer.Model.GeometryModel, geo_resource
441
468
  """
469
+ self.get_file_infos.cache_clear()
442
470
  geo_resource = self.add_geometry_resource(file_name)
443
471
  file_info = FileInfo(geo_resource.CurrentFullPath)
444
472
  try:
@@ -469,6 +497,7 @@ class DataModel:
469
497
  model_name,
470
498
  self.service_provider)
471
499
 
500
+ self.get_file_infos.cache_clear()
472
501
  return new_resource
473
502
 
474
503
  def add_empty_resource(self, filename: str):
@@ -479,6 +508,7 @@ class DataModel:
479
508
  """
480
509
  # return self.project.AddResourceFile(FileInfo(str(filename)))
481
510
 
511
+ self.get_file_infos.cache_clear()
482
512
  return self.project.AddEmptyResource(FileInfo(str(filename)))
483
513
 
484
514
  def add_resource(self,
@@ -490,43 +520,50 @@ class DataModel:
490
520
  :param tag: tag to add to the resource
491
521
  :return:
492
522
  """
493
-
494
- del_copy = False
495
-
496
- existing_files = [x.Name for x in self.project_data_manager.AssetManager.Resources]
497
523
  try:
498
- act_filename = filename.replace('\\', os.sep)
499
- except TypeError:
500
- act_filename = filename
501
-
502
- if os.path.basename(act_filename) in existing_files:
503
- # create copy with running counter in temp dir and use this file:
504
- counter = 1
505
- while True:
506
- new_filename = os.path.basename(filename) + f'({str(counter)})'
507
- if new_filename not in existing_files and not os.path.exists(new_filename):
508
- break
509
- counter += 1
510
- shutil.copy(filename, os.path.join(os.path.dirname(filename), new_filename))
511
- filename = os.path.join(os.path.dirname(filename), new_filename)
512
- del_copy = True
513
-
514
- if isinstance(filename, (str, PosixPath, WindowsPath)):
515
- filename = FileInfo(str(filename))
516
-
517
- resource = self.project.CopyResourceAsContainedFileEntry(filename,
518
- self.project.ProjectUnpackFolder,
519
- '1')
520
-
521
- if del_copy:
522
- os.remove(str(filename))
523
-
524
- # file_id = self.project_data_manager.AssetManager.AddResourceEntry(FileInfo(filename))
525
- # return self.project_data_manager.AssetManager.Resources[file_id]
526
- if tag is not None:
527
- add_tag_to_resource(resource, tag)
528
-
529
- return resource
524
+
525
+ del_copy = False
526
+
527
+ existing_files = [x.Name for x in self.project_data_manager.AssetManager.Resources]
528
+ try:
529
+ act_filename = filename.replace('\\', os.sep)
530
+ except TypeError:
531
+ act_filename = filename
532
+
533
+ if os.path.basename(act_filename) in existing_files:
534
+ # create copy with running counter in temp dir and use this file:
535
+ counter = 1
536
+ while True:
537
+ new_filename = os.path.basename(filename) + f'({str(counter)})'
538
+ if new_filename not in existing_files and not os.path.exists(new_filename):
539
+ break
540
+ counter += 1
541
+ shutil.copy(filename, os.path.join(os.path.dirname(filename), new_filename))
542
+ filename = os.path.join(os.path.dirname(filename), new_filename)
543
+ del_copy = True
544
+
545
+ if isinstance(filename, (str, PosixPath, WindowsPath)):
546
+ filename = FileInfo(str(filename))
547
+
548
+ resource = self.project.CopyResourceAsContainedFileEntry(filename,
549
+ self.project.ProjectUnpackFolder,
550
+ '1')
551
+
552
+ if del_copy:
553
+ os.remove(str(filename))
554
+
555
+ # file_id = self.project_data_manager.AssetManager.AddResourceEntry(FileInfo(filename))
556
+ # return self.project_data_manager.AssetManager.Resources[file_id]
557
+ if tag is not None:
558
+ add_tag_to_resource(resource, tag)
559
+
560
+ # sleep(0.2) # this is necessary to avoid race conditions System.ArgumentException: An item with the same
561
+ # key has already been added. Key: at System.Collections.Generic.Dictionary`2.TryInsert(TKey key,
562
+ # TValue value, InsertionBehavior behavior)
563
+ return resource
564
+ except Exception as e:
565
+ logger.error(f'Error while adding resource {filename} to project {self.project_path}: {e}')
566
+ raise e
530
567
 
531
568
  def delete_resource(self, resource: Union[ResourceEntry, FileInfo, ContainedResourceFileEntry]):
532
569
  """
@@ -543,6 +580,7 @@ class DataModel:
543
580
  logger.info(f'Deleted resource {resource.Name} from project {self.project_path}')
544
581
  else:
545
582
  logger.error(f'Could not delete resource {resource.Name} from project {self.project_path}')
583
+ self.get_file_infos.cache_clear()
546
584
  return success
547
585
 
548
586
  def add_table(self, table: SimMultiValueBigTable):
@@ -584,6 +622,9 @@ class DataModel:
584
622
  # else:
585
623
  # return get_component_geometry(self, geometry_model, component)
586
624
 
625
+ def get_taxonomy_by_key(self, key: str):
626
+ return next((x for x in self.taxonomies if x.Key == key), None)
627
+
587
628
  def create_taxonomy(self, name: str, key: str, description: str = ''):
588
629
  """
589
630
  Create a new taxonomy and add it to the project
@@ -594,21 +635,16 @@ class DataModel:
594
635
  """
595
636
  return create_taxonomy(name, key, description, data_model=self)
596
637
 
597
- def get_taxonomy_entry(self, key):
598
- for entry in self.taxonomies:
599
- if entry.Key == key:
600
- return entry
638
+ def get_taxonomy_entry(self,
639
+ key,
640
+ taxonomy: Union[SimTaxonomy, str] = None) -> SimTaxonomyEntry:
601
641
 
602
- def create_mongo_instance(self):
603
- from .mongo_utils.base_classes import DataModel as MongoDataModel
604
- from .redis_utils.base_classes import save_in_redis
642
+ taxonomy = self.get_taxonomy_by_key(taxonomy) if isinstance(taxonomy, str) else taxonomy
643
+ taxonomies = [taxonomy] if taxonomy is not None else self.taxonomies
605
644
 
606
- logger.info(f'Creating mongo instance for project {self.project_data_manager.Project.Name}')
607
- self._mongo_instance, created = MongoDataModel.get_or_create(self)
608
- if created:
609
- logger.info(f'Created new mongo instance for {self.project_data_manager.Project.Name}')
610
- else:
611
- logger.info(f'Found existing mongo instance for {self.project_data_manager.Project.Name}')
645
+ for entry in taxonomies:
646
+ if entry.Key == key:
647
+ return entry
612
648
 
613
649
  def save_in_mongodb(self, db):
614
650
  """
@@ -618,14 +654,8 @@ class DataModel:
618
654
  """
619
655
  self._mongo_instance.save(db)
620
656
 
621
- def save_in_redis(self):
622
- """
623
- save the object in the redis database
624
- :return: None
625
- """
626
- save_in_redis(self)
627
-
628
- def get_taxonomy_entries(self):
657
+ def get_taxonomy_entries(self,
658
+ taxonomy: Union[SimTaxonomy, str] = None) -> dict[str, SimTaxonomyEntry]:
629
659
 
630
660
  def add_sub_entries(tax_entry, tax_entries_dict):
631
661
  for sub_entry in tax_entry.Children:
@@ -634,7 +664,9 @@ class DataModel:
634
664
  return tax_entries_dict
635
665
 
636
666
  taxonomy_entries = {}
637
- for taxonomy in self.taxonomies:
667
+ taxonomies = [taxonomy] if isinstance(taxonomy, SimTaxonomy) else self.taxonomies
668
+
669
+ for taxonomy in taxonomies:
638
670
  taxonomy_entries[taxonomy.Key] = taxonomy
639
671
  for entry in list(taxonomy.Entries):
640
672
  taxonomy_entries[entry.Key] = entry
@@ -677,6 +709,79 @@ class DataModel:
677
709
  mapper.current_data_model = self
678
710
  return mapper.get_typed_data(self, component_list=self.data.Items, create_all=False)
679
711
 
712
+ @lru_cache()
713
+ def create_component_dict(self):
714
+ new_component_list = set()
715
+
716
+ def get_subcomponents(sim_component: SimComponent):
717
+ new_subcomponents = set()
718
+ if isinstance(sim_component, SimultanObject):
719
+ sim_component = sim_component._wrapped_obj
720
+
721
+ if sim_component in new_component_list:
722
+ return
723
+ else:
724
+ new_component_list.add(sim_component)
725
+
726
+ if sim_component is None:
727
+ return []
728
+
729
+ for sub_component in sim_component.Components.Items:
730
+ if sub_component is None:
731
+ continue
732
+ new_subcomponents.add(sub_component.Component)
733
+ for ref_component in sim_component.ReferencedComponents.Items:
734
+ if ref_component is None:
735
+ continue
736
+ new_subcomponents.add(ref_component.Target)
737
+
738
+ for new_subcomponent in new_subcomponents:
739
+ get_subcomponents(new_subcomponent)
740
+
741
+ new_component_list.update(new_subcomponents)
742
+
743
+ for component in self.data.Items:
744
+ if component is None:
745
+ continue
746
+ get_subcomponents(component)
747
+ component_list = list(new_component_list)
748
+
749
+ self.component_dict = {x.Id: x for x in component_list}
750
+ return self.component_dict
751
+
752
+ @lru_cache()
753
+ def get_component_by_id(self,
754
+ item_id: SimId,
755
+ search_subcomponents=False) -> Union[SimComponent, None]:
756
+
757
+ # print(item_id.GlobalId, item_id.LocalId)
758
+ # _ = [print((x.Id.GlobalId, x.Id.LocalId)) for x in self.data.Items]
759
+
760
+ component = next((x for x in self.data.Items if x.Id.Equals(item_id)), None)
761
+
762
+ if component is None and search_subcomponents:
763
+ component = self.component_dict.get(item_id, None)
764
+ if component is None:
765
+ self.create_component_dict()
766
+ component = self.component_dict.get(item_id, None)
767
+
768
+ return component
769
+
770
+ def get_component_by_name(self, name: str) -> list[SimComponent]:
771
+ return [x for x in self.create_component_dict.values() if x.Name == name]
772
+
773
+ @lru_cache()
774
+ def get_file_infos(self) -> list[PythonFileInfo]:
775
+ return [PythonFileInfo(resource_entry=asset) for asset in self.assets]
776
+
777
+ def get_file_info_by_key(self,
778
+ key: int) -> Optional[PythonFileInfo]:
779
+
780
+ if isinstance(key, str):
781
+ key = int(key)
782
+
783
+ return next((PythonFileInfo(resource_entry=asset) for asset in self.assets if asset.Key == key), None)
784
+
680
785
  def __del__(self):
681
786
  self.cleanup()
682
787