PySimultan 0.4.0__py3-none-any.whl → 0.4.2__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/__about__.py CHANGED
@@ -1 +1 @@
1
- version = '0.4.0'
1
+ version = '0.4.2'
PySimultan2/__init__.py CHANGED
@@ -1,38 +1,105 @@
1
+ import os
1
2
  import sys
2
3
  import colorlog
3
- from .config import *
4
+ # from .config import *
5
+ from ruamel.yaml import YAML, yaml_object, add_representer
6
+
7
+ def setup_logging():
8
+ handler = colorlog.StreamHandler()
9
+ formatter = colorlog.ColoredFormatter(
10
+ "%(log_color)s%(levelname)-8s%(reset)s %(blue)s%(message)s",
11
+ datefmt=None,
12
+ reset=True,
13
+ log_colors={
14
+ 'DEBUG': 'cyan',
15
+ 'INFO': 'green',
16
+ 'WARNING': 'yellow',
17
+ 'ERROR': 'red',
18
+ 'CRITICAL': 'red,bg_white',
19
+ },
20
+ secondary_log_colors={},
21
+ style='%'
22
+ )
23
+
24
+ handler.setFormatter(formatter)
25
+
26
+ logger = colorlog.getLogger('PySimultan')
27
+ logger.addHandler(handler)
28
+
29
+ return logger
30
+
31
+
32
+ def setup():
33
+ import colorlog
34
+ try:
35
+ import importlib.resources as pkg_resources
36
+ except ImportError:
37
+ # Try backported to PY<37 importlib_resources.
38
+ import importlib_resources as pkg_resources
39
+
40
+ from . import resources
41
+ sys.path.append(str(pkg_resources.files(resources)))
42
+
43
+ logger = colorlog.getLogger('PySimultan')
44
+ logger.setLevel('DEBUG')
45
+
46
+ dll_path = os.environ.get('SIMULTAN_SDK_DIR', None)
47
+ if dll_path is None:
48
+ with pkg_resources.path(resources, 'SIMULTAN.dll') as r_path:
49
+ dll_path = str(r_path)
50
+ sys.path.append(dll_path)
51
+
52
+ from pythonnet import load
53
+ from pythonnet import clr_loader, set_runtime
54
+ list(clr_loader.find_runtimes())
55
+ load('coreclr')
56
+ import clr
57
+ test = clr.AddReference(
58
+ os.path.join(dll_path, 'SIMULTAN.dll') if not dll_path.endswith('SIMULTAN.dll') else dll_path)
59
+ clr.AddReference("System.Security.Cryptography")
60
+ # clr.AddReference(os.path.join(dll_path, 'SIMULTAN'))
61
+
62
+ from SIMULTAN.Data.Components import SimComponent
63
+
64
+ continue_on_error = True
65
+
66
+ def represent_none(self, _):
67
+ return self.represent_scalar('tag:yaml.org,2002:null', '')
68
+
69
+ add_representer(type(None), represent_none)
70
+ yaml = YAML()
71
+ yaml.default_flow_style = None
72
+ yaml.preserve_quotes = True
73
+ yaml.allow_unicode = True
74
+
75
+ return yaml
76
+
77
+
78
+ logger = setup_logging()
79
+ yaml = setup()
80
+
81
+
82
+ class Config:
83
+ def __init__(self):
84
+ self._default_data_model = None
85
+ self._default_mapper = None
86
+ self.logger = logger
87
+
88
+ def get_default_data_model(self, *args, **kwargs):
89
+ return self._default_data_model
90
+
91
+ def get_default_mapper(self, *args, **kwargs):
92
+ return self._default_mapper
93
+
94
+ def set_default_data_model(self, data_model):
95
+ self._default_data_model = data_model
96
+
97
+ def set_default_mapper(self, mapper):
98
+ self._default_mapper = mapper
99
+
100
+
101
+ config = Config()
102
+
4
103
  from .data_model import DataModel
5
104
  from .files import FileInfo
6
105
  from .object_mapper import PythonMapper
7
-
8
- # from .simultan_utils import create_component
9
- # from .template_tools import Template, TemplateParser
10
- # from .geo_default_types import BaseGeometricLayer, BaseGeometricVertex, BaseGeometricEdge, BaseGeometricEdgeLoop, BaseGeometricFace, BaseGeometricVolume
11
- #
12
- # print(sys.version)
13
- #
14
- # from ParameterStructure.Components import SimComponent
15
- # from ParameterStructure.Parameters import SimParameter
16
-
17
- # from .utils import create_component
18
-
19
- handler = colorlog.StreamHandler()
20
- formatter = colorlog.ColoredFormatter(
21
- "%(log_color)s%(levelname)-8s%(reset)s %(blue)s%(message)s",
22
- datefmt=None,
23
- reset=True,
24
- log_colors={
25
- 'DEBUG': 'cyan',
26
- 'INFO': 'green',
27
- 'WARNING': 'yellow',
28
- 'ERROR': 'red',
29
- 'CRITICAL': 'red,bg_white',
30
- },
31
- secondary_log_colors={},
32
- style='%'
33
- )
34
-
35
- handler.setFormatter(formatter)
36
-
37
- logger = colorlog.getLogger('PySimultan')
38
- logger.addHandler(handler)
PySimultan2/data_model.py CHANGED
@@ -3,7 +3,6 @@ import os
3
3
  import shutil
4
4
  from uuid import uuid4
5
5
  from colorlog import getLogger
6
- from functools import lru_cache, reduce
7
6
  from weakref import WeakSet, WeakValueDictionary
8
7
  from . import config
9
8
  from .utils import *
@@ -46,6 +45,7 @@ from .files import add_tag_to_resource
46
45
 
47
46
  if TYPE_CHECKING:
48
47
  from .object_mapper import PythonMapper
48
+ from .geometry import GeometryModel
49
49
 
50
50
 
51
51
  logger = getLogger('PySimultan')
@@ -114,12 +114,12 @@ class DataModel:
114
114
  else:
