py10x-universe 0.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- core_10x/__init__.py +42 -0
- core_10x/backbone/__init__.py +0 -0
- core_10x/backbone/backbone_store.py +59 -0
- core_10x/backbone/backbone_traitable.py +30 -0
- core_10x/backbone/backbone_user.py +66 -0
- core_10x/backbone/bound_data_domain.py +49 -0
- core_10x/backbone/namespace.py +101 -0
- core_10x/backbone/vault.py +38 -0
- core_10x/code_samples/__init__.py +0 -0
- core_10x/code_samples/_package_manifest.py +3 -0
- core_10x/code_samples/directories.py +181 -0
- core_10x/code_samples/person.py +76 -0
- core_10x/concrete_traits.py +356 -0
- core_10x/conftest.py +12 -0
- core_10x/curve.py +321 -0
- core_10x/data_domain.py +48 -0
- core_10x/data_domain_binder.py +45 -0
- core_10x/directory.py +250 -0
- core_10x/entity.py +8 -0
- core_10x/entity_filter.py +5 -0
- core_10x/environment_variables.py +147 -0
- core_10x/exec_control.py +84 -0
- core_10x/experimental/__init__.py +0 -0
- core_10x/experimental/data_protocol_ex.py +34 -0
- core_10x/global_cache.py +121 -0
- core_10x/manual_tests/__init__.py +0 -0
- core_10x/manual_tests/calendar_test.py +35 -0
- core_10x/manual_tests/ctor_update_bug.py +58 -0
- core_10x/manual_tests/debug_graph_on.py +17 -0
- core_10x/manual_tests/debug_graphoff_inside_graph_on.py +28 -0
- core_10x/manual_tests/enum_bits_test.py +17 -0
- core_10x/manual_tests/env_vars_trivial_test.py +12 -0
- core_10x/manual_tests/existing_traitable.py +33 -0
- core_10x/manual_tests/k10x_test1.py +13 -0
- core_10x/manual_tests/named_constant_test.py +121 -0
- core_10x/manual_tests/nucleus_trivial_test.py +42 -0
- core_10x/manual_tests/polars_test.py +14 -0
- core_10x/manual_tests/py_class_test.py +4 -0
- core_10x/manual_tests/rc_test.py +42 -0
- core_10x/manual_tests/rdate_test.py +12 -0
- core_10x/manual_tests/reference_serialization_bug.py +19 -0
- core_10x/manual_tests/resource_trivial_test.py +10 -0
- core_10x/manual_tests/store_uri_test.py +6 -0
- core_10x/manual_tests/trait_definition_test.py +19 -0
- core_10x/manual_tests/trait_filter_test.py +15 -0
- core_10x/manual_tests/trait_flag_modification_test.py +42 -0
- core_10x/manual_tests/trait_modification_bug.py +26 -0
- core_10x/manual_tests/traitable_as_of_test.py +82 -0
- core_10x/manual_tests/traitable_heir_test.py +39 -0
- core_10x/manual_tests/traitable_history_test.py +41 -0
- core_10x/manual_tests/traitable_serialization_test.py +54 -0
- core_10x/manual_tests/traitable_trivial_test.py +71 -0
- core_10x/manual_tests/trivial_graph_test.py +16 -0
- core_10x/manual_tests/ts_class_association_test.py +64 -0
- core_10x/manual_tests/ts_trivial_test.py +35 -0
- core_10x/named_constant.py +425 -0
- core_10x/nucleus.py +81 -0
- core_10x/package_manifest.py +85 -0
- core_10x/package_refactoring.py +153 -0
- core_10x/py_class.py +431 -0
- core_10x/rc.py +155 -0
- core_10x/rdate.py +339 -0
- core_10x/resource.py +189 -0
- core_10x/roman_number.py +67 -0
- core_10x/testlib/__init__.py +0 -0
- core_10x/testlib/test_store.py +240 -0
- core_10x/testlib/traitable_history_tests.py +787 -0
- core_10x/testlib/ts_tests.py +280 -0
- core_10x/trait.py +377 -0
- core_10x/trait_definition.py +176 -0
- core_10x/trait_filter.py +205 -0
- core_10x/trait_method_error.py +36 -0
- core_10x/traitable.py +1082 -0
- core_10x/traitable_cli.py +153 -0
- core_10x/traitable_heir.py +33 -0
- core_10x/traitable_id.py +31 -0
- core_10x/ts_store.py +172 -0
- core_10x/ts_store_type.py +26 -0
- core_10x/ts_union.py +147 -0
- core_10x/ui_hint.py +153 -0
- core_10x/unit_tests/test_concrete_traits.py +156 -0
- core_10x/unit_tests/test_converters.py +51 -0
- core_10x/unit_tests/test_curve.py +157 -0
- core_10x/unit_tests/test_directory.py +54 -0
- core_10x/unit_tests/test_documentation.py +172 -0
- core_10x/unit_tests/test_environment_variables.py +15 -0
- core_10x/unit_tests/test_filters.py +239 -0
- core_10x/unit_tests/test_graph.py +348 -0
- core_10x/unit_tests/test_named_constant.py +98 -0
- core_10x/unit_tests/test_rc.py +11 -0
- core_10x/unit_tests/test_rdate.py +484 -0
- core_10x/unit_tests/test_trait_method_error.py +80 -0
- core_10x/unit_tests/test_trait_modification.py +19 -0
- core_10x/unit_tests/test_traitable.py +959 -0
- core_10x/unit_tests/test_traitable_history.py +1 -0
- core_10x/unit_tests/test_ts_store.py +1 -0
- core_10x/unit_tests/test_ts_union.py +369 -0
- core_10x/unit_tests/test_ui_nodes.py +81 -0
- core_10x/unit_tests/test_xxcalendar.py +471 -0
- core_10x/vault/__init__.py +0 -0
- core_10x/vault/sec_keys.py +133 -0
- core_10x/vault/security_keys_old.py +168 -0
- core_10x/vault/vault.py +56 -0
- core_10x/vault/vault_traitable.py +56 -0
- core_10x/vault/vault_user.py +70 -0
- core_10x/xdate_time.py +136 -0
- core_10x/xnone.py +71 -0
- core_10x/xxcalendar.py +228 -0
- infra_10x/__init__.py +0 -0
- infra_10x/manual_tests/__init__.py +0 -0
- infra_10x/manual_tests/test_misc.py +16 -0
- infra_10x/manual_tests/test_prepare_filter_and_pipeline.py +25 -0
- infra_10x/mongodb_admin.py +111 -0
- infra_10x/mongodb_store.py +346 -0
- infra_10x/mongodb_utils.py +129 -0
- infra_10x/unit_tests/conftest.py +13 -0
- infra_10x/unit_tests/test_mongo_db.py +36 -0
- infra_10x/unit_tests/test_mongo_history.py +1 -0
- py10x_universe-0.1.3.dist-info/METADATA +406 -0
- py10x_universe-0.1.3.dist-info/RECORD +214 -0
- py10x_universe-0.1.3.dist-info/WHEEL +4 -0
- py10x_universe-0.1.3.dist-info/licenses/LICENSE +21 -0
- ui_10x/__init__.py +0 -0
- ui_10x/apps/__init__.py +0 -0
- ui_10x/apps/collection_editor_app.py +100 -0
- ui_10x/choice.py +212 -0
- ui_10x/collection_editor.py +135 -0
- ui_10x/concrete_trait_widgets.py +220 -0
- ui_10x/conftest.py +8 -0
- ui_10x/entity_stocker.py +173 -0
- ui_10x/examples/__init__.py +0 -0
- ui_10x/examples/_guess_word_data.py +14076 -0
- ui_10x/examples/collection_editor.py +17 -0
- ui_10x/examples/date_selector.py +14 -0
- ui_10x/examples/entity_stocker.py +18 -0
- ui_10x/examples/guess_word.py +392 -0
- ui_10x/examples/message_box.py +20 -0
- ui_10x/examples/multi_choice.py +17 -0
- ui_10x/examples/py_data_browser.py +66 -0
- ui_10x/examples/radiobox.py +29 -0
- ui_10x/examples/single_choice.py +31 -0
- ui_10x/examples/style_sheet.py +47 -0
- ui_10x/examples/trivial_entity_editor.py +18 -0
- ui_10x/platform.py +20 -0
- ui_10x/platform_interface.py +517 -0
- ui_10x/py_data_browser.py +249 -0
- ui_10x/qt6/__init__.py +0 -0
- ui_10x/qt6/conftest.py +8 -0
- ui_10x/qt6/manual_tests/__init__.py +0 -0
- ui_10x/qt6/manual_tests/basic_test.py +35 -0
- ui_10x/qt6/platform_implementation.py +275 -0
- ui_10x/qt6/utils.py +665 -0
- ui_10x/rio/__init__.py +0 -0
- ui_10x/rio/apps/examples/examples/__init__.py +22 -0
- ui_10x/rio/apps/examples/examples/components/__init__.py +3 -0
- ui_10x/rio/apps/examples/examples/components/collection_editor.py +15 -0
- ui_10x/rio/apps/examples/examples/pages/collection_editor.py +21 -0
- ui_10x/rio/apps/examples/examples/pages/login_page.py +88 -0
- ui_10x/rio/apps/examples/examples/pages/style_sheet.py +21 -0
- ui_10x/rio/apps/examples/rio.toml +14 -0
- ui_10x/rio/component_builder.py +497 -0
- ui_10x/rio/components/__init__.py +9 -0
- ui_10x/rio/components/group_box.py +31 -0
- ui_10x/rio/components/labeled_checkbox.py +18 -0
- ui_10x/rio/components/line_edit.py +37 -0
- ui_10x/rio/components/radio_button.py +32 -0
- ui_10x/rio/components/separator.py +24 -0
- ui_10x/rio/components/splitter.py +121 -0
- ui_10x/rio/components/tree_view.py +75 -0
- ui_10x/rio/conftest.py +35 -0
- ui_10x/rio/internals/__init__.py +0 -0
- ui_10x/rio/internals/app.py +192 -0
- ui_10x/rio/manual_tests/__init__.py +0 -0
- ui_10x/rio/manual_tests/basic_test.py +24 -0
- ui_10x/rio/manual_tests/splitter.py +27 -0
- ui_10x/rio/platform_implementation.py +91 -0
- ui_10x/rio/style_sheet.py +53 -0
- ui_10x/rio/unit_tests/test_collection_editor.py +68 -0
- ui_10x/rio/unit_tests/test_internals.py +630 -0
- ui_10x/rio/unit_tests/test_style_sheet.py +37 -0
- ui_10x/rio/widgets/__init__.py +46 -0
- ui_10x/rio/widgets/application.py +109 -0
- ui_10x/rio/widgets/button.py +48 -0
- ui_10x/rio/widgets/button_group.py +60 -0
- ui_10x/rio/widgets/calendar.py +23 -0
- ui_10x/rio/widgets/checkbox.py +24 -0
- ui_10x/rio/widgets/dialog.py +137 -0
- ui_10x/rio/widgets/group_box.py +27 -0
- ui_10x/rio/widgets/layout.py +34 -0
- ui_10x/rio/widgets/line_edit.py +37 -0
- ui_10x/rio/widgets/list.py +105 -0
- ui_10x/rio/widgets/message_box.py +70 -0
- ui_10x/rio/widgets/scroll_area.py +31 -0
- ui_10x/rio/widgets/spacer.py +6 -0
- ui_10x/rio/widgets/splitter.py +45 -0
- ui_10x/rio/widgets/text_edit.py +28 -0
- ui_10x/rio/widgets/tree.py +89 -0
- ui_10x/rio/widgets/unit_tests/test_button.py +101 -0
- ui_10x/rio/widgets/unit_tests/test_button_group.py +33 -0
- ui_10x/rio/widgets/unit_tests/test_calendar.py +114 -0
- ui_10x/rio/widgets/unit_tests/test_checkbox.py +109 -0
- ui_10x/rio/widgets/unit_tests/test_group_box.py +158 -0
- ui_10x/rio/widgets/unit_tests/test_label.py +43 -0
- ui_10x/rio/widgets/unit_tests/test_line_edit.py +140 -0
- ui_10x/rio/widgets/unit_tests/test_list.py +146 -0
- ui_10x/table_header_view.py +305 -0
- ui_10x/table_view.py +174 -0
- ui_10x/trait_editor.py +189 -0
- ui_10x/trait_widget.py +131 -0
- ui_10x/traitable_editor.py +200 -0
- ui_10x/traitable_view.py +131 -0
- ui_10x/unit_tests/conftest.py +8 -0
- ui_10x/unit_tests/test_platform.py +9 -0
- ui_10x/utils.py +661 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from core_10x.nucleus import Nucleus
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# -- TODO: should I re-incarnate deriving from a metaclass, so that I can do: NAMED_CONSTANT[name] ?
|
|
9
|
+
class NamedConstant(Nucleus):
|
|
10
|
+
"""
|
|
11
|
+
In a subclass, each line representing a member must be one of the following:
|
|
12
|
+
MEMBER_NAME = (label, value) #-- label, value
|
|
13
|
+
MEMBER_NAME = (label, ) #-- label, auto-value
|
|
14
|
+
MEMBER_NAME = () #-- MEMBER_NAME, auto-value
|
|
15
|
+
MEMBER_NAME = value #-- MEMBER_NAME, value
|
|
16
|
+
|
|
17
|
+
where:
|
|
18
|
+
|
|
19
|
+
MEMBER_NAME - a valid uppercase identifier
|
|
20
|
+
label - a string
|
|
21
|
+
value - any value
|
|
22
|
+
auto-value - automatically generated (int) value
|
|
23
|
+
|
|
24
|
+
NOTE: all the members must have either explicit or auto-generated values exclusively
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
__slots__ = 'label', 'name', 'value'
|
|
28
|
+
|
|
29
|
+
def __init__(self, name: str = '', label: str = '', value: Any = None):
|
|
30
|
+
super().__init__()
|
|
31
|
+
self.name = name
|
|
32
|
+
self.label = label
|
|
33
|
+
self.value = value
|
|
34
|
+
|
|
35
|
+
def __eq__(self, other):
|
|
36
|
+
return self.name == other.name
|
|
37
|
+
|
|
38
|
+
def __hash__(self):
|
|
39
|
+
return hash(self.name)
|
|
40
|
+
|
|
41
|
+
def __deepcopy__(self, memo=None):
|
|
42
|
+
return self
|
|
43
|
+
|
|
44
|
+
# -- Makes sense only for NamedConstants with Callable values
|
|
45
|
+
def __call__(self, *args, **kwargs):
|
|
46
|
+
return self.value(*args, **kwargs)
|
|
47
|
+
|
|
48
|
+
def is_member_by_name(self, other_class) -> bool:
|
|
49
|
+
return self.name in other_class.s_dir
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def _create(cls, args: Any) -> NamedConstant:
|
|
53
|
+
cdef = cls()
|
|
54
|
+
if type(args) is not tuple: # -- just a value
|
|
55
|
+
cdef.value = args
|
|
56
|
+
|
|
57
|
+
else:
|
|
58
|
+
n = len(args)
|
|
59
|
+
if n == 0: # -- ()
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
elif n == 1: # -- just a label
|
|
63
|
+
cdef.label = args[0]
|
|
64
|
+
|
|
65
|
+
elif n == 2: # -- (label, value)
|
|
66
|
+
cdef.label = args[0]
|
|
67
|
+
cdef.value = args[1]
|
|
68
|
+
|
|
69
|
+
else:
|
|
70
|
+
raise ValueError(f"'{args}' may have at most two items")
|
|
71
|
+
|
|
72
|
+
return cdef
|
|
73
|
+
|
|
74
|
+
#===================================================================================================================
|
|
75
|
+
# Nucleus Interface implementation
|
|
76
|
+
#===================================================================================================================
|
|
77
|
+
|
|
78
|
+
def to_str(self) -> str:
|
|
79
|
+
return f'{self.__class__.__name__}.{self.name}'
|
|
80
|
+
|
|
81
|
+
def to_id(self) -> str:
|
|
82
|
+
return self.name
|
|
83
|
+
|
|
84
|
+
def serialize(self, embed: bool) -> str:
|
|
85
|
+
return self.name
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
def deserialize(cls, name: str) -> NamedConstant:
|
|
89
|
+
sdir = cls.s_dir
|
|
90
|
+
cdef = sdir.get(name, sdir)
|
|
91
|
+
if cdef is sdir:
|
|
92
|
+
raise TypeError(f'{cls} - unknown constant {name}')
|
|
93
|
+
|
|
94
|
+
return cdef
|
|
95
|
+
|
|
96
|
+
@classmethod
|
|
97
|
+
def from_str(cls, s: str) -> NamedConstant:
|
|
98
|
+
return cls.s_dir.get(s)
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def from_any_xstr(cls, data) -> NamedConstant | None:
|
|
102
|
+
if type(data) is cls.s_data_type:
|
|
103
|
+
reverse_dir = cls.s_reverse_dir
|
|
104
|
+
if reverse_dir:
|
|
105
|
+
return reverse_dir.get(data)
|
|
106
|
+
|
|
107
|
+
# -- the last resort - this is slow!
|
|
108
|
+
for cdef in cls.s_dir.values():
|
|
109
|
+
if cdef.value == data:
|
|
110
|
+
return cdef
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
@classmethod
|
|
114
|
+
def same_values(cls, value1, value2) -> bool:
|
|
115
|
+
return value1 is value2
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
def choose_from(cls):
|
|
119
|
+
return cls.s_dir
|
|
120
|
+
|
|
121
|
+
# ===================================================================================================================
|
|
122
|
+
|
|
123
|
+
s_dir: dict[str, NamedConstant] = {}
|
|
124
|
+
s_reverse_dir = {}
|
|
125
|
+
s_data_type = None
|
|
126
|
+
s_default_labels = False
|
|
127
|
+
s_lowercase_values = False
|
|
128
|
+
|
|
129
|
+
# fmt: off
|
|
130
|
+
def __init_subclass__(
|
|
131
|
+
cls,
|
|
132
|
+
default_labels: bool = None, #-- if True and a label is not defined, creates it by calling default_label(name)
|
|
133
|
+
lowercase_values: bool = None, #-- if a value is not defined, sets it to name, or name.lower() if True
|
|
134
|
+
data_type: type = None, #-- if value is not defined it is taken from superclass or the first value
|
|
135
|
+
):
|
|
136
|
+
# fmt: on
|
|
137
|
+
sdir = cls.s_dir = {name: cls(cdef.name, cdef.label, cdef.value) for name, cdef in cls.s_dir.items()}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if default_labels is not None:
|
|
141
|
+
cls.s_default_labels = default_labels
|
|
142
|
+
else:
|
|
143
|
+
default_labels = cls.s_default_labels
|
|
144
|
+
|
|
145
|
+
if lowercase_values is not None:
|
|
146
|
+
cls.s_lowercase_values = lowercase_values
|
|
147
|
+
else:
|
|
148
|
+
lowercase_values = cls.s_lowercase_values
|
|
149
|
+
|
|
150
|
+
if data_type is not None:
|
|
151
|
+
cls.s_data_type = data_type
|
|
152
|
+
else:
|
|
153
|
+
data_type = cls.s_data_type
|
|
154
|
+
|
|
155
|
+
for name, constant_definition in cls.__dict__.items():
|
|
156
|
+
if not name.isupper():
|
|
157
|
+
continue
|
|
158
|
+
|
|
159
|
+
cdef = cls._create(constant_definition)
|
|
160
|
+
cdef.name = name
|
|
161
|
+
if not cdef.label:
|
|
162
|
+
cdef.label = cls.default_label(name) if default_labels else name
|
|
163
|
+
|
|
164
|
+
if cdef.value is None:
|
|
165
|
+
value = cls.next_auto_value()
|
|
166
|
+
if value is None:
|
|
167
|
+
value = name if not lowercase_values else name.lower()
|
|
168
|
+
cdef.value = value
|
|
169
|
+
|
|
170
|
+
dt = type(cdef.value)
|
|
171
|
+
if data_type is None:
|
|
172
|
+
data_type = dt
|
|
173
|
+
else:
|
|
174
|
+
assert issubclass(dt, data_type), f'{cls}.{name} must be a subclass of {data_type}'
|
|
175
|
+
|
|
176
|
+
sdir[name] = cdef
|
|
177
|
+
|
|
178
|
+
cls.s_data_type = data_type
|
|
179
|
+
if getattr(data_type, '__hash__', None): #-- check if data_type is hashable and build the reverse dir if so
|
|
180
|
+
cls.s_reverse_dir = {cdef.value: cdef for cdef in sdir.values()}
|
|
181
|
+
|
|
182
|
+
for name, cdef in sdir.items():
|
|
183
|
+
setattr(cls, name, cdef)
|
|
184
|
+
|
|
185
|
+
@staticmethod
|
|
186
|
+
def union(*named_constant_classes):
|
|
187
|
+
class _union(NamedConstant):
|
|
188
|
+
pass
|
|
189
|
+
dir = _union.s_dir
|
|
190
|
+
for cls in named_constant_classes:
|
|
191
|
+
dir.update(cls.s_dir)
|
|
192
|
+
|
|
193
|
+
for name, value in dir.items():
|
|
194
|
+
setattr(_union, name, value)
|
|
195
|
+
|
|
196
|
+
return _union
|
|
197
|
+
|
|
198
|
+
@classmethod
|
|
199
|
+
def default_label(cls, name: str) -> str:
|
|
200
|
+
return name.title().replace('_', ' ')
|
|
201
|
+
|
|
202
|
+
@classmethod
|
|
203
|
+
def next_auto_value(cls):
|
|
204
|
+
return None
|
|
205
|
+
|
|
206
|
+
@classmethod
|
|
207
|
+
def item(cls, symbol_name: str) -> NamedConstant:
|
|
208
|
+
return cls.s_dir.get(symbol_name)
|
|
209
|
+
|
|
210
|
+
class Enum(NamedConstant):
|
|
211
|
+
"""
|
|
212
|
+
Enum constants definitions are in a simplified form:
|
|
213
|
+
- an empty tuple (next enum auto value)
|
|
214
|
+
- a string - just a label
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
s_last_value = 0
|
|
218
|
+
s_step = 1
|
|
219
|
+
|
|
220
|
+
def __init_subclass__(cls, seed: int = None, step: int = None, **kwargs):
|
|
221
|
+
if seed is not None:
|
|
222
|
+
cls.s_last_value = seed
|
|
223
|
+
else:
|
|
224
|
+
cls.s_last_value = cls.s_last_value
|
|
225
|
+
|
|
226
|
+
if step is not None:
|
|
227
|
+
cls.s_step = step
|
|
228
|
+
else:
|
|
229
|
+
cls.s_step = cls.s_step
|
|
230
|
+
|
|
231
|
+
super().__init_subclass__(**kwargs)
|
|
232
|
+
|
|
233
|
+
def __int__(self):
|
|
234
|
+
return self.value
|
|
235
|
+
|
|
236
|
+
@classmethod
|
|
237
|
+
def _create(cls, args: Any) -> Enum:
|
|
238
|
+
cdef = cls()
|
|
239
|
+
if args == ():
|
|
240
|
+
return cdef
|
|
241
|
+
|
|
242
|
+
if type(args) is str: # -- just a label
|
|
243
|
+
cdef.label = args
|
|
244
|
+
return cdef
|
|
245
|
+
|
|
246
|
+
raise ValueError('an empty tuple or string is expected')
|
|
247
|
+
|
|
248
|
+
@classmethod
|
|
249
|
+
def next_auto_value(cls) -> int:
|
|
250
|
+
last_value = cls.s_last_value
|
|
251
|
+
cls.s_last_value += cls.s_step
|
|
252
|
+
return last_value
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
NO_FLAGS_TAG = 'NONE'
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class EnumBits(NamedConstant):
|
|
259
|
+
s_last_flag = 0x1
|
|
260
|
+
|
|
261
|
+
def __init_subclass__(cls, **kwargs):
|
|
262
|
+
cls.s_last_flag = cls.s_last_flag
|
|
263
|
+
super().__init_subclass__(**kwargs)
|
|
264
|
+
setattr(cls, NO_FLAGS_TAG, cls(name=NO_FLAGS_TAG, value=0x0))
|
|
265
|
+
|
|
266
|
+
@classmethod
|
|
267
|
+
def next_auto_value(cls):
|
|
268
|
+
mask = cls.s_last_flag
|
|
269
|
+
cls.s_last_flag <<= 1
|
|
270
|
+
return mask
|
|
271
|
+
|
|
272
|
+
@classmethod
|
|
273
|
+
def names_from_value(cls, value: int) -> tuple:
|
|
274
|
+
return tuple(name for name, cdef in cls.s_dir.items() if cdef.value & value)
|
|
275
|
+
|
|
276
|
+
def __or__(self, other):
|
|
277
|
+
the_value = self.value
|
|
278
|
+
value = the_value | other.value
|
|
279
|
+
if value == the_value:
|
|
280
|
+
return self
|
|
281
|
+
|
|
282
|
+
cls = self.__class__
|
|
283
|
+
return cls.from_int(value)
|
|
284
|
+
|
|
285
|
+
def __and__(self, other):
|
|
286
|
+
the_value = self.value
|
|
287
|
+
value = the_value & other.value
|
|
288
|
+
if value == the_value:
|
|
289
|
+
return self
|
|
290
|
+
|
|
291
|
+
cls = self.__class__
|
|
292
|
+
return cls.from_int(value)
|
|
293
|
+
|
|
294
|
+
def __sub__(self, other):
|
|
295
|
+
the_value = self.value
|
|
296
|
+
value = the_value & ~other.value
|
|
297
|
+
if value == the_value:
|
|
298
|
+
return self
|
|
299
|
+
|
|
300
|
+
cls = self.__class__
|
|
301
|
+
return cls.from_int(value)
|
|
302
|
+
|
|
303
|
+
@classmethod
|
|
304
|
+
def names_to_value(cls, cnames: list) -> int:
|
|
305
|
+
value = 0x0
|
|
306
|
+
sdir = cls.s_dir
|
|
307
|
+
for cname in cnames:
|
|
308
|
+
cdef = sdir.get(cname)
|
|
309
|
+
if cdef is None:
|
|
310
|
+
raise TypeError(f'{cls} - unknown bit {cname}')
|
|
311
|
+
|
|
312
|
+
value |= cdef.value
|
|
313
|
+
|
|
314
|
+
return value
|
|
315
|
+
|
|
316
|
+
@classmethod
|
|
317
|
+
def from_str(cls, s: str) -> EnumBits:
|
|
318
|
+
if not s:
|
|
319
|
+
return getattr(cls, NO_FLAGS_TAG)
|
|
320
|
+
|
|
321
|
+
found = cls.s_dir.get(s)
|
|
322
|
+
if found is not None:
|
|
323
|
+
return found
|
|
324
|
+
|
|
325
|
+
cnames = s.split('|')
|
|
326
|
+
value = cls.names_to_value(cnames)
|
|
327
|
+
return cls(s, s, value)
|
|
328
|
+
|
|
329
|
+
@classmethod
|
|
330
|
+
def from_int(cls, value: int) -> EnumBits:
|
|
331
|
+
cnames = cls.names_from_value(value)
|
|
332
|
+
if not cnames:
|
|
333
|
+
return getattr(cls, NO_FLAGS_TAG)
|
|
334
|
+
|
|
335
|
+
name = '|'.join(cnames)
|
|
336
|
+
return cls(name, name, value)
|
|
337
|
+
|
|
338
|
+
@classmethod
|
|
339
|
+
def from_any_xstr(cls, data) -> EnumBits:
|
|
340
|
+
dt = type(data)
|
|
341
|
+
if dt is int:
|
|
342
|
+
return cls.from_int(data)
|
|
343
|
+
|
|
344
|
+
if dt is tuple or dt is list:
|
|
345
|
+
value = cls.names_to_value(data)
|
|
346
|
+
if not value:
|
|
347
|
+
return getattr(cls, NO_FLAGS_TAG)
|
|
348
|
+
|
|
349
|
+
name = '|'.join(data)
|
|
350
|
+
return cls(name, name, value)
|
|
351
|
+
return None
|
|
352
|
+
|
|
353
|
+
@classmethod
|
|
354
|
+
def deserialize(cls, data) -> EnumBits:
|
|
355
|
+
return cls.from_str(data)
|
|
356
|
+
|
|
357
|
+
@classmethod
|
|
358
|
+
def same_values(cls, value1, value2) -> bool:
|
|
359
|
+
return value1 is value2 or value1.name == value2.name
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
class ErrorCode(Enum, seed=-1, step=-1):
|
|
363
|
+
def __call__(self, *args, **kwargs):
|
|
364
|
+
return self.label.format(*args, **kwargs)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
class NamedConstantValue:
|
|
368
|
+
__slots__ = 'data', 'named_constant_class'
|
|
369
|
+
|
|
370
|
+
def __init__(self, named_constant_class, **named_constant_values):
|
|
371
|
+
assert issubclass(named_constant_class, NamedConstant), f'{named_constant_class} must be a subclass of NamedConstant'
|
|
372
|
+
c_defs = named_constant_class.s_dir
|
|
373
|
+
num_values = len(c_defs)
|
|
374
|
+
assert num_values == len(named_constant_values), f'{named_constant_class} - number of named values must be {num_values}'
|
|
375
|
+
self.named_constant_class = named_constant_class
|
|
376
|
+
|
|
377
|
+
self.data = data = {}
|
|
378
|
+
for cname, value in named_constant_values.items():
|
|
379
|
+
cdef = c_defs.get(cname)
|
|
380
|
+
assert cdef, f'{named_constant_class}.{cname} - unknown named constant'
|
|
381
|
+
self.process_row(cdef, data, value)
|
|
382
|
+
|
|
383
|
+
def process_row(self, cdef: NamedConstant, data: dict, row):
|
|
384
|
+
data[cdef] = row
|
|
385
|
+
|
|
386
|
+
def __getitem__(self, key):
|
|
387
|
+
try:
|
|
388
|
+
return self.data[key] # -- if it's a known NamedConstant
|
|
389
|
+
|
|
390
|
+
except Exception as e:
|
|
391
|
+
# -- check if it is a name of a constant
|
|
392
|
+
named_constant_class = self.named_constant_class
|
|
393
|
+
cdef = named_constant_class.s_dir.get(key)
|
|
394
|
+
if not cdef:
|
|
395
|
+
raise KeyError(f'{named_constant_class}.{key} - unknown named constant') from e
|
|
396
|
+
|
|
397
|
+
return self.data[cdef]
|
|
398
|
+
|
|
399
|
+
def __setitem__(self, key, value):
|
|
400
|
+
raise AssertionError(f'{self.__class__} - may not be modified')
|
|
401
|
+
|
|
402
|
+
def __getattr__(self, key):
|
|
403
|
+
return self.__getitem__(key)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
class NamedConstantTable(NamedConstantValue):
|
|
407
|
+
__slots__ = 'col_named_constant_class', 'data', 'named_constant_class'
|
|
408
|
+
|
|
409
|
+
def __init__(self, row_nc_class, col_nc_class, **named_tuple_values):
|
|
410
|
+
assert issubclass(col_nc_class, NamedConstant), f'{col_nc_class} must be a subclass of NamedConstant'
|
|
411
|
+
self.col_named_constant_class = col_nc_class
|
|
412
|
+
super().__init__(row_nc_class, **named_tuple_values)
|
|
413
|
+
|
|
414
|
+
def process_row(self, cdef: NamedConstant, data: dict, row):
|
|
415
|
+
assert type(row) is tuple, f'{cdef.name} = is not a tuple'
|
|
416
|
+
col_defs = self.col_named_constant_class.s_dir
|
|
417
|
+
assert len(row) == len(col_defs), f'{cdef.name} must have {len(col_defs)} values'
|
|
418
|
+
data[cdef] = NamedConstantValue(self.col_named_constant_class, **{col_name: row[i] for i, col_name in enumerate(col_defs)})
|
|
419
|
+
|
|
420
|
+
def primary_key(self, sec_key, value):
|
|
421
|
+
for primary_key, row in self.data.items():
|
|
422
|
+
if row[sec_key] == value:
|
|
423
|
+
return primary_key
|
|
424
|
+
|
|
425
|
+
return None
|
core_10x/nucleus.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from py10x_core import BNucleus
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Nucleus:
|
|
7
|
+
# fmt: off
|
|
8
|
+
__slots__ = ()
|
|
9
|
+
TYPE_TAG = BNucleus.TYPE_TAG
|
|
10
|
+
CLASS_TAG = BNucleus.CLASS_TAG
|
|
11
|
+
REVISION_TAG = BNucleus.REVISION_TAG
|
|
12
|
+
OBJECT_TAG = BNucleus.OBJECT_TAG
|
|
13
|
+
COLLECTION_TAG = BNucleus.COLLECTION_TAG
|
|
14
|
+
ID_TAG = BNucleus.ID_TAG
|
|
15
|
+
NX_RECORD_TAG = BNucleus.NX_RECORD_TAG
|
|
16
|
+
TYPE_RECORD_TAG = BNucleus.TYPE_RECORD_TAG
|
|
17
|
+
PICKLE_RECORD_TAG = BNucleus.PICKLE_RECORD_TAG
|
|
18
|
+
|
|
19
|
+
serialize_any = BNucleus.serialize_any
|
|
20
|
+
deserialize_any = BNucleus.deserialize_any
|
|
21
|
+
|
|
22
|
+
serialize_type = BNucleus.serialize_type
|
|
23
|
+
deserialize_type = BNucleus.deserialize_type
|
|
24
|
+
serialize_complex = BNucleus.serialize_complex
|
|
25
|
+
deserialize_complex = BNucleus.deserialize_complex
|
|
26
|
+
serialize_date = BNucleus.serialize_date
|
|
27
|
+
deserialize_date = BNucleus.deserialize_date
|
|
28
|
+
serialize_list = BNucleus.serialize_list
|
|
29
|
+
deserialize_list = BNucleus.deserialize_list
|
|
30
|
+
serialize_dict = BNucleus.serialize_dict
|
|
31
|
+
deserialize_dict = BNucleus.deserialize_dict
|
|
32
|
+
deserialize_record = BNucleus.deserialize_record
|
|
33
|
+
# fmt: on
|
|
34
|
+
# ===============================================================================================================================
|
|
35
|
+
# The following methods must be implemented by a subclass of Nucleus
|
|
36
|
+
# ===============================================================================================================================
|
|
37
|
+
|
|
38
|
+
def __repr__(self):
|
|
39
|
+
return self.to_str()
|
|
40
|
+
|
|
41
|
+
def __eq__(self, other):
|
|
42
|
+
return self.__class__.same_values(self, other)
|
|
43
|
+
|
|
44
|
+
def to_str(self) -> str:
|
|
45
|
+
return str(self)
|
|
46
|
+
|
|
47
|
+
def to_id(self) -> str:
|
|
48
|
+
return self.to_str()
|
|
49
|
+
|
|
50
|
+
def serialize(self, embed: bool):
|
|
51
|
+
raise NotImplementedError
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def deserialize(cls, serialized_data) -> Nucleus:
|
|
55
|
+
raise NotImplementedError
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def from_str(cls, s: str) -> Nucleus:
|
|
59
|
+
raise NotImplementedError
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def from_any_xstr(cls, value) -> Nucleus:
|
|
63
|
+
raise NotImplementedError
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def from_any(cls, value) -> Nucleus:
|
|
67
|
+
if isinstance(value, cls):
|
|
68
|
+
return value
|
|
69
|
+
|
|
70
|
+
if isinstance(value, str):
|
|
71
|
+
return cls.from_str(value)
|
|
72
|
+
|
|
73
|
+
return cls.from_any_xstr(value)
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def same_values(cls, value1, value2) -> bool:
|
|
77
|
+
raise NotImplementedError
|
|
78
|
+
|
|
79
|
+
@classmethod
|
|
80
|
+
def choose_from(cls):
|
|
81
|
+
return {}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from core_10x.data_domain import GeneralDomain
|
|
6
|
+
from core_10x.py_class import PyClass
|
|
7
|
+
from core_10x.resource import TS_STORE
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from core_10x.resource import ResourceRequirements
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PackageManifest:
|
|
14
|
+
"""
|
|
15
|
+
To associate a subclass of Traitable to a particular Data Domain Category
|
|
16
|
+
it must have a record in a package manifest file.
|
|
17
|
+
Example:
|
|
18
|
+
# module x.etrading_domain
|
|
19
|
+
class ETradingDomain(DataDomain):
|
|
20
|
+
GENERAL = TS_STORE()
|
|
21
|
+
ORDERS = TS_STORE()
|
|
22
|
+
ALGO_ORDERS = TS_STORE()
|
|
23
|
+
...
|
|
24
|
+
|
|
25
|
+
#module x.y.order
|
|
26
|
+
class Order(Traitable):
|
|
27
|
+
...
|
|
28
|
+
|
|
29
|
+
class AlgoOrder(Order):
|
|
30
|
+
...
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
#module x.y._package_manifest
|
|
34
|
+
from x.etrading_domain import ETradingDomain as ET
|
|
35
|
+
|
|
36
|
+
manifest = dict( #-- variable manifest: dict must be defined as follows
|
|
37
|
+
_category = ET.GENERAL, #-- default category for Traitables in x.y package, if any
|
|
38
|
+
|
|
39
|
+
order = dict( #-- specific association(s) for any module inside x.y package, if any
|
|
40
|
+
_category = ET.ORDERS #-- default category for Traitables in x.y.order, if any
|
|
41
|
+
|
|
42
|
+
AlgoOrder = ET.ALGO_ORDERS #-- specific association class x.y.order.AlgoOrder, if any
|
|
43
|
+
...
|
|
44
|
+
),
|
|
45
|
+
...
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
If no association could be found for a subclass of Traitable, the default association will be used: GeneralDomain.GENERAL
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
# fmt: off
|
|
52
|
+
SYMBOL = '_package_manifest.manifest'
|
|
53
|
+
CATEGORY = '_category'
|
|
54
|
+
# fmt: on
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def _resource_requirements(cls) -> ResourceRequirements:
|
|
58
|
+
module = cls.__module__
|
|
59
|
+
parts = module.split('.')
|
|
60
|
+
if len(parts) < 2:
|
|
61
|
+
return None # -- should be at least package.module, so it's most probably '__main__.Class'
|
|
62
|
+
|
|
63
|
+
package = '.'.join(parts[:-1])
|
|
64
|
+
man_def: dict = PyClass.find_symbol(f'{package}.{PackageManifest.SYMBOL}')
|
|
65
|
+
if not man_def:
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
short_module = parts[-1]
|
|
69
|
+
module_entry = man_def.get(short_module)
|
|
70
|
+
if module_entry:
|
|
71
|
+
rr: ResourceRequirements = module_entry.get(cls.__name__)
|
|
72
|
+
if not rr:
|
|
73
|
+
rr = module_entry.get(PackageManifest.CATEGORY)
|
|
74
|
+
if rr:
|
|
75
|
+
return rr
|
|
76
|
+
|
|
77
|
+
return man_def.get(PackageManifest.CATEGORY)
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def resource_requirements(cls) -> ResourceRequirements:
|
|
81
|
+
rr = PackageManifest._resource_requirements(cls) or GeneralDomain.GENERAL
|
|
82
|
+
assert rr.resource_type is TS_STORE, f'{cls} - invalid category in the _package_manifest'
|
|
83
|
+
return rr
|
|
84
|
+
|
|
85
|
+
# -- TODO: handle parent classes, if ResourceRequirements for the class in not found
|