PySimultan 0.4.0__py3-none-any.whl → 0.4.2__py3-none-any.whl

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