115
115
  print("Failed to create project")
116
116
 
117
- return cls(project_path=project_path, user_name=user_name, password=password)
117
+ return cls(project_path=project_path, user_name=user_name, password=password, project_data_manager=projectData)
118
118
 
119
119
  def __new__(cls, *args, **kwargs):
120
120
 
121
121
  instance = super().__new__(cls)
122
- config.default_data_model = instance
122
+ config.set_default_data_model(instance)
123
123
  try:
124
124
  data_models.add(instance)
125
125
  except Exception as e:
@@ -147,6 +147,8 @@ class DataModel:
147
147
  self._project = None
148
148
  self._zip_loader = None
149
149
 
150
+ self.project_data_manager = kwargs.get('project_data_manager', None)
151
+
150
152
  self.project_path = kwargs.get('project_path', None)
151
153
 
152
154
  self.service_provider = Utils.ServicesProvider()
@@ -156,38 +158,10 @@ class DataModel:
156
158
  self.i_aut_service.password = self.password
157
159
 
158
160
  self.service_provider.AddService[SimultanUsers.IAuthenticationService](self.i_aut_service())
159
-
160
- # self.serv = GeometryViewerService([], self.service_provider)
161
- # self.service_provider.AddService[IGeometryViewerService](self.serv)
162
-
163
161
  self.exch = self.project.AllProjectDataManagers.ComponentGeometryExchange
164
162
  # self.exch.ModelStore = self.serv
165
163
 
166
164
  self.resources = {}
167
- # self.models_dict = {}
168
- #
169
- # if self.project_data_manager.AssetManager.Resources.__len__() > 0:
170
- # for resource in self.project_data_manager.AssetManager.Resources:
171
- # if resource is None:
172
- # continue
173
- # self.resources[resource.Key] = resource
174
- # self.models_dict[resource.Key] = None
175
- # current_full_path = resource.CurrentFullPath
176
- # if current_full_path == '?':
177
- # continue
178
- #
179
- # if resource.Extension == '.simgeo':
180
- # error_list = NetList[SimGeoIOError]()
181
- #
182
- # model = SimGeoIO.Load(resource, self.project_data_manager, error_list, OffsetAlgorithm.Full)
183
- # self.models_dict[resource.Key] = model
184
- # try:
185
- # self.project_data_manager.GeometryModels.AddGeometryModel(model)
186
- # except Exception as e:
187
- # logger.warning(f'Error while loading Model: {model} from {model.File}: {e}. Trying reload...')
188
- # raise e
189
-
190
- self.ValueFields = self.project_data_manager.ValueManager.Items
191
165
  self.import_data_model()
192
166
 
193
167
  self.__mongo_instance = None
@@ -197,40 +171,41 @@ class DataModel:
197
171
  return self.project_data_manager.AssetManager.Resources
198
172
 
199
173
  @property
200
- def _mongo_instance(self):
201
- if self.__mongo_instance is None:
202
- self.create_mongo_instance()
203
- return self.__mongo_instance
174
+ def models(self) -> dict[int, 'GeometryModel']:
175
+ """
176
+ Return the geometry models of the project
177
+ :return: dict[int, GeometryModel]
178
+ """
204
179
 
205
- @_mongo_instance.setter
206
- def _mongo_instance(self, value):
207
- self.__mongo_instance = value
180
+ # if self.models_dict:
181
+ # return self.models_dict
208
182
 
209
- @property
210
- def models(self):
211
183
  self.models_dict = {}
212
184
 
213
- if self.project_data_manager.AssetManager.Resources.__len__() > 0:
214
- for resource in self.project_data_manager.AssetManager.Resources:
215
- if resource is None:
216
- continue
217
- self.resources[resource.Key] = resource
185
+ # self.project_data_manager.Reset()
186
+
187
+ resources = self.project_data_manager.AssetManager.Resources
188
+
189
+ for resource in resources:
190
+ if resource is None:
191
+ continue
192
+ self.resources[resource.Key] = resource
218
193
 
219
- current_full_path = resource.CurrentFullPath
220
- if current_full_path == '?':
221
- continue
194
+ current_full_path = resource.CurrentFullPath
195
+ if current_full_path == '?':
196
+ continue
222
197
 
223
- if resource.Extension == '.simgeo':
224
- self.models_dict[resource.Key] = None
225
- error_list = NetList[SimGeoIOError]()
198
+ if resource.Extension == '.simgeo':
199
+ self.models_dict[resource.Key] = None
200
+ error_list = NetList[SimGeoIOError]()
226
201
 
227
- model = SimGeoIO.Load(resource, self.project_data_manager, error_list, OffsetAlgorithm.Full)
228
- self.models_dict[resource.Key] = model
229
- try:
230
- self.project_data_manager.GeometryModels.AddGeometryModel(model)
231
- except Exception as e:
232
- logger.warning(f'Error while loading Model: {model} from {model.File}: {e}. Trying reload...')
233
- raise e
202
+ model = SimGeoIO.Load(resource, self.project_data_manager, error_list, OffsetAlgorithm.Full)
203
+ self.models_dict[resource.Key] = model
204
+ try:
205
+ self.project_data_manager.GeometryModels.AddGeometryModel(model)
206
+ except Exception as e:
207
+ logger.warning(f'Error while loading Model: {model} from {model.File}: {e}')
208
+ raise e
234
209
 
235
210
  return self.models_dict
236
211
 
@@ -238,14 +213,20 @@ class DataModel:
238
213
  def taxonomies(self):
239
214
  return self.project_data_manager.Taxonomies
240
215
 
216
+ @property
217
+ def ValueFields(self):
218
+ return self.project_data_manager.ValueManager.Items
219
+
241
220
  @property
242
221
  def value_fields(self):
243
222
  return self.project_data_manager.ValueManager
244
223
 
245
224
  @property
246
225
  def project_data_manager(self):
247
- if (self._project_data_manager) is None and (self.user is not None):
226
+
227
+ if self._project_data_manager is None:
248
228
  self._project_data_manager = ExtendedProjectData()
