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 @@
|
|
|
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
|