psr-factory 5.0.0b69__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.

Potentially problematic release.


This version of psr-factory might be problematic. Click here for more details.

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