229
+
249
230
  return self._project_data_manager
250
231
 
251
232
  @project_data_manager.setter
@@ -261,7 +242,6 @@ class DataModel:
261
242
  @user.setter
262
243
  def user(self, value: SimultanUsers.SimUserRole):
263
244
  if value != self._user:
264
- self.project_data_manager = None
265
245
  self._project = None
266
246
  self._user = value
267
247
 
@@ -306,7 +286,6 @@ class DataModel:
306
286
  def remove_field(self, field: SimMultiValueField3D):
307
287
  self.project_data_manager.ValueManager.Remove(field)
308
288
 
309
- @lru_cache(maxsize=None)
310
289
  def get_geo_instance(self, file_id, type, id):
311
290
  geo_model = self.models[file_id]
312
291
  objects = getattr(geo_model.Geometry, type)
@@ -381,16 +360,28 @@ class DataModel:
381
360
  """
382
361
  logger.info('closing project...')
383
362
  try:
363
+
384
364
  self._project.DisableProjectUnpackFolderWatcher()
385
365
  if self._project is not None:
366
+ if self._project.IsOpened:
367
+ ZipProjectIO.Close(self._project, True)
386
368
  if self._project.IsLoaded:
387
369
  ZipProjectIO.Unload(self._project)
388
- if self._project.IsOpened:
389
- ZipProjectIO.Close(self._project, False, True)
390
370
 
391
- self._project_data_manager.Reset()
392
371
  except Exception as e:
393
372
  pass
373
+ finally:
374
+ if self._project_data_manager is not None:
375
+ del self._project_data_manager
376
+ self._project_data_manager = None
377
+
378
+ data_models = WeakSet()
379
+ data_models_dict = WeakValueDictionary()
380
+
381
+ if config.get_default_data_model() is self:
382
+ config.set_default_data_model(None)
383
+
384
+ del self
394
385
 
395
386
  # def create_new_component(self):
396
387
  #
@@ -570,14 +561,13 @@ class DataModel:
570
561
  if isinstance(component, SimultanObject):
571
562
  component = component._wrapped_obj
572
563
 
573
- if not component.Instances:
574
- return []
575
-
576
564
  for instance in component.Instances:
577
565
  for placement in instance.Placements.Items:
578
566
  geo_model = next((x for x in self.models.values() if x is not None and x.File.Key == placement.FileId), None)
579
567
  if geo_model is not None:
580
568
  ref_geometries.append((geo_model.Geometry.GeometryFromId(placement.GeometryId), geo_model))
569
+ if geo_model is None:
570
+ logger.warning(f'Geometry model with id {placement.FileId} not found in project {self.project_path}')
581
571
 
582
572
  return ref_geometries
583
573
 
@@ -665,7 +655,6 @@ class DataModel:
665
655
  None)
666
656
  return model_to_work_with, resource_file
667
657
 
668
- @lru_cache(maxsize=None)
669
658
  def get_or_create_taxonomy(self, taxonomy_key: str, taxonomy_name: str = None, description='', create=True):
670
659
  taxonomy = next((x for x in self.taxonomies if x.Key == taxonomy_key), None)
671
660
  if taxonomy is None:
@@ -676,7 +665,6 @@ class DataModel:
676
665
 
677
666
  return next((x for x in self.taxonomies if x.Key == taxonomy_key), None)
678
667
 
679
- @lru_cache(maxsize=None)
680
668
  def get_or_create_taxonomy_entry(self,
681
669
  name: str,
682
670
  key: str,
@@ -113,7 +113,7 @@ class ComponentList(SimultanObject):
113
113
 
114
114
  try:
115
115
  indices = sort_slots(slots)
116
- return [self._object_mapper.create_python_object(x) for x in
116
+ return [self._object_mapper.create_python_object(x, data_model=self._data_model) for x in
117
117
  [all_components[i] for i in np.argsort(indices)]]
118
118
  except TypeError as e:
119
119
  logger.warning(f'Could not sort list {all_components}:\n{e}')
@@ -259,7 +259,7 @@ class ComponentList(SimultanObject):
259
259
  return f'List {self.name}: ' + repr(list(self.data))
260
260
 
261
261
  def __iter__(self):
262
- return iter([self._object_mapper.create_python_object(x) for x in self.data])
262
+ return iter([self._object_mapper.create_python_object(x, data_model=self._data_model) for x in self.data])
263
263
 
264
264
  def __next__(self):
265
265
  try:
PySimultan2/files.py CHANGED
@@ -18,7 +18,9 @@ from SIMULTAN.Data.Assets import ResourceEntry, ResourceFileEntry, ContainedReso
18
18
  from SIMULTAN.Data.Taxonomy import SimTaxonomyEntry, SimTaxonomyEntryReference, SimTaxonomy
19
19
  from SIMULTAN.Data.Components import SimComponent, ComponentMapping
20
20
 
21
- from .config import default_data_model
21
+ # from .config import default_data_model
22
+
23
+ from . import config, logger
22
24
 
23
25
  from typing import TYPE_CHECKING
24
26
  if TYPE_CHECKING:
@@ -195,7 +197,7 @@ class FileInfo(object, metaclass=MetaMock):
195
197
  :return: FileInfo
196
198
  """
197
199
 
198
- data_model = kwargs.get('data_model', default_data_model)
200
+ data_model = kwargs.get('data_model', config.get_default_data_model())
199
201
  resource = create_asset_from_string(filename, content, *args, **kwargs)
200
202
 
