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 @@
1
+ from core_10x.testlib.traitable_history_tests import TestTraitableHistory, test_collection, test_store
@@ -0,0 +1 @@
1
+ from core_10x.testlib.ts_tests import TestTSStore, ts_setup
@@ -0,0 +1,369 @@
1
+ from unittest.mock import MagicMock
2
+
3
+ import pytest
4
+ from core_10x.nucleus import Nucleus
5
+ from core_10x.testlib.test_store import TestStore as TraitableStore
6
+ from core_10x.trait_filter import GT, f
7
+ from core_10x.ts_store import TsStore
8
+ from core_10x.ts_union import TsUnion, TsUnionCollection, _OrderKey
9
+
10
+
11
+ @pytest.fixture
12
+ def union_collection():
13
+ collection1 = MagicMock()
14
+ collection2 = MagicMock()
15
+ union = TsUnionCollection(collection1, collection2)
16
+ return union, collection1, collection2
17
+
18
+
19
+ def test_empty():
20
+ col = TsUnionCollection()
21
+ assert col.collections == ()
22
+
23
+ assert not col.id_exists('1')
24
+ assert not col.exists(f(x=GT(1)))
25
+ assert list(col.find()) == []
26
+ assert col.max('x') is None
27
+ assert col.min('x') is None
28
+ assert col.count() == 0
29
+
30
+
31
+ def test_find(union_collection, args=None):
32
+ union, collection1, collection2 = union_collection
33
+ args = (f(x=GT(1)),) if args is None else args
34
+ collection1.find.return_value = [{Nucleus.ID_TAG(): 2}]
35
+ collection2.find.return_value = [{Nucleus.ID_TAG(): 1}]
36
+ results = list(union.find(*args))
37
+ assert results == [{Nucleus.ID_TAG(): 1}, {Nucleus.ID_TAG(): 2}]
38
+ collection1.find.assert_called_once_with((args and args[0]) or None, _order=None, _at_most=0)
39
+ collection2.find.assert_called_once_with((args and args[0]) or None, _order=None, _at_most=0)
40
+
41
+
42
+ def test_no_args(union_collection):
43
+ test_find(union_collection, args=())
44
+
45
+
46
+ def test_find_empty(union_collection):
47
+ union, collection1, collection2 = union_collection
48
+ collection1.find.return_value = []
49
+ collection2.find.return_value = []
50
+ results = list(union.find())
51
+ assert results == []
52
+
53
+
54
+ def test_save_new(union_collection):
55
+ union, collection1, collection2 = union_collection
56
+ serialized_traitable = {Nucleus.ID_TAG(): 1}
57
+ union.save_new(serialized_traitable)
58
+ collection1.save_new.assert_called_once_with(serialized_traitable, overwrite=False)
59
+ collection2.save.assert_not_called()
60
+
61
+
62
+ def test_save(union_collection):
63
+ union, collection1, collection2 = union_collection
64
+ serialized_traitable = {Nucleus.ID_TAG(): 1}
65
+ collection1.exists.return_value = False
66
+ union.save(serialized_traitable)
67
+ collection1.save_new.assert_called_once_with(serialized_traitable)
68
+ collection1.save.assert_not_called()
69
+ collection2.save_new.assert_not_called()
70
+ collection2.save.assert_not_called()
71
+
72
+ collection1.reset_mock()
73
+ collection1.exists.return_value = True
74
+ union.save(serialized_traitable)
75
+ collection1.save_new.assert_not_called()
76
+ collection1.save.assert_called_once_with(serialized_traitable)
77
+ collection2.save_new.assert_not_called()
78
+ collection2.save.assert_not_called()
79
+
80
+
81
+ def test_delete(union_collection):
82
+ union, collection1, collection2 = union_collection
83
+ id_value = '1'
84
+ collection1.delete.return_value = True
85
+ collection1.count.return_value = 0
86
+ collection2.count.return_value = 0
87
+ result = union.delete(id_value)
88
+ assert result
89
+ collection1.delete.assert_called_once_with(id_value)
90
+ collection2.delete.assert_not_called()
91
+
92
+ collection2.count.return_value = 1
93
+ result = union.delete(id_value)
94
+ assert not result
95
+ collection2.delete.assert_not_called()
96
+
97
+
98
+ def test_create_index(union_collection):
99
+ union, collection1, collection2 = union_collection
100
+ name = 'index_name'
101
+ trait_name = 'trait_name'
102
+ union.create_index(name, trait_name)
103
+ collection1.create_index.assert_called_once_with(name, trait_name)
104
+ collection2.create_index.assert_not_called()
105
+
106
+
107
+ def test_max(union_collection):
108
+ union, collection1, collection2 = union_collection
109
+ trait_name = 'trait_name'
110
+ collection1.max.return_value = {'trait_name': 1}
111
+ collection2.max.return_value = {'trait_name': 2}
112
+ result = union.max(trait_name)
113
+ assert result == {'trait_name': 2}
114
+ collection1.max.assert_called_once_with(trait_name, None)
115
+ collection2.max.assert_called_once_with(trait_name, None)
116
+
117
+
118
+ def test_max_empty(union_collection):
119
+ union, collection1, collection2 = union_collection
120
+ trait_name = 'trait_name'
121
+ collection1.max.return_value = None
122
+ collection2.max.return_value = None
123
+ result = union.max(trait_name)
124
+ assert result is None
125
+
126
+
127
+ def test_min(union_collection):
128
+ union, collection1, collection2 = union_collection
129
+ trait_name = 'trait_name'
130
+ collection1.min.return_value = {'trait_name': 1}
131
+ collection2.min.return_value = {'trait_name': 2}
132
+ result = union.min(trait_name)
133
+ assert result == {'trait_name': 1}
134
+ collection1.min.assert_called_once_with(trait_name, None)
135
+ collection2.min.assert_called_once_with(trait_name, None)
136
+
137
+
138
+ def test_min_empty(union_collection):
139
+ union, collection1, collection2 = union_collection
140
+ trait_name = 'trait_name'
141
+ collection1.min.return_value = None
142
+ collection2.min.return_value = None
143
+ result = union.min(trait_name)
144
+ assert result is None
145
+
146
+
147
+ def test_multiple_sort_keys(union_collection):
148
+ union, collection1, collection2 = union_collection
149
+ data1 = [
150
+ {'_id': '1', 'group': 'A', 'value': 30},
151
+ {'_id': '2', 'group': 'A', 'value': 10},
152
+ {'_id': '3', 'group': 'B', 'value': 10},
153
+ ]
154
+ data2 = [
155
+ {'_id': '5', 'group': 'A', 'value': 40},
156
+ {'_id': '6', 'group': 'B', 'value': 20},
157
+ {'_id': '7', 'group': 'B', 'value': 20},
158
+ ]
159
+ collection1.find.return_value = data1
160
+ collection2.find.return_value = data2
161
+
162
+ # Test multiple sort keys
163
+ results = list(union.find(_order={'group': 1, 'value': -1}))
164
+ sorted_results = [
165
+ {'_id': '5', 'group': 'A', 'value': 40},
166
+ {'_id': '1', 'group': 'A', 'value': 30},
167
+ {'_id': '2', 'group': 'A', 'value': 10},
168
+ {'_id': '6', 'group': 'B', 'value': 20},
169
+ {'_id': '7', 'group': 'B', 'value': 20},
170
+ {'_id': '3', 'group': 'B', 'value': 10},
171
+ ]
172
+ assert results == sorted_results
173
+
174
+
175
+ def test_none_handling(union_collection):
176
+ union, collection1, collection2 = union_collection
177
+ data2 = [
178
+ {'_id': '2', 'value': 20},
179
+ {'_id': '4', 'value': 40},
180
+ ]
181
+ collection1.find.return_value = None
182
+ collection2.find.return_value = data2
183
+
184
+ # Test handling None results
185
+ results = list(union.find())
186
+ assert len(results) == 2
187
+ assert [r['_id'] for r in results] == ['2', '4']
188
+
189
+ # Test all collections returning None
190
+ collection2.find.return_value = None
191
+ results = list(union.find())
192
+ assert len(results) == 0
193
+
194
+
195
+ def test_sorting(union_collection):
196
+ union, collection1, collection2 = union_collection
197
+ data1 = [
198
+ {'_id': '1', 'value': 30},
199
+ {'_id': '3', 'value': 10},
200
+ ]
201
+ data2 = [
202
+ {'_id': '2', 'value': 40},
203
+ {'_id': '4', 'value': 20},
204
+ ]
205
+ collection1.find.return_value = data1
206
+ collection2.find.return_value = data2
207
+
208
+ # Test default sorting by _id ascending
209
+ results = list(union.find())
210
+ assert len(results) == 4
211
+ assert [r['_id'] for r in results] == ['1', '2', '3', '4']
212
+
213
+ # Test descending sort by value with limit
214
+ results = list(union.find(_order={'value': -1}, _at_most=2))
215
+ assert [r['value'] for r in results] == [40, 30]
216
+
217
+ # Test ascending sort by value with limit
218
+ collection1.find.return_value = reversed(data1)
219
+ collection2.find.return_value = reversed(data2)
220
+ results = list(union.find(_order={'value': 1}, _at_most=3))
221
+ assert len(results) == 3
222
+ assert [r['value'] for r in results] == [10, 20, 30]
223
+
224
+
225
+ def test_sorting_dict(union_collection):
226
+ union, collection1, collection2 = union_collection
227
+ data1 = [
228
+ {'_id': '1', 'dict_field': {'a': 1, 'b': 2}},
229
+ {'_id': '3', 'dict_field': {'a': 2, 'b': 1}},
230
+ ]
231
+ data2 = [
232
+ {'_id': '2', 'dict_field': {'a': 1, 'b': 3}},
233
+ {'_id': '4', 'dict_field': {'a': 2, 'b': 2}},
234
+ ]
235
+ # Test ascending sort by dict field
236
+ collection1.find.return_value = data1
237
+ collection2.find.return_value = data2
238
+ results = list(union.find(_order={'dict_field': 1}))
239
+ assert len(results) == 4
240
+ assert [r['_id'] for r in results] == ['1', '2', '3', '4']
241
+
242
+ # Test descending sort by dict field
243
+ collection1.find.return_value = reversed(data1)
244
+ collection2.find.return_value = reversed(data2)
245
+ results = list(union.find(_order={'dict_field': -1}))
246
+ assert len(results) == 4
247
+ assert [r['_id'] for r in results] == ['3', '1', '4', '2']
248
+
249
+
250
+ @pytest.fixture
251
+ def union_store():
252
+ mock_store1 = MagicMock()
253
+ mock_store2 = MagicMock()
254
+ union_store = TsUnion(mock_store1, mock_store2)
255
+ return union_store, mock_store1, mock_store2
256
+
257
+
258
+ def test_collection_names(union_store):
259
+ union_store, mock_store1, mock_store2 = union_store
260
+ mock_store1.collection_names.return_value = ['collection1']
261
+ mock_store2.collection_names.return_value = ['collection2']
262
+ result = union_store.collection_names()
263
+ assert set(result) == {'collection1', 'collection2'}
264
+ mock_store1.collection_names.assert_called_once()
265
+ mock_store2.collection_names.assert_called_once()
266
+
267
+
268
+ def test_collection(union_store):
269
+ union_store, mock_store1, mock_store2 = union_store
270
+ collection_name = 'collection_name'
271
+ mock_store1.collection.return_value = MagicMock()
272
+ mock_store2.collection.return_value = MagicMock()
273
+ result = union_store.collection(collection_name)
274
+ assert isinstance(result, TsUnionCollection)
275
+ mock_store1.collection.assert_called_once_with(collection_name)
276
+ mock_store2.collection.assert_called_once_with(collection_name)
277
+
278
+
279
+ def test_delete_collection(union_store):
280
+ union_store, mock_store1, mock_store2 = union_store
281
+ collection_name = 'collection_name'
282
+ union_store.delete_collection(collection_name)
283
+ mock_store1.delete_collection.assert_called_once_with(collection_name)
284
+ mock_store2.delete_collection.assert_not_called()
285
+
286
+
287
+ @pytest.fixture
288
+ def ts_union():
289
+ assert not TsUnion.s_instances
290
+ store_spec = dict(driver_name='TEST_DB', hostname='localhost', dbname='dbname1', username='')
291
+ union_store = TsUnion.instance(store_spec, store_spec | dict(dbname='dbname2'))
292
+ yield union_store
293
+ TsUnion.s_instances.clear()
294
+
295
+
296
+ def test_new_instance(ts_union):
297
+ assert isinstance(ts_union, TsUnion)
298
+ assert all(isinstance(store, TraitableStore) for store in ts_union.stores)
299
+
300
+ assert sum(1 for v in TsStore.s_instances.values() if isinstance(v, TsUnion)) == 1
301
+ assert sum(1 for v in TsStore.s_instances.values() if isinstance(v, TraitableStore)) == 2
302
+
303
+ assert list(TsUnion.s_instances.keys()) == [
304
+ (('dbname', 'dbname1'), ('hostname', 'localhost'), ('username', '')),
305
+ (('dbname', 'dbname2'), ('hostname', 'localhost'), ('username', '')),
306
+ (
307
+ (('dbname', 'dbname1'), ('driver_name', 'TEST_DB'), ('hostname', 'localhost'), ('username', '')),
308
+ (('dbname', 'dbname2'), ('driver_name', 'TEST_DB'), ('hostname', 'localhost'), ('username', '')),
309
+ ),
310
+ ]
311
+
312
+
313
+ def test_equal_same_order():
314
+ assert 0 == _OrderKey._dict_cmp({'a': 1, 'b': 2}, {'a': 1, 'b': 2})
315
+
316
+
317
+ def test_equal_different_order():
318
+ assert 1 == _OrderKey._dict_cmp({'b': 1, 'a': 2}, {'a': 2, 'b': 1})
319
+ assert -1 == _OrderKey._dict_cmp({'a': 1, 'b': 2}, {'b': 2, 'a': 1})
320
+
321
+
322
+ def test_less_key_order():
323
+ assert -1 == _OrderKey._dict_cmp({'a': 1, 'b': 2}, {'b': 2, 'a': 1}) # 'a' < 'b'
324
+
325
+
326
+ def test_greater_key_order():
327
+ assert 1 == _OrderKey._dict_cmp({'b': 2, 'a': 1}, {'a': 1, 'b': 2}) # 'b' > 'a'
328
+
329
+
330
+ def test_less_value():
331
+ assert -1 == _OrderKey._dict_cmp({'a': 1, 'b': 2}, {'a': 1, 'b': 3})
332
+
333
+
334
+ def test_greater_value():
335
+ assert 1 == _OrderKey._dict_cmp({'a': 1, 'b': 3}, {'a': 1, 'b': 2})
336
+
337
+
338
+ def test_shorter_less():
339
+ assert -1 == _OrderKey._dict_cmp({'a': 1}, {'a': 1, 'b': 2})
340
+
341
+
342
+ def test_longer_greater():
343
+ assert 1 == _OrderKey._dict_cmp({'a': 1, 'b': 2}, {'a': 1})
344
+
345
+
346
+ def test_nested_less():
347
+ assert -1 == _OrderKey._dict_cmp({'a': {'x': 1}}, {'a': {'y': 2}}) # 'x' < 'y'
348
+
349
+
350
+ def test_nested_greater():
351
+ assert 1 == _OrderKey._dict_cmp({'a': {'y': 2}}, {'a': {'x': 1}}) # 'y' > 'x'
352
+
353
+
354
+ def test_example_from_query():
355
+ d = {'y': 20, 'x': 10} # order: y, x
356
+ od = {'x': 10, 'y': 25} # order: x, y
357
+ assert 1 == _OrderKey._dict_cmp(d, od) # 'y' > 'x'
358
+
359
+
360
+ def test_counterexample_values_ignored_on_key_diff():
361
+ d = {'a': 100}
362
+ od = {'b': 1}
363
+ assert -1 == _OrderKey._dict_cmp(d, od) # 'a' < 'b', values ignored
364
+
365
+
366
+ def test_counterexample_early_value_diff():
367
+ d = {'a': 1, 'c': 4}
368
+ od = {'a': 2, 'b': 3}
369
+ assert -1 == _OrderKey._dict_cmp(d, od) # 1 < 2, later ignored
@@ -0,0 +1,81 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import partial
4
+ from unittest.mock import MagicMock
5
+
6
+ import pytest
7
+ from core_10x.exec_control import BTP, INTERACTIVE
8
+ from core_10x.rc import RC
9
+ from core_10x.trait_method_error import TraitMethodError
10
+ from core_10x.traitable import Traitable
11
+
12
+
13
+ class X(Traitable):
14
+ x: int
15
+ y: int
16
+ z: int
17
+
18
+ def x_set(self, trait, value) -> RC:
19
+ self.raw_set_value(trait, value)
20
+ return self.set_values(y=value)
21
+
22
+ def z_get(self):
23
+ return self.x
24
+
25
+
26
+ def callback(btp, x, t, v):
27
+ assert btp is BTP.current()
28
+ # assert x.get_value(t) == v
29
+ print(btp, BTP.current())
30
+ x.bui_class().update_ui_node(x, t)
31
+
32
+
33
+ def test_ui_nodes():
34
+ x = X(x=1)
35
+
36
+ def t(ov, v):
37
+ mx = MagicMock(side_effect=partial(callback, BTP.current(), x, x.T.x, v))
38
+ my = MagicMock(side_effect=partial(callback, BTP.current(), x, x.T.y, v))
39
+ mz = MagicMock(side_effect=partial(callback, BTP.current(), x, x.T.z, v))
40
+ x.bui_class().create_ui_node(x, x.T.x, mx)
41
+ x.bui_class().create_ui_node(x, x.T.y, my)
42
+ x.bui_class().create_ui_node(x, x.T.z, mz)
43
+
44
+ assert x.x == x.y == x.z == ov
45
+
46
+ x.x = v
47
+
48
+ assert mx.call_count == my.call_count == mz.call_count == 1
49
+ assert x.x == x.y == x.z == v
50
+
51
+ return mx, my, mz
52
+
53
+ with INTERACTIVE() as i0:
54
+ print(i0)
55
+ mx, my, mz = t(1, 2)
56
+ with INTERACTIVE() as i:
57
+ print(i)
58
+ t(2, 3)
59
+ i.export_nodes()
60
+ assert x.x == x.y == x.z == 3
61
+ assert mx.call_count == my.call_count == mz.call_count == 2
62
+
63
+
64
+ def test_exception():
65
+ def callback():
66
+ x.bui_class().update_ui_node(x, x.T.x) # TODO: should not be required when throwing
67
+ raise RuntimeError('test')
68
+
69
+ x = X(x=1)
70
+ with INTERACTIVE():
71
+ m = MagicMock(side_effect=callback)
72
+ x.bui_class().create_ui_node(x, x.T.x, m)
73
+ with pytest.raises(TraitMethodError): # TODO: should be throwing RuntimeError?
74
+ x.x = 2
75
+ assert x.x == 2 # TODO: should not set value when callback failed?
76
+ with INTERACTIVE() as i:
77
+ x.x = 3
78
+ with pytest.raises(RuntimeError): # TODO: RuntimeError or TraitMethodError?
79
+ i.export_nodes()
80
+
81
+ assert m.call_count == 2