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.
Files changed (57) hide show
  1. exdrf/__init__.py +0 -0
  2. exdrf/__version__.py +24 -0
  3. exdrf/api.py +51 -0
  4. exdrf/constants.py +30 -0
  5. exdrf/dataset.py +197 -0
  6. exdrf/field.py +554 -0
  7. exdrf/field_types/__init__.py +0 -0
  8. exdrf/field_types/api.py +78 -0
  9. exdrf/field_types/blob_field.py +44 -0
  10. exdrf/field_types/bool_field.py +47 -0
  11. exdrf/field_types/date_field.py +49 -0
  12. exdrf/field_types/date_time.py +52 -0
  13. exdrf/field_types/dur_field.py +44 -0
  14. exdrf/field_types/enum_field.py +41 -0
  15. exdrf/field_types/filter_field.py +11 -0
  16. exdrf/field_types/float_field.py +85 -0
  17. exdrf/field_types/float_list.py +18 -0
  18. exdrf/field_types/formatted.py +39 -0
  19. exdrf/field_types/int_field.py +70 -0
  20. exdrf/field_types/int_list.py +18 -0
  21. exdrf/field_types/ref_base.py +105 -0
  22. exdrf/field_types/ref_m2m.py +39 -0
  23. exdrf/field_types/ref_m2o.py +23 -0
  24. exdrf/field_types/ref_o2m.py +36 -0
  25. exdrf/field_types/ref_o2o.py +32 -0
  26. exdrf/field_types/sort_field.py +18 -0
  27. exdrf/field_types/str_field.py +77 -0
  28. exdrf/field_types/str_list.py +18 -0
  29. exdrf/field_types/time_field.py +49 -0
  30. exdrf/filter.py +653 -0
  31. exdrf/filter_dsl.py +950 -0
  32. exdrf/filter_op_catalog.py +222 -0
  33. exdrf/label_dsl.py +691 -0
  34. exdrf/moment.py +496 -0
  35. exdrf/py.typed +0 -0
  36. exdrf/py_support.py +21 -0
  37. exdrf/resource.py +901 -0
  38. exdrf/sa_fi_item.py +69 -0
  39. exdrf/sa_filter_op.py +324 -0
  40. exdrf/utils.py +17 -0
  41. exdrf/validator.py +45 -0
  42. exdrf/var_bag.py +328 -0
  43. exdrf/visitor.py +58 -0
  44. exdrf-0.0.1.dev0.dist-info/METADATA +42 -0
  45. exdrf-0.0.1.dev0.dist-info/RECORD +57 -0
  46. exdrf-0.0.1.dev0.dist-info/WHEEL +5 -0
  47. exdrf-0.0.1.dev0.dist-info/top_level.txt +3 -0
  48. exdrf_tests/__init__.py +0 -0
  49. exdrf_tests/test_dataset.py +422 -0
  50. exdrf_tests/test_field.py +109 -0
  51. exdrf_tests/test_filter.py +425 -0
  52. exdrf_tests/test_filter_dsl.py +556 -0
  53. exdrf_tests/test_label_dsl.py +234 -0
  54. exdrf_tests/test_resource.py +107 -0
  55. exdrf_tests/test_utils.py +43 -0
  56. exdrf_tests/test_visitor.py +31 -0
  57. exdrf_tests/var_bag_test.py +502 -0
