exdrf 0.0.1.dev0__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.
- exdrf/__init__.py +0 -0
- exdrf/__version__.py +24 -0
- exdrf/api.py +51 -0
- exdrf/constants.py +30 -0
- exdrf/dataset.py +197 -0
- exdrf/field.py +554 -0
- exdrf/field_types/__init__.py +0 -0
- exdrf/field_types/api.py +78 -0
- exdrf/field_types/blob_field.py +44 -0
- exdrf/field_types/bool_field.py +47 -0
- exdrf/field_types/date_field.py +49 -0
- exdrf/field_types/date_time.py +52 -0
- exdrf/field_types/dur_field.py +44 -0
- exdrf/field_types/enum_field.py +41 -0
- exdrf/field_types/filter_field.py +11 -0
- exdrf/field_types/float_field.py +85 -0
- exdrf/field_types/float_list.py +18 -0
- exdrf/field_types/formatted.py +39 -0
- exdrf/field_types/int_field.py +70 -0
- exdrf/field_types/int_list.py +18 -0
- exdrf/field_types/ref_base.py +105 -0
- exdrf/field_types/ref_m2m.py +39 -0
- exdrf/field_types/ref_m2o.py +23 -0
- exdrf/field_types/ref_o2m.py +36 -0
- exdrf/field_types/ref_o2o.py +32 -0
- exdrf/field_types/sort_field.py +18 -0
- exdrf/field_types/str_field.py +77 -0
- exdrf/field_types/str_list.py +18 -0
- exdrf/field_types/time_field.py +49 -0
- exdrf/filter.py +653 -0
- exdrf/filter_dsl.py +950 -0
- exdrf/filter_op_catalog.py +222 -0
- exdrf/label_dsl.py +691 -0
- exdrf/moment.py +496 -0
- exdrf/py.typed +0 -0
- exdrf/py_support.py +21 -0
- exdrf/resource.py +901 -0
- exdrf/sa_fi_item.py +69 -0
- exdrf/sa_filter_op.py +324 -0
- exdrf/utils.py +17 -0
- exdrf/validator.py +45 -0
- exdrf/var_bag.py +328 -0
- exdrf/visitor.py +58 -0
- exdrf-0.0.1.dev0.dist-info/METADATA +42 -0
- exdrf-0.0.1.dev0.dist-info/RECORD +57 -0
- exdrf-0.0.1.dev0.dist-info/WHEEL +5 -0
- exdrf-0.0.1.dev0.dist-info/top_level.txt +3 -0
- exdrf_tests/__init__.py +0 -0
- exdrf_tests/test_dataset.py +422 -0
- exdrf_tests/test_field.py +109 -0
- exdrf_tests/test_filter.py +425 -0
- exdrf_tests/test_filter_dsl.py +556 -0
- exdrf_tests/test_label_dsl.py +234 -0
- exdrf_tests/test_resource.py +107 -0
- exdrf_tests/test_utils.py +43 -0
- exdrf_tests/test_visitor.py +31 -0
- exdrf_tests/var_bag_test.py +502 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from exdrf.dataset import ExDataset
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_exdataset_hash():
|
|
7
|
+
# Create two datasets with the same name
|
|
8
|
+
dataset1 = ExDataset(name="TestDataset")
|
|
9
|
+
dataset2 = ExDataset(name="TestDataset")
|
|
10
|
+
|
|
11
|
+
# Create a dataset with a different name
|
|
12
|
+
dataset3 = ExDataset(name="AnotherDataset")
|
|
13
|
+
|
|
14
|
+
# Assert that datasets with the same name have the same hash
|
|
15
|
+
assert hash(dataset1) == hash(dataset2)
|
|
16
|
+
|
|
17
|
+
# Assert that datasets with different names have different hashes
|
|
18
|
+
assert hash(dataset1) != hash(dataset3)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TestExDatasetGetItem:
|
|
22
|
+
def test_by_index(self):
|
|
23
|
+
# Create a mock resource
|
|
24
|
+
mock_resource = type("MockResource", (), {"name": "Resource1"})()
|
|
25
|
+
|
|
26
|
+
# Create a dataset and add the mock resource
|
|
27
|
+
dataset = ExDataset()
|
|
28
|
+
dataset.resources.append(mock_resource)
|
|
29
|
+
|
|
30
|
+
# Access the resource by index
|
|
31
|
+
assert dataset[0] == mock_resource
|
|
32
|
+
|
|
33
|
+
def test_by_name(self):
|
|
34
|
+
# Create mock resources
|
|
35
|
+
mock_resource1 = type("MockResource", (), {"name": "Resource1"})()
|
|
36
|
+
mock_resource2 = type("MockResource", (), {"name": "Resource2"})()
|
|
37
|
+
|
|
38
|
+
# Create a dataset and add the mock resources
|
|
39
|
+
dataset = ExDataset()
|
|
40
|
+
dataset.resources.extend([mock_resource1, mock_resource2])
|
|
41
|
+
|
|
42
|
+
# Access the resources by name
|
|
43
|
+
assert dataset["Resource1"] == mock_resource1
|
|
44
|
+
assert dataset["Resource2"] == mock_resource2
|
|
45
|
+
|
|
46
|
+
def test_invalid_index(self):
|
|
47
|
+
# Create a dataset with no resources
|
|
48
|
+
dataset = ExDataset()
|
|
49
|
+
|
|
50
|
+
# Attempt to access an invalid index
|
|
51
|
+
with pytest.raises(IndexError):
|
|
52
|
+
_ = dataset[0]
|
|
53
|
+
|
|
54
|
+
def test_invalid_name(self):
|
|
55
|
+
# Create a mock resource
|
|
56
|
+
mock_resource = type("MockResource", (), {"name": "Resource1"})()
|
|
57
|
+
|
|
58
|
+
# Create a dataset and add the mock resource
|
|
59
|
+
dataset = ExDataset()
|
|
60
|
+
dataset.resources.append(mock_resource)
|
|
61
|
+
|
|
62
|
+
# Attempt to access a resource by an invalid name
|
|
63
|
+
with pytest.raises(KeyError, match="No resource found for key: InvalidName"):
|
|
64
|
+
_ = dataset["InvalidName"]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class TestExDatasetAddResource:
|
|
68
|
+
def test_add_valid_resource(self):
|
|
69
|
+
# Create a mock resource
|
|
70
|
+
mock_resource = type(
|
|
71
|
+
"MockResource",
|
|
72
|
+
(),
|
|
73
|
+
{"name": "Resource1", "categories": ["Category1", "SubCategory1"]},
|
|
74
|
+
)()
|
|
75
|
+
|
|
76
|
+
# Create a dataset and add the mock resource
|
|
77
|
+
dataset = ExDataset(res_class=type(mock_resource))
|
|
78
|
+
dataset.add_resource(mock_resource)
|
|
79
|
+
|
|
80
|
+
# Assert that the resource is added to the dataset
|
|
81
|
+
assert mock_resource in dataset.resources
|
|
82
|
+
assert (
|
|
83
|
+
dataset.category_map["Category1"]["SubCategory1"]["Resource1"]
|
|
84
|
+
== mock_resource
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def test_add_invalid_resource_type(self):
|
|
88
|
+
# Create a mock resource of a different type
|
|
89
|
+
mock_resource = type("InvalidResource", (), {"name": "Resource1"})()
|
|
90
|
+
|
|
91
|
+
# Create a dataset with a specific resource class
|
|
92
|
+
dataset = ExDataset(res_class=type("ValidResource", (), {}))
|
|
93
|
+
|
|
94
|
+
# Attempt to add the invalid resource and assert a TypeError is raised
|
|
95
|
+
with pytest.raises(TypeError, match="Expected resource of type"):
|
|
96
|
+
dataset.add_resource(mock_resource)
|
|
97
|
+
|
|
98
|
+
def test_add_resource_updates_category_map(self):
|
|
99
|
+
# Create a shared MockResource class
|
|
100
|
+
MockResource = type(
|
|
101
|
+
"MockResource",
|
|
102
|
+
(),
|
|
103
|
+
{},
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Create mock resources
|
|
107
|
+
mock_resource1 = MockResource()
|
|
108
|
+
mock_resource1.name = "Resource1"
|
|
109
|
+
mock_resource1.categories = ["Category1"]
|
|
110
|
+
|
|
111
|
+
mock_resource2 = MockResource()
|
|
112
|
+
mock_resource2.name = "Resource2"
|
|
113
|
+
mock_resource2.categories = ["Category1", "SubCategory1"]
|
|
114
|
+
|
|
115
|
+
# Create a dataset and add the mock resources
|
|
116
|
+
dataset = ExDataset(res_class=MockResource)
|
|
117
|
+
dataset.add_resource(mock_resource1)
|
|
118
|
+
dataset.add_resource(mock_resource2)
|
|
119
|
+
|
|
120
|
+
# Assert that the category map is updated correctly
|
|
121
|
+
assert "Category1" in dataset.category_map
|
|
122
|
+
assert "SubCategory1" in dataset.category_map["Category1"]
|
|
123
|
+
assert dataset.category_map["Category1"]["Resource1"] == mock_resource1
|
|
124
|
+
assert (
|
|
125
|
+
dataset.category_map["Category1"]["SubCategory1"]["Resource2"]
|
|
126
|
+
== mock_resource2
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class TestExDatasetVisit:
|
|
131
|
+
def test_visit_dataset(self, mocker):
|
|
132
|
+
# Create a mock visitor
|
|
133
|
+
mock_visitor = mocker.Mock()
|
|
134
|
+
mock_visitor.visit_dataset.return_value = True
|
|
135
|
+
|
|
136
|
+
# Create a mock resource
|
|
137
|
+
mock_resource = mocker.Mock()
|
|
138
|
+
mock_resource.visit.return_value = True
|
|
139
|
+
mock_resource.name = "TestResource"
|
|
140
|
+
|
|
141
|
+
# Create a dataset and add the mock resource
|
|
142
|
+
dataset = ExDataset()
|
|
143
|
+
dataset.resources.append(mock_resource)
|
|
144
|
+
dataset.category_map["TestResource"] = mock_resource
|
|
145
|
+
|
|
146
|
+
# Call the visit method
|
|
147
|
+
result = dataset.visit(mock_visitor)
|
|
148
|
+
|
|
149
|
+
# Assert that the visitor's visit_dataset method was called
|
|
150
|
+
mock_visitor.visit_dataset.assert_called_once_with(dataset)
|
|
151
|
+
|
|
152
|
+
# Assert that the resource's visit method was called
|
|
153
|
+
mock_resource.visit.assert_called_once_with(mock_visitor, omit_fields=False)
|
|
154
|
+
|
|
155
|
+
# Assert that the visit method returned True
|
|
156
|
+
assert result is True
|
|
157
|
+
|
|
158
|
+
def test_visit_dataset_stops_on_false(self, mocker):
|
|
159
|
+
# Create a mock visitor
|
|
160
|
+
mock_visitor = mocker.Mock()
|
|
161
|
+
mock_visitor.visit_dataset.return_value = False
|
|
162
|
+
|
|
163
|
+
# Create a dataset
|
|
164
|
+
dataset = ExDataset()
|
|
165
|
+
|
|
166
|
+
# Call the visit method
|
|
167
|
+
result = dataset.visit(mock_visitor)
|
|
168
|
+
|
|
169
|
+
# Assert that the visitor's visit_dataset method was called
|
|
170
|
+
mock_visitor.visit_dataset.assert_called_once_with(dataset)
|
|
171
|
+
|
|
172
|
+
# Assert that the visit method returned False
|
|
173
|
+
assert result is False
|
|
174
|
+
|
|
175
|
+
def test_visit_omit_categories(self, mocker):
|
|
176
|
+
# Create a mock visitor
|
|
177
|
+
mock_visitor = mocker.Mock()
|
|
178
|
+
mock_visitor.visit_dataset.return_value = True
|
|
179
|
+
|
|
180
|
+
# Create mock resources
|
|
181
|
+
mock_resource1 = mocker.Mock()
|
|
182
|
+
mock_resource1.visit.return_value = True
|
|
183
|
+
mock_resource2 = mocker.Mock()
|
|
184
|
+
mock_resource2.visit.return_value = True
|
|
185
|
+
|
|
186
|
+
# Create a dataset and add the mock resources
|
|
187
|
+
dataset = ExDataset()
|
|
188
|
+
dataset.resources.extend([mock_resource1, mock_resource2])
|
|
189
|
+
|
|
190
|
+
# Call the visit method with omit_categories=True
|
|
191
|
+
result = dataset.visit(mock_visitor, omit_categories=True)
|
|
192
|
+
|
|
193
|
+
# Assert that the visitor's visit_dataset method was called
|
|
194
|
+
mock_visitor.visit_dataset.assert_called_once_with(dataset)
|
|
195
|
+
|
|
196
|
+
# Assert that each resource's visit method was called
|
|
197
|
+
mock_resource1.visit.assert_called_once_with(mock_visitor, omit_fields=False)
|
|
198
|
+
mock_resource2.visit.assert_called_once_with(mock_visitor, omit_fields=False)
|
|
199
|
+
|
|
200
|
+
# Assert that the visit method returned True
|
|
201
|
+
assert result is True
|
|
202
|
+
|
|
203
|
+
def test_visit_category_map(self, mocker):
|
|
204
|
+
# Create a mock visitor
|
|
205
|
+
mock_visitor = mocker.Mock()
|
|
206
|
+
mock_visitor.visit_dataset.return_value = True
|
|
207
|
+
mock_visitor.visit_category = mocker.Mock()
|
|
208
|
+
|
|
209
|
+
# Create mock resources
|
|
210
|
+
mock_resource1 = mocker.Mock()
|
|
211
|
+
mock_resource1.visit.return_value = True
|
|
212
|
+
mock_resource1.name = "Resource1"
|
|
213
|
+
mock_resource2 = mocker.Mock()
|
|
214
|
+
mock_resource2.visit.return_value = True
|
|
215
|
+
mock_resource2.name = "Resource2"
|
|
216
|
+
|
|
217
|
+
# Create a dataset and add the mock resources
|
|
218
|
+
dataset = ExDataset()
|
|
219
|
+
dataset.category_map = {
|
|
220
|
+
"Category1": {
|
|
221
|
+
"SubCategory1": {"Resource1": mock_resource1},
|
|
222
|
+
"Resource2": mock_resource2,
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
# Call the visit method
|
|
227
|
+
result = dataset.visit(mock_visitor)
|
|
228
|
+
|
|
229
|
+
# Assert that the visitor's visit_dataset method was called
|
|
230
|
+
mock_visitor.visit_dataset.assert_called_once_with(dataset)
|
|
231
|
+
|
|
232
|
+
# Assert visit_category was called for each category.
|
|
233
|
+
mock_visitor.visit_category.assert_any_call("Category1", 0, mocker.ANY)
|
|
234
|
+
mock_visitor.visit_category.assert_any_call("SubCategory1", 1, mocker.ANY)
|
|
235
|
+
|
|
236
|
+
# Assert that each resource's visit method was called
|
|
237
|
+
mock_resource1.visit.assert_called_once_with(mock_visitor, omit_fields=False)
|
|
238
|
+
mock_resource2.visit.assert_called_once_with(mock_visitor, omit_fields=False)
|
|
239
|
+
|
|
240
|
+
# Assert that the visit method returned True
|
|
241
|
+
assert result is True
|
|
242
|
+
|
|
243
|
+
def test_visit_category_map_stops_on_false(self, mocker):
|
|
244
|
+
# Create a mock visitor
|
|
245
|
+
mock_visitor = mocker.Mock()
|
|
246
|
+
mock_visitor.visit_dataset.return_value = True
|
|
247
|
+
mock_visitor.visit_category = mocker.Mock(return_value=True)
|
|
248
|
+
|
|
249
|
+
# Create a mock resource that returns False for visit
|
|
250
|
+
mock_resource = mocker.Mock()
|
|
251
|
+
mock_resource.visit.return_value = False
|
|
252
|
+
mock_resource.name = "Resource1"
|
|
253
|
+
|
|
254
|
+
# Create a dataset and add the mock resource
|
|
255
|
+
dataset = ExDataset()
|
|
256
|
+
dataset.category_map = {"Category1": {"Resource1": mock_resource}}
|
|
257
|
+
|
|
258
|
+
# Call the visit method
|
|
259
|
+
result = dataset.visit(mock_visitor)
|
|
260
|
+
|
|
261
|
+
# Assert that the visitor's visit_dataset method was called
|
|
262
|
+
mock_visitor.visit_dataset.assert_called_once_with(dataset)
|
|
263
|
+
|
|
264
|
+
# Assert that the resource's visit method was called
|
|
265
|
+
mock_resource.visit.assert_called_once_with(mock_visitor, omit_fields=False)
|
|
266
|
+
|
|
267
|
+
# Assert that the visit method returned False
|
|
268
|
+
assert result is False
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class TestExDatasetSortedByDeps:
|
|
272
|
+
def test_sorted_by_deps_no_dependencies(self):
|
|
273
|
+
# Create mock resources with no dependencies
|
|
274
|
+
mock_resource1 = type(
|
|
275
|
+
"MockResource",
|
|
276
|
+
(),
|
|
277
|
+
{
|
|
278
|
+
"name": "Resource1",
|
|
279
|
+
"get_dependencies": lambda self, fk_only=False: [],
|
|
280
|
+
},
|
|
281
|
+
)()
|
|
282
|
+
mock_resource2 = type(
|
|
283
|
+
"MockResource",
|
|
284
|
+
(),
|
|
285
|
+
{
|
|
286
|
+
"name": "Resource2",
|
|
287
|
+
"get_dependencies": lambda self, fk_only=False: [],
|
|
288
|
+
},
|
|
289
|
+
)()
|
|
290
|
+
|
|
291
|
+
# Create a dataset and add the mock resources
|
|
292
|
+
dataset = ExDataset()
|
|
293
|
+
dataset.resources.extend([mock_resource1, mock_resource2])
|
|
294
|
+
|
|
295
|
+
# Call sorted_by_deps
|
|
296
|
+
sorted_resources = dataset.sorted_by_deps()
|
|
297
|
+
|
|
298
|
+
# Assert that the resources are sorted correctly
|
|
299
|
+
assert sorted_resources == [mock_resource1, mock_resource2]
|
|
300
|
+
|
|
301
|
+
def test_sorted_by_deps_with_dependencies(self):
|
|
302
|
+
# Create mock resources with dependencies
|
|
303
|
+
mock_resource1 = type(
|
|
304
|
+
"MockResource",
|
|
305
|
+
(),
|
|
306
|
+
{
|
|
307
|
+
"name": "Resource1",
|
|
308
|
+
"get_dependencies": lambda self, fk_only=False: [],
|
|
309
|
+
},
|
|
310
|
+
)()
|
|
311
|
+
mock_resource2 = type(
|
|
312
|
+
"MockResource",
|
|
313
|
+
(),
|
|
314
|
+
{
|
|
315
|
+
"name": "Resource2",
|
|
316
|
+
"get_dependencies": lambda self, fk_only=False: (
|
|
317
|
+
[] if fk_only else [mock_resource1]
|
|
318
|
+
),
|
|
319
|
+
},
|
|
320
|
+
)()
|
|
321
|
+
mock_resource3 = type(
|
|
322
|
+
"MockResource",
|
|
323
|
+
(),
|
|
324
|
+
{
|
|
325
|
+
"name": "Resource3",
|
|
326
|
+
"get_dependencies": lambda self, fk_only=False: (
|
|
327
|
+
[] if fk_only else [mock_resource2]
|
|
328
|
+
),
|
|
329
|
+
},
|
|
330
|
+
)()
|
|
331
|
+
|
|
332
|
+
# Create a dataset and add the mock resources
|
|
333
|
+
dataset = ExDataset()
|
|
334
|
+
dataset.resources.extend([mock_resource3, mock_resource2, mock_resource1])
|
|
335
|
+
|
|
336
|
+
# Call sorted_by_deps
|
|
337
|
+
sorted_resources = dataset.sorted_by_deps()
|
|
338
|
+
|
|
339
|
+
# Assert that the resources are sorted correctly
|
|
340
|
+
assert sorted_resources == [
|
|
341
|
+
mock_resource1,
|
|
342
|
+
mock_resource2,
|
|
343
|
+
mock_resource3,
|
|
344
|
+
]
|
|
345
|
+
|
|
346
|
+
def test_sorted_by_deps_with_circular_dependency(self, capsys):
|
|
347
|
+
# Create mock resources with circular dependencies
|
|
348
|
+
mock_resource1 = type(
|
|
349
|
+
"MockResource",
|
|
350
|
+
(),
|
|
351
|
+
{
|
|
352
|
+
"name": "Resource1",
|
|
353
|
+
"get_dependencies": lambda self, fk_only=False: (
|
|
354
|
+
[] if fk_only else [mock_resource2]
|
|
355
|
+
),
|
|
356
|
+
},
|
|
357
|
+
)()
|
|
358
|
+
mock_resource2 = type(
|
|
359
|
+
"MockResource",
|
|
360
|
+
(),
|
|
361
|
+
{
|
|
362
|
+
"name": "Resource2",
|
|
363
|
+
"get_dependencies": lambda self, fk_only=False: (
|
|
364
|
+
[] if fk_only else [mock_resource1]
|
|
365
|
+
),
|
|
366
|
+
},
|
|
367
|
+
)()
|
|
368
|
+
|
|
369
|
+
# Create a dataset and add the mock resources
|
|
370
|
+
dataset = ExDataset()
|
|
371
|
+
dataset.resources.extend([mock_resource1, mock_resource2])
|
|
372
|
+
|
|
373
|
+
# Call sorted_by_deps; circular deps may print a warning.
|
|
374
|
+
sorted_resources = dataset.sorted_by_deps()
|
|
375
|
+
|
|
376
|
+
# Capture the output after calling sorted_by_deps
|
|
377
|
+
captured = capsys.readouterr()
|
|
378
|
+
|
|
379
|
+
# The circular dependency detection happens in recursive function
|
|
380
|
+
# and prints to stdout. Check if it was captured.
|
|
381
|
+
output = captured.out
|
|
382
|
+
if "Circular dependency detected" not in output:
|
|
383
|
+
# If not captured, function still works but warning may not print.
|
|
384
|
+
# depending on execution path. Just verify the function completes.
|
|
385
|
+
pass
|
|
386
|
+
|
|
387
|
+
# Assert that the sorted resources are returned (partial order)
|
|
388
|
+
# Even with circular deps, the function should return resources
|
|
389
|
+
assert len(sorted_resources) == 2
|
|
390
|
+
assert mock_resource1 in sorted_resources
|
|
391
|
+
assert mock_resource2 in sorted_resources
|
|
392
|
+
|
|
393
|
+
def test_sorted_by_deps_with_fk_only_dependencies(self):
|
|
394
|
+
# Create mock resources with foreign key-only dependencies
|
|
395
|
+
mock_resource1 = type(
|
|
396
|
+
"MockResource",
|
|
397
|
+
(),
|
|
398
|
+
{
|
|
399
|
+
"name": "Resource1",
|
|
400
|
+
"get_dependencies": lambda self, fk_only=False: [],
|
|
401
|
+
},
|
|
402
|
+
)()
|
|
403
|
+
mock_resource2 = type(
|
|
404
|
+
"MockResource",
|
|
405
|
+
(),
|
|
406
|
+
{
|
|
407
|
+
"name": "Resource2",
|
|
408
|
+
"get_dependencies": lambda self, fk_only=False: (
|
|
409
|
+
[mock_resource1] if fk_only else [mock_resource1]
|
|
410
|
+
),
|
|
411
|
+
},
|
|
412
|
+
)()
|
|
413
|
+
|
|
414
|
+
# Create a dataset and add the mock resources
|
|
415
|
+
dataset = ExDataset()
|
|
416
|
+
dataset.resources.extend([mock_resource2, mock_resource1])
|
|
417
|
+
|
|
418
|
+
# Call sorted_by_deps
|
|
419
|
+
sorted_resources = dataset.sorted_by_deps()
|
|
420
|
+
|
|
421
|
+
# Assert that the resources are sorted correctly
|
|
422
|
+
assert sorted_resources == [mock_resource1, mock_resource2]
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from unittest.mock import Mock
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from exdrf.constants import (
|
|
6
|
+
FIELD_TYPE_REF_MANY_TO_MANY,
|
|
7
|
+
FIELD_TYPE_REF_MANY_TO_ONE,
|
|
8
|
+
FIELD_TYPE_REF_ONE_TO_MANY,
|
|
9
|
+
FIELD_TYPE_REF_ONE_TO_ONE,
|
|
10
|
+
)
|
|
11
|
+
from exdrf.field import ExField
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture
|
|
15
|
+
def mock_resource():
|
|
16
|
+
resource = Mock()
|
|
17
|
+
resource.name = "test_resource"
|
|
18
|
+
return resource
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.fixture
|
|
22
|
+
def ex_field(mock_resource):
|
|
23
|
+
return ExField(
|
|
24
|
+
name="test_field",
|
|
25
|
+
resource=mock_resource,
|
|
26
|
+
type_name=FIELD_TYPE_REF_ONE_TO_MANY,
|
|
27
|
+
is_list=True,
|
|
28
|
+
primary=True,
|
|
29
|
+
visible=True,
|
|
30
|
+
read_only=False,
|
|
31
|
+
nullable=False,
|
|
32
|
+
sortable=True,
|
|
33
|
+
filterable=True,
|
|
34
|
+
exportable=True,
|
|
35
|
+
qsearch=True,
|
|
36
|
+
resizable=True,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_exfield_initialization(ex_field):
|
|
41
|
+
assert ex_field.name == "test_field"
|
|
42
|
+
assert ex_field.resource.name == "test_resource"
|
|
43
|
+
assert ex_field.type_name == FIELD_TYPE_REF_ONE_TO_MANY
|
|
44
|
+
assert ex_field.is_list is True
|
|
45
|
+
assert ex_field.primary is True
|
|
46
|
+
assert ex_field.visible is True
|
|
47
|
+
assert ex_field.read_only is False
|
|
48
|
+
assert ex_field.nullable is False
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_exfield_pascal_case_name(ex_field):
|
|
52
|
+
assert ex_field.pascal_case_name == "TestField"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_exfield_snake_case_name(ex_field):
|
|
56
|
+
assert ex_field.snake_case_name == "test_field"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_exfield_snake_case_name_plural(ex_field):
|
|
60
|
+
ex_field.name = "test_field"
|
|
61
|
+
assert ex_field.snake_case_name_plural == "test_fields"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_exfield_camel_case_name(ex_field):
|
|
65
|
+
assert ex_field.camel_case_name == "testField"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_exfield_text_name(ex_field):
|
|
69
|
+
assert ex_field.text_name == "Test field"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_exfield_doc_lines(ex_field):
|
|
73
|
+
ex_field.description = "This is a test field."
|
|
74
|
+
assert ex_field.doc_lines == ["This is a test field."]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_exfield_is_ref_type(ex_field):
|
|
78
|
+
assert ex_field.is_ref_type is True
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_exfield_is_one_to_many_type(ex_field):
|
|
82
|
+
assert ex_field.is_one_to_many_type is True
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_exfield_is_one_to_one_type(ex_field):
|
|
86
|
+
ex_field.type_name = FIELD_TYPE_REF_ONE_TO_ONE
|
|
87
|
+
assert ex_field.is_one_to_one_type is True
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_exfield_is_many_to_many_type(ex_field):
|
|
91
|
+
ex_field.type_name = FIELD_TYPE_REF_MANY_TO_MANY
|
|
92
|
+
assert ex_field.is_many_to_many_type is True
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_exfield_is_many_to_one_type(ex_field):
|
|
96
|
+
ex_field.type_name = FIELD_TYPE_REF_MANY_TO_ONE
|
|
97
|
+
assert ex_field.is_many_to_one_type is True
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_exfield_visit(ex_field):
|
|
101
|
+
mock_visitor = Mock()
|
|
102
|
+
mock_visitor.visit_field.return_value = True
|
|
103
|
+
assert ex_field.visit(mock_visitor) is True
|
|
104
|
+
mock_visitor.visit_field.assert_called_once_with(ex_field)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_exfield_extra_ref(ex_field):
|
|
108
|
+
mock_dataset = Mock()
|
|
109
|
+
assert ex_field.extra_ref(mock_dataset) == []
|