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

Sign up to get free protection for your applications and to get access to all the features.
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