201
203
  file_info = cls(resource_entry=resource,
@@ -239,7 +241,8 @@ class FileInfo(object, metaclass=MetaMock):
239
241
  def resource_entry(self) -> Union[ResourceFileEntry, ContainedResourceFileEntry, None]:
240
242
  if self._resource_entry is None:
241
243
  if self.data_model is None:
242
- self.data_model = default_data_model
244
+ logger.warning(f'No data model provided. Using default data model: {config.get_default_data_model().id}.')
245
+ self.data_model = config.get_default_data_model()
243
246
  if self.data_model is not None:
244
247
  self.resource_entry = self.data_model.add_resource(self.file_path)
245
248
  return self._resource_entry
@@ -30,7 +30,7 @@ from SIMULTAN.Data.Geometry import VolumeAlgorithms
30
30
  # from ..utils import create_mapped_python_object, create_python_object
31
31
  # from ..files import create_asset_from_file, FileInfo, create_asset_from_string
32
32
  from .. import config
33
- from ..config import logger
33
+ from .. import logger
34
34
 
35
35
  from typing import TYPE_CHECKING
36
36
  if TYPE_CHECKING:
@@ -63,7 +63,7 @@ class BaseGeometry(object, metaclass=MetaMock):
63
63
  def __init__(self, *args, **kwargs):
64
64
  self._wrapped_object: Union[Vertex, Edge, Face, Volume, EdgeLoop, Layer] = kwargs.get('wrapped_object', None)
65
65
  self._geometry_model: Optional[GeometryModel] = kwargs.get('geometry_model', None)
66
- self._object_mapper = kwargs.get('object_mapper', config.default_mapper)
66
+ self._object_mapper = kwargs.get('object_mapper', config.get_default_mapper())
67
67
  self._data_model = kwargs.get('data_model', None)
68
68
 
69
69
  @property
@@ -537,19 +537,20 @@ class GeometryModel(object, metaclass=MetaMock):
537
537
  @classmethod
538
538
  def create_simultan_instance(cls, *args, **kwargs):
539
539
 
540
- data_model: DataModel = kwargs.get('data_model', config.default_data_model)
541
- name = kwargs.get('name', 'GeometryModel')
540
+ data_model: DataModel = kwargs.get('data_model', config.get_default_data_model())
541
+ name: str = kwargs.get('name', 'GeometryModel')
542
542
 
543
543
  new_geo_model, resource = data_model.create_new_geometry_model(name=name)
544
544
  data_model.project_data_manager.GeometryModels.AddGeometryModel(new_geo_model)
545
545
  data_model.models_dict[resource.Key] = new_geo_model
546
+ data_model.save()
546
547
 
547
548
  return new_geo_model
548
549
 
549
550
  def __init__(self, *args, **kwargs):
550
551
  self._wrapped_object: NetGeometryModel = kwargs.get('wrapped_object', None)
551
- self._object_mapper = kwargs.get('object_mapper', config.default_mapper)
552
- self._data_model = kwargs.get('data_model', config.default_data_model)
552
+ self._object_mapper = kwargs.get('object_mapper', config.get_default_mapper())
553
+ self._data_model = kwargs.get('data_model', config.get_default_data_model())
553
554
 
554
555
  @property
555
556
  def name(self):
@@ -57,7 +57,7 @@ def create_cube(data_model,
57
57
  scale: Optional[float] = 1):
58
58
 
59
59
  if obj_mapper is None:
60
- obj_mapper = config.default_mapper
60
+ obj_mapper = config.get_default_mapper()
61
61
 
62
62
  new_layer = obj_mapper.registered_geometry_classes[Layer](geometry_model=geo_model,
63
63
  data_model=data_model,
@@ -29,7 +29,7 @@ class PythonMapper(object):
29
29
 
30
30
  def __new__(cls, *args, **kwargs):
31
31
  instance = super(PythonMapper, cls).__new__(cls)
32
- config.default_mapper = instance
32
+ config.set_default_mapper(instance)
33
33
  return instance
34
34
 
35
35
  def __init__(self, *args, **kwargs):
@@ -136,15 +136,18 @@ class PythonMapper(object):
136
136
  typed_data.append(typed_object)
137
137
  return typed_data
138
138
 
139
- # @lru_cache(maxsize=None)
139
+ # @lru_cache(maxsize=500)
140
140
  def create_python_object(self, component, cls=None, data_model=None, *args, **kwargs):
141
141
 
142
142
  if component is None:
143
143
  return None
144
144
 
145
145
  if data_model is None:
146
- data_model_id = list(data_models)[0].id
147
- data_model = list(data_models)[0]
146
+ logger.warning(f'No data model provided. Using default data model: {config.get_default_data_model().id}.')
147
+ data_model = config.get_default_data_model()
148
+ data_model_id = data_model.id
149
+ # data_model_id = list(data_models)[0].id
150
+ # data_model = list(data_models)[0]
148
151
  else:
149
152
  data_model_id = data_model.id
150
153
 
@@ -201,6 +204,7 @@ class PythonMapper(object):
201
204
  for prop in taxonomy_map.content:
202
205
 
203
206
  prop_dict[prop.property_name] = add_properties(prop_name=prop.property_name,
207
+ text_or_key=prop.text_or_key,
204
208
  content=prop,
205
209
  taxonomy_map=taxonomy_map,
206
210
  taxonomy=taxonomy)
@@ -213,6 +217,10 @@ class PythonMapper(object):
213
217
 
214
218
  for cls in self.mapped_classes.values():
215
219
  cls._cls_instances = WeakSet()
220
+ cls.__property_cache__ = {}
221
+
222
+ if config.get_default_mapper() is self:
223
+ config.set_default_mapper(None)
216
224
 
217
225
  def copy(self):
218
226
  new_mapper = PythonMapper()
@@ -222,5 +230,5 @@ class PythonMapper(object):
222
230
  return new_mapper
223
231
 
224
232
 
225
- if config.default_mapper is None:
226
- config.default_mapper = PythonMapper()
233
+ if config.get_default_mapper() is None:
234
+ config.set_default_mapper(PythonMapper())
@@ -6,7 +6,7 @@ from weakref import WeakSet, WeakValueDictionary
6
6
  from . import utils
7
7
  from numpy import ndarray
8
8
  import colorlog
9
- from typing import Union
9
+ from typing import Union, Optional
10
10
 
11
11
  logger = colorlog.getLogger('PySimultan')
12
12
 
@@ -68,8 +68,10 @@ class MetaMock(type):
68
68
  data_model = list(data_models.data)[0]()
69
69
  kwargs['data_model'] = data_model
70
70
  else:
71
- if config.default_data_model is not None:
72
- data_model = config.default_data_model
71
+ if config.get_default_data_model() is not None:
72
+ logger.warning(
73
+ f'No data model provided. Using default data model: {config.get_default_data_model().id}')
74
+ data_model = config.get_default_data_model()
73
75
  kwargs['data_model'] = data_model
74
76
  else:
75
77
  raise TypeError((f'Error creating new instance of class {cls.__name__}:\n'
@@ -102,6 +104,11 @@ class SimultanObject(object, metaclass=MetaMock):
102
104
  _cls_instances_dict_cache = None
103
105
  __type_view__ = None # ui view cls
104
106
 
107
+ @classmethod
108
+ def reset_cls(cls):
109
+ cls._cls_instances = WeakSet()
110
+ cls._cls_instances_dict_cache = None
111
+
105
112
  @classmethod
106
113
  def get_instance_by_id(cls, id: SimId) -> 'SimultanObject':
107
114
  return cls._cls_instances_dict.get(id, None)
@@ -147,11 +154,12 @@ class SimultanObject(object, metaclass=MetaMock):
147
154
 
148
155
  self._wrapped_obj: Union[SimComponent, None] = kwargs.get('wrapped_obj', None)
149
156
  self.__obj_init__ = kwargs.get('__obj_init__', False)
150
- self._data_model_id = kwargs.get('data_model_id', None)
151
- self._data_model: Union[DataModel, None] = kwargs.get('data_model', config.default_data_model)
152
- self._object_mapper: Union[PythonMapper, None] = kwargs.get('object_mapper', config.default_mapper)
157
+ self._data_model: Union[DataModel, None] = kwargs.get('data_model', config.get_default_data_model())
158
+ self._object_mapper: Union[PythonMapper, None] = kwargs.get('object_mapper', config.get_default_mapper())
153
159
  self.name = kwargs.get('name', None)
154
160
 
161
+ self.__property_cache__ = {}
162
+
155
163
  self._slot = None
156
164
 
157
165
  def __getattribute__(self, attr):
@@ -328,8 +336,16 @@ class SimultanObject(object, metaclass=MetaMock):
328
336
  """
329
337
  other.associate(self)
330
338
 
331
- def get_raw_attr(self, attr: str):
332
- return utils.get_component_taxonomy_entry(self._wrapped_obj, attr)
339
+ def get_raw_attr(self, attr: Optional[str] = None, text_or_key: Optional[str] = None):
340
+ if attr is not None:
341
+ content = self._taxonomy_map.get_content_by_property_name(attr)
342
+ if content is None:
343
+ raise KeyError(f'No content found for attribute {attr}')
344
+
345
+ return utils.get_component_taxonomy_entry(self._wrapped_obj, content.text_or_key)
346
+
347
+ if text_or_key is not None:
348
+ return utils.get_component_taxonomy_entry(self._wrapped_obj, text_or_key)
333
349
 
334
350
  def set_attr_prop(self, attr: str, prop: str, value):
335
351
  """
@@ -1,6 +1,7 @@
1
1
  import io
2
+ from functools import cache
2
3
  from ruamel.yaml import YAML, yaml_object, add_representer
3
- from .config import yaml
4
+ from . import yaml
4
5
 
5
6
  from typing import TYPE_CHECKING, Optional, Union, Literal
6
7
  if TYPE_CHECKING:
@@ -113,6 +114,9 @@ class TaxonomyMap(object):
113
114
  content._taxonomy_map = self
114
115
  self._content_dict = {}
115
116
 
117
+ self.get_content_by_property_name.cache_clear()
118
+ self.get_content_by_text_or_key.cache_clear()
119
+
116
120
  @property
117
121
  def content_dict(self):
118
122
  if self._content_dict == {}:
@@ -167,3 +171,11 @@ class TaxonomyMap(object):
167
171
 
168
172
  def get_slot(self, data_model: 'DataModel'):
169
173
  return SimTaxonomyEntryReference(self.get_or_create_simultan_taxonomy_entry(data_model=data_model, create=True))
174
+
175
+ @cache
176
+ def get_content_by_property_name(self, property_name: str):
177
+ return next((x for x in self.content if x.property_name == property_name), None)
178
+
179
+ @cache
180
+ def get_content_by_text_or_key(self, text_or_key: str):
181
+ return next((x for x in self.content if x.text_or_key == text_or_key), None)
PySimultan2/utils.py CHANGED
@@ -1,9 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- from . import config
4
3
  from enum import Enum
5
4
  from weakref import WeakSet
6
- from functools import lru_cache
7
5
  import numpy as np
8
6
  import pandas as pd
9
7
  from typing import List as TypeList, Union, Optional, Type
@@ -32,7 +30,7 @@ if TYPE_CHECKING:
32
30
  from .taxonomy_maps import TaxonomyMap, Content
33
31
 
34
32
 
35
- from .config import logger
33
+ from . import logger
36
34
  from . import config
37
35
  from .simultan_object import SimultanObject
38
36
 
@@ -94,7 +92,7 @@ def create_python_object(wrapped_obj: SimComponent, cls: Type[SimultanObject], *
94
92
  for content in cls._taxonomy_map.content:
95
93
  # logger.debug(f'Get property {content.text_or_key} from wrapped object {wrapped_obj.Name}')
96
94
  kwargs[content.text_or_key] = get_property(wrapped_obj=wrapped_obj,
97
- prop_name=content.text_or_key,
95
+ text_or_key=content.text_or_key,
98
96
  object_mapper=kwargs.get('object_mapper', None),
99
97
  )
100
98
 
@@ -103,6 +101,7 @@ def create_python_object(wrapped_obj: SimComponent, cls: Type[SimultanObject], *
103
101
 
104
102
  obj = cls.__new__(cls)
105
103
  obj.__obj_init__ = True
104
+ obj.__property_cache__ = dict()
106
105
  obj._wrapped_obj = wrapped_obj
107
106
  obj._data_model = kwargs.get('data_model', None)
108
107
  obj._object_mapper = kwargs.get('object_mapper', None)
@@ -227,7 +226,7 @@ def get_default_slot(default_type: Union[SimTaxonomyEntryReference, SimTaxonomyE
227
226
  :return:
228
227
  """
229
228
 
230
- default_taxonomy_entry = SimDefaultSlotKeys.GetDefaultSlot(config.default_data_model.project_data_manager.Taxonomies,
229
+ default_taxonomy_entry = SimDefaultSlotKeys.GetDefaultSlot(config.get_default_data_model().project_data_manager.Taxonomies,
231
230
  SimDefaultSlotKeys.Undefined)
232
231
 
233
232
  if default_type is SimTaxonomyEntryReference:
@@ -604,7 +603,7 @@ def create_simultan_component_for_taxonomy(cls, *args, **kwargs) -> SimComponent
604
603
 
605
604
  data_model = kwargs.get('data_model', None)
606
605
  if data_model is None:
607
- data_model = config.default_data_model
606
+ data_model = config.get_default_data_model()
608
607
 
609
608
  # simultan_taxonomy = cls._taxonomy_map.get_or_create_simultan_taxonomy(data_model=data_model)
610
609
  # tayonomy_entry = cls._taxonomy_map.get_or_create_simultan_taxonomy_entry(data_model=data_model)
@@ -662,15 +661,25 @@ def sort_slots(slots, check_same_slot=False) -> list[SimSlot]:
662
661
  return slot_extensions
663
662
 
664
663
 
665
- def get_property(prop_name, component=None, wrapped_obj=None, object_mapper=None):
664
+ def get_property(prop_name: Optional[str] = None,
665
+ text_or_key: Optional[str] = None,
666
+ component=None,
667
+ wrapped_obj=None,
668
+ object_mapper=None):
669
+
670
+ if prop_name is None and text_or_key is None:
671
+ raise ValueError('Either prop_name or text_or_key must be set.')
672
+ if prop_name is not None:
673
+ content = component._taxonomy_map.get_content_by_property_name(prop_name)
674
+ text_or_key = content.text_or_key
666
675
 
667
676
  if component is not None:
668
- obj = get_component_taxonomy_entry(component._wrapped_obj, prop_name)
677
+ obj = get_component_taxonomy_entry(component._wrapped_obj, text_or_key)
669
678
  data_model = component._data_model
670
679
  object_mapper = component._object_mapper
671
680
  else:
672
- data_model = config.default_data_model
673
- obj = get_component_taxonomy_entry(wrapped_obj, prop_name)
681
+ data_model = config.get_default_data_model()
682
+ obj = get_component_taxonomy_entry(wrapped_obj, text_or_key)
674
683
 
675
684
  return get_obj_value(obj, data_model=data_model, object_mapper=object_mapper)
676
685
 
@@ -867,7 +876,7 @@ def create_mapped_python_object(value: SimComponent,
867
876
  """
868
877
 
869
878
  if object_mapper is None:
870
- object_mapper = config.default_mapper
879
+ object_mapper = config.get_default_mapper()
871
880
 
872
881
  # logger.debug(f'Creating mapped python object for {value}.')
873
882
  if type(value) in object_mapper.registered_classes.values():
@@ -963,13 +972,13 @@ def set_property_to_list(value: Union[list, tuple, set, ComponentList],
963
972
 
964
973
  if 'ComponentList' in [x.Target.Key for x in component.Slots]:
965
974
  if not hasattr(component, '_object_mapper'):
966
- mapper = config.default_mapper
975
+ mapper = config.get_default_mapper()
967
976
  component._object_mapper = mapper
968
977
  else:
969
978
  mapper = component._object_mapper
970
979
 
971
980
  if not hasattr(component, '_data_model'):
972
- data_model = config.default_data_model
981
+ data_model = config.get_default_data_model()
973
982
  component._data_model = data_model
974
983
  else:
975
984
  data_model = component._data_model
@@ -1230,13 +1239,13 @@ def set_property_to_dict(value: dict,
1230
1239
 
1231
1240
  if 'ComponentDictionary' in [x.Target.Key for x in component.Slots]:
1232
1241
  if not hasattr(component, '_object_mapper'):
1233
- mapper = config.default_mapper
1242
+ mapper = config.get_default_mapper()
1234
1243
  component._object_mapper = mapper
1235
1244
  else:
1236
1245
  mapper = component._object_mapper
1237
1246
 
1238
1247
  if not hasattr(component, '_data_model'):
1239
- data_model = config.default_data_model
1248
+ data_model = config.get_default_data_model()
1240
1249
  component._data_model = data_model
1241
1250
  else:
1242
1251
  data_model = component._data_model
@@ -1269,6 +1278,7 @@ def set_property_to_dict(value: dict,
1269
1278
 
1270
1279
 
1271
1280
  def add_properties(prop_name: str,
1281
+ text_or_key: str,
1272
1282
  content: Content,
1273
1283
  taxonomy: str,
1274
1284
  taxonomy_map: 'TaxonomyMap') -> property:
@@ -1276,6 +1286,7 @@ def add_properties(prop_name: str,
1276
1286
  """
1277
1287
  create property for a class
1278
1288
  :param prop_name: name of the property (str)
1289
+ :param text_or_key: text or key of the taxonomy entry (str)
1279
1290
  :param content: content of the property (Content)
1280
1291
  :param prop_name: name of the synonym (str)
1281
1292
  :param taxonomy: taxonomy to use (str)
@@ -1310,32 +1321,36 @@ def add_properties(prop_name: str,
1310
1321
  np.ndarray: set_property_to_value_field,
1311
1322
  pd.DataFrame: set_property_to_value_field}
1312
1323
 
1324
+ class Empty:
1325
+ pass
1326
+
1313
1327
  def getx(self):
1314
- return get_property(component=self,
1315
- prop_name=content.text_or_key,
1316
- object_mapper=self._object_mapper)
1317
1328
 
1318
- getx.__taxonomy__ = taxonomy
1329
+ cache_value = self.__property_cache__.get(content.text_or_key, Empty)
1319
1330
 
1320
- content = next((x for x in taxonomy_map.content if x.property_name == prop_name), None)
1331
+ if cache_value is not Empty:
1332
+ return self.__property_cache__[content.text_or_key]
1333
+
1334
+ val = get_property(component=self,
1335
+ text_or_key=content.text_or_key,
1336
+ object_mapper=self._object_mapper)
1337
+
1338
+ self.__property_cache__[content.text_or_key] = val
1339
+ return val
1340
+
1341
+ getx.__taxonomy__ = taxonomy
1342
+ content = taxonomy_map.get_content_by_property_name(prop_name)
1321
1343
 
1322
1344
  def setx(self, value: Union[int, float, SimComponent, SimultanObject]):
1323
- # logger.debug(f'{self.name} {self.id}: Setting {prop_name} to {value}.')
1345
+ self.__property_cache__.pop(content.text_or_key, None)
1346
+
1324
1347
  slot_extension = content.slot_extension
1325
1348
 
1326
1349
  if slot_extension is None:
1327
1350
  slot_extension = 0
1328
1351
 
1329
- # sim_taxonomy = taxonomy_map.get_or_create_simultan_taxonomy(self._data_model)
1330
1352
  taxonomy_entry = content.get_taxonomie_entry(self._data_model)
1331
1353
 
1332
- # sim_taxonomy = self._data_model.get_or_create_taxonomy(taxonomy_name=taxonomy_map.taxonomy_name,
1333
- # taxonomy_key=taxonomy_map.taxonomy_key)
1334
- # taxonomy_entry = self._data_model.get_or_create_taxonomy_entry(key=content.text_or_key,
1335
- # name=content.property_name,
1336
- # sim_taxonomy=sim_taxonomy)
1337
- # getx.cache_clear()
1338
-
1339
1354
  component_idx, ref_component_idx, parameter_idx, ref_asset_idx = get_param_indices(self._wrapped_obj,
1340
1355
  taxonomy_entry)
1341
1356
 
@@ -1372,25 +1387,6 @@ def add_properties(prop_name: str,
1372
1387
 
1373
1388
  setter_fcn(*fcn_arg_list)
1374
1389
 
1375
- # elif isinstance(value, (SimComponent, SimultanObject)) and not isinstance(value, ComponentList):
1376
- # set_property_to_sim_component(*fcn_arg_list)
1377
- #
1378
- # elif isinstance(value, (str, int, float)):
1379
- # set_property_to_parameter(*fcn_arg_list)
1380
- #
1381
- # elif isinstance(value, (np.ndarray, pd.DataFrame)):
1382
- # set_propperty_to_value_field(*fcn_arg_list)
1383
- #
1384
- # elif isinstance(value, (list, tuple, set, ComponentList)):
1385
- # set_property_to_list(*fcn_arg_list)
1386
- #
1387
- # elif isinstance(value, FileInfo):
1388
- # set_property_to_file_info(*fcn_arg_list, content=content)
1389
- #
1390
- # else:
1391
- # new_val = create_mapped_python_object(value, self._object_mapper, self._data_model)
1392
- # setattr(self, prop_name, new_val)
1393
-
1394
1390
  setx.__taxonomy__ = taxonomy
1395
1391
 
1396
1392
  def delx(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: PySimultan
3
- Version: 0.4.0
3
+ Version: 0.4.2
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
@@ -1,17 +1,16 @@
1
- PySimultan2/__about__.py,sha256=NLz2y04spAo9hkDBgrxcVBhjKElO7Jf_NlVw_P6fGxc,19
2
- PySimultan2/__init__.py,sha256=X10eSCNtac3CG28w7Ogo1csNalhapO9V4oVSIucc0Kw,1121
3
- PySimultan2/config.py,sha256=Bazt2vDSEga_cFEIPWcAYBsj3TUN5jgtob8TtUvGm5E,1523
4
- PySimultan2/data_model.py,sha256=2Qq_JyUxtDgsIt3p5hIXIqNy7eAtvn-6Of_Wzb9AWoE,28004
5
- PySimultan2/default_types.py,sha256=C6CB5NIjpT0zBeruMBzojKa9LPz4_8VCY6yOLNQPOCg,22888
6
- PySimultan2/files.py,sha256=q6A5KTqU1nCwh0W0Qf3Se7qcvhGiDAWza2v-X-rt6E4,12473
1
+ PySimultan2/__about__.py,sha256=Dz7KO6jRqp7b9P43mwLgOykNdRlA8qMxtHiAsqZsQbE,19
2
+ PySimultan2/__init__.py,sha256=2pdrZP8ECaVRlaCfwzFblht_30JfenzyQ2rEt-QldeU,2876
3
+ PySimultan2/data_model.py,sha256=m9q3P5SfxYXdmwdQuPoTazHZAJ1xwazixFtdetJ2Dgk,26968
4
+ PySimultan2/default_types.py,sha256=GGAnuOCwF7YSt6tPDMr6houAILWyRsAhMfb9Y_Rpetk,22946
5
+ PySimultan2/files.py,sha256=gx3BA6WYjNVplqqes7jkPopp6O50pgLvantXgmitx54,12657
7
6
  PySimultan2/multi_values.py,sha256=ZFXlTLuZo32x7_7diYAp2XEjp5uwgHLgNOzN7v74-5I,13650
8
- PySimultan2/object_mapper.py,sha256=RCIJl0hj1cmWCTOj2HkwRY5EWrSdjziyEg-xIqj1kUw,9239
9
- PySimultan2/simultan_object.py,sha256=PWpveGPFi1nlcHSK8vT_3lyEoa27eBY6ZpKAtgR-KGg,16215
10
- PySimultan2/taxonomy_maps.py,sha256=qgKM0CdwwgLCFj-ivzY38VaCpE_eCPKyCiBaTBazpBk,7509
11
- PySimultan2/utils.py,sha256=FSMvcK_6i8-Z7xGlxxRV6SJPp9UZS8Jj-CX5y7TxXSw,63171
7
+ PySimultan2/object_mapper.py,sha256=hRYvgQYZb4NBZ1DyA9Nwd04i19q8SawFv-8aJHFba_g,9702
8
+ PySimultan2/simultan_object.py,sha256=F5XeHHmbh4s3hb4K8f4m-Pl9Oz1d0Pxc72VV91CQi3w,16929
9
+ PySimultan2/taxonomy_maps.py,sha256=aU9zUJph7QcInIZq0W-Vqoy4DYr0CEs-VsXwPMK_cxU,7976
10
+ PySimultan2/utils.py,sha256=j5xnjPIWy6k3_zY2xTXN0VsnpjQgRSyakbO9DIqBsLo,62482
12
11
  PySimultan2/geometry/__init__.py,sha256=nJolTD1i5J8qUkOQa-r3D20aq3Co3sN31Xc0n4wJpJo,248
13
- PySimultan2/geometry/geometry_base.py,sha256=IQQPVxkgIdBsFJp8rPSCNiCiKO7TxkVWy-XmE8GjDbE,23367
14
- PySimultan2/geometry/utils.py,sha256=K_3HnqPMAlJkOh01oqjspeqsLrooG9NwIQKWf14IJ48,8513
12
+ PySimultan2/geometry/geometry_base.py,sha256=jOTNMISGLRjUUjVfPZ64A2Fp4oinv42polIct9bgIY4,23417
13
+ PySimultan2/geometry/utils.py,sha256=J25YsK8sso_UL7xRusItQZvyjtvxdOsSPelBQYFABhY,8519
15
14
  PySimultan2/resources/AssimpNet.dll,sha256=x8uwMHPRmEH9fDQihfEQLUdblM1u7RP-CCnUjOpXcLo,205312
16
15
  PySimultan2/resources/AvalonDock.dll,sha256=9tCcw7cpaVq0bh1H2sfcxb8EWhySmgujPs89lAqIPZs,500224
17
16
  PySimultan2/resources/BruTile.dll,sha256=ZiE_vovBW_CZOjDgOn8eaq_tfWRBD3-nSEk0ctBSdKI,198144
@@ -76,7 +75,7 @@ PySimultan2/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
76
75
  PySimultan2/resources/assimp.dll,sha256=HwfDwXqoPDTFRyoQpA3qmgZoUdFtziJkV5fNtktEZEU,6081536
77
76
  PySimultan2/resources/defaultsettings.xml,sha256=s6Tk1tubLz5UYqXZWpD42EDHzedemRY1nEneoIVcUfg,392
78
77
  PySimultan2/resources/setup.bat,sha256=fjvvYfVM6TalS-QTSiKAbAId5nTsk8kGGo06ba-wWaY,32
79
- pysimultan-0.4.0.dist-info/METADATA,sha256=6o0gfQ0uVpgmXt5ssaelcmqPziQyhXQB8Me_vv934aA,1657
80
- pysimultan-0.4.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
81
- pysimultan-0.4.0.dist-info/licenses/LICENSE.txt,sha256=pmSr98k6N005KMojnZxzLGRuRlDjDx3PUrK1lFj53HA,1126
82
- pysimultan-0.4.0.dist-info/RECORD,,
78
+ pysimultan-0.4.2.dist-info/METADATA,sha256=bwynJBG0p5oUVISh5e51xjWYfKmdU5IGPYpCkRmt7Tk,1657
79
+ pysimultan-0.4.2.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
80
+ pysimultan-0.4.2.dist-info/licenses/LICENSE.txt,sha256=pmSr98k6N005KMojnZxzLGRuRlDjDx3PUrK1lFj53HA,1126
81
+ pysimultan-0.4.2.dist-info/RECORD,,
PySimultan2/config.py DELETED
@@ -1,52 +0,0 @@
1
- import os
2
- import sys
3
- from ruamel.yaml import YAML, yaml_object, add_representer
4
-
5
- import colorlog
6
- try:
7
- import importlib.resources as pkg_resources
8
- except ImportError:
9
- # Try backported to PY<37 importlib_resources.
10
- import importlib_resources as pkg_resources
11
-
12
-
13
- from . import resources
14
- sys.path.append(str(pkg_resources.files(resources)))
15
-
16
- logger = colorlog.getLogger('PySimultan')
17
- logger.setLevel('DEBUG')
18
-
19
- dll_path = os.environ.get('SIMULTAN_SDK_DIR', None)
20
- if dll_path is None:
21
- with pkg_resources.path(resources, 'SIMULTAN.dll') as r_path:
22
- dll_path = str(r_path)
23
- sys.path.append(dll_path)
24
-
25
- from pythonnet import load
26
- from pythonnet import clr_loader, set_runtime
27
- list(clr_loader.find_runtimes())
28
- load('coreclr')
29
- import clr
30
- test = clr.AddReference(os.path.join(dll_path, 'SIMULTAN.dll') if not dll_path.endswith('SIMULTAN.dll') else dll_path)
31
- clr.AddReference("System.Security.Cryptography")
32
- # clr.AddReference(os.path.join(dll_path, 'SIMULTAN'))
33
-
34
- from SIMULTAN.Data.Components import SimComponent
35
-
36
- continue_on_error = True
37
-
38
-
39
- def represent_none(self, _):
40
- return self.represent_scalar('tag:yaml.org,2002:null', '')
41
-
42
-
43
- add_representer(type(None), represent_none)
44
- yaml = YAML()
45
- yaml.default_flow_style = None
46
- yaml.preserve_quotes = True
47
- yaml.allow_unicode = True
48
-
49
- # define which axis is in up/down direction; 0: x-axis; 1: y-axis; 2: z-axis; In SIMULTAN the y-axis is the up/down axis
50
- cs_axis_up = 2
51
- default_data_model = None
52
- default_mapper = None