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.
Files changed (214) hide show
  1. core_10x/__init__.py +42 -0
  2. core_10x/backbone/__init__.py +0 -0
  3. core_10x/backbone/backbone_store.py +59 -0
  4. core_10x/backbone/backbone_traitable.py +30 -0
  5. core_10x/backbone/backbone_user.py +66 -0
  6. core_10x/backbone/bound_data_domain.py +49 -0
  7. core_10x/backbone/namespace.py +101 -0
  8. core_10x/backbone/vault.py +38 -0
  9. core_10x/code_samples/__init__.py +0 -0
  10. core_10x/code_samples/_package_manifest.py +3 -0
  11. core_10x/code_samples/directories.py +181 -0
  12. core_10x/code_samples/person.py +76 -0
  13. core_10x/concrete_traits.py +356 -0
  14. core_10x/conftest.py +12 -0
  15. core_10x/curve.py +321 -0
  16. core_10x/data_domain.py +48 -0
  17. core_10x/data_domain_binder.py +45 -0
  18. core_10x/directory.py +250 -0
  19. core_10x/entity.py +8 -0
  20. core_10x/entity_filter.py +5 -0
  21. core_10x/environment_variables.py +147 -0
  22. core_10x/exec_control.py +84 -0
  23. core_10x/experimental/__init__.py +0 -0
  24. core_10x/experimental/data_protocol_ex.py +34 -0
  25. core_10x/global_cache.py +121 -0
  26. core_10x/manual_tests/__init__.py +0 -0
  27. core_10x/manual_tests/calendar_test.py +35 -0
  28. core_10x/manual_tests/ctor_update_bug.py +58 -0
  29. core_10x/manual_tests/debug_graph_on.py +17 -0
  30. core_10x/manual_tests/debug_graphoff_inside_graph_on.py +28 -0
  31. core_10x/manual_tests/enum_bits_test.py +17 -0
  32. core_10x/manual_tests/env_vars_trivial_test.py +12 -0
  33. core_10x/manual_tests/existing_traitable.py +33 -0
  34. core_10x/manual_tests/k10x_test1.py +13 -0
  35. core_10x/manual_tests/named_constant_test.py +121 -0
  36. core_10x/manual_tests/nucleus_trivial_test.py +42 -0
  37. core_10x/manual_tests/polars_test.py +14 -0
  38. core_10x/manual_tests/py_class_test.py +4 -0
  39. core_10x/manual_tests/rc_test.py +42 -0
  40. core_10x/manual_tests/rdate_test.py +12 -0
  41. core_10x/manual_tests/reference_serialization_bug.py +19 -0
  42. core_10x/manual_tests/resource_trivial_test.py +10 -0
  43. core_10x/manual_tests/store_uri_test.py +6 -0
  44. core_10x/manual_tests/trait_definition_test.py +19 -0
  45. core_10x/manual_tests/trait_filter_test.py +15 -0
  46. core_10x/manual_tests/trait_flag_modification_test.py +42 -0
  47. core_10x/manual_tests/trait_modification_bug.py +26 -0
  48. core_10x/manual_tests/traitable_as_of_test.py +82 -0
  49. core_10x/manual_tests/traitable_heir_test.py +39 -0
  50. core_10x/manual_tests/traitable_history_test.py +41 -0
  51. core_10x/manual_tests/traitable_serialization_test.py +54 -0
  52. core_10x/manual_tests/traitable_trivial_test.py +71 -0
  53. core_10x/manual_tests/trivial_graph_test.py +16 -0
  54. core_10x/manual_tests/ts_class_association_test.py +64 -0
  55. core_10x/manual_tests/ts_trivial_test.py +35 -0
  56. core_10x/named_constant.py +425 -0
  57. core_10x/nucleus.py +81 -0
  58. core_10x/package_manifest.py +85 -0
  59. core_10x/package_refactoring.py +153 -0
  60. core_10x/py_class.py +431 -0
  61. core_10x/rc.py +155 -0
  62. core_10x/rdate.py +339 -0
  63. core_10x/resource.py +189 -0
  64. core_10x/roman_number.py +67 -0
  65. core_10x/testlib/__init__.py +0 -0
  66. core_10x/testlib/test_store.py +240 -0
  67. core_10x/testlib/traitable_history_tests.py +787 -0
  68. core_10x/testlib/ts_tests.py +280 -0
  69. core_10x/trait.py +377 -0
  70. core_10x/trait_definition.py +176 -0
  71. core_10x/trait_filter.py +205 -0
  72. core_10x/trait_method_error.py +36 -0
  73. core_10x/traitable.py +1082 -0
  74. core_10x/traitable_cli.py +153 -0
  75. core_10x/traitable_heir.py +33 -0
  76. core_10x/traitable_id.py +31 -0
  77. core_10x/ts_store.py +172 -0
  78. core_10x/ts_store_type.py +26 -0
  79. core_10x/ts_union.py +147 -0
  80. core_10x/ui_hint.py +153 -0
  81. core_10x/unit_tests/test_concrete_traits.py +156 -0
  82. core_10x/unit_tests/test_converters.py +51 -0
  83. core_10x/unit_tests/test_curve.py +157 -0
  84. core_10x/unit_tests/test_directory.py +54 -0
  85. core_10x/unit_tests/test_documentation.py +172 -0
  86. core_10x/unit_tests/test_environment_variables.py +15 -0
  87. core_10x/unit_tests/test_filters.py +239 -0
  88. core_10x/unit_tests/test_graph.py +348 -0
  89. core_10x/unit_tests/test_named_constant.py +98 -0
  90. core_10x/unit_tests/test_rc.py +11 -0
  91. core_10x/unit_tests/test_rdate.py +484 -0
  92. core_10x/unit_tests/test_trait_method_error.py +80 -0
  93. core_10x/unit_tests/test_trait_modification.py +19 -0
  94. core_10x/unit_tests/test_traitable.py +959 -0
  95. core_10x/unit_tests/test_traitable_history.py +1 -0
  96. core_10x/unit_tests/test_ts_store.py +1 -0
  97. core_10x/unit_tests/test_ts_union.py +369 -0
  98. core_10x/unit_tests/test_ui_nodes.py +81 -0
  99. core_10x/unit_tests/test_xxcalendar.py +471 -0
  100. core_10x/vault/__init__.py +0 -0
  101. core_10x/vault/sec_keys.py +133 -0
  102. core_10x/vault/security_keys_old.py +168 -0
  103. core_10x/vault/vault.py +56 -0
  104. core_10x/vault/vault_traitable.py +56 -0
  105. core_10x/vault/vault_user.py +70 -0
  106. core_10x/xdate_time.py +136 -0
  107. core_10x/xnone.py +71 -0
  108. core_10x/xxcalendar.py +228 -0
  109. infra_10x/__init__.py +0 -0
  110. infra_10x/manual_tests/__init__.py +0 -0
  111. infra_10x/manual_tests/test_misc.py +16 -0
  112. infra_10x/manual_tests/test_prepare_filter_and_pipeline.py +25 -0
  113. infra_10x/mongodb_admin.py +111 -0
  114. infra_10x/mongodb_store.py +346 -0
  115. infra_10x/mongodb_utils.py +129 -0
  116. infra_10x/unit_tests/conftest.py +13 -0
  117. infra_10x/unit_tests/test_mongo_db.py +36 -0
  118. infra_10x/unit_tests/test_mongo_history.py +1 -0
  119. py10x_universe-0.1.3.dist-info/METADATA +406 -0
  120. py10x_universe-0.1.3.dist-info/RECORD +214 -0
  121. py10x_universe-0.1.3.dist-info/WHEEL +4 -0
  122. py10x_universe-0.1.3.dist-info/licenses/LICENSE +21 -0
  123. ui_10x/__init__.py +0 -0
  124. ui_10x/apps/__init__.py +0 -0
  125. ui_10x/apps/collection_editor_app.py +100 -0
  126. ui_10x/choice.py +212 -0
  127. ui_10x/collection_editor.py +135 -0
  128. ui_10x/concrete_trait_widgets.py +220 -0
  129. ui_10x/conftest.py +8 -0
  130. ui_10x/entity_stocker.py +173 -0
  131. ui_10x/examples/__init__.py +0 -0
  132. ui_10x/examples/_guess_word_data.py +14076 -0
  133. ui_10x/examples/collection_editor.py +17 -0
  134. ui_10x/examples/date_selector.py +14 -0
  135. ui_10x/examples/entity_stocker.py +18 -0
  136. ui_10x/examples/guess_word.py +392 -0
  137. ui_10x/examples/message_box.py +20 -0
  138. ui_10x/examples/multi_choice.py +17 -0
  139. ui_10x/examples/py_data_browser.py +66 -0
  140. ui_10x/examples/radiobox.py +29 -0
  141. ui_10x/examples/single_choice.py +31 -0
  142. ui_10x/examples/style_sheet.py +47 -0
  143. ui_10x/examples/trivial_entity_editor.py +18 -0
  144. ui_10x/platform.py +20 -0
  145. ui_10x/platform_interface.py +517 -0
  146. ui_10x/py_data_browser.py +249 -0
  147. ui_10x/qt6/__init__.py +0 -0
  148. ui_10x/qt6/conftest.py +8 -0
  149. ui_10x/qt6/manual_tests/__init__.py +0 -0
  150. ui_10x/qt6/manual_tests/basic_test.py +35 -0
  151. ui_10x/qt6/platform_implementation.py +275 -0
  152. ui_10x/qt6/utils.py +665 -0
  153. ui_10x/rio/__init__.py +0 -0
  154. ui_10x/rio/apps/examples/examples/__init__.py +22 -0
  155. ui_10x/rio/apps/examples/examples/components/__init__.py +3 -0
  156. ui_10x/rio/apps/examples/examples/components/collection_editor.py +15 -0
  157. ui_10x/rio/apps/examples/examples/pages/collection_editor.py +21 -0
  158. ui_10x/rio/apps/examples/examples/pages/login_page.py +88 -0
  159. ui_10x/rio/apps/examples/examples/pages/style_sheet.py +21 -0
  160. ui_10x/rio/apps/examples/rio.toml +14 -0
  161. ui_10x/rio/component_builder.py +497 -0
  162. ui_10x/rio/components/__init__.py +9 -0
  163. ui_10x/rio/components/group_box.py +31 -0
  164. ui_10x/rio/components/labeled_checkbox.py +18 -0
  165. ui_10x/rio/components/line_edit.py +37 -0
  166. ui_10x/rio/components/radio_button.py +32 -0
  167. ui_10x/rio/components/separator.py +24 -0
  168. ui_10x/rio/components/splitter.py +121 -0
  169. ui_10x/rio/components/tree_view.py +75 -0
  170. ui_10x/rio/conftest.py +35 -0
  171. ui_10x/rio/internals/__init__.py +0 -0
  172. ui_10x/rio/internals/app.py +192 -0
  173. ui_10x/rio/manual_tests/__init__.py +0 -0
  174. ui_10x/rio/manual_tests/basic_test.py +24 -0
  175. ui_10x/rio/manual_tests/splitter.py +27 -0
  176. ui_10x/rio/platform_implementation.py +91 -0
  177. ui_10x/rio/style_sheet.py +53 -0
  178. ui_10x/rio/unit_tests/test_collection_editor.py +68 -0
  179. ui_10x/rio/unit_tests/test_internals.py +630 -0
  180. ui_10x/rio/unit_tests/test_style_sheet.py +37 -0
  181. ui_10x/rio/widgets/__init__.py +46 -0
  182. ui_10x/rio/widgets/application.py +109 -0
  183. ui_10x/rio/widgets/button.py +48 -0
  184. ui_10x/rio/widgets/button_group.py +60 -0
  185. ui_10x/rio/widgets/calendar.py +23 -0
  186. ui_10x/rio/widgets/checkbox.py +24 -0
  187. ui_10x/rio/widgets/dialog.py +137 -0
  188. ui_10x/rio/widgets/group_box.py +27 -0
  189. ui_10x/rio/widgets/layout.py +34 -0
  190. ui_10x/rio/widgets/line_edit.py +37 -0
  191. ui_10x/rio/widgets/list.py +105 -0
  192. ui_10x/rio/widgets/message_box.py +70 -0
  193. ui_10x/rio/widgets/scroll_area.py +31 -0
  194. ui_10x/rio/widgets/spacer.py +6 -0
  195. ui_10x/rio/widgets/splitter.py +45 -0
  196. ui_10x/rio/widgets/text_edit.py +28 -0
  197. ui_10x/rio/widgets/tree.py +89 -0
  198. ui_10x/rio/widgets/unit_tests/test_button.py +101 -0
  199. ui_10x/rio/widgets/unit_tests/test_button_group.py +33 -0
  200. ui_10x/rio/widgets/unit_tests/test_calendar.py +114 -0
  201. ui_10x/rio/widgets/unit_tests/test_checkbox.py +109 -0
  202. ui_10x/rio/widgets/unit_tests/test_group_box.py +158 -0
  203. ui_10x/rio/widgets/unit_tests/test_label.py +43 -0
  204. ui_10x/rio/widgets/unit_tests/test_line_edit.py +140 -0
  205. ui_10x/rio/widgets/unit_tests/test_list.py +146 -0
  206. ui_10x/table_header_view.py +305 -0
  207. ui_10x/table_view.py +174 -0
  208. ui_10x/trait_editor.py +189 -0
  209. ui_10x/trait_widget.py +131 -0
  210. ui_10x/traitable_editor.py +200 -0
  211. ui_10x/traitable_view.py +131 -0
  212. ui_10x/unit_tests/conftest.py +8 -0
  213. ui_10x/unit_tests/test_platform.py +9 -0
  214. 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)
@@ -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