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,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'
@@ -0,0 +1,11 @@
1
+ from core_10x.rc import RC
2
+
3
+
4
+ def test_add():
5
+ rc1 = RC(True)
6
+ rc2 = RC(True)
7
+
8
+ assert rc1 and rc2
9
+ rc1 += rc2
10
+
11
+ assert rc1 and rc2