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