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,176 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import copy
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
|
|
6
|
+
from py10x_core import BFlags, BTraitFlags
|
|
7
|
+
from typing_extensions import Never
|
|
8
|
+
|
|
9
|
+
from core_10x.ui_hint import Ui, UiHintModification
|
|
10
|
+
from core_10x.xnone import XNone, XNoneType
|
|
11
|
+
|
|
12
|
+
# fmt: off
|
|
13
|
+
#---- Attribute Tags
|
|
14
|
+
NAME_TAG = 'name'
|
|
15
|
+
DATATYPE_TAG = 'data_type'
|
|
16
|
+
FLAGS_TAG = 'flags'
|
|
17
|
+
DEFAULT_TAG = 'default'
|
|
18
|
+
FORMAT_TAG = 'fmt'
|
|
19
|
+
PARAMS_TAG = 'params'
|
|
20
|
+
GETTER_PARAMS_TAG = 'getter_params'
|
|
21
|
+
UI_HINT_TAG = 'ui_hint'
|
|
22
|
+
# fmt: on
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TraitDefinition:
|
|
26
|
+
# fmt: off
|
|
27
|
+
__slots__ = (
|
|
28
|
+
NAME_TAG,
|
|
29
|
+
DATATYPE_TAG,
|
|
30
|
+
FLAGS_TAG,
|
|
31
|
+
DEFAULT_TAG,
|
|
32
|
+
FORMAT_TAG,
|
|
33
|
+
PARAMS_TAG,
|
|
34
|
+
UI_HINT_TAG,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
s_known_attributes = {
|
|
38
|
+
DATATYPE_TAG: lambda: XNoneType,
|
|
39
|
+
FLAGS_TAG: lambda: BFlags(0x0),
|
|
40
|
+
DEFAULT_TAG: lambda: XNone,
|
|
41
|
+
FORMAT_TAG: lambda: '',
|
|
42
|
+
UI_HINT_TAG: lambda: Ui(),
|
|
43
|
+
}
|
|
44
|
+
# fmt: on
|
|
45
|
+
|
|
46
|
+
def __init__(self, *args, **kwargs):
|
|
47
|
+
"""
|
|
48
|
+
T([default_value,] [t_flags,] [Ui(...),] **kwargs
|
|
49
|
+
"""
|
|
50
|
+
self.process_args(args, kwargs)
|
|
51
|
+
|
|
52
|
+
for tag, def_value_fn in self.s_known_attributes.items():
|
|
53
|
+
def_value = def_value_fn()
|
|
54
|
+
value = kwargs.pop(tag, def_value)
|
|
55
|
+
setattr(self, tag, value)
|
|
56
|
+
|
|
57
|
+
self.params = kwargs
|
|
58
|
+
self.name = None
|
|
59
|
+
|
|
60
|
+
def __floordiv__(self, comment):
|
|
61
|
+
"""Add or replace comment in params with // operator"""
|
|
62
|
+
assert isinstance(comment, str), f'Trait comment must be a string: {comment}'
|
|
63
|
+
ui_hint = getattr(self, UI_HINT_TAG)
|
|
64
|
+
ui_hint.tip = comment
|
|
65
|
+
return self
|
|
66
|
+
|
|
67
|
+
def __call__(self, *args, **kwargs):
|
|
68
|
+
"""Prevent IDE from complaining about calling traits with parameters"""
|
|
69
|
+
...
|
|
70
|
+
|
|
71
|
+
def set_widget_type(self, widget_type: Ui.WIDGET_TYPE):
|
|
72
|
+
ui_hint = getattr(self, UI_HINT_TAG)
|
|
73
|
+
ui_hint.widget_type = widget_type
|
|
74
|
+
|
|
75
|
+
def copy(self) -> TraitDefinition:
|
|
76
|
+
return copy.deepcopy(self)
|
|
77
|
+
|
|
78
|
+
def flags_change(self, flags_value):
|
|
79
|
+
dt = type(flags_value)
|
|
80
|
+
if dt is tuple:
|
|
81
|
+
assert len(flags_value) == 2, f'Changing {self.name} flags expects (flags_to_set, flags_to_reset)'
|
|
82
|
+
self.flags.set_reset(*(0 if flag is None else flag.value() for flag in flags_value))
|
|
83
|
+
else:
|
|
84
|
+
self.flags.set(flags_value.value())
|
|
85
|
+
|
|
86
|
+
@classmethod
|
|
87
|
+
def process_args(cls, args: tuple, kwargs: dict):
|
|
88
|
+
"""
|
|
89
|
+
args:
|
|
90
|
+
optional default_value
|
|
91
|
+
optional T.flags
|
|
92
|
+
optional ui hint: Ui(...)
|
|
93
|
+
kwargs:
|
|
94
|
+
known attributes and extra params (usually empty)
|
|
95
|
+
"""
|
|
96
|
+
the_args = list(args)
|
|
97
|
+
already_processed = defaultdict(bool)
|
|
98
|
+
|
|
99
|
+
n = len(the_args)
|
|
100
|
+
while n:
|
|
101
|
+
arg = the_args.pop(0)
|
|
102
|
+
dt = type(arg)
|
|
103
|
+
if dt is Ui: # -- only Ui hint is given, no more args
|
|
104
|
+
assert not already_processed[UI_HINT_TAG], f'Duplicated Ui hint: {args}'
|
|
105
|
+
assert n == 1, f'No positional args after Ui hint: {args}'
|
|
106
|
+
kwargs[UI_HINT_TAG] = arg
|
|
107
|
+
already_processed[UI_HINT_TAG] = True
|
|
108
|
+
|
|
109
|
+
elif issubclass(dt, BFlags): # -- no default value => n <=2
|
|
110
|
+
assert not already_processed[FLAGS_TAG], f'Duplicated T.flags: {args}'
|
|
111
|
+
assert n <= 2, f'Too many positional args after T.flags: {args}'
|
|
112
|
+
kwargs[FLAGS_TAG] = arg
|
|
113
|
+
already_processed[FLAGS_TAG] = True
|
|
114
|
+
|
|
115
|
+
else: # -- must be a default value
|
|
116
|
+
assert not already_processed[DEFAULT_TAG], f'Duplicated default value: {args}'
|
|
117
|
+
kwargs[DEFAULT_TAG] = arg
|
|
118
|
+
already_processed[DEFAULT_TAG] = True
|
|
119
|
+
|
|
120
|
+
n -= 1
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class TraitModification(TraitDefinition):
|
|
124
|
+
# fmt: off
|
|
125
|
+
s_known_attributes = {
|
|
126
|
+
FLAGS_TAG: lambda: Never,
|
|
127
|
+
DEFAULT_TAG: lambda: Never,
|
|
128
|
+
FORMAT_TAG: lambda: Never,
|
|
129
|
+
UI_HINT_TAG: UiHintModification
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
s_modifiers = {
|
|
133
|
+
FLAGS_TAG: lambda self, flags_modification: self.flags_change(flags_modification),
|
|
134
|
+
UI_HINT_TAG: lambda self, ui_hint_modification: setattr(self,UI_HINT_TAG,ui_hint_modification.apply(self.ui_hint))
|
|
135
|
+
}
|
|
136
|
+
# fmt: on
|
|
137
|
+
def apply(self, trait_def: TraitDefinition) -> TraitDefinition:
|
|
138
|
+
res = trait_def.copy()
|
|
139
|
+
modifiers = self.__class__.s_modifiers
|
|
140
|
+
for attr_name in self.__class__.s_known_attributes:
|
|
141
|
+
modified_value = getattr(self, attr_name)
|
|
142
|
+
if modified_value is not Never:
|
|
143
|
+
modifier = modifiers.get(attr_name)
|
|
144
|
+
if modifier:
|
|
145
|
+
modifier(res, modified_value)
|
|
146
|
+
else:
|
|
147
|
+
setattr(res, attr_name, modified_value)
|
|
148
|
+
res.params.update(self.params)
|
|
149
|
+
return res
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class T(BTraitFlags):
|
|
153
|
+
def __new__(cls, *args, **kwargs) -> TraitDefinition:
|
|
154
|
+
return TraitDefinition(*args, **kwargs)
|
|
155
|
+
|
|
156
|
+
@staticmethod
|
|
157
|
+
def fg_color(color: str) -> str:
|
|
158
|
+
return f'color: {color}' if color else ''
|
|
159
|
+
|
|
160
|
+
@staticmethod
|
|
161
|
+
def bg_color(color: str) -> str:
|
|
162
|
+
return f'background-color: {color}' if color else ''
|
|
163
|
+
|
|
164
|
+
@staticmethod
|
|
165
|
+
def colors(bg_color: str, fg_color: str) -> str:
|
|
166
|
+
return f'background-color: {bg_color}; color: {fg_color}' if bg_color and fg_color else ''
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def RT(*args, **kwargs) -> TraitDefinition: # noqa: N802
|
|
170
|
+
trait_def = TraitDefinition(*args, **kwargs)
|
|
171
|
+
trait_def.flags.set(T.RUNTIME.value())
|
|
172
|
+
return trait_def
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def M(*args, **kwargs) -> TraitModification: # noqa: N802
|
|
176
|
+
return TraitModification(*args, **kwargs)
|
core_10x/trait_filter.py
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from py10x_core import BTraitableClass
|
|
8
|
+
|
|
9
|
+
from core_10x.trait import Trait
|
|
10
|
+
|
|
11
|
+
# ===================================================================================================================================
|
|
12
|
+
#
|
|
13
|
+
# age = LT(value)
|
|
14
|
+
# name = 'Sasha' #-- name = EQ('Sasha')
|
|
15
|
+
# weight = BETWEEN(170, 180, bounds = (True, False)
|
|
16
|
+
# weight =
|
|
17
|
+
# ===================================================================================================================================
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# fmt: off
|
|
21
|
+
class _mongo_label:
|
|
22
|
+
EQ = '$eq'
|
|
23
|
+
NE = '$ne'
|
|
24
|
+
GT = '$gt'
|
|
25
|
+
GE = '$gte'
|
|
26
|
+
LT = '$lt'
|
|
27
|
+
LE = '$lte'
|
|
28
|
+
IN = '$in'
|
|
29
|
+
NIN = '$nin'
|
|
30
|
+
REGEX = '$regex'
|
|
31
|
+
AND = '$and'
|
|
32
|
+
OR = '$or'
|
|
33
|
+
#NOT = '$not'
|
|
34
|
+
# fmt: on
|
|
35
|
+
|
|
36
|
+
LABEL = _mongo_label
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class _filter(ABC):
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def eval(self, left_value) -> bool: ...
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def prefix_notation(self, trait: Trait = None, traitable_class: BTraitableClass = None) -> dict: ...
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Op(_filter, ABC):
|
|
47
|
+
label = ''
|
|
48
|
+
|
|
49
|
+
def __init_subclass__(cls, label: str = None):
|
|
50
|
+
if label is None:
|
|
51
|
+
label = getattr(LABEL, cls.__name__)
|
|
52
|
+
cls.label = label
|
|
53
|
+
|
|
54
|
+
def __new__(cls, expression=None):
|
|
55
|
+
obj = super().__new__(cls)
|
|
56
|
+
obj.right_value = expression
|
|
57
|
+
return obj
|
|
58
|
+
|
|
59
|
+
def serialize_right_value(self, trait: Trait = None, traitable_class: BTraitableClass = None) -> dict:
|
|
60
|
+
return trait.serialize_value(self.right_value, replace_xnone=True) if trait and traitable_class else self.right_value
|
|
61
|
+
|
|
62
|
+
def prefix_notation(self, trait: Trait = None, traitable_class: BTraitableClass = None) -> dict:
|
|
63
|
+
# noinspection PyTypeChecker
|
|
64
|
+
return {self.label: self.serialize_right_value(trait, traitable_class)}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class NOT_EMPTY(Op, label=''):
|
|
68
|
+
def prefix_notation(self, trait: Trait = None, traitable_class: BTraitableClass = None) -> dict:
|
|
69
|
+
raise NotImplementedError
|
|
70
|
+
|
|
71
|
+
def eval(self, left_value) -> bool:
|
|
72
|
+
return bool(left_value)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class EQ(Op):
|
|
76
|
+
def eval(self, left_value) -> bool:
|
|
77
|
+
return left_value == self.right_value
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class NE(Op):
|
|
81
|
+
def eval(self, left_value) -> bool:
|
|
82
|
+
return left_value != self.right_value
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class GT(Op):
|
|
86
|
+
def eval(self, left_value) -> bool:
|
|
87
|
+
return left_value > self.right_value
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class GE(Op):
|
|
91
|
+
def eval(self, left_value) -> bool:
|
|
92
|
+
return left_value >= self.right_value
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class LT(Op):
|
|
96
|
+
def eval(self, left_value) -> bool:
|
|
97
|
+
return left_value < self.right_value
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class LE(Op):
|
|
101
|
+
def eval(self, left_value) -> bool:
|
|
102
|
+
return left_value <= self.right_value
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class IN(Op):
|
|
106
|
+
def __new__(cls, values: list | tuple):
|
|
107
|
+
assert isinstance(values, list) or isinstance(values, tuple), f'{cls.__name__}() requires a list or tuple'
|
|
108
|
+
return super().__new__(cls, values)
|
|
109
|
+
|
|
110
|
+
def serialize_right_value(self, trait: Trait = None, traitable_class: BTraitableClass = None) -> dict:
|
|
111
|
+
return [trait.serialize_value(value, replace_xnone=True) for value in self.right_value] if trait and traitable_class else self.right_value
|
|
112
|
+
|
|
113
|
+
def eval(self, left_value) -> bool:
|
|
114
|
+
return left_value in self.right_value
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class NIN(IN):
|
|
118
|
+
def eval(self, left_value) -> bool:
|
|
119
|
+
return left_value not in self.right_value
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# class REGEX(Op):
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class BETWEEN(Op, label=''):
|
|
126
|
+
def __new__(cls, a, b, bounds=(True, True)):
|
|
127
|
+
obj = super().__new__(cls)
|
|
128
|
+
assert isinstance(bounds, tuple) and len(bounds) == 2, f'{cls.__name__} - (bool, bool) is expected for bounds'
|
|
129
|
+
|
|
130
|
+
bound_a, bound_b = bounds
|
|
131
|
+
obj.left = GE(a) if bound_a else GT(a)
|
|
132
|
+
obj.right = LE(b) if bound_b else LT(b)
|
|
133
|
+
return obj
|
|
134
|
+
|
|
135
|
+
def eval(self, left_value) -> bool:
|
|
136
|
+
return self.left.eval(left_value) and self.right.eval(left_value)
|
|
137
|
+
|
|
138
|
+
def prefix_notation(self, trait: Trait = None, traitable_class: BTraitableClass = None) -> dict:
|
|
139
|
+
res = self.left.prefix_notation(trait, traitable_class)
|
|
140
|
+
res.update(self.right.prefix_notation(trait, traitable_class))
|
|
141
|
+
return res
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class BoolOp(Op, ABC, label=''):
|
|
145
|
+
s_false: IN = IN([])
|
|
146
|
+
|
|
147
|
+
@classmethod
|
|
148
|
+
def _simplify(cls, expressions: tuple, false: IN) -> list: ...
|
|
149
|
+
|
|
150
|
+
def __new__(cls, *expressions):
|
|
151
|
+
expressions = cls._simplify(expressions, cls.s_false)
|
|
152
|
+
if len(expressions) == 1:
|
|
153
|
+
return expressions[0]
|
|
154
|
+
|
|
155
|
+
obj = super().__new__(cls, expressions)
|
|
156
|
+
return obj
|
|
157
|
+
|
|
158
|
+
def prefix_notation(self, trait: Trait = None, traitable_class: BTraitableClass = None) -> dict:
|
|
159
|
+
rvalues = [pn for e in self.right_value if (pn := e.prefix_notation(trait, traitable_class))]
|
|
160
|
+
return {self.label: rvalues} if rvalues else {}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class AND(BoolOp):
|
|
164
|
+
@classmethod
|
|
165
|
+
def _simplify(cls, expressions, false):
|
|
166
|
+
return [false] if false in expressions else expressions
|
|
167
|
+
|
|
168
|
+
def eval(self, left_value) -> bool:
|
|
169
|
+
return all(e.eval(left_value) for e in self.right_value)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class OR(BoolOp):
|
|
173
|
+
@classmethod
|
|
174
|
+
def _simplify(cls, expressions, false):
|
|
175
|
+
expressions = [expression for expression in expressions if expression is not false]
|
|
176
|
+
return [false] if not expressions else expressions
|
|
177
|
+
|
|
178
|
+
def eval(self, left_value) -> bool:
|
|
179
|
+
return any(e.eval(left_value) for e in self.right_value)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class f(_filter):
|
|
183
|
+
def __init__(self, _f: _filter = None, _t: BTraitableClass = None, **named_expressions):
|
|
184
|
+
self.filter = _f
|
|
185
|
+
self.traitable_class = _t
|
|
186
|
+
self.named_expressions = {
|
|
187
|
+
name: expression if isinstance(expression, _filter) else EQ(expression) for name, expression in named_expressions.items()
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
def eval(self, traitable_or_dict) -> bool:
|
|
191
|
+
if self.filter:
|
|
192
|
+
if not self.filter.eval(traitable_or_dict):
|
|
193
|
+
return False
|
|
194
|
+
|
|
195
|
+
return all(item.eval(traitable_or_dict[name]) for name, item in self.named_expressions.items())
|
|
196
|
+
|
|
197
|
+
def prefix_notation(self, trait: Trait = None, traitable_class: BTraitableClass = None) -> dict:
|
|
198
|
+
traitable_class = traitable_class or self.traitable_class
|
|
199
|
+
trait_dir = traitable_class.trait_dir() if traitable_class else {}
|
|
200
|
+
clause = {name: pn for name, item in self.named_expressions.items() if (pn := item.prefix_notation(trait_dir.get(name), traitable_class))}
|
|
201
|
+
if self.filter:
|
|
202
|
+
filter_clause = self.filter.prefix_notation(traitable_class=traitable_class)
|
|
203
|
+
clause = {AND.label: [filter_clause, clause]} if clause else filter_clause
|
|
204
|
+
|
|
205
|
+
return clause
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from core_10x.xnone import XNone
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TraitMethodError(Exception):
|
|
5
|
+
"""
|
|
6
|
+
NOTE: other_exc must be set in except clause ONLY!
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
@staticmethod
|
|
10
|
+
def create(traitable, traitable_class, trait_name: str, method_name: str, value=XNone, other_exc: Exception = None, args=()):
|
|
11
|
+
assert other_exc
|
|
12
|
+
|
|
13
|
+
if isinstance(other_exc, TraitMethodError):
|
|
14
|
+
return other_exc
|
|
15
|
+
|
|
16
|
+
msg = []
|
|
17
|
+
traitable_class = traitable_class or traitable.__class__
|
|
18
|
+
msg.append(f'Failed in {traitable_class}.{trait_name}.{method_name}')
|
|
19
|
+
if traitable:
|
|
20
|
+
msg.append(f' object = {traitable.id()};')
|
|
21
|
+
|
|
22
|
+
if value is not XNone:
|
|
23
|
+
msg.append(f' value = {value}')
|
|
24
|
+
|
|
25
|
+
if args:
|
|
26
|
+
msg.append(f' args = {args}')
|
|
27
|
+
|
|
28
|
+
if other_exc:
|
|
29
|
+
msg.append(f'original exception = {type(other_exc).__name__}: {other_exc!s}')
|
|
30
|
+
|
|
31
|
+
exc = TraitMethodError('\n'.join(msg))
|
|
32
|
+
|
|
33
|
+
if other_exc and (tb := other_exc.__traceback__):
|
|
34
|
+
exc = exc.with_traceback(tb)
|
|
35
|
+
|
|
36
|
+
return exc
|