@@ -0,0 +1,502 @@
1
+ from datetime import date, datetime
2
+
3
+ import pytest
4
+
5
+ from exdrf.constants import FIELD_TYPE_STRING
6
+ from exdrf.field_types.api import DateTimeField, StrField
7
+ from exdrf.var_bag import VarBag
8
+
9
+
10
+ @pytest.fixture
11
+ def empty_var_bag():
12
+ """Create an empty VarBag."""
13
+ return VarBag()
14
+
15
+
16
+ @pytest.fixture
17
+ def sample_field():
18
+ """Create a sample StrField."""
19
+ return StrField(name="test_field")
20
+
21
+
22
+ @pytest.fixture
23
+ def sample_var_bag(sample_field):
24
+ """Create a VarBag with one field."""
25
+ bag = VarBag()
26
+ bag.add_field(sample_field, "test_value")
27
+ return bag
28
+
29
+
30
+ class TestVarBagInitialization:
31
+ """Tests for VarBag initialization."""
32
+
33
+ def test_empty_initialization(self, empty_var_bag):
34
+ """Test that VarBag can be initialized empty."""
35
+ assert len(empty_var_bag) == 0
36
+ assert empty_var_bag.values == {}
37
+ assert empty_var_bag._fields == {}
38
+ assert list(empty_var_bag) == []
39
+
40
+ def test_initialization_with_values(self):
41
+ """Test that VarBag can be initialized with values."""
42
+ bag = VarBag(values={"key1": "value1", "key2": 42})
43
+ assert len(bag) == 2
44
+ assert "key1" in bag
45
+ assert "key2" in bag
46
+
47
+
48
+ class TestVarBagProperties:
49
+ """Tests for VarBag properties."""
50
+
51
+ def test_var_names(self, sample_var_bag):
52
+ """Test var_names property."""
53
+ assert sample_var_bag.var_names == ["test_field"]
54
+
55
+ def test_var_names_empty(self, empty_var_bag):
56
+ """Test var_names on empty bag."""
57
+ assert empty_var_bag.var_names == []
58
+
59
+ def test_var_names_multiple(self):
60
+ """Test var_names with multiple fields."""
61
+ bag = VarBag()
62
+ bag.values["field1"] = "value1"
63
+ bag.values["field2"] = "value2"
64
+ assert set(bag.var_names) == {"field1", "field2"}
65
+
66
+ def test_var_values(self, sample_var_bag):
67
+ """Test var_values property."""
68
+ assert sample_var_bag.var_values == ["test_value"]
69
+
70
+ def test_var_values_empty(self, empty_var_bag):
71
+ """Test var_values on empty bag."""
72
+ assert empty_var_bag.var_values == []
73
+
74
+ def test_field_names(self, sample_var_bag):
75
+ """Test field_names property."""
76
+ assert sample_var_bag.field_names == ["test_field"]
77
+
78
+ def test_field_names_empty(self, empty_var_bag):
79
+ """Test field_names on empty bag."""
80
+ assert empty_var_bag.field_names == []
81
+
82
+ def test_field_values(self, sample_var_bag):
83
+ """Test field_values property."""
84
+ assert sample_var_bag.field_values == ["test_value"]
85
+
86
+ def test_field_values_empty(self, empty_var_bag):
87
+ """Test field_values on empty bag."""
88
+ assert empty_var_bag.field_values == []
89
+
90
+ def test_field_count(self, sample_var_bag):
91
+ """Test field_count property."""
92
+ assert sample_var_bag.field_count == 1
93
+
94
+ def test_field_count_empty(self, empty_var_bag):
95
+ """Test field_count on empty bag."""
96
+ assert empty_var_bag.field_count == 0
97
+
98
+ def test_field_count_multiple(self):
99
+ """Test field_count with multiple fields."""
100
+ bag = VarBag()
101
+ bag.values["field1"] = "value1"
102
+ bag.values["field2"] = "value2"
103
+ assert bag.field_count == 2
104
+
105
+ def test_as_field_dict(self, sample_var_bag):
106
+ """Test as_field_dict property."""
107
+ assert sample_var_bag.as_field_dict == {"test_field": "test_value"}
108
+
109
+ def test_as_field_dict_empty(self, empty_var_bag):
110
+ """Test as_field_dict on empty bag."""
111
+ assert empty_var_bag.as_field_dict == {}
112
+
113
+ def test_fields_property(self, sample_var_bag, sample_field):
114
+ """Test fields property."""
115
+ fields = sample_var_bag.fields
116
+ assert len(fields) == 1
117
+ assert fields[0].name == "test_field"
118
+
119
+ def test_fields_property_without_field_object(self):
120
+ """Test fields property when value exists but no field object."""
121
+ bag = VarBag()
122
+ bag.values["raw_value"] = "some_value"
123
+ assert len(bag.fields) == 0
124
+
125
+ def test_as_dict(self, sample_var_bag):
126
+ """Test as_dict property."""
127
+ assert sample_var_bag.as_dict == {"test_field": "test_value"}
128
+
129
+
130
+ class TestVarBagAddField:
131
+ """Tests for add_field method."""
132
+
133
+ def test_add_field(self, empty_var_bag, sample_field):
134
+ """Test adding a single field."""
135
+ empty_var_bag.add_field(sample_field, "test_value")
136
+ assert "test_field" in empty_var_bag
137
+ assert empty_var_bag["test_field"] == "test_value"
138
+ assert empty_var_bag._fields["test_field"] == sample_field
139
+
140
+ def test_add_field_updates_existing(self, sample_var_bag):
141
+ """Test that add_field updates existing field."""
142
+ new_field = StrField(name="test_field")
143
+ sample_var_bag.add_field(new_field, "new_value")
144
+ assert sample_var_bag["test_field"] == "new_value"
145
+ assert sample_var_bag._fields["test_field"] == new_field
146
+
147
+ def test_add_field_with_none_value(self, empty_var_bag, sample_field):
148
+ """Test adding a field with None value."""
149
+ empty_var_bag.add_field(sample_field, None)
150
+ assert "test_field" in empty_var_bag
151
+ assert empty_var_bag["test_field"] is None
152
+
153
+
154
+ class TestVarBagAddFields:
155
+ """Tests for add_fields method."""
156
+
157
+ def test_add_fields(self, empty_var_bag):
158
+ """Test adding multiple fields."""
159
+ field1 = StrField(name="field1")
160
+ field2 = StrField(name="field2")
161
+ empty_var_bag.add_fields([(field1, "value1"), (field2, "value2")])
162
+ assert "field1" in empty_var_bag
163
+ assert "field2" in empty_var_bag
164
+ assert empty_var_bag["field1"] == "value1"
165
+ assert empty_var_bag["field2"] == "value2"
166
+
167
+ def test_add_fields_updates_existing(self, sample_var_bag):
168
+ """Test that add_fields updates existing fields."""
169
+ new_field = StrField(name="test_field")
170
+ field2 = StrField(name="field2")
171
+ sample_var_bag.add_fields([(new_field, "updated"), (field2, "value2")])
172
+ assert sample_var_bag["test_field"] == "updated"
173
+ assert sample_var_bag["field2"] == "value2"
174
+
175
+
176
+ class TestVarBagContainsField:
177
+ """Tests for contains_field method."""
178
+
179
+ def test_contains_field_true(self, sample_var_bag):
180
+ """Test contains_field returns True for existing field."""
181
+ assert sample_var_bag.contains_field("test_field") is True
182
+
183
+ def test_contains_field_false(self, empty_var_bag):
184
+ """Test contains_field returns False for non-existing field."""
185
+ assert empty_var_bag.contains_field("nonexistent") is False
186
+
187
+ def test_contains_field_with_raw_value(self):
188
+ """Test contains_field with raw value (no field object)."""
189
+ bag = VarBag()
190
+ bag.values["raw_value"] = "some_value"
191
+ assert bag.contains_field("raw_value") is True
192
+
193
+
194
+ class TestVarBagIsField:
195
+ """Tests for is_field method."""
196
+
197
+ def test_is_field_true(self, sample_var_bag):
198
+ """Test is_field returns True when field object exists."""
199
+ assert sample_var_bag.is_field("test_field") is True
200
+
201
+ def test_is_field_false(self, empty_var_bag):
202
+ """Test is_field returns False for non-existing field."""
203
+ assert empty_var_bag.is_field("nonexistent") is False
204
+
205
+ def test_is_field_false_with_raw_value(self):
206
+ """Test is_field returns False for raw value without field object."""
207
+ bag = VarBag()
208
+ bag.values["raw_value"] = "some_value"
209
+ assert bag.is_field("raw_value") is False
210
+
211
+
212
+ class TestVarBagGetFieldValue:
213
+ """Tests for get_field_value method."""
214
+
215
+ def test_get_field_value(self, sample_var_bag):
216
+ """Test getting field value."""
217
+ assert sample_var_bag.get_field_value("test_field") == "test_value"
218
+
219
+ def test_get_field_value_raises_keyerror(self, empty_var_bag):
220
+ """Test get_field_value raises KeyError for non-existing field."""
221
+ with pytest.raises(KeyError, match="Key nonexistent not found"):
222
+ empty_var_bag.get_field_value("nonexistent")
223
+
224
+
225
+ class TestVarBagSetFieldValue:
226
+ """Tests for set_field_value method."""
227
+
228
+ def test_set_field_value(self, sample_var_bag):
229
+ """Test setting field value."""
230
+ sample_var_bag.set_field_value("test_field", "new_value")
231
+ assert sample_var_bag["test_field"] == "new_value"
232
+
233
+ def test_set_field_value_raises_keyerror(self, empty_var_bag):
234
+ """Test set_field_value raises KeyError for non-existing field."""
235
+ with pytest.raises(KeyError, match="Key nonexistent is not a field"):
236
+ empty_var_bag.set_field_value("nonexistent", "value")
237
+
238
+
239
+ class TestVarBagMagicMethods:
240
+ """Tests for magic methods."""
241
+
242
+ def test_contains(self, sample_var_bag):
243
+ """Test __contains__ method."""
244
+ assert "test_field" in sample_var_bag
245
+ assert "nonexistent" not in sample_var_bag
246
+
247
+ def test_getitem(self, sample_var_bag):
248
+ """Test __getitem__ method."""
249
+ assert sample_var_bag["test_field"] == "test_value"
250
+
251
+ def test_getitem_raises_keyerror(self, empty_var_bag):
252
+ """Test __getitem__ raises KeyError for non-existing key."""
253
+ with pytest.raises(KeyError, match="Key nonexistent not found"):
254
+ _ = empty_var_bag["nonexistent"]
255
+
256
+ def test_setitem(self, sample_var_bag):
257
+ """Test __setitem__ method."""
258
+ sample_var_bag["test_field"] = "updated_value"
259
+ assert sample_var_bag["test_field"] == "updated_value"
260
+
261
+ def test_setitem_raises_keyerror(self, empty_var_bag):
262
+ """Test __setitem__ raises KeyError for non-existing key."""
263
+ with pytest.raises(KeyError, match="Key nonexistent not found"):
264
+ empty_var_bag["nonexistent"] = "value"
265
+
266
+ def test_iter(self, sample_var_bag):
267
+ """Test __iter__ method."""
268
+ keys = list(sample_var_bag)
269
+ assert keys == ["test_field"]
270
+
271
+ def test_iter_empty(self, empty_var_bag):
272
+ """Test __iter__ on empty bag."""
273
+ assert list(empty_var_bag) == []
274
+
275
+ def test_len(self, sample_var_bag):
276
+ """Test __len__ method."""
277
+ assert len(sample_var_bag) == 1
278
+
279
+ def test_len_empty(self, empty_var_bag):
280
+ """Test __len__ on empty bag."""
281
+ assert len(empty_var_bag) == 0
282
+
283
+
284
+ class TestVarBagFiltered:
285
+ """Tests for filtered method."""
286
+
287
+ def test_filtered_empty_text(self, sample_var_bag):
288
+ """Test filtered with empty text returns same bag."""
289
+ result = sample_var_bag.filtered(True, "", False)
290
+ assert result.values == sample_var_bag.values
291
+ assert result._fields == sample_var_bag._fields
292
+
293
+ def test_filtered_by_name_exact(self, sample_var_bag):
294
+ """Test filtered by name with exact match."""
295
+ field2 = StrField(name="another_field")
296
+ sample_var_bag.add_field(field2, "value2")
297
+ result = sample_var_bag.filtered(True, "test_field", True)
298
+ assert "test_field" in result
299
+ assert "another_field" not in result
300
+
301
+ def test_filtered_by_name_pattern(self):
302
+ """Test filtered by name with pattern matching."""
303
+ bag = VarBag()
304
+ bag.values["field1"] = "value1"
305
+ bag.values["field2"] = "value2"
306
+ bag.values["other"] = "value3"
307
+ result = bag.filtered(True, "field*", False)
308
+ assert "field1" in result
309
+ assert "field2" in result
310
+ assert "other" not in result
311
+
312
+ def test_filtered_by_value(self):
313
+ """Test filtered by value."""
314
+ bag = VarBag()
315
+ bag.values["field1"] = "hello world"
316
+ bag.values["field2"] = "goodbye"
317
+ result = bag.filtered(False, "hello", False)
318
+ assert "field1" in result
319
+ assert "field2" not in result
320
+
321
+ def test_filtered_preserves_field_objects(self):
322
+ """Test that filtered preserves field objects."""
323
+ bag = VarBag()
324
+ field1 = StrField(name="field1")
325
+ bag.add_field(field1, "value1")
326
+ bag.values["field2"] = "value2" # Raw value without field object
327
+ result = bag.filtered(True, "field*", False)
328
+ assert "field1" in result._fields
329
+ assert "field2" not in result._fields
330
+
331
+
332
+ class TestVarBagFilteredFields:
333
+ """Tests for filtered_fields method."""
334
+
335
+ def test_filtered_fields(self):
336
+ """Test filtered_fields method."""
337
+ bag = VarBag()
338
+ field1 = StrField(name="field1")
339
+ field2 = StrField(name="field2")
340
+ bag.add_field(field1, "value1")
341
+ bag.add_field(field2, "value2")
342
+ result = bag.filtered_fields(True, "field1", True)
343
+ assert "field1" in result
344
+ assert "field2" not in result
345
+
346
+
347
+ class TestVarBagAddNow:
348
+ """Tests for add_now method."""
349
+
350
+ def test_add_now(self, empty_var_bag):
351
+ """Test add_now adds current datetime."""
352
+ empty_var_bag.add_now()
353
+ assert "now" in empty_var_bag
354
+ assert isinstance(empty_var_bag["now"], datetime)
355
+ assert isinstance(empty_var_bag._fields["now"], DateTimeField)
356
+
357
+
358
+ class TestVarBagSimplifyValue:
359
+ """Tests for simplify_value method."""
360
+
361
+ def test_simplify_value_str(self, empty_var_bag):
362
+ """Test simplifying string value."""
363
+ assert empty_var_bag.simplify_value("test") == "test"
364
+
365
+ def test_simplify_value_int(self, empty_var_bag):
366
+ """Test simplifying int value."""
367
+ assert empty_var_bag.simplify_value(42) == 42
368
+
369
+ def test_simplify_value_float(self, empty_var_bag):
370
+ """Test simplifying float value."""
371
+ assert empty_var_bag.simplify_value(3.14) == 3.14
372
+
373
+ def test_simplify_value_bool(self, empty_var_bag):
374
+ """Test simplifying bool value."""
375
+ assert empty_var_bag.simplify_value(True) is True
376
+
377
+ def test_simplify_value_datetime(self, empty_var_bag):
378
+ """Test simplifying datetime value."""
379
+ dt = datetime(2023, 1, 1, 12, 30, 45)
380
+ assert empty_var_bag.simplify_value(dt) == "2023-01-01T12:30:45"
381
+
382
+ def test_simplify_value_date(self, empty_var_bag):
383
+ """Test simplifying date value."""
384
+ d = date(2023, 1, 1)
385
+ assert empty_var_bag.simplify_value(d) == "2023-01-01"
386
+
387
+ def test_simplify_value_list(self, empty_var_bag):
388
+ """Test simplifying list value."""
389
+ result = empty_var_bag.simplify_value([1, 2, 3])
390
+ assert result == [1, 2, 3]
391
+
392
+ def test_simplify_value_dict(self, empty_var_bag):
393
+ """Test simplifying dict value."""
394
+ result = empty_var_bag.simplify_value({"key": "value"})
395
+ assert result == {"key": "value"}
396
+
397
+ def test_simplify_value_nested_list(self, empty_var_bag):
398
+ """Test simplifying nested list."""
399
+ dt = datetime(2023, 1, 1, 12, 0, 0)
400
+ result = empty_var_bag.simplify_value([dt, "test"])
401
+ assert result == ["2023-01-01T12:00:00", "test"]
402
+
403
+ def test_simplify_value_nested_dict(self, empty_var_bag):
404
+ """Test simplifying nested dict."""
405
+ dt = datetime(2023, 1, 1, 12, 0, 0)
406
+ result = empty_var_bag.simplify_value({"time": dt})
407
+ assert result == {"time": "2023-01-01T12:00:00"}
408
+
409
+ def test_simplify_value_custom_class(self, empty_var_bag):
410
+ """Test simplifying custom class."""
411
+
412
+ class CustomClass:
413
+ pass
414
+
415
+ result = empty_var_bag.simplify_value(CustomClass())
416
+ assert result == "<CustomClass>"
417
+
418
+
419
+ class TestVarBagToSimpleData:
420
+ """Tests for to_simple_data method."""
421
+
422
+ def test_to_simple_data_with_field(self, sample_var_bag):
423
+ """Test to_simple_data with field object."""
424
+ data = sample_var_bag.to_simple_data()
425
+ assert len(data) == 1
426
+ assert data[0]["name"] == "test_field"
427
+ assert data[0]["type"] == FIELD_TYPE_STRING
428
+ assert data[0]["value"] == "test_value"
429
+
430
+ def test_to_simple_data_without_field(self):
431
+ """Test to_simple_data without field object."""
432
+ bag = VarBag()
433
+ bag.values["raw_value"] = "some_value"
434
+ data = bag.to_simple_data()
435
+ assert len(data) == 1
436
+ assert data[0]["name"] == "raw_value"
437
+ assert data[0]["type"] == FIELD_TYPE_STRING
438
+ assert data[0]["value"] == "some_value"
439
+
440
+ def test_to_simple_data_empty(self, empty_var_bag):
441
+ """Test to_simple_data on empty bag."""
442
+ assert empty_var_bag.to_simple_data() == []
443
+
444
+ def test_to_simple_data_with_datetime(self):
445
+ """Test to_simple_data with datetime value."""
446
+ bag = VarBag()
447
+ field = DateTimeField(name="dt_field")
448
+ dt = datetime(2023, 1, 1, 12, 30, 45)
449
+ bag.add_field(field, dt)
450
+ data = bag.to_simple_data()
451
+ assert data[0]["value"] == "2023-01-01T12:30:45"
452
+
453
+
454
+ class TestVarBagFromSimpleData:
455
+ """Tests for from_simple_data method."""
456
+
457
+ def test_from_simple_data(self, empty_var_bag):
458
+ """Test from_simple_data with valid data."""
459
+ data = [
460
+ {"name": "field1", "type": FIELD_TYPE_STRING, "value": "value1"},
461
+ {"name": "field2", "type": FIELD_TYPE_STRING, "value": "value2"},
462
+ ]
463
+ empty_var_bag.from_simple_data(data)
464
+ assert "field1" in empty_var_bag
465
+ assert "field2" in empty_var_bag
466
+ assert empty_var_bag["field1"] == "value1"
467
+ assert empty_var_bag["field2"] == "value2"
468
+
469
+ def test_from_simple_data_skips_empty_name(self, empty_var_bag):
470
+ """Test from_simple_data skips items with empty name."""
471
+ data = [
472
+ {"name": "", "type": FIELD_TYPE_STRING, "value": "value"},
473
+ {"name": "field1", "type": FIELD_TYPE_STRING, "value": "value1"},
474
+ ]
475
+ empty_var_bag.from_simple_data(data)
476
+ assert "" not in empty_var_bag
477
+ assert "field1" in empty_var_bag
478
+
479
+ def test_from_simple_data_updates_existing(self, sample_var_bag):
480
+ """Test from_simple_data updates existing fields."""
481
+ data = [
482
+ {
483
+ "name": "test_field",
484
+ "type": FIELD_TYPE_STRING,
485
+ "value": "new_value",
486
+ }
487
+ ]
488
+ sample_var_bag.from_simple_data(data)
489
+ assert sample_var_bag["test_field"] == "new_value"
490
+
491
+ def test_from_simple_data_roundtrip(self):
492
+ """Test roundtrip conversion."""
493
+ bag = VarBag()
494
+ field1 = StrField(name="field1")
495
+ field2 = StrField(name="field2")
496
+ bag.add_field(field1, "value1")
497
+ bag.add_field(field2, "value2")
498
+ data = bag.to_simple_data()
499
+ new_bag = VarBag()
500
+ new_bag.from_simple_data(data)
501
+ assert new_bag["field1"] == "value1"
502
+ assert new_bag["field2"] == "value2"