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,348 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
from weakref import WeakKeyDictionary
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
from core_10x.code_samples.person import WEIGHT_QU, Person
|
|
8
|
+
from core_10x.exec_control import BTP, CACHE_ONLY, GRAPH_OFF, GRAPH_ON, INTERACTIVE
|
|
9
|
+
from core_10x.trait_definition import RT, T
|
|
10
|
+
from core_10x.traitable import Traitable
|
|
11
|
+
from core_10x.traitable_id import ID
|
|
12
|
+
from core_10x.xnone import XNone
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def call_counter(method):
|
|
16
|
+
@functools.wraps(method)
|
|
17
|
+
def ctr(self, *args, **kwargs):
|
|
18
|
+
ctr.call_counts[self] = ctr.call_counts.get(self, 0) + 1
|
|
19
|
+
return method(self, *args, **kwargs)
|
|
20
|
+
|
|
21
|
+
ctr.call_counts = WeakKeyDictionary()
|
|
22
|
+
ctr.call_count = lambda obj: ctr.call_counts.get(obj, 0) if obj else sum(ctr.call_counts.values())
|
|
23
|
+
return ctr
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CallCount:
|
|
27
|
+
def __init__(self, obj, method):
|
|
28
|
+
self.obj = obj
|
|
29
|
+
self.method = method
|
|
30
|
+
assert hasattr(method, 'call_count')
|
|
31
|
+
|
|
32
|
+
def __enter__(self):
|
|
33
|
+
self.method.call_counts[self.obj] = 0
|
|
34
|
+
return self
|
|
35
|
+
|
|
36
|
+
def __exit__(self, *args):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def call_count(self):
|
|
41
|
+
return self.method.call_count(self.obj)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class TestablePerson(Person):
|
|
45
|
+
older_than_get = call_counter(Person.older_than_get)
|
|
46
|
+
weight_get = call_counter(Person.weight_get)
|
|
47
|
+
weight_set = call_counter(Person.weight_set)
|
|
48
|
+
|
|
49
|
+
young: bool = RT()
|
|
50
|
+
|
|
51
|
+
@call_counter
|
|
52
|
+
def young_get(self) -> bool:
|
|
53
|
+
return self.age < 30
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def load_data(cls, id: ID) -> dict | None:
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@pytest.fixture
|
|
61
|
+
def testable_person():
|
|
62
|
+
with CACHE_ONLY():
|
|
63
|
+
return TestablePerson(first_name='John', last_name='Smith')
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def reset_person(p):
|
|
67
|
+
for trait in p.s_dir.values():
|
|
68
|
+
if not trait.getter_params:
|
|
69
|
+
p.invalidate_value(trait)
|
|
70
|
+
if not trait.flags_on(T.ID): # id traits may be set in base layer
|
|
71
|
+
if trait.f_get.__name__ == 'default_value': # TODO: replace with flags
|
|
72
|
+
assert p.get_value(trait) is trait.default, trait.name
|
|
73
|
+
elif trait.f_get.__name__.endswith('_get'):
|
|
74
|
+
assert p.get_value(trait) == getattr(p, f'{trait.name}_get')()
|
|
75
|
+
else:
|
|
76
|
+
assert p.get_value(trait) == trait.f_get(p)
|
|
77
|
+
else:
|
|
78
|
+
# TODO: use nodes?
|
|
79
|
+
...
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_get_set(testable_person):
|
|
83
|
+
on = BTP.current().flags() & BTP.ON_GRAPH
|
|
84
|
+
p = testable_person
|
|
85
|
+
p.weight_lbs = 100.0
|
|
86
|
+
p.weight_qu = WEIGHT_QU.LB
|
|
87
|
+
|
|
88
|
+
assert p.weight == 100
|
|
89
|
+
|
|
90
|
+
with CallCount(p, TestablePerson.weight_get) as cc:
|
|
91
|
+
assert p.weight == 100
|
|
92
|
+
assert cc.call_count == (not on)
|
|
93
|
+
|
|
94
|
+
p.weight_qu = WEIGHT_QU.KG
|
|
95
|
+
assert p.weight_qu is WEIGHT_QU.KG
|
|
96
|
+
|
|
97
|
+
with CallCount(p, TestablePerson.weight_get) as cc:
|
|
98
|
+
assert p.weight == 100 / WEIGHT_QU.KG.value
|
|
99
|
+
assert cc.call_count == 1
|
|
100
|
+
|
|
101
|
+
# now use the setter...
|
|
102
|
+
with CallCount(p, TestablePerson.weight_set) as cc:
|
|
103
|
+
p.weight = 100.0
|
|
104
|
+
assert cc.call_count == 1
|
|
105
|
+
|
|
106
|
+
with CallCount(p, TestablePerson.weight_get) as cc:
|
|
107
|
+
assert p.weight == 100
|
|
108
|
+
assert cc.call_count == 1
|
|
109
|
+
|
|
110
|
+
with CallCount(p, TestablePerson.weight_get) as cc:
|
|
111
|
+
assert p.weight_lbs == 100 * WEIGHT_QU.KG.value
|
|
112
|
+
assert cc.call_count == 0
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_dep_change(testable_person):
|
|
116
|
+
on = BTP.current().flags() & BTP.ON_GRAPH
|
|
117
|
+
p = testable_person
|
|
118
|
+
p.age = 30
|
|
119
|
+
|
|
120
|
+
assert not p.young
|
|
121
|
+
|
|
122
|
+
with CallCount(p, TestablePerson.young_get) as cc:
|
|
123
|
+
assert not p.young
|
|
124
|
+
assert cc.call_count == (not on)
|
|
125
|
+
|
|
126
|
+
p.age = 20
|
|
127
|
+
with CallCount(p, TestablePerson.young_get) as cc:
|
|
128
|
+
assert p.young
|
|
129
|
+
assert cc.call_count == 1
|
|
130
|
+
|
|
131
|
+
p.age = 30
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_dep_change_with_arg(testable_person):
|
|
135
|
+
on = BTP.current().flags() & BTP.ON_GRAPH
|
|
136
|
+
|
|
137
|
+
p = testable_person
|
|
138
|
+
p.age = 30
|
|
139
|
+
|
|
140
|
+
assert not p.older_than(30)
|
|
141
|
+
|
|
142
|
+
with CallCount(p, TestablePerson.older_than_get) as cc:
|
|
143
|
+
assert not p.older_than(30)
|
|
144
|
+
assert cc.call_count == (not on)
|
|
145
|
+
|
|
146
|
+
p.age = 40
|
|
147
|
+
with CallCount(p, TestablePerson.older_than_get) as cc:
|
|
148
|
+
assert p.older_than(30)
|
|
149
|
+
assert cc.call_count == 1
|
|
150
|
+
|
|
151
|
+
p.age = 30
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def test_nested():
|
|
155
|
+
class P(Traitable):
|
|
156
|
+
first_name: str = RT()
|
|
157
|
+
last_name: str = RT()
|
|
158
|
+
full_name: str = RT()
|
|
159
|
+
|
|
160
|
+
def full_name_get(self):
|
|
161
|
+
return f'{self.first_name} {self.last_name}'
|
|
162
|
+
|
|
163
|
+
p = P(first_name='Jane', last_name='Smith')
|
|
164
|
+
assert p.full_name == 'Jane Smith'
|
|
165
|
+
with INTERACTIVE() as i1:
|
|
166
|
+
p.last_name = 'Baker'
|
|
167
|
+
assert p.full_name == 'Jane Baker'
|
|
168
|
+
with INTERACTIVE() as i2:
|
|
169
|
+
p.first_name = 'Tom'
|
|
170
|
+
assert p.full_name == 'Tom Baker'
|
|
171
|
+
assert p.full_name == 'Jane Baker'
|
|
172
|
+
with i2:
|
|
173
|
+
assert p.full_name == 'Tom Baker'
|
|
174
|
+
assert p.full_name == 'Jane Baker'
|
|
175
|
+
|
|
176
|
+
assert p.full_name == 'Jane Smith'
|
|
177
|
+
with i1:
|
|
178
|
+
assert p.full_name == 'Jane Baker'
|
|
179
|
+
|
|
180
|
+
assert p.full_name == 'Jane Smith'
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def test_convert(testable_person, on=False):
|
|
184
|
+
assert on == bool(BTP.current().flags() & BTP.CONVERT_VALUES)
|
|
185
|
+
if not on:
|
|
186
|
+
with pytest.raises(TypeError):
|
|
187
|
+
Person(first_name=1, last_name=2)
|
|
188
|
+
else:
|
|
189
|
+
p = Person(first_name=1, last_name=2)
|
|
190
|
+
assert p.full_name == '1 2'
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def test_graph(testable_person, on=False):
|
|
194
|
+
assert on == bool(BTP.current().flags() & BTP.ON_GRAPH)
|
|
195
|
+
test_dep_change(testable_person)
|
|
196
|
+
test_dep_change_with_arg(testable_person)
|
|
197
|
+
test_get_set(testable_person)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def test_exec_control(testable_person, graph=False, convert=False, debug=False):
|
|
201
|
+
with CACHE_ONLY():
|
|
202
|
+
test_graph(testable_person, on=graph)
|
|
203
|
+
reset_person(testable_person)
|
|
204
|
+
test_convert(testable_person, on=convert)
|
|
205
|
+
reset_person(testable_person)
|
|
206
|
+
if not convert:
|
|
207
|
+
test_debug(testable_person, on=debug)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def test_repro(testable_person):
|
|
211
|
+
with GRAPH_ON():
|
|
212
|
+
testable_person.weight_lbs = 100
|
|
213
|
+
reset_person(testable_person)
|
|
214
|
+
with GRAPH_OFF():
|
|
215
|
+
testable_person.weight_lbs = 100
|
|
216
|
+
reset_person(testable_person)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def test_graph_on(testable_person):
|
|
220
|
+
with GRAPH_ON():
|
|
221
|
+
test_exec_control(testable_person, True, False, False)
|
|
222
|
+
with GRAPH_OFF():
|
|
223
|
+
test_exec_control(testable_person, False, False, False)
|
|
224
|
+
reset_person(testable_person)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def test_debug(testable_person, on=False):
|
|
228
|
+
assert on == bool(BTP.current().flags() & BTP.DEBUG)
|
|
229
|
+
p = TestablePerson(first_name='John', last_name='Smith')
|
|
230
|
+
assert p.weight_lbs is XNone
|
|
231
|
+
|
|
232
|
+
p.weight_lbs = 100.0
|
|
233
|
+
|
|
234
|
+
if on:
|
|
235
|
+
with pytest.raises(TypeError):
|
|
236
|
+
p.weight_lbs = '200'
|
|
237
|
+
|
|
238
|
+
assert p.weight == 100.0
|
|
239
|
+
|
|
240
|
+
p.weight_lbs = 200
|
|
241
|
+
assert p.weight == 200.0
|
|
242
|
+
|
|
243
|
+
p.invalidate_value(p.T.weight_lbs)
|
|
244
|
+
assert p.weight_lbs is XNone
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def test_graph_convert_debug(testable_person):
|
|
248
|
+
with GRAPH_ON(convert_values=True, debug=True):
|
|
249
|
+
test_exec_control(testable_person, True, True, True)
|
|
250
|
+
with GRAPH_OFF():
|
|
251
|
+
test_exec_control(testable_person, False, True, True)
|
|
252
|
+
with GRAPH_OFF(convert_values=False):
|
|
253
|
+
test_exec_control(testable_person, False, False, True)
|
|
254
|
+
with GRAPH_OFF(debug=False, convert_values=False):
|
|
255
|
+
test_exec_control(testable_person, False, False, False)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def test_graph_convert(testable_person):
|
|
259
|
+
with GRAPH_ON(convert_values=True):
|
|
260
|
+
test_exec_control(testable_person, True, True, False)
|
|
261
|
+
with GRAPH_OFF():
|
|
262
|
+
test_exec_control(testable_person, False, True, False)
|
|
263
|
+
with GRAPH_OFF(convert_values=False):
|
|
264
|
+
test_exec_control(testable_person, False, False, False)
|
|
265
|
+
with GRAPH_OFF(debug=True, convert_values=False):
|
|
266
|
+
test_exec_control(testable_person, False, False, True)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def test_graph_debug(testable_person):
|
|
270
|
+
with GRAPH_ON(debug=True):
|
|
271
|
+
test_exec_control(testable_person, True, False, True)
|
|
272
|
+
|
|
273
|
+
with GRAPH_OFF():
|
|
274
|
+
test_exec_control(testable_person, False, False, True)
|
|
275
|
+
with GRAPH_OFF(debug=False):
|
|
276
|
+
test_exec_control(testable_person, False, False, False)
|
|
277
|
+
with GRAPH_OFF(debug=False, convert_values=True):
|
|
278
|
+
test_exec_control(testable_person, False, True, False)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
@pytest.mark.parametrize('on_graph', [0, 1])
|
|
282
|
+
@pytest.mark.parametrize('debug', [0, 1])
|
|
283
|
+
@pytest.mark.parametrize('convert_values', [0, 1])
|
|
284
|
+
@pytest.mark.parametrize('on_graph2', [0, 1])
|
|
285
|
+
@pytest.mark.parametrize('debug2', [0, 1])
|
|
286
|
+
@pytest.mark.parametrize('convert_values2', [0, 1])
|
|
287
|
+
def test_traitable_processor_creation(on_graph, debug, convert_values, on_graph2, debug2, convert_values2):
|
|
288
|
+
class X(Traitable):
|
|
289
|
+
x: int = RT(T.ID)
|
|
290
|
+
v: int = RT()
|
|
291
|
+
|
|
292
|
+
X(x=1, v=10, _replace=True)
|
|
293
|
+
assert X(x=1).v == 10
|
|
294
|
+
|
|
295
|
+
default_cache = BTP.current().cache()
|
|
296
|
+
with BTP.create(on_graph, debug, convert_values, use_parent_cache=False, use_default_cache=False):
|
|
297
|
+
X(x=2, v=20, _replace=True)
|
|
298
|
+
parent_cache = BTP.current().cache()
|
|
299
|
+
assert default_cache is not parent_cache
|
|
300
|
+
with BTP.create(on_graph2, debug2, convert_values2, use_parent_cache=False, use_default_cache=False):
|
|
301
|
+
X(x=3, v=30, _replace=True)
|
|
302
|
+
child_cache = BTP.current().cache()
|
|
303
|
+
assert child_cache is not parent_cache
|
|
304
|
+
assert child_cache is not default_cache
|
|
305
|
+
assert X(x=1).v == 10
|
|
306
|
+
assert X(x=2).v == 20
|
|
307
|
+
|
|
308
|
+
with BTP.create(on_graph2, debug2, convert_values2, use_parent_cache=True, use_default_cache=False):
|
|
309
|
+
X(x=4, v=40, _replace=True)
|
|
310
|
+
child_cache = BTP.current().cache()
|
|
311
|
+
if on_graph == on_graph2: # use_parent_cache only works if both parent and child are either on_graph or off_graph
|
|
312
|
+
assert child_cache is parent_cache
|
|
313
|
+
else:
|
|
314
|
+
assert child_cache is not parent_cache
|
|
315
|
+
assert child_cache is not default_cache
|
|
316
|
+
with BTP.create(on_graph2, debug2, convert_values2, use_parent_cache=False, use_default_cache=True):
|
|
317
|
+
X(x=5, v=50, _replace=True)
|
|
318
|
+
child_cache = BTP.current().cache()
|
|
319
|
+
if not on_graph2: # use_default_cache only works for off-graph mode
|
|
320
|
+
assert child_cache is default_cache
|
|
321
|
+
assert X(x=2).v is XNone
|
|
322
|
+
else:
|
|
323
|
+
assert child_cache is not parent_cache
|
|
324
|
+
assert child_cache is not default_cache
|
|
325
|
+
assert X(x=2).v == 20 # from parent
|
|
326
|
+
assert X(x=1).v == 10
|
|
327
|
+
|
|
328
|
+
assert X(x=1).v == 10 # from parent caches
|
|
329
|
+
assert X(x=2).v == 20 # set in this cache
|
|
330
|
+
assert X(x=3).v is XNone # not set as was set in child with use_parent_cache=False
|
|
331
|
+
if on_graph == on_graph2: # use_parent_cache only works if both parent and child are either on_graph or off_graph
|
|
332
|
+
assert X(x=4).v == 40 # this cache, as was set in child with use_parent_cache=True
|
|
333
|
+
if not on_graph2: # use_default_cache only works for off-graph mode
|
|
334
|
+
assert X(x=5).v == 50 # in default cache, which is our parent
|
|
335
|
+
|
|
336
|
+
assert X(x=1).v == 10
|
|
337
|
+
assert X(x=2).v is XNone
|
|
338
|
+
assert X(x=3).v is XNone
|
|
339
|
+
assert X(x=4).v is XNone
|
|
340
|
+
if not on_graph2: # use_default_cache only works for off-graph mode
|
|
341
|
+
assert X(x=5).v == 50 # we are in default cache, and it was set in default cache
|
|
342
|
+
|
|
343
|
+
# TODO assert behavior with conflicting params, e.g.
|
|
344
|
+
#
|
|
345
|
+
# with pytest.raises(Exception):
|
|
346
|
+
# BTP.create(-1,-1,-1,use_parent_cache=True,use_default_cache=True)
|
|
347
|
+
|
|
348
|
+
# TODO: node set, cleared, checked - each in nested cache level
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from core_10x.named_constant import Enum, EnumBits, ErrorCode, NamedConstant, NamedConstantTable
|
|
3
|
+
from core_10x.traitable import T, Traitable
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Status(NamedConstant):
|
|
7
|
+
ACTIVE = ()
|
|
8
|
+
INACTIVE = ()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class StatusEx(Status):
|
|
12
|
+
DEPRECATED = ()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class X(Traitable):
|
|
16
|
+
status: Status = T()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@pytest.mark.parametrize('status', [Status.ACTIVE, StatusEx.DEPRECATED])
|
|
20
|
+
def test_serialize(ts_instance, status):
|
|
21
|
+
with ts_instance:
|
|
22
|
+
x = X(status=status)
|
|
23
|
+
s = x.serialize_object()
|
|
24
|
+
status_val = {'_type': '_nx', '_cls': 'test_named_constant/StatusEx', '_obj': 'DEPRECATED'} if status is StatusEx.DEPRECATED else 'ACTIVE'
|
|
25
|
+
assert s == {'_id': x.id().value, '_rev': 0, 'status': status_val}
|
|
26
|
+
|
|
27
|
+
x.save()
|
|
28
|
+
|
|
29
|
+
assert x == X.load(x.id())
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_named_constant_value_and_table():
|
|
33
|
+
class Row(NamedConstant):
|
|
34
|
+
A = ()
|
|
35
|
+
B = ()
|
|
36
|
+
|
|
37
|
+
class Col(NamedConstant):
|
|
38
|
+
X = ()
|
|
39
|
+
Y = ()
|
|
40
|
+
|
|
41
|
+
table = NamedConstantTable(
|
|
42
|
+
Row,
|
|
43
|
+
Col,
|
|
44
|
+
A=(1, 2),
|
|
45
|
+
B=(3, 4),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
assert isinstance(table, NamedConstantTable)
|
|
49
|
+
# Access by constant and by name
|
|
50
|
+
assert table[Row.A]['X'] == 1
|
|
51
|
+
assert table['A']['Y'] == 2
|
|
52
|
+
assert table[Row.B]['X'] == 3
|
|
53
|
+
assert table['B']['Y'] == 4
|
|
54
|
+
|
|
55
|
+
# primary_key lookup by secondary key/value
|
|
56
|
+
assert table.primary_key('Y', 2) == Row.A
|
|
57
|
+
assert table.primary_key('Y', 4) == Row.B
|
|
58
|
+
assert table.primary_key('Y', 999) is None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_enum_and_enum_bits_operations():
|
|
62
|
+
class Priority(Enum, seed=1):
|
|
63
|
+
LOW = ()
|
|
64
|
+
MEDIUM = ()
|
|
65
|
+
HIGH = ()
|
|
66
|
+
|
|
67
|
+
assert int(Priority.LOW.value) == 1
|
|
68
|
+
assert int(Priority.MEDIUM.value) == 2
|
|
69
|
+
assert int(Priority.HIGH.value) == 3
|
|
70
|
+
|
|
71
|
+
class Permissions(EnumBits):
|
|
72
|
+
READ = ()
|
|
73
|
+
WRITE = ()
|
|
74
|
+
EXECUTE = ()
|
|
75
|
+
|
|
76
|
+
read = Permissions.READ
|
|
77
|
+
write = Permissions.WRITE
|
|
78
|
+
both = read | write
|
|
79
|
+
assert isinstance(both, Permissions)
|
|
80
|
+
# bitwise ops may return equivalent-but-not-identical instances; compare by value/name
|
|
81
|
+
assert (both & read).value == read.value
|
|
82
|
+
assert (both & write).value == write.value
|
|
83
|
+
assert Permissions.names_from_value(both.value) == ('READ', 'WRITE')
|
|
84
|
+
|
|
85
|
+
# round trips from string/int/tuple via from_any_xstr
|
|
86
|
+
assert Permissions.from_any_xstr(both.value).value == both.value
|
|
87
|
+
assert Permissions.from_any_xstr(('READ', 'WRITE')).value == both.value
|
|
88
|
+
none_const = Permissions.NONE
|
|
89
|
+
assert Permissions.from_any_xstr(()).value == none_const.value
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_error_code_formatting():
|
|
93
|
+
class MyErrors(ErrorCode):
|
|
94
|
+
NOT_FOUND = 'Item {0} not found'
|
|
95
|
+
INVALID_VALUE = 'Invalid value {value}'
|
|
96
|
+
|
|
97
|
+
assert MyErrors.NOT_FOUND(42) == 'Item 42 not found'
|
|
98
|
+
assert MyErrors.INVALID_VALUE(value='X') == 'Invalid value X'
|