psr-factory 4.1.0b5__py3-none-manylinux_2_28_x86_64.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.
psr/factory/api.py ADDED
@@ -0,0 +1,2339 @@
1
+ # PSR Factory. Copyright (C) PSR, Inc - All Rights Reserved
2
+ # Unauthorized copying of this file, via any medium is strictly prohibited
3
+ # Proprietary and confidential
4
+
5
+ import locale
6
+ from typing import Dict, List, Optional, Tuple, Union
7
+ from types import ModuleType
8
+ import ctypes
9
+ import datetime as dt
10
+ import enum
11
+ import numbers
12
+ import os
13
+ import sys
14
+ import threading
15
+ import pathlib
16
+ import warnings
17
+
18
+ from . import factorylib
19
+
20
+
21
+ # Check whether pandas' dataframe is available.
22
+ _HAS_PANDAS: Optional[bool] = None
23
+
24
+ # Check whether polars' dataframe is available.
25
+ _HAS_POLARS: Optional[bool] = None
26
+
27
+
28
+ pandas: Optional[ModuleType] = None
29
+ polars: Optional[ModuleType] = None
30
+ numpy: Optional[ModuleType] = None
31
+
32
+
33
+ def _has_pandas() -> bool:
34
+ """Check if pandas is available."""
35
+ global _HAS_PANDAS
36
+ global pandas
37
+ global numpy
38
+ if _HAS_PANDAS is None:
39
+ try:
40
+ import pandas
41
+ import pandas.api.interchange
42
+ import pandas.api.types
43
+ if numpy is not None:
44
+ import numpy
45
+ import numpy.ctypeslib
46
+ _HAS_PANDAS = True
47
+ except ImportError:
48
+ _HAS_PANDAS = False
49
+ return _HAS_PANDAS
50
+
51
+
52
+ def _has_polars() -> bool:
53
+ """Check if polars is available."""
54
+ global _HAS_POLARS
55
+ global polars
56
+ global numpy
57
+ if _HAS_POLARS is None:
58
+ try:
59
+ import polars
60
+ import polars.datatypes.classes
61
+ if numpy is not None:
62
+ import numpy
63
+ import numpy.ctypeslib
64
+ _HAS_POLARS = True
65
+ except ImportError:
66
+ _HAS_POLARS = False
67
+ return _HAS_POLARS
68
+
69
+
70
+ # States whether the library is initialized.
71
+ # It should be to correctly load and build models.
72
+ _initialized = False
73
+ _initialized_lock = threading.Lock()
74
+
75
+ _loaded = False
76
+ _loaded_lock = threading.Lock()
77
+
78
+ # System encoding for interface with the library.
79
+ _preferred_encoding = locale.getpreferredencoding()
80
+
81
+ # Internal date epoch
82
+ # TODO: make it a library call.
83
+ _date_transform = 12622780800
84
+
85
+
86
+ def _check_initialized():
87
+ """Checks if the module was initialized."""
88
+ global _initialized
89
+ if not _initialized:
90
+ _initialize()
91
+ return _initialized
92
+
93
+
94
+ def _check_loaded() -> bool:
95
+ """Checks if the library was loaded."""
96
+ global _loaded
97
+ if not _loaded:
98
+ _load_library()
99
+ return _loaded
100
+
101
+
102
+ def _c_str(value: str) -> bytes:
103
+ """Convert a Python object/string into a bytes/c-array."""
104
+ return bytes(value, encoding=_preferred_encoding)
105
+
106
+
107
+ def _from_c_str(value: bytes) -> str:
108
+ """Convert ASCII bytes back into utf-8 strings."""
109
+ return value.decode(encoding=_preferred_encoding)
110
+
111
+
112
+ def _bytes(value: str) -> int:
113
+ """Return the bytes' count of the equivalent C buffer to
114
+ hold this string."""
115
+ return len(value) + 1
116
+
117
+
118
+ class FactoryException(Exception):
119
+ pass
120
+
121
+
122
+ class LogLevel(enum.Enum):
123
+ NOTSET = 0
124
+ DEBUG = 10
125
+ INFO = 20
126
+ WARNING = 30
127
+ ERROR = 40
128
+ CRITICAL = 50
129
+
130
+
131
+ class ValueType(enum.Enum):
132
+ INT32 = 0
133
+ INT64 = 1
134
+ FLOAT32 = 2
135
+ FLOAT64 = 3
136
+ BOOL = 4
137
+ STRING = 5
138
+ DATE = 6
139
+ OBJECT = 7
140
+ LIST = 8
141
+ DICT = 9
142
+ NULL = 10
143
+
144
+
145
+ def _version_long() -> str:
146
+ _check_loaded()
147
+ size = 200
148
+ buffer = ctypes.create_string_buffer(size)
149
+ status = factorylib.lib.psrd_version_long(buffer, size)
150
+ if status == 0:
151
+ return _from_c_str(buffer.value)
152
+ return ""
153
+
154
+
155
+ def _version_short() -> str:
156
+ _check_loaded()
157
+ size = 200
158
+ buffer = ctypes.create_string_buffer(size)
159
+ status = factorylib.lib.psrd_version_short(buffer, size)
160
+ if status == 0:
161
+ return _from_c_str(buffer.value)
162
+ return ""
163
+
164
+
165
+ def version() -> str:
166
+ """Returns module version."""
167
+ return _version_long()
168
+
169
+
170
+ def build_version() -> str:
171
+ """Returns short library version."""
172
+ return _version_short()
173
+
174
+
175
+ def get_log_level() -> LogLevel:
176
+ """Get log level."""
177
+ _check_loaded()
178
+ log_level = ctypes.c_int()
179
+ code = factorylib.lib.psrd_get_log_level(ctypes.byref(log_level))
180
+ if code != 0:
181
+ raise FactoryException("Error getting log level")
182
+ return LogLevel(log_level.value)
183
+
184
+
185
+ def set_log_level(log_level: LogLevel):
186
+ """Set log level."""
187
+ if not isinstance(log_level, LogLevel):
188
+ raise TypeError("log_level must be an instance of LogLevel")
189
+ _check_loaded()
190
+ as_int = log_level.value
191
+ code = factorylib.lib.psrd_set_log_level(as_int)
192
+ if code != 0:
193
+ raise FactoryException("Error setting log level")
194
+
195
+
196
+ def set_debug_mode(value: Union[bool, int]):
197
+ """Set debug mode."""
198
+ _check_loaded()
199
+ if isinstance(value, bool):
200
+ value = 1 if value else 0
201
+ code = factorylib.lib.psrd_set_debug_mode(value)
202
+ if code != 0:
203
+ raise FactoryException("Error setting debug mode")
204
+
205
+
206
+ def get_setting(key: str) -> Union[str, int, float, bool]:
207
+ global _initialized
208
+ global _initialized_lock
209
+ with _initialized_lock:
210
+ _check_loaded()
211
+ error = Error()
212
+ value = Value()
213
+ factorylib.lib.psrd_get_global_setting(_c_str(key),
214
+ _bytes(key),
215
+ value.handler(),
216
+ error.handler())
217
+ if error.code != 0:
218
+ raise FactoryException(error.what)
219
+ return value.get()
220
+
221
+
222
+ def set_setting(key: str, value: Union[str, int, float, bool]):
223
+ global _initialized
224
+ global _initialized_lock
225
+ with _initialized_lock:
226
+ _check_loaded()
227
+ error = Error()
228
+ _value = Value()
229
+ _value.set(value)
230
+ factorylib.lib.psrd_set_global_setting(_c_str(key),
231
+ _bytes(key),
232
+ _value.handler(),
233
+ error.handler())
234
+ if error.code != 0:
235
+ raise FactoryException(error.what)
236
+
237
+
238
+
239
+ def _get_context(models_or_context: Union[str, list, dict, "Context", None],
240
+ blocks: Optional[int] = None) -> "Value":
241
+ value = Value()
242
+ if isinstance(models_or_context, (Context, dict)):
243
+ context = models_or_context
244
+ elif isinstance(models_or_context, (str, list)) or models_or_context is None:
245
+ context = dict()
246
+ if isinstance(models_or_context, list):
247
+ context["Models"] = models_or_context
248
+ elif isinstance(models_or_context, str):
249
+ context["Models"] = [models_or_context, ]
250
+ else:
251
+ raise TypeError("Unexpected type for profile_or_context argument.")
252
+ if blocks is not None and isinstance(blocks, int):
253
+ if isinstance(blocks, Context):
254
+ context.set("Blocks", blocks)
255
+ else:
256
+ context["Blocks"] = blocks
257
+ value.set(context)
258
+ return value
259
+
260
+ def _get_arg_object(arg: Union[dict, "Value", "DataObject", None]) -> "Value":
261
+ if isinstance(arg, dict):
262
+ value = Value()
263
+ value.set(arg)
264
+ return value
265
+ elif isinstance(arg, Value):
266
+ return arg
267
+ elif isinstance(arg, DataObject):
268
+ value = Value()
269
+ value.set(arg)
270
+ return value
271
+ elif arg is None:
272
+ return Value()
273
+ else:
274
+ raise TypeError("Unexpected type for argument.")
275
+
276
+
277
+
278
+ class _BaseObject:
279
+ def __init__(self):
280
+ self._hdr = None
281
+
282
+ def handler(self):
283
+ return self._hdr
284
+
285
+ def __hash__(self):
286
+ return self._hdr
287
+
288
+
289
+ class Error(_BaseObject):
290
+ def __init__(self):
291
+ super().__init__()
292
+ self._hdr = factorylib.lib.psrd_new_error()
293
+
294
+ @property
295
+ def code(self) -> int:
296
+ return factorylib.lib.psrd_error_code(self._hdr)
297
+
298
+ @code.setter
299
+ def code(self, value):
300
+ raise AttributeError("do not set code")
301
+
302
+ @code.deleter
303
+ def code(self):
304
+ raise AttributeError("do not delete code")
305
+
306
+ @property
307
+ def what(self) -> str:
308
+ size = factorylib.lib.psrd_error_message(self._hdr, None, 0)
309
+ if size <= 0:
310
+ size = 800
311
+ buffer = ctypes.create_string_buffer(size)
312
+ status = factorylib.lib.psrd_error_message(self._hdr,
313
+ buffer, size)
314
+ if status == 0:
315
+ return _from_c_str(buffer.value)
316
+ return ""
317
+
318
+ @what.deleter
319
+ def what(self):
320
+ raise AttributeError("do not delete what")
321
+
322
+ @what.setter
323
+ def what(self, value):
324
+ raise AttributeError("do not set what")
325
+
326
+ def __del__(self):
327
+ if self._hdr is not None:
328
+ factorylib.lib.psrd_free_error(self._hdr)
329
+
330
+ def __repr__(self):
331
+ return f"Error object with code \"{self.code}\" and message:\n" \
332
+ f"{self.what}"
333
+
334
+ def __str__(self):
335
+ return self.what
336
+
337
+
338
+ class _TableColumn:
339
+ def __init__(self):
340
+ self.name = ""
341
+ # values: a pure Python list or a ctypes array
342
+ self.values: Union[list, ctypes.c_int, ctypes.c_long, ctypes.c_float, ctypes.c_double] = []
343
+
344
+ def __len__(self):
345
+ return len(self.values)
346
+
347
+
348
+ class ValueList(_BaseObject):
349
+ def __init__(self, initialized=True):
350
+ super().__init__()
351
+ self._hdr = factorylib.lib.psrd_new_list() if initialized else None
352
+
353
+ def __del__(self):
354
+ if self._hdr is not None:
355
+ factorylib.lib.psrd_free_list(self._hdr)
356
+
357
+ @staticmethod
358
+ def from_list(value: Union[List, Tuple]):
359
+ _err = Error()
360
+ list_obj = ValueList()
361
+ for obj in value:
362
+ val_obj = Value()
363
+ val_obj.set(obj)
364
+ factorylib.lib.psrd_list_append(list_obj.handler(),
365
+ val_obj.handler(),
366
+ _err.handler())
367
+ if _err.code != 0:
368
+ FactoryException(_err.what)
369
+ return list_obj
370
+
371
+ def to_list(self) -> list:
372
+ _err = Error()
373
+ count_value = ctypes.c_long()
374
+ factorylib.lib.psrd_list_count(self._hdr,
375
+ ctypes.byref(count_value),
376
+ _err.handler())
377
+ if _err.code != 0:
378
+ raise FactoryException(_err.what)
379
+ values_count = int(count_value.value)
380
+
381
+ list_of_values = []
382
+ _value = Value()
383
+ for i_value in range(values_count):
384
+ factorylib.lib.psrd_list_get(self._hdr, i_value,
385
+ _value.handler(), _err.handler())
386
+ if _err.code != 0:
387
+ raise FactoryException(_err.what)
388
+ list_of_values.append(_value.get())
389
+ return list_of_values
390
+
391
+
392
+ class ValueDict(_BaseObject):
393
+ def __init__(self, initialized=True):
394
+ super().__init__()
395
+ self._hdr = factorylib.lib.psrd_new_dict() if initialized else None
396
+
397
+ def __del__(self):
398
+ if self._hdr is not None:
399
+ factorylib.lib.psrd_free_dict(self._hdr)
400
+
401
+ def __getitem__(self, key: Union["Value", bool, int, float, dt.datetime, str, "DataObject", list, dict, None]) -> Union["Value", bool, int, float, dt.datetime, str, "DataObject", list, dict, None]:
402
+ if not isinstance(key, Value):
403
+ old_key = key
404
+ key = Value()
405
+ key.set(old_key)
406
+ error = Error()
407
+ value = Value()
408
+ factorylib.lib.psrd_dict_get_by_key(self._hdr,
409
+ key.handler(),
410
+ value.handler(),
411
+ error.handler())
412
+ if error.code != 0:
413
+ raise FactoryException(error.what)
414
+ return value.get()
415
+
416
+ def __contains__(self, key: Union["Value", bool, int, float, dt.datetime, str, "DataObject", list, dict, None]) -> bool:
417
+ if not isinstance(key, Value):
418
+ old_key = key
419
+ key = Value()
420
+ key.set(old_key)
421
+ error = Error()
422
+ value = Value()
423
+ factorylib.lib.psrd_dict_get_by_key(self._hdr,
424
+ key.handler(),
425
+ value.handler(),
426
+ error.handler())
427
+ return error.code == 0
428
+
429
+ def __len__(self) -> int:
430
+ error = Error()
431
+ count_value = ctypes.c_long()
432
+ factorylib.lib.psrd_dict_count(self._hdr,
433
+ ctypes.byref(count_value),
434
+ error.handler())
435
+ if error.code != 0:
436
+ raise FactoryException(error.what)
437
+ return int(count_value.value)
438
+
439
+ class KeyIterator:
440
+ def __init__(self, dict_obj: "ValueDict"):
441
+ self.dict_obj = dict_obj
442
+ self.error = Error()
443
+ self.key = Value()
444
+ self.index = 0
445
+
446
+ def __iter__(self):
447
+ return self
448
+
449
+ def __next__(self) -> "Value":
450
+ if self.index >= self.dict_obj.__len__():
451
+ raise StopIteration
452
+ factorylib.lib.psrd_dict_get_key_by_index(self.dict_obj._hdr, self.index,
453
+ self.key.handler(),
454
+ self.error.handler())
455
+ if self.error.code != 0:
456
+ raise FactoryException(self.error.what)
457
+ self.index += 1
458
+ return self.key.get()
459
+
460
+ def keys(self) -> KeyIterator:
461
+ return self.KeyIterator(self)
462
+
463
+ class ValueIterator:
464
+ def __init__(self, dict_obj: "ValueDict"):
465
+ self.dict_obj = dict_obj
466
+ self.error = Error()
467
+ self.value = Value()
468
+ self.index = 0
469
+
470
+ def __iter__(self):
471
+ return self
472
+
473
+ def __next__(self) -> "Value":
474
+ if self.index >= self.dict_obj.__len__():
475
+ raise StopIteration
476
+ factorylib.lib.psrd_dict_get_value_by_index(self.dict_obj._hdr, self.index,
477
+ self.value.handler(),
478
+ self.error.handler())
479
+ if self.error.code != 0:
480
+ raise FactoryException(self.error.what)
481
+ self.index += 1
482
+ return self.value.get()
483
+
484
+ def values(self) -> ValueIterator:
485
+ return self.ValueIterator(self)
486
+
487
+ class ItemIterator:
488
+ def __init__(self, dict_obj: "ValueDict"):
489
+ self.dict_obj = dict_obj
490
+ self.error = Error()
491
+ self.key = Value()
492
+ self.value = Value()
493
+ self.index = 0
494
+
495
+ def __iter__(self):
496
+ return self
497
+
498
+ def __next__(self) -> Tuple["Value", "Value"]:
499
+ if self.index >= self.dict_obj.__len__():
500
+ raise StopIteration
501
+ factorylib.lib.psrd_dict_get_by_index(self.dict_obj._hdr, self.index,
502
+ self.key.handler(),
503
+ self.value.handler(),
504
+ self.error.handler())
505
+ if self.error.code != 0:
506
+ raise FactoryException(self.error.what)
507
+ self.index += 1
508
+ return self.key.get(), self.value.get()
509
+
510
+ def items(self) -> ItemIterator:
511
+ return self.ItemIterator(self)
512
+
513
+ def clear(self):
514
+ error = Error()
515
+ factorylib.lib.psrd_dict_clear(self._hdr, error.handler())
516
+ if error.code != 0:
517
+ raise FactoryException(error.what)
518
+
519
+
520
+ @staticmethod
521
+ def from_dict(dict_value: dict):
522
+ error = Error()
523
+ dict_obj = ValueDict()
524
+ key_obj = Value()
525
+ val_obj = Value()
526
+ for key, value in dict_value.items():
527
+ key_obj.set(key)
528
+ val_obj.set(value)
529
+ factorylib.lib.psrd_dict_set(dict_obj.handler(),
530
+ key_obj.handler(),
531
+ val_obj.handler(),
532
+ error.handler())
533
+ if error.code != 0:
534
+ FactoryException(error.what)
535
+ return dict_obj
536
+
537
+ def to_dict(self) -> dict:
538
+ """Converts Factory dictionary to Python's"""
539
+ error = Error()
540
+ count_value: Union[ctypes.c_long, int] = ctypes.c_long()
541
+ factorylib.lib.psrd_dict_count(self._hdr,
542
+ ctypes.byref(count_value),
543
+ error.handler())
544
+ if error.code != 0:
545
+ raise FactoryException(error.what)
546
+ count_value = int(count_value.value)
547
+
548
+ read_dict = dict()
549
+ key = Value()
550
+ value = Value()
551
+ for i_value in range(count_value):
552
+ factorylib.lib.psrd_dict_get_by_index(self._hdr, i_value,
553
+ key.handler(),
554
+ value.handler(),
555
+ error.handler())
556
+ if error.code != 0:
557
+ raise FactoryException(error.what)
558
+ read_dict[key.get()] = value.get()
559
+ return read_dict
560
+
561
+
562
+ class Value(_BaseObject):
563
+ def __init__(self):
564
+ super().__init__()
565
+ _check_loaded()
566
+ self._hdr = factorylib.lib.psrd_new_value()
567
+
568
+ def __del__(self):
569
+ if self._hdr is not None:
570
+ factorylib.lib.psrd_free_value(self._hdr)
571
+
572
+ def get(self) -> Union[bool, int, float, dt.datetime, str, "DataObject", list, dict, None]:
573
+ _err = Error()
574
+ uint_value = ctypes.c_long()
575
+ factorylib.lib.psrd_value_get_type(self._hdr,
576
+ ctypes.byref(uint_value),
577
+ _err.handler())
578
+ if _err.code != 0:
579
+ raise FactoryException(_err.what)
580
+ var_type = int(uint_value.value)
581
+ if var_type == ValueType.INT32.value:
582
+ int_value = ctypes.c_int()
583
+ factorylib.lib.psrd_value_get_int32(self._hdr,
584
+ ctypes.byref(int_value),
585
+ _err.handler())
586
+ if _err.code != 0:
587
+ raise FactoryException(_err.what)
588
+ return int(int_value.value)
589
+ elif var_type == ValueType.INT64.value:
590
+ long_value = ctypes.c_long()
591
+ factorylib.lib.psrd_value_get_int64(self._hdr,
592
+ ctypes.byref(long_value),
593
+ _err.handler())
594
+ if _err.code != 0:
595
+ raise FactoryException(_err.what)
596
+ return int(int_value.value)
597
+ elif var_type == ValueType.FLOAT32.value:
598
+ float_value = ctypes.c_float()
599
+ factorylib.lib.psrd_value_get_float32(self._hdr,
600
+ ctypes.byref(float_value),
601
+ _err.handler())
602
+ if _err.code != 0:
603
+ raise FactoryException(_err.what)
604
+ return float(float_value.value)
605
+ elif var_type == ValueType.FLOAT64.value:
606
+ float_value = ctypes.c_double()
607
+ factorylib.lib.psrd_value_get_float64(self._hdr,
608
+ ctypes.byref(float_value),
609
+ _err.handler())
610
+ if _err.code != 0:
611
+ raise FactoryException(_err.what)
612
+ return float(float_value.value)
613
+ elif var_type == ValueType.STRING.value:
614
+ size = factorylib.lib.psrd_value_get_string(self._hdr, None, 0,
615
+ _err.handler())
616
+ buffer = ctypes.create_string_buffer(size)
617
+ factorylib.lib.psrd_value_get_string(self._hdr, buffer, size,
618
+ _err.handler())
619
+ if _err.code != 0:
620
+ raise FactoryException(_err.what)
621
+ return _from_c_str(buffer.value)
622
+ elif var_type == ValueType.DATE.value:
623
+ date_value = ctypes.c_longlong()
624
+ factorylib.lib.psrd_value_get_date(self._hdr,
625
+ ctypes.byref(date_value),
626
+ _err.handler())
627
+ if _err.code != 0:
628
+ raise FactoryException(_err.what)
629
+
630
+ return dt.datetime.fromtimestamp(date_value.value - _date_transform, dt.timezone.utc)
631
+
632
+ elif var_type == ValueType.BOOL.value:
633
+ # read bool as int first
634
+ bool_value = ctypes.c_bool()
635
+ factorylib.lib.psrd_value_get_bool(self._hdr,
636
+ ctypes.byref(bool_value),
637
+ _err.handler())
638
+ if _err.code != 0:
639
+ raise FactoryException(_err.what)
640
+ return bool(bool_value.value)
641
+ elif var_type == ValueType.NULL.value:
642
+ # Null type
643
+ return None
644
+ elif var_type == ValueType.OBJECT.value:
645
+ obj = DataObject()
646
+ ref = factorylib.lib.psrd_value_get_object(self._hdr,
647
+ _err.handler())
648
+ if _err.code != 0 or ref is None:
649
+ raise FactoryException(_err.what)
650
+ obj._hdr = ref
651
+ return obj
652
+ elif var_type == ValueType.LIST.value:
653
+ dict_obj = ValueList()
654
+ ref = factorylib.lib.psrd_value_get_list(self._hdr,
655
+ _err.handler())
656
+ if _err.code != 0 or ref is None:
657
+ raise FactoryException(_err.what)
658
+ dict_obj._hdr = ref
659
+ return dict_obj.to_list()
660
+ elif var_type == ValueType.DICT.value:
661
+ dict_obj = ValueDict()
662
+ ref = factorylib.lib.psrd_value_get_dict(self._hdr,
663
+ _err.handler())
664
+ if _err.code != 0 or ref is None:
665
+ raise FactoryException(_err.what)
666
+ dict_obj._hdr = ref
667
+ return dict_obj.to_dict()
668
+ else:
669
+ raise NotImplementedError()
670
+
671
+ def set(self, value: Union[bool, int, float, dt.datetime, str, "DataObject", list, dict, None]):
672
+ _err = Error()
673
+ if isinstance(value, bool):
674
+ factorylib.lib.psrd_value_set_bool(self._hdr, value,
675
+ _err.handler())
676
+ if _err.code != 0:
677
+ raise FactoryException(_err.what)
678
+ elif isinstance(value, dt.datetime):
679
+ value.replace(tzinfo=dt.timezone.utc)
680
+ date_epoch = int(value.timestamp()) + _date_transform
681
+ factorylib.lib.psrd_value_set_date(self._hdr, date_epoch,
682
+ _err.handler())
683
+ if _err.code != 0:
684
+ raise FactoryException(_err.what)
685
+ # TODO: individual test for int32 and int64
686
+ elif isinstance(value, numbers.Integral):
687
+ factorylib.lib.psrd_value_set_int32(self._hdr, value,
688
+ _err.handler())
689
+ if _err.code != 0:
690
+ raise FactoryException(_err.what)
691
+
692
+ # TODO: individual test for float32 and float64
693
+ elif isinstance(value, numbers.Real):
694
+ factorylib.lib.psrd_value_set_float64(self._hdr, value,
695
+ _err.handler())
696
+ if _err.code != 0:
697
+ raise FactoryException(_err.what)
698
+
699
+ elif isinstance(value, str):
700
+ factorylib.lib.psrd_value_set_string(self._hdr,
701
+ _c_str(value),
702
+ _bytes(value),
703
+ _err.handler())
704
+ if _err.code != 0:
705
+ raise FactoryException(_err.what)
706
+
707
+ elif isinstance(value, DataObject):
708
+ factorylib.lib.psrd_value_set_object(self._hdr,
709
+ value.handler(),
710
+ _err.handler())
711
+ if _err.code != 0:
712
+ raise FactoryException(_err.what)
713
+
714
+ elif isinstance(value, (list, tuple, ValueList)):
715
+ if isinstance(value, (list, tuple)):
716
+ dict_obj = ValueList.from_list(value)
717
+ else:
718
+ dict_obj = value
719
+ factorylib.lib.psrd_value_set_list(self._hdr,
720
+ dict_obj.handler(),
721
+ _err.handler())
722
+ if _err.code != 0:
723
+ raise FactoryException(_err.what)
724
+
725
+ elif isinstance(value, dict):
726
+ dict_obj = ValueDict.from_dict(value)
727
+ factorylib.lib.psrd_value_set_dict(self._hdr,
728
+ dict_obj.handler(),
729
+ _err.handler())
730
+ if _err.code != 0:
731
+ raise FactoryException(_err.what)
732
+
733
+ elif isinstance(value, Study):
734
+ raise FactoryException("Study object cannot be set as value.")
735
+
736
+ elif value is None:
737
+ factorylib.lib.psrd_value_set_null(self._hdr,
738
+ _err.handler())
739
+ if _err.code != 0:
740
+ raise FactoryException(_err.what)
741
+
742
+ else:
743
+ raise FactoryException(f"Unsupported type \"{type(value).name}\" for value.")
744
+
745
+
746
+ class PropertyDescription(_BaseObject):
747
+ def __init__(self):
748
+ super().__init__()
749
+ self._hdr = None
750
+
751
+ def __del__(self):
752
+ if self._hdr is not None:
753
+ factorylib.lib.psrd_free_property_description(self._hdr)
754
+
755
+ @property
756
+ def name(self) -> str:
757
+ _err = Error()
758
+ # TODO: determine size automatically
759
+ size = 300
760
+ buffer = ctypes.create_string_buffer(size)
761
+ factorylib.lib.psrd_property_description_get_name(self._hdr, buffer, size,
762
+ _err.handler())
763
+ if _err.code != 0:
764
+ raise FactoryException(_err.what)
765
+ return _from_c_str(buffer.value)
766
+
767
+ @name.setter
768
+ def name(self, value):
769
+ raise AttributeError("do not set name")
770
+
771
+ @name.deleter
772
+ def name(self):
773
+ raise AttributeError("do not delete name")
774
+
775
+ @property
776
+ def alt_name(self) -> str:
777
+ _err = Error()
778
+ # TODO: determine size automatically
779
+ size = 300
780
+ buffer = ctypes.create_string_buffer(size)
781
+ factorylib.lib.psrd_property_description_get_alternative_name(
782
+ self._hdr, buffer, size, _err.handler())
783
+ if _err.code != 0:
784
+ raise FactoryException(_err.what)
785
+ return _from_c_str(buffer.value)
786
+
787
+ @alt_name.setter
788
+ def alt_name(self, value):
789
+ raise AttributeError("do not set alt_name")
790
+
791
+ @alt_name.deleter
792
+ def alt_name(self):
793
+ raise AttributeError("do not delete alt_name")
794
+
795
+ def is_dynamic(self) -> bool:
796
+ _err = Error()
797
+ value = ctypes.c_bool()
798
+ factorylib.lib.psrd_property_description_is_dynamic(self._hdr,
799
+ ctypes.byref(value),
800
+ _err.handler())
801
+ if _err.code != 0:
802
+ raise FactoryException(_err.what)
803
+ return bool(value.value)
804
+
805
+ def is_indexed(self) -> bool:
806
+ _err = Error()
807
+ value = ctypes.c_bool()
808
+ factorylib.lib.psrd_property_description_is_indexed(self._hdr,
809
+ ctypes.byref(value),
810
+ _err.handler())
811
+ if _err.code != 0:
812
+ raise FactoryException(_err.what)
813
+ return bool(value.value)
814
+
815
+ def is_grouped(self) -> bool:
816
+ _err = Error()
817
+ value = ctypes.c_bool()
818
+ factorylib.lib.psrd_property_description_is_grouped(self._hdr,
819
+ ctypes.byref(value),
820
+ _err.handler())
821
+ if _err.code != 0:
822
+ raise FactoryException(_err.what)
823
+ return bool(value.value)
824
+
825
+ def grouped_with(self) -> List[str]:
826
+ _err = Error()
827
+ _list_obj = ValueList()
828
+ ref = factorylib.lib.psrd_property_description_grouped_with(self._hdr,
829
+ _err.handler())
830
+ if _err.code != 0 or ref is None:
831
+ raise FactoryException(_err.what)
832
+ _list_obj._hdr = ref
833
+ return _list_obj.to_list()
834
+
835
+ def dimensions(self) -> Dict[str, int]:
836
+ _err = Error()
837
+ dimensions = {}
838
+ value = ctypes.c_long()
839
+ factorylib.lib.psrd_property_description_dimensions_count(self._hdr,
840
+ ctypes.byref(value),
841
+ _err.handler())
842
+ if _err.code != 0:
843
+ raise FactoryException(_err.what)
844
+ dimensions_count = int(value.value)
845
+
846
+ for i_dim in range(dimensions_count):
847
+ # TODO: get size automatically
848
+ size = 100
849
+ buffer = ctypes.create_string_buffer(size)
850
+ factorylib.lib.psrd_property_description_get_dimension_name(self._hdr,
851
+ i_dim, buffer,
852
+ size,
853
+ _err.handler())
854
+ if _err.code != 0:
855
+ raise FactoryException(_err.what)
856
+ name = _from_c_str(buffer.value)
857
+
858
+ factorylib.lib.psrd_property_description_get_dimension_size(self._hdr,
859
+ i_dim,
860
+ ctypes.byref(value),
861
+ _err.handler())
862
+ if _err.code != 0:
863
+ raise FactoryException(_err.what)
864
+ size = int(value.value)
865
+
866
+ dimensions[name] = size
867
+ return dimensions
868
+
869
+ def type(self) -> ValueType:
870
+ _err = Error()
871
+ value = ctypes.c_long()
872
+ factorylib.lib.psrd_property_description_get_type(self._hdr,
873
+ ctypes.byref(value),
874
+ _err.handler())
875
+ if _err.code != 0:
876
+ raise FactoryException(_err.what)
877
+ return ValueType(value.value)
878
+
879
+ def __repr__(self):
880
+ return self.__str__()
881
+
882
+ def __str__(self):
883
+ dimensions = self.dimensions()
884
+ if len(dimensions) == 0:
885
+ return f"Property {self.name}"
886
+ else:
887
+ return f"Property {self.name} with dimensions {self.dimensions()}"
888
+
889
+
890
+
891
+ class DataObject(_BaseObject):
892
+ def __init__(self):
893
+ super().__init__()
894
+ self._hdr = None
895
+
896
+ def __del__(self):
897
+ if self._hdr is not None:
898
+ factorylib.lib.psrd_free_object(self._hdr)
899
+
900
+ def __eq__(self, other):
901
+ if not isinstance(other, DataObject):
902
+ return False
903
+ _err = Error()
904
+ value = ctypes.c_bool()
905
+ if self._hdr == other.handler():
906
+ return True
907
+ factorylib.lib.psrd_object_is_equals_to(self._hdr,
908
+ other.handler(),
909
+ ctypes.byref(value),
910
+ _err.handler())
911
+ if _err.code != 0:
912
+ raise FactoryException(_err.what)
913
+ return bool(value.value)
914
+
915
+ def __hash__(self):
916
+ _err = Error()
917
+ handler = factorylib.lib.psrd_object_get_handler(self._hdr, _err.handler())
918
+ if _err.code != 0:
919
+ raise FactoryException(_err.what)
920
+ return handler
921
+
922
+ def __copy__(self):
923
+ dest = DataObject()
924
+ _err = Error()
925
+ ref = factorylib.lib.psrd_object_clone(self.handler(),
926
+ _err.handler())
927
+ if _err.code != 0 or ref is None:
928
+ raise FactoryException(_err.what)
929
+ dest._hdr = ref
930
+ return dest
931
+
932
+ def __deepcopy__(self, memodict=None):
933
+ raise NotImplementedError()
934
+
935
+ def __repr__(self):
936
+ identifiers = []
937
+ if self.code != 0:
938
+ identifiers.append(f"code={self.code}")
939
+ if self.id != "":
940
+ identifiers.append(f"id={self.id.strip()}")
941
+ if self.name != "":
942
+ identifiers.append(f"name={self.name.strip()}")
943
+ return f"psr.factory.DataObject({self.type}, {', '.join(identifiers)})"
944
+
945
+ def help(self) -> str:
946
+ return help(self.type)
947
+
948
+ @property
949
+ def context(self) -> "Context":
950
+ _check_initialized()
951
+ obj = Context()
952
+ _err = Error()
953
+ ref = factorylib.lib.psrd_object_context(self._hdr,
954
+ _err.handler())
955
+ if _err.code != 0 or ref is None:
956
+ raise FactoryException(_err.what)
957
+ obj._hdr = ref
958
+ return obj
959
+
960
+ def properties(self) -> Dict[str, PropertyDescription]:
961
+ _err = Error()
962
+ value = ctypes.c_long()
963
+ factorylib.lib.psrd_object_property_description_count(self._hdr,
964
+ ctypes.byref(value),
965
+ _err.handler())
966
+ if _err.code != 0:
967
+ raise FactoryException(_err.what)
968
+ var_count = int(value.value)
969
+ properties = {}
970
+ for i_var in range(var_count):
971
+ var = PropertyDescription()
972
+ ref = factorylib.lib.psrd_object_get_property_description(self._hdr,
973
+ i_var,
974
+ _err.handler())
975
+ if _err.code != 0 or ref is None:
976
+ raise FactoryException(_err.what)
977
+ var._hdr = ref
978
+ properties[var.name] = var
979
+ return properties
980
+
981
+ def get(self, expression: str) -> Union[int, float, dt.datetime, str, "DataObject", list, None]:
982
+ value = Value()
983
+ _err = Error()
984
+ factorylib.lib.psrd_object_get_value(self._hdr,
985
+ _c_str(expression),
986
+ value.handler(),
987
+ _err.handler())
988
+ if _err.code != 0:
989
+ raise FactoryException(_err.what)
990
+ return value.get()
991
+
992
+ def get_at(self, expression: str, range_expr: Union[str, dt.datetime]) -> Union[int, float, dt.datetime, str, "DataObject", list, None]:
993
+ if not isinstance(range_expr, (str, dt.datetime)):
994
+ raise FactoryException("range_expr must be a string or datetime object.")
995
+ _value = Value()
996
+ _err = Error()
997
+ _range = Value()
998
+ _range.set(range_expr)
999
+ factorylib.lib.psrd_object_get_value_at(self._hdr,
1000
+ _c_str(expression),
1001
+ _range.handler(),
1002
+ _value.handler(),
1003
+ _err.handler())
1004
+ if _err.code != 0:
1005
+ raise FactoryException(_err.what)
1006
+ return _value.get()
1007
+
1008
+ def as_dict(self) -> Dict[str, any]:
1009
+ value_dict = ValueDict()
1010
+ error = Error()
1011
+ handler = factorylib.lib.psrd_object_get_as_dict(self._hdr,
1012
+ error.handler())
1013
+ if error.code != 0 or handler is None:
1014
+ raise FactoryException(error.what)
1015
+ value_dict._hdr = handler
1016
+ return value_dict.to_dict()
1017
+
1018
+ def from_dict(self, input_dict: Dict[str, any]):
1019
+ value_dict = ValueDict.from_dict(input_dict)
1020
+ error = Error()
1021
+ factorylib.lib.psrd_object_set_from_dict(self._hdr, value_dict.handler(),
1022
+ error.handler())
1023
+ if error.code != 0:
1024
+ raise FactoryException(error.what)
1025
+
1026
+ def get_df(self, expression: str) -> "pandas.DataFrame":
1027
+ _err = Error()
1028
+ _df = DataFrame()
1029
+ factorylib.lib.psrd_object_get_table(self._hdr, _df.handler(),
1030
+ _c_str(expression),
1031
+ _bytes(expression),
1032
+ _err.handler())
1033
+ if _err.code != 0:
1034
+ raise FactoryException(_err.what)
1035
+ df_builder = _DataFrameBuilder()
1036
+ df_builder.build_dataframe(_df)
1037
+ return df_builder.build_pandas_dataframe()
1038
+
1039
+ def set(self, expression: str, value):
1040
+ _err = Error()
1041
+ _val = Value()
1042
+ _val.set(value)
1043
+ factorylib.lib.psrd_object_set_value(self._hdr, _c_str(expression),
1044
+ _bytes(expression),
1045
+ _val.handler(),
1046
+ _err.handler())
1047
+ if _err.code != 0:
1048
+ raise FactoryException(_err.what)
1049
+
1050
+ def set_at(self, expression: str, range_expr: Union[str, dt.datetime], value):
1051
+ if not isinstance(range_expr, (str, dt.datetime)):
1052
+ raise FactoryException("range_expr must be a string or datetime object.")
1053
+ _err = Error()
1054
+ _value = Value()
1055
+ _value.set(value)
1056
+ _range = Value()
1057
+ _range.set(range_expr)
1058
+ factorylib.lib.psrd_object_set_value_at(self._hdr,
1059
+ _c_str(expression),
1060
+ _bytes(expression),
1061
+ _range.handler(),
1062
+ _value.handler(),
1063
+ _err.handler())
1064
+ if _err.code != 0:
1065
+ raise FactoryException(_err.what)
1066
+
1067
+ def set_df(self, dataframe_like):
1068
+ if not _has_pandas():
1069
+ raise ModuleNotFoundError("pandas required.")
1070
+ dataframe_like = pandas.api.interchange.from_dataframe(dataframe_like)
1071
+ df_builder = _DataFrameBuilder()
1072
+ _df = df_builder.build_from_pandas(dataframe_like)
1073
+ _err = Error()
1074
+ factorylib.lib.psrd_object_set_table(self._hdr, _df.handler(),
1075
+ _err.handler())
1076
+ if _err.code != 0:
1077
+ raise FactoryException(_err.what)
1078
+
1079
+
1080
+ def clear_values(self, expression: str):
1081
+ _err = Error()
1082
+ factorylib.lib.psrd_object_clear_values(self._hdr,
1083
+ _c_str(expression),
1084
+ _bytes(expression),
1085
+ _err.handler())
1086
+ if _err.code != 0:
1087
+ raise FactoryException(_err.what)
1088
+
1089
+ def parent(self) -> Optional["Study"]:
1090
+ study_ptr = Study()
1091
+ _err = Error()
1092
+ ref = factorylib.lib.psrd_object_get_parent(self._hdr,
1093
+ _err.handler())
1094
+ if _err.code != 0:
1095
+ raise FactoryException(_err.what)
1096
+ if ref is None:
1097
+ return None
1098
+ study_ptr._hdr = ref
1099
+ return study_ptr
1100
+
1101
+ def referenced_by(self) -> List["DataObject"]:
1102
+ object_list = ValueList(False)
1103
+ _err = Error()
1104
+ ref = factorylib.lib.psrd_object_referenced_by(self._hdr,
1105
+ _err.handler())
1106
+ if _err.code != 0 or ref is None:
1107
+ raise FactoryException(_err.what)
1108
+ object_list._hdr = ref
1109
+ return object_list.to_list()
1110
+
1111
+ @property
1112
+ def code(self) -> int:
1113
+ _err = Error()
1114
+ value = ctypes.c_int()
1115
+ factorylib.lib.psrd_object_get_code(self._hdr,
1116
+ ctypes.byref(value),
1117
+ _err.handler())
1118
+ if _err.code != 0:
1119
+ raise FactoryException(_err.what)
1120
+ return value.value
1121
+
1122
+ @code.setter
1123
+ def code(self, value: int):
1124
+ _err = Error()
1125
+ factorylib.lib.psrd_object_set_code(self._hdr, value,
1126
+ _err.handler())
1127
+ if _err.code != 0:
1128
+ raise FactoryException(_err.what)
1129
+
1130
+ @code.deleter
1131
+ def code(self):
1132
+ raise AttributeError("do not delete code")
1133
+
1134
+ @property
1135
+ def type(self) -> str:
1136
+ err = Error()
1137
+ size = factorylib.lib.psrd_object_get_type(self._hdr, None,
1138
+ 0, err.handler())
1139
+ if err.code != 0:
1140
+ raise FactoryException(err.what)
1141
+ buffer = ctypes.create_string_buffer(size)
1142
+ factorylib.lib.psrd_object_get_type(self._hdr, buffer,
1143
+ size, err.handler())
1144
+ if err.code != 0:
1145
+ raise FactoryException(err.what)
1146
+ return _from_c_str(buffer.value)
1147
+
1148
+ @type.setter
1149
+ def type(self, value: str):
1150
+ raise AttributeError("do not set type")
1151
+
1152
+ @type.deleter
1153
+ def type(self):
1154
+ raise AttributeError("do not delete type")
1155
+
1156
+ @property
1157
+ def name(self) -> str:
1158
+ err = Error()
1159
+ size = factorylib.lib.psrd_object_get_name(self._hdr, None,
1160
+ 0, err.handler())
1161
+ if err.code != 0:
1162
+ raise FactoryException(err.what)
1163
+ buffer = ctypes.create_string_buffer(size)
1164
+ factorylib.lib.psrd_object_get_name(self._hdr, buffer,
1165
+ size, err.handler())
1166
+ if err.code == 0:
1167
+ return _from_c_str(buffer.value)
1168
+ raise FactoryException(err.what)
1169
+
1170
+ @name.setter
1171
+ def name(self, value: str):
1172
+ err = Error()
1173
+ factorylib.lib.psrd_object_set_name(self._hdr,
1174
+ _c_str(value),
1175
+ _bytes(value),
1176
+ err.handler())
1177
+ if err.code != 0:
1178
+ raise FactoryException(err.what)
1179
+
1180
+ @name.deleter
1181
+ def name(self):
1182
+ raise AttributeError("do not delete name")
1183
+
1184
+ @property
1185
+ def id(self) -> str:
1186
+ err = Error()
1187
+ size = factorylib.lib.psrd_object_get_id(self._hdr, None,
1188
+ 0, err.handler())
1189
+ if err.code != 0:
1190
+ raise FactoryException(err.what)
1191
+ buffer = ctypes.create_string_buffer(size)
1192
+ factorylib.lib.psrd_object_get_id(self._hdr, buffer,
1193
+ size, err.handler())
1194
+ if err.code == 0:
1195
+ return _from_c_str(buffer.value)
1196
+ raise FactoryException(err.what)
1197
+
1198
+ @id.setter
1199
+ def id(self, value: str):
1200
+ _err = Error()
1201
+ factorylib.lib.psrd_object_set_id(self._hdr,
1202
+ _c_str(value),
1203
+ _bytes(value),
1204
+ _err.handler())
1205
+ if _err.code != 0:
1206
+ raise FactoryException(_err.what)
1207
+
1208
+ @id.deleter
1209
+ def id(self):
1210
+ raise AttributeError("do not delete id")
1211
+
1212
+
1213
+ class Context(DataObject):
1214
+ @staticmethod
1215
+ def default_context() -> "Context":
1216
+ _check_initialized()
1217
+ context = Context()
1218
+ err = Error()
1219
+ ref = factorylib.lib.psrd_get_default_context(err.handler())
1220
+ if err.code != 0 or ref is None:
1221
+ raise FactoryException(err.what)
1222
+ context._hdr = ref
1223
+ return context
1224
+
1225
+ @staticmethod
1226
+ def create() -> "Context":
1227
+ context_obj = create("Context", None)
1228
+ context = Context()
1229
+ context._hdr = context_obj._hdr
1230
+ context_obj._hdr = None
1231
+ return context
1232
+
1233
+
1234
+ class Study(_BaseObject):
1235
+ def __init__(self):
1236
+ super().__init__()
1237
+ self.find_by_name = self.find
1238
+
1239
+ def __del__(self):
1240
+ if self._hdr is not None:
1241
+ factorylib.lib.psrd_free_study(self._hdr)
1242
+
1243
+ def __hash__(self):
1244
+ return factorylib.lib.psrd_study_get_handler(self._hdr)
1245
+
1246
+ def __eq__(self, other: "Study"):
1247
+ _err = Error()
1248
+ value = ctypes.c_bool()
1249
+ if self._hdr == other.handler():
1250
+ return True
1251
+ factorylib.lib.psrd_study_is_equals_to(self._hdr,
1252
+ other.handler(),
1253
+ ctypes.byref(value),
1254
+ _err.handler())
1255
+ if _err.code != 0:
1256
+ raise FactoryException(_err.what)
1257
+ return bool(value.value)
1258
+
1259
+ def __copy__(self):
1260
+ raise NotImplementedError()
1261
+
1262
+ def __deepcopy__(self, memodict=None):
1263
+ dest = Study()
1264
+ _err = Error()
1265
+ ref = factorylib.lib.psrd_study_clone(self.handler(),
1266
+ _err.handler())
1267
+ if _err.code != 0 or ref is None:
1268
+ raise FactoryException(_err.what)
1269
+ dest._hdr = ref
1270
+ return dest
1271
+
1272
+ @staticmethod
1273
+ def help():
1274
+ return help("Study")
1275
+
1276
+ @staticmethod
1277
+ def create_object(profile_or_context: Union[str, Context, dict, None],
1278
+ blocks: Optional[int] = None):
1279
+ _check_initialized()
1280
+ err = Error()
1281
+ context = _get_context(profile_or_context, blocks)
1282
+ study = Study()
1283
+ study._hdr = factorylib.lib.psrd_study_create(context.handler(),
1284
+ err.handler())
1285
+ if err.code != 0:
1286
+ raise FactoryException(err.what)
1287
+ return study
1288
+
1289
+ @staticmethod
1290
+ def load(study_path: Union[str, pathlib.Path], profile_or_context: Union[str, Context, None],
1291
+ settings_only: bool = False,
1292
+ options: Optional[Union[dict, "Value", "DataObject"]] = None):
1293
+ if not isinstance(options, (DataObject, type(None))):
1294
+ raise TypeError("options must be a DataObject or None.")
1295
+ _check_initialized()
1296
+ study_path = str(study_path)
1297
+ context = _get_context(profile_or_context, None)
1298
+ err = Error()
1299
+ options_value = _get_arg_object(options)
1300
+ study = Study()
1301
+ if not settings_only:
1302
+ load_fn = factorylib.lib.psrd_study_load
1303
+ else:
1304
+ load_fn = factorylib.lib.psrd_study_load_settings
1305
+ study._hdr = load_fn(_c_str(study_path), _bytes(study_path),
1306
+ options_value.handler(), context.handler(),
1307
+ err.handler())
1308
+ if err.code != 0:
1309
+ raise FactoryException(err.what)
1310
+ return study
1311
+
1312
+ def save(self, output_path: Union[str, pathlib.Path],
1313
+ options: Optional[Union[dict, Value, DataObject]] = None):
1314
+ output_path = str(output_path)
1315
+ _err = Error()
1316
+ options_value = _get_arg_object(options)
1317
+ factorylib.lib.psrd_study_save(self._hdr,
1318
+ _c_str(output_path), _bytes(output_path),
1319
+ options_value.handler(),
1320
+ _err.handler())
1321
+ if _err.code != 0:
1322
+ raise FactoryException(_err.what)
1323
+
1324
+ def save_settings(self, output_path: Union[str, pathlib.Path],
1325
+ options: Optional[Union[dict, Value, DataObject]] = None):
1326
+ output_path = str(output_path)
1327
+ _err = Error()
1328
+ options_value = _get_arg_object(options)
1329
+ factorylib.lib.psrd_study_save_settings(self._hdr, _c_str(output_path),
1330
+ _bytes(output_path),
1331
+ options_value.handler(),
1332
+ _err.handler())
1333
+ if _err.code != 0:
1334
+ raise FactoryException(_err.what)
1335
+
1336
+ @property
1337
+ def context(self) -> "Context":
1338
+ _check_initialized()
1339
+ obj = Context()
1340
+ _err = Error()
1341
+ ref = factorylib.lib.psrd_study_context(self._hdr,
1342
+ _err.handler())
1343
+ if _err.code != 0 or ref is None:
1344
+ raise FactoryException(_err.what)
1345
+ obj._hdr = ref
1346
+ return obj
1347
+
1348
+ def get(self, expression: str) -> Union[int, float, dt.datetime, str, "DataObject", list, None]:
1349
+ value = Value()
1350
+ _err = Error()
1351
+ factorylib.lib.psrd_study_get_value(self._hdr,
1352
+ _c_str(expression),
1353
+ value.handler(),
1354
+ _err.handler())
1355
+ if _err.code != 0:
1356
+ raise FactoryException(_err.what)
1357
+ return value.get()
1358
+
1359
+ def get_at(self, expression: str, range_expr: Union[str, dt.datetime]) -> Union[int, float, dt.datetime, str, "DataObject", list, None]:
1360
+ if not isinstance(range_expr, str):
1361
+ raise FactoryException("range_expr must be a string or datetime object.")
1362
+ _value = Value()
1363
+ _err = Error()
1364
+ _range = Value()
1365
+ _range.set(range_expr)
1366
+ factorylib.lib.psrd_study_get_value_at(self._hdr,
1367
+ _c_str(expression),
1368
+ _range.handler(),
1369
+ _value.handler(),
1370
+ _err.handler())
1371
+ if _err.code != 0:
1372
+ raise FactoryException(_err.what)
1373
+ return _value.get()
1374
+
1375
+ def as_dict(self) -> Dict[str, any]:
1376
+ value_dict = ValueDict()
1377
+ error = Error()
1378
+ handler = factorylib.lib.psrd_study_get_as_dict(self._hdr,
1379
+ error.handler())
1380
+ if error.code != 0 or handler is None:
1381
+ raise FactoryException(error.what)
1382
+ value_dict._hdr = handler
1383
+ return value_dict.to_dict()
1384
+
1385
+ def from_dict(self, input_dict: Dict[str, any]):
1386
+ value_dict = ValueDict.from_dict(input_dict)
1387
+ error = Error()
1388
+ factorylib.lib.psrd_study_set_from_dict(self._hdr, value_dict.handler(),
1389
+ error.handler())
1390
+ if error.code != 0:
1391
+ raise FactoryException(error.what)
1392
+
1393
+ def add(self, obj: DataObject):
1394
+ if not isinstance(obj, DataObject):
1395
+ raise TypeError("obj must be a DataObject.")
1396
+ _err = Error()
1397
+ factorylib.lib.psrd_study_add(self._hdr,
1398
+ obj.handler(),
1399
+ _err.handler())
1400
+ if _err.code != 0:
1401
+ raise FactoryException(_err.what)
1402
+
1403
+ def remove(self, obj: DataObject):
1404
+ if not isinstance(obj, DataObject):
1405
+ raise TypeError("obj must be a DataObject.")
1406
+ _err = Error()
1407
+ factorylib.lib.psrd_study_remove(self._hdr,
1408
+ obj.handler(),
1409
+ _err.handler())
1410
+ if _err.code != 0:
1411
+ raise FactoryException(_err.what)
1412
+
1413
+ def get_all_objects(self) -> List[DataObject]:
1414
+ object_list = ValueList(False)
1415
+ error = Error()
1416
+ ref = factorylib.lib.psrd_study_get_all_objects(self._hdr,
1417
+ error.handler())
1418
+ if error.code != 0 or ref is None:
1419
+ raise FactoryException(error.what)
1420
+ object_list._hdr = ref
1421
+ return object_list.to_list()
1422
+
1423
+ def find(self, expression: str) -> List[DataObject]:
1424
+ object_list = ValueList(False)
1425
+ _err = Error()
1426
+ ref = factorylib.lib.psrd_study_find(self._hdr,
1427
+ _c_str(expression),
1428
+ _err.handler())
1429
+ if _err.code != 0 or ref is None:
1430
+ raise FactoryException(_err.what)
1431
+ object_list._hdr = ref
1432
+ return object_list.to_list()
1433
+
1434
+ def find_by_name(self, type_name: str, name: str) -> List[DataObject]:
1435
+ object_list = ValueList(False)
1436
+ _err = Error()
1437
+ if name.strip() == "":
1438
+ name = "*"
1439
+ expression = f"{type_name}.{name}"
1440
+ ref = factorylib.lib.psrd_study_find(self._hdr,
1441
+ _c_str(expression),
1442
+ _err.handler())
1443
+ if _err.code != 0 or ref is None:
1444
+ raise FactoryException(_err.what)
1445
+ object_list._hdr = ref
1446
+ return object_list.to_list()
1447
+
1448
+ def find_by_code(self, type_name: str, code: Optional[int] = None) -> List[DataObject]:
1449
+ if code is None:
1450
+ warnings.warn(DeprecationWarning("Starting from Factory 4.0.9 "
1451
+ "the second argument 'code' must be provided.\n"
1452
+ "Use find_by_code(type_name, code)"))
1453
+
1454
+ type_name, code_str = type_name.split(".", 1)
1455
+ code = int(code_str)
1456
+
1457
+ object_list = ValueList(False)
1458
+ _err = Error()
1459
+ ref = factorylib.lib.psrd_study_find_by_code(self._hdr,
1460
+ _c_str(type_name),
1461
+ code,
1462
+ _err.handler())
1463
+ if _err.code != 0 or ref is None:
1464
+ raise FactoryException(_err.what)
1465
+ object_list._hdr = ref
1466
+ return object_list.to_list()
1467
+
1468
+ def find_by_id(self, expression: str) -> List[DataObject]:
1469
+ object_list = ValueList(False)
1470
+ _err = Error()
1471
+ ref = factorylib.lib.psrd_study_find_by_id(self._hdr,
1472
+ _c_str(expression),
1473
+ _err.handler())
1474
+ if _err.code != 0 or ref is None:
1475
+ raise FactoryException(_err.what)
1476
+ object_list._hdr = ref
1477
+ return object_list.to_list()
1478
+
1479
+ def set(self, expression: str, value):
1480
+ _err = Error()
1481
+ _val = Value()
1482
+ _val.set(value)
1483
+ factorylib.lib.psrd_study_set_value(self._hdr,
1484
+ _c_str(expression),
1485
+ _bytes(expression),
1486
+ _val.handler(),
1487
+ _err.handler())
1488
+ if _err.code != 0:
1489
+ raise FactoryException(_err.what)
1490
+
1491
+ def set_at(self, expression: str, range_expr: Union[str, dt.datetime], value):
1492
+ if not isinstance(range_expr, (str, dt.datetime)):
1493
+ raise FactoryException("range_expr must be a string or datetime object.")
1494
+ _err = Error()
1495
+ _value = Value()
1496
+ _value.set(value)
1497
+ _range = Value()
1498
+ _range.set(range_expr)
1499
+ factorylib.lib.psrd_study_set_value_at(self._hdr,
1500
+ _c_str(expression),
1501
+ _bytes(expression),
1502
+ _range.handler(),
1503
+ _value.handler(),
1504
+ _err.handler())
1505
+ if _err.code != 0:
1506
+ raise FactoryException(_err.what)
1507
+
1508
+ def get_df(self, expression: str) -> "pandas.DataFrame":
1509
+ _err = Error()
1510
+ _df = DataFrame()
1511
+ factorylib.lib.psrd_study_get_table(self._hdr, _df.handler(),
1512
+ _c_str(expression),
1513
+ _bytes(expression),
1514
+ _err.handler())
1515
+ if _err.code != 0:
1516
+ raise FactoryException(_err.what)
1517
+ df_builder = _DataFrameBuilder()
1518
+ df_builder.build_dataframe(_df)
1519
+ return df_builder.build_pandas_dataframe()
1520
+
1521
+ def get_objects_values(self, object_type: str, columns: List[str]) -> "pandas.DataFrame":
1522
+ _err = Error()
1523
+ _table = DataFrame()
1524
+ columns_list = Value()
1525
+ columns_list.set(columns)
1526
+ factorylib.lib.psrd_study_get_objects_values(self._hdr, _table.handler(),
1527
+ _c_str(object_type),
1528
+ columns_list.handler(),
1529
+ _err.handler())
1530
+ if _err.code != 0:
1531
+ raise FactoryException(_err.what)
1532
+ df_builder = _DataFrameBuilder()
1533
+ df_builder.build_dataframe(_table)
1534
+ return df_builder.build_pandas_dataframe()
1535
+
1536
+ def get_objects_values_at(self, object_type: str, columns: List[str], range: Union[str, dt.datetime]) -> "pandas.DataFrame":
1537
+ _err = Error()
1538
+ _df = DataFrame()
1539
+ _range = Value()
1540
+ _range.set(range)
1541
+ columns_list = Value()
1542
+ columns_list.set(columns)
1543
+ factorylib.lib.psrd_study_get_objects_values_at(self._hdr, _df.handler(),
1544
+ _c_str(object_type),
1545
+ columns_list.handler(),
1546
+ _range.handler(),
1547
+ _err.handler())
1548
+ if _err.code != 0:
1549
+ raise FactoryException(_err.what)
1550
+ df_builder = _DataFrameBuilder()
1551
+ df_builder.build_dataframe(_df)
1552
+ return df_builder.build_pandas_dataframe()
1553
+
1554
+ def properties(self) -> Dict[str, PropertyDescription]:
1555
+ _err = Error()
1556
+ value = ctypes.c_long()
1557
+ factorylib.lib.psrd_study_property_description_count(self._hdr,
1558
+ ctypes.byref(value),
1559
+ _err.handler())
1560
+ if _err.code != 0:
1561
+ raise FactoryException(_err.what)
1562
+ var_count = int(value.value)
1563
+ properties = {}
1564
+ for i_var in range(var_count):
1565
+ var = PropertyDescription()
1566
+ ref = factorylib.lib.psrd_study_get_property_description(self._hdr,
1567
+ i_var,
1568
+ _err.handler())
1569
+ if _err.code != 0 or ref is None:
1570
+ raise FactoryException(_err.what)
1571
+ var._hdr = ref
1572
+ properties[var.name] = var
1573
+ return properties
1574
+
1575
+ def set_df(self, dataframe_like):
1576
+ if not _has_pandas():
1577
+ raise ModuleNotFoundError("pandas required.")
1578
+ dataframe_like = pandas.api.interchange.from_dataframe(dataframe_like)
1579
+ df_builder = _DataFrameBuilder()
1580
+ _df = df_builder.build_from_pandas(dataframe_like)
1581
+ _err = Error()
1582
+ factorylib.lib.psrd_study_set_table(self._hdr, _df.handler(),
1583
+ _err.handler())
1584
+ if _err.code != 0:
1585
+ raise FactoryException(_err.what)
1586
+
1587
+ def clear_values(self, expression: str):
1588
+ _err = Error()
1589
+ factorylib.lib.psrd_study_clear_values(self._hdr,
1590
+ _c_str(expression),
1591
+ _bytes(expression),
1592
+ _err.handler())
1593
+ if _err.code != 0:
1594
+ raise FactoryException(_err.what)
1595
+
1596
+
1597
+ def _is_int64(value):
1598
+ return isinstance(value, int) or isinstance(value, numpy.int64) or (isinstance(value, numpy.ndarray) and value.dtype == numpy.int64)
1599
+
1600
+ def _is_float32(value):
1601
+ return isinstance(value, (numpy.float32,)) or (isinstance(value, numpy.ndarray) and value.dtype == numpy.float32)
1602
+
1603
+ def _is_float64(value):
1604
+ return isinstance(value, (numpy.float64, float)) or (isinstance(value, numpy.ndarray) and value.dtype == numpy.float64)
1605
+
1606
+
1607
+ class _DataFrameBuilder:
1608
+ def __init__(self):
1609
+ self.indices: List[Optional[_TableColumn]] = []
1610
+ self.columns: List[Optional[_TableColumn]] = []
1611
+ self.column_names: List[str] = []
1612
+ self.index_names: List[str] = []
1613
+ self.column_types: List[int] = []
1614
+ self.index_types: List[int] = []
1615
+ self._not_built = True
1616
+ self._value: Optional[Value] = None
1617
+ self._err: Optional[Error] = None
1618
+
1619
+ def _pandas_dtype_to_column_type(self, dtype: str) -> int:
1620
+ if dtype == "object":
1621
+ return 0
1622
+ elif dtype == "int32":
1623
+ return 1
1624
+ elif dtype == "int64":
1625
+ return 2
1626
+ elif dtype == "float32":
1627
+ return 3
1628
+ elif dtype == "float64":
1629
+ return 4
1630
+ elif dtype == "string":
1631
+ return 5
1632
+ elif dtype == "datetime64[ns]":
1633
+ return 6
1634
+ else:
1635
+ raise FactoryException(f"Unsupported pandas dtype \"{dtype}\".")
1636
+
1637
+ def _polars_dtype_to_column_type(self, dtype: "polars.datatypes.classes.DataTypeClass") -> int:
1638
+ if dtype == polars.Int32:
1639
+ return 1
1640
+ if dtype == polars.Int64:
1641
+ return 2
1642
+ if dtype == polars.Float64:
1643
+ return 3
1644
+ if dtype == polars.Float64:
1645
+ return 4
1646
+ if dtype == polars.String:
1647
+ return 5
1648
+ else:
1649
+ raise FactoryException(f"Unsupported polars dtype \"{dtype}\".")
1650
+
1651
+
1652
+ def build_dataframe(self, df: "DataFrame"):
1653
+ self._err = Error()
1654
+ name_buffer_length = 200
1655
+ _columns_count = ctypes.c_long()
1656
+ factorylib.lib.psrd_table_columns_count(df.handler(),
1657
+ ctypes.byref(_columns_count),
1658
+ self._err.handler())
1659
+ if self._err.code != 0:
1660
+ raise FactoryException(self._err.what)
1661
+ columns_count = _columns_count.value
1662
+
1663
+ _rows_count = ctypes.c_long()
1664
+ factorylib.lib.psrd_table_rows_count(df.handler(),
1665
+ ctypes.byref(_rows_count),
1666
+ self._err.handler())
1667
+ if self._err.code != 0:
1668
+ raise FactoryException(self._err.what)
1669
+ rows_count = _rows_count.value
1670
+
1671
+ _indices_count = ctypes.c_long()
1672
+ factorylib.lib.psrd_table_index_count(df.handler(),
1673
+ ctypes.byref(_indices_count),
1674
+ self._err.handler())
1675
+ if self._err.code != 0:
1676
+ raise FactoryException(self._err.what)
1677
+ indices_count = _indices_count.value
1678
+
1679
+ value = Value()
1680
+ buffer = ctypes.create_string_buffer(name_buffer_length)
1681
+
1682
+ self.indices = [_TableColumn() for _ in range(indices_count)]
1683
+ for index in range(indices_count):
1684
+ factorylib.lib.psrd_table_index_get_name(df.handler(), index,
1685
+ buffer, name_buffer_length,
1686
+ self._err.handler())
1687
+ if self._err.code != 0:
1688
+ raise FactoryException(self._err.what)
1689
+ self.indices[index].name = _from_c_str(buffer.value)
1690
+
1691
+ self.indices[index].values = [None] * rows_count
1692
+ for i_row in range(0, rows_count):
1693
+ factorylib.lib.psrd_table_index_get_value(df.handler(), index,
1694
+ i_row, value.handler(),
1695
+ self._err.handler())
1696
+ if self._err.code != 0:
1697
+ raise FactoryException(self._err.what)
1698
+ self.indices[index].values[i_row] = value.get()
1699
+
1700
+ self.columns = [_TableColumn() for _ in range(columns_count)]
1701
+ for column in range(columns_count):
1702
+ factorylib.lib.psrd_table_column_get_name(df.handler(), column,
1703
+ buffer, name_buffer_length,
1704
+ self._err.handler())
1705
+ if self._err.code != 0:
1706
+ raise FactoryException(self._err.what)
1707
+ self.columns[column].name = _from_c_str(buffer.value)
1708
+
1709
+ self.columns[column].values = [None] * rows_count
1710
+ for row in range(rows_count):
1711
+ factorylib.lib.psrd_table_column_get_value(df.handler(),
1712
+ column, row,
1713
+ value.handler(),
1714
+ self._err.handler())
1715
+ if self._err.code != 0:
1716
+ raise FactoryException(self._err.what)
1717
+ self.columns[column].values[row] = value.get()
1718
+ self._not_built = False
1719
+
1720
+ def build_dataframe_of_integral_types(self, df: "DataFrame"):
1721
+ self._err = Error()
1722
+ name_buffer_length = 200
1723
+ _columns_count = ctypes.c_long()
1724
+ factorylib.lib.psrd_table_columns_count(df.handler(),
1725
+ ctypes.byref(_columns_count),
1726
+ self._err.handler())
1727
+ if self._err.code != 0:
1728
+ raise FactoryException(self._err.what)
1729
+ columns_count = _columns_count.value
1730
+
1731
+ _rows_count = ctypes.c_long()
1732
+ factorylib.lib.psrd_table_rows_count(df.handler(),
1733
+ ctypes.byref(_rows_count),
1734
+ self._err.handler())
1735
+ if self._err.code != 0:
1736
+ raise FactoryException(self._err.what)
1737
+ rows_count = _rows_count.value
1738
+
1739
+ _indices_count = ctypes.c_long()
1740
+ factorylib.lib.psrd_table_index_count(df.handler(),
1741
+ ctypes.byref(_indices_count),
1742
+ self._err.handler())
1743
+ if self._err.code != 0:
1744
+ raise FactoryException(self._err.what)
1745
+ indices_count = _indices_count.value
1746
+
1747
+ buffer = ctypes.create_string_buffer(name_buffer_length)
1748
+
1749
+ self.indices = [_TableColumn() for _ in range(indices_count)]
1750
+ for index in range(indices_count):
1751
+ factorylib.lib.psrd_table_index_get_name(df.handler(), index,
1752
+ buffer, name_buffer_length,
1753
+ self._err.handler())
1754
+ if self._err.code != 0:
1755
+ raise FactoryException(self._err.what)
1756
+ index_name = _from_c_str(buffer.value)
1757
+ self.indices[index].name = index_name
1758
+ self.indices[index].values = [None] * rows_count
1759
+ if index_name in ("date", "datetime"):
1760
+ array_values = (ctypes.c_longlong * rows_count)()
1761
+ factorylib.lib.psrd_table_index_get_date_values(df.handler(),
1762
+ index,
1763
+ array_values,
1764
+ self._err.handler())
1765
+ if self._err.code != 0:
1766
+ raise FactoryException(self._err.what)
1767
+ # convert array values to python datetime
1768
+ self.indices[index].values = [dt.datetime.utcfromtimestamp(value - _date_transform) for value in array_values]
1769
+ else:
1770
+ array_values = (ctypes.c_int * rows_count)()
1771
+ factorylib.lib.psrd_table_index_get_int32_values(df.handler(),
1772
+ index,
1773
+ array_values,
1774
+ self._err.handler())
1775
+ if self._err.code != 0:
1776
+ raise FactoryException(self._err.what)
1777
+ self.indices[index].values = array_values
1778
+
1779
+ self.columns = [_TableColumn() for _ in range(columns_count)]
1780
+ for column in range(columns_count):
1781
+ factorylib.lib.psrd_table_column_get_name(df.handler(), column,
1782
+ buffer, name_buffer_length,
1783
+ self._err.handler())
1784
+ if self._err.code != 0:
1785
+ raise FactoryException(self._err.what)
1786
+ self.columns[column].name = _from_c_str(buffer.value)
1787
+
1788
+ array_values = (ctypes.c_double * rows_count)()
1789
+ factorylib.lib.psrd_table_column_get_float64_values(df.handler(),
1790
+ column,
1791
+ array_values,
1792
+ self._err.handler())
1793
+ if self._err.code != 0:
1794
+ raise FactoryException(self._err.what)
1795
+ self.columns[column].values = array_values
1796
+ self._not_built = False
1797
+
1798
+ def build_pandas_dataframe(self, **kwargs) -> "pandas.DataFrame":
1799
+ use_object_dtype = kwargs.get("use_object_dtype", True)
1800
+ if not _has_pandas():
1801
+ raise ModuleNotFoundError("pandas required.")
1802
+ def convert_column_values(values):
1803
+ if isinstance(values, list):
1804
+ return values
1805
+ # Looks like ctype array, smells like ctype array
1806
+ if hasattr(values, "_length_") and hasattr(values, "_type_"):
1807
+ return numpy.ctypeslib.as_array(values)
1808
+ return values
1809
+
1810
+ data = {column.name: convert_column_values(column.values)
1811
+ for column in self.columns}
1812
+ if len(self.indices) > 1:
1813
+ # TODO: store index as rows of tuples
1814
+ index = pandas.MultiIndex.from_tuples(
1815
+ [tuple(self.indices[i].values[row] for i in range(len(self.indices))) for row in range(len(self.indices[0].values))],
1816
+ names=[index.name for index in self.indices])
1817
+ elif len(self.indices) == 1:
1818
+ index_value_type = type(self.indices[0].values[0]) if len(self.indices[0].values) > 0 else object
1819
+ if index_value_type == dt.datetime:
1820
+ index = pandas.DatetimeIndex(self.indices[0].values, name=self.indices[0].name)
1821
+ else:
1822
+ if index_value_type == DataObject:
1823
+ index_value_type = object
1824
+ index = pandas.Index(tuple(self.indices[0].values), dtype=index_value_type, name=self.indices[0].name)
1825
+ else:
1826
+ index = None
1827
+ if use_object_dtype:
1828
+ return pandas.DataFrame(data=data, index=index, dtype=object)
1829
+ else:
1830
+ return pandas.DataFrame(data=data, index=index)
1831
+
1832
+ def build_from_pandas(self, table_data: "pandas.DataFrame") -> "DataFrame":
1833
+ # check if the table has indices and if its multi-index or common index
1834
+ if isinstance(table_data.index, pandas.MultiIndex):
1835
+ table_data_indices = table_data.index.levels
1836
+ elif isinstance(table_data.index, pandas.Index) and not table_data.index.empty:
1837
+ table_data_indices = [table_data.index]
1838
+ else:
1839
+ table_data_indices = []
1840
+
1841
+ self.column_names = table_data.columns
1842
+ self.index_names = [index.name for index in table_data_indices]
1843
+ self.column_types = [self._pandas_dtype_to_column_type(dtype) for dtype in table_data.dtypes]
1844
+ self.index_types = [self._pandas_dtype_to_column_type(index.dtype) for index in table_data_indices]
1845
+ replaced_name = False
1846
+ for i, name in enumerate(self.index_names):
1847
+ if name is None:
1848
+ self.index_names[i] = 'date'
1849
+ replaced_name = True
1850
+ rows = len(table_data.index)
1851
+ _df = self._pre_build_generic(rows, self.index_types, self.column_types)
1852
+
1853
+ test_conversion_types = {
1854
+ pandas.api.types.is_integer_dtype: numpy.int32,
1855
+ _is_int64: numpy.int64,
1856
+ _is_float32: numpy.float32,
1857
+ _is_float64: numpy.float64,
1858
+ pandas.api.types.is_datetime64_any_dtype: numpy.datetime64,
1859
+ }
1860
+ convert_to_ctype = {
1861
+ numpy.int32: ctypes.c_int32,
1862
+ numpy.int64: ctypes.c_int64,
1863
+ numpy.float32: ctypes.c_float,
1864
+ numpy.float64: ctypes.c_double,
1865
+ numpy.datetime64: ctypes.c_longlong,
1866
+
1867
+ }
1868
+
1869
+ # Check column value types - if they support, call efficient set methods
1870
+ column_convert_to = {}
1871
+ column_fast_set = {}
1872
+ for i_column, column_name in enumerate(table_data.columns):
1873
+ column_values = table_data[column_name]
1874
+ column_fast_set[column_name] = False
1875
+ for test_func, convert_to_type in test_conversion_types.items():
1876
+ if test_func(column_values):
1877
+ column_convert_to[column_name] = convert_to_type
1878
+ column_fast_set[column_name] = True
1879
+ break
1880
+
1881
+ if replaced_name:
1882
+ for i, name in enumerate(self.index_names):
1883
+ if name == "date":
1884
+ self.index_names[i] = None
1885
+ # check index value types
1886
+ index_convert_to = {}
1887
+ index_fast_set = {}
1888
+ for i_index, index_name in enumerate(self.index_names):
1889
+ index_fast_set[index_name] = False
1890
+ index_values = table_data.index.get_level_values(index_name)
1891
+ for test_func, convert_to_type in test_conversion_types.items():
1892
+ if test_func(index_values):
1893
+ index_convert_to[index_name] = convert_to_type
1894
+ index_fast_set[index_name] = True
1895
+ break
1896
+
1897
+ # replace None as index name with "date", the default index type.
1898
+ for i_index, index_name in enumerate(self.index_names):
1899
+ if index_name is None:
1900
+ self.index_names[i_index] = "date"
1901
+
1902
+ for i_index, index_name in enumerate(self.index_names):
1903
+ if index_name in index_convert_to.keys():
1904
+ convert_to_type = index_convert_to[index_name]
1905
+ else:
1906
+ convert_to_type = None
1907
+ if isinstance(table_data.index, pandas.MultiIndex):
1908
+ index_values = table_data.index.get_level_values(index_name).to_numpy(dtype=convert_to_type)
1909
+ else:
1910
+ index_values = table_data.index.to_numpy(dtype=convert_to_type)
1911
+ if index_name in index_fast_set.keys() and index_fast_set[index_name]:
1912
+ if convert_to_type == numpy.datetime64:
1913
+ # convert index_values to utc timezone and then to timestamp
1914
+ # TODO: check if original dataframe values is unaltered
1915
+ index_values = index_values.astype('datetime64[s]').astype(dt.datetime)
1916
+ # for each value, convert to timestamp
1917
+ for ix, x in enumerate(index_values):
1918
+ index_values[ix] = int(x.replace(tzinfo=dt.timezone.utc).timestamp() + _date_transform)
1919
+ # convert to int64
1920
+ index_values = index_values.astype(numpy.int64)
1921
+ ptr = index_values.ctypes.data_as(ctypes.POINTER(convert_to_ctype[convert_to_type]))
1922
+ factorylib.lib.psrd_table_index_set_date_values(_df.handler(),
1923
+ i_index,
1924
+ ptr,
1925
+ self._err.handler())
1926
+ if self._err.code != 0:
1927
+ raise FactoryException(self._err.what)
1928
+ elif convert_to_type == numpy.int32:
1929
+ ptr = index_values.ctypes.data_as(ctypes.POINTER(convert_to_ctype[convert_to_type]))
1930
+ factorylib.lib.psrd_table_index_set_int32_values(_df.handler(),
1931
+ i_index,
1932
+ ptr,
1933
+ self._err.handler())
1934
+ if self._err.code != 0:
1935
+ raise FactoryException(self._err.what)
1936
+ elif convert_to_type == numpy.int64:
1937
+ ptr = index_values.ctypes.data_as(ctypes.POINTER(convert_to_ctype[convert_to_type]))
1938
+ factorylib.lib.psrd_table_index_set_int64_values(_df.handler(),
1939
+ i_index,
1940
+ ptr,
1941
+ self._err.handler())
1942
+ if self._err.code != 0:
1943
+ raise FactoryException(self._err.what)
1944
+ elif convert_to_type == numpy.float32:
1945
+ ptr = index_values.ctypes.data_as(ctypes.POINTER(convert_to_ctype[convert_to_type]))
1946
+ factorylib.lib.psrd_table_index_set_float32_values(_df.handler(),
1947
+ i_index,
1948
+ ptr,
1949
+ self._err.handler())
1950
+ if self._err.code != 0:
1951
+ raise FactoryException(self._err.what)
1952
+ elif convert_to_type == numpy.float64:
1953
+ ptr = index_values.ctypes.data_as(ctypes.POINTER(convert_to_ctype[convert_to_type]))
1954
+ factorylib.lib.psrd_table_index_set_float64_values(_df.handler(),
1955
+ i_index,
1956
+ ptr,
1957
+ self._err.handler())
1958
+ if self._err.code != 0:
1959
+ raise FactoryException(self._err.what)
1960
+ else:
1961
+ raise FactoryException("Unsupported index type: " + str(convert_to_type))
1962
+ else:
1963
+ for i_row, column_value in enumerate(index_values):
1964
+ self._value.set(column_value)
1965
+ factorylib.lib.psrd_table_index_set_value(_df.handler(),
1966
+ i_index,
1967
+ i_row,
1968
+ self._value.handler(),
1969
+ self._err.handler())
1970
+ if self._err.code != 0:
1971
+ raise FactoryException(self._err.what)
1972
+
1973
+ for i_column, column_name in enumerate(self.column_names):
1974
+ if column_name in column_convert_to.keys():
1975
+ convert_to_type = column_convert_to[column_name]
1976
+ else:
1977
+ convert_to_type = None
1978
+ column_values = table_data[column_name].to_numpy(dtype=convert_to_type)
1979
+ if column_name in column_fast_set.keys() and column_fast_set[column_name]:
1980
+ if convert_to_type == numpy.float32:
1981
+ ptr = column_values.ctypes.data_as(ctypes.POINTER(convert_to_ctype[convert_to_type]))
1982
+ factorylib.lib.psrd_table_column_set_float32_values(_df.handler(),
1983
+ i_column,
1984
+ ptr,
1985
+ self._err.handler())
1986
+ if self._err.code != 0:
1987
+ raise FactoryException(self._err.code)
1988
+ if convert_to_type == numpy.float64:
1989
+ ptr = column_values.ctypes.data_as(ctypes.POINTER(convert_to_ctype[convert_to_type]))
1990
+ factorylib.lib.psrd_table_column_set_float64_values(_df.handler(),
1991
+ i_column,
1992
+ ptr,
1993
+ self._err.handler())
1994
+ if self._err.code != 0:
1995
+ raise FactoryException(self._err.what)
1996
+ elif convert_to_type == numpy.int32:
1997
+ ptr = column_values.ctypes.data_as(ctypes.POINTER(convert_to_ctype[convert_to_type]))
1998
+ factorylib.lib.psrd_table_column_set_int32_values(_df.handler(),
1999
+ i_column,
2000
+ ptr,
2001
+ self._err.handler())
2002
+ if self._err.code != 0:
2003
+ raise FactoryException(self._err.what)
2004
+ elif convert_to_type == numpy.int64:
2005
+ ptr = column_values.ctypes.data_as(ctypes.POINTER(convert_to_ctype[convert_to_type]))
2006
+ factorylib.lib.psrd_table_column_set_int64_values(_df.handler(),
2007
+ i_column,
2008
+ ptr,
2009
+ self._err.handler())
2010
+ if self._err.code != 0:
2011
+ raise FactoryException(self._err.what)
2012
+ else:
2013
+ column_values = table_data[column_name]
2014
+ for i_row, column_value in enumerate(column_values):
2015
+ self._value.set(column_value)
2016
+ factorylib.lib.psrd_table_column_set_value(_df.handler(),
2017
+ i_column,
2018
+ i_row,
2019
+ self._value.handler(),
2020
+ self._err.handler())
2021
+ if self._err.code != 0:
2022
+ raise FactoryException(self._err.what)
2023
+ return _df
2024
+
2025
+
2026
+ def build_polars_dataframe(self, **kwargs) -> "polars.DataFrame":
2027
+ use_object_dtype = kwargs.get("use_object_dtype", True)
2028
+ if not _has_polars():
2029
+ raise ModuleNotFoundError("polars required.")
2030
+ def convert_column_values(column_name:str, values):
2031
+ if isinstance(values, list):
2032
+ return values
2033
+ # Looks like ctype array, smells like ctype array
2034
+ if hasattr(values, "_length_") and hasattr(values, "_type_"):
2035
+ return polars.Series(column_name, numpy.ctypeslib.as_array(values))
2036
+ return values
2037
+
2038
+ data = {column.name: convert_column_values(column.name, column.values)
2039
+ for column in self.indices + self.columns}
2040
+ if use_object_dtype:
2041
+ return polars.DataFrame(data=data, dtype=object)
2042
+ else:
2043
+ return polars.DataFrame(data=data)
2044
+
2045
+ def build_from_polars(self, table_data: "polars.DataFrame") -> "DataFrame":
2046
+ # check if the table has indices and if its multi-index or common index
2047
+ _index_names = ("year", "week", "month", "hour", "scenario", "block", "stage")
2048
+ column_index = 0
2049
+ data_columns = table_data.columns[:]
2050
+ index_columns = []
2051
+ while column_index < len(data_columns):
2052
+ if data_columns[column_index] in _index_names:
2053
+ index_columns.append(data_columns.pop(column_index))
2054
+ continue
2055
+ column_index += 1
2056
+ self.column_types = [self._polars_dtype_to_column_type(table_data[column_name].dtype) for column_name in data_columns]
2057
+ self.index_types = [self._polars_dtype_to_column_type(table_data[index_name].dtype) for index_name in index_columns]
2058
+
2059
+ self.column_names = data_columns
2060
+ self.index_names = index_columns
2061
+ rows = table_data.height
2062
+ _df = self._pre_build_generic(rows, self.index_types, self.column_types)
2063
+
2064
+ for i_row, all_row_values in enumerate(table_data.iter_rows()):
2065
+ index = all_row_values[:len(index_columns)]
2066
+ row_values = all_row_values[len(index_columns):]
2067
+ self._set_row_values(_df, i_row, index, row_values)
2068
+ return _df
2069
+
2070
+ def _pre_build_generic(self, rows: int, index_types: List[int], column_types: List[int]) -> "DataFrame":
2071
+ _df = DataFrame()
2072
+ self._err = Error()
2073
+ self._value = Value()
2074
+
2075
+ factorylib.lib.psrd_table_resize(_df.handler(), rows,
2076
+ self._err.handler())
2077
+ if self._err.code != 0:
2078
+ raise FactoryException(self._err.what)
2079
+
2080
+ for i_index, index_type in enumerate(index_types):
2081
+ factorylib.lib.psrd_table_configure_index(_df.handler(),
2082
+ i_index,
2083
+ index_type,
2084
+ self._err.handler())
2085
+ if self._err.code != 0:
2086
+ raise FactoryException(self._err.what)
2087
+ for i_column, column_type in enumerate(column_types):
2088
+ factorylib.lib.psrd_table_configure_column(_df.handler(),
2089
+ i_column,
2090
+ column_type,
2091
+ self._err.handler())
2092
+ if self._err.code != 0:
2093
+ raise FactoryException(self._err.what)
2094
+
2095
+ # Set column names
2096
+ for i_column, column_name in enumerate(self.column_names):
2097
+ factorylib.lib.psrd_table_column_set_name(_df.handler(),
2098
+ i_column,
2099
+ _c_str(column_name),
2100
+ _bytes(column_name),
2101
+ self._err.handler())
2102
+ if self._err.code != 0:
2103
+ raise FactoryException(self._err.what)
2104
+
2105
+ # Set index names
2106
+ for i_index, index_name in enumerate(self.index_names):
2107
+ factorylib.lib.psrd_table_index_set_name(_df.handler(),
2108
+ i_index,
2109
+ _c_str(index_name),
2110
+ _bytes(index_name),
2111
+ self._err.handler())
2112
+ if self._err.code != 0:
2113
+ raise FactoryException(self._err.what)
2114
+
2115
+ return _df
2116
+
2117
+ def _set_row_values(self, df: "DataFrame", i_row: int, index_values: List[Union[int, float, str]], column_values: List[Union[int, float, str]]):
2118
+ self._value = Value()
2119
+ for i_index, index_value in enumerate(index_values):
2120
+ self._value.set(index_value)
2121
+ factorylib.lib.psrd_table_index_set_value(df.handler(),
2122
+ i_index,
2123
+ i_row,
2124
+ self._value.handler(),
2125
+ self._err.handler())
2126
+ if self._err.code != 0:
2127
+ raise FactoryException(self._err.what)
2128
+
2129
+ for i_column, column_value in enumerate(column_values):
2130
+ self._value.set(column_value)
2131
+ factorylib.lib.psrd_table_column_set_value(df.handler(),
2132
+ i_column,
2133
+ i_row,
2134
+ self._value.handler(),
2135
+ self._err.handler())
2136
+ if self._err.code != 0:
2137
+ raise FactoryException(self._err.what)
2138
+
2139
+
2140
+ class DataFrame(_BaseObject):
2141
+ def __init__(self):
2142
+ super().__init__()
2143
+ self._hdr = factorylib.lib.psrd_new_table()
2144
+ self._not_built = True
2145
+
2146
+ def __del__(self):
2147
+ if self._hdr is not None:
2148
+ factorylib.lib.psrd_free_table(self._hdr)
2149
+
2150
+ @staticmethod
2151
+ def load_from_file(input_file: Union[str, pathlib.Path], options: Optional[Union[dict, Value, DataObject]] = None) -> "DataFrame":
2152
+ input_file = str(input_file)
2153
+ _check_initialized()
2154
+ _err = Error()
2155
+ table = DataFrame()
2156
+ options_value = _get_arg_object(options)
2157
+ factorylib.lib.psrd_table_load(table.handler(),
2158
+ _c_str(input_file),
2159
+ _bytes(input_file),
2160
+ options_value.handler(),
2161
+ _err.handler())
2162
+ if _err.code != 0:
2163
+ raise FactoryException(_err.what)
2164
+ return table
2165
+
2166
+ @staticmethod
2167
+ def from_dataframe(df: Union["pandas.DataFrame", "polars.DataFrame"], **kwargs) -> "DataFrame":
2168
+ _check_initialized()
2169
+ df_builder = _DataFrameBuilder()
2170
+ if _has_pandas() and isinstance(df, pandas.DataFrame):
2171
+ dataframe_like = pandas.api.interchange.from_dataframe(df)
2172
+ return df_builder.build_from_pandas(dataframe_like)
2173
+ if _has_polars() and isinstance(df, polars.DataFrame):
2174
+ dataframe_like = polars.from_dataframe(df)
2175
+ # FIXME: needs auto tests.
2176
+ return df_builder.build_from_polars(dataframe_like)
2177
+ raise ImportError("Pandas or polars is not available. Please install pandas to use this feature.")
2178
+
2179
+ def save(self, output_file: Union[str, pathlib.Path], options: Optional[Union[dict, Value, DataObject]] = None):
2180
+ output_file = str(output_file)
2181
+ _err = Error()
2182
+ options_value = _get_arg_object(options)
2183
+ factorylib.lib.psrd_table_save(self._hdr, _c_str(output_file),
2184
+ _bytes(output_file),
2185
+ options_value.handler(),
2186
+ _err.handler())
2187
+ if _err.code != 0:
2188
+ raise FactoryException(_err.what)
2189
+
2190
+ def to_pandas(self) -> "pandas.DataFrame":
2191
+ df_builder = _DataFrameBuilder()
2192
+ df_builder.build_dataframe_of_integral_types(self)
2193
+ return df_builder.build_pandas_dataframe(use_object_dtype=False)
2194
+
2195
+ def to_polars(self) -> "polars.DataFrame":
2196
+ df_builder = _DataFrameBuilder()
2197
+ df_builder.build_dataframe_of_integral_types(self)
2198
+ return df_builder.build_polars_dataframe(use_object_dtype=False)
2199
+
2200
+
2201
+ def load_dataframe(input_file: Union[str, pathlib.Path], **kwargs) -> DataFrame:
2202
+ options = kwargs.get("options", None)
2203
+ return DataFrame.load_from_file(input_file, options)
2204
+
2205
+
2206
+ def create_dataframe(data: "pandas.DataFrame", **kwargs) -> DataFrame:
2207
+ return DataFrame.from_dataframe(data, **kwargs)
2208
+
2209
+
2210
+ def _load_library():
2211
+ global _loaded
2212
+ global _loaded_lock
2213
+ with _loaded_lock:
2214
+ factorylib.initialize()
2215
+ _loaded = True
2216
+ return _loaded
2217
+
2218
+
2219
+
2220
+ def _initialize():
2221
+ global _initialized
2222
+ global _initialized_lock
2223
+ with _initialized_lock:
2224
+ _check_loaded()
2225
+ _err = Error()
2226
+
2227
+ # Set binding info
2228
+ map_prop_values = {
2229
+ "NULL_TYPE": "None",
2230
+ "LIST_TYPE": "list",
2231
+ "INDEX_STARTS_AT_ZERO": True,
2232
+ "NAME": "Python",
2233
+ "VERSION": f"{sys.version}",
2234
+ "EXE": f"{sys.executable}",
2235
+ "LIB": f"{factorylib.get_lib_path()}",
2236
+ "BASE_PREFIX": f"{sys.base_prefix}",
2237
+ "REAL_PREFIX": f"{sys.prefix}",
2238
+ }
2239
+ for prop, value in map_prop_values.items():
2240
+ _value = Value()
2241
+ _value.set(value)
2242
+ factorylib.lib.psrd_set_binding_property(_c_str(prop),
2243
+ _bytes(prop),
2244
+ _value.handler(),
2245
+ _err.handler())
2246
+ if _err.code != 0:
2247
+ raise FactoryException(_err.what)
2248
+
2249
+ # Where to look for pmd and pmk files
2250
+ common_path = os.path.dirname(__file__)
2251
+ factorylib.lib.psrd_initialize(_c_str(common_path),
2252
+ _bytes(common_path),
2253
+ _err.handler())
2254
+ if _err.code != 0:
2255
+ raise FactoryException(_err.what)
2256
+ _initialized = True
2257
+
2258
+
2259
+ def _unload():
2260
+ _err = Error()
2261
+ factorylib.lib.psrd_unload(_err.handler())
2262
+ if _err.code != 0:
2263
+ raise FactoryException(_err.what)
2264
+
2265
+
2266
+ def help(context: str = "") -> str:
2267
+ _err = Error()
2268
+ size = factorylib.lib.psrd_help(_c_str(context), _bytes(context),
2269
+ None, 0, _err.handler())
2270
+ if _err.code != 0:
2271
+ raise FactoryException(_err.what)
2272
+ buffer = ctypes.create_string_buffer(size)
2273
+ factorylib.lib.psrd_help(_c_str(context), _bytes(context),
2274
+ buffer, size, _err.handler())
2275
+ if _err.code != 0:
2276
+ raise FactoryException(_err.what)
2277
+ return _from_c_str(buffer.value)
2278
+
2279
+
2280
+ def create_study(*args, **kwargs) -> Study:
2281
+ blocks = kwargs.get("blocks", None)
2282
+ models = kwargs.get("models", None)
2283
+ context = kwargs.get("context", None) if len(args) == 0 else args[0]
2284
+ profile = kwargs.get("profile", None)
2285
+ if models is None and profile is not None and len(profile) > 0:
2286
+ models = [profile, ]
2287
+ profile_or_context = models if models is not None and len(models) > 0 \
2288
+ else context
2289
+ return Study.create_object(profile_or_context, blocks)
2290
+
2291
+
2292
+ def load_study(study_path: Union[str, pathlib.Path],
2293
+ profile_or_context: Union[str, Context, None] = None,
2294
+ options: Optional[DataObject] = None) -> Study:
2295
+ settings_only = False
2296
+ return Study.load(study_path, profile_or_context, settings_only, options)
2297
+
2298
+
2299
+ def load_study_settings(study_path: Union[str, pathlib.Path],
2300
+ profile_or_context: Union[str, Context, None] = None,
2301
+ options: Optional[DataObject] = None) -> Study:
2302
+ settings_only = True
2303
+ return Study.load(study_path, profile_or_context, settings_only, options)
2304
+
2305
+
2306
+ def create(class_name: str,
2307
+ profile_or_context: Union[str, Context, None] = None) -> Optional[DataObject]:
2308
+ _check_initialized()
2309
+ obj = DataObject()
2310
+ _err = Error()
2311
+ context = _get_context(profile_or_context, None) \
2312
+ if class_name != "Context" else None
2313
+ context_hdr = context.handler() if context is not None else None
2314
+ ref = factorylib.lib.psrd_create(_c_str(class_name),
2315
+ context_hdr,
2316
+ _err.handler())
2317
+ if _err.code != 0 or ref is None:
2318
+ raise FactoryException(_err.what)
2319
+ obj._hdr = ref
2320
+ return obj
2321
+
2322
+
2323
+ def get_default_context() -> "Context":
2324
+ _check_initialized()
2325
+ return Context.default_context()
2326
+
2327
+
2328
+ def get_new_context() -> "Context":
2329
+ _check_initialized()
2330
+ return Context.create()
2331
+
2332
+
2333
+ def get_default_encoding() -> str:
2334
+ return _preferred_encoding
2335
+
2336
+
2337
+ def set_default_encoding(encoding: str):
2338
+ global _preferred_encoding
2339
+ _preferred_encoding = encoding