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
exdrf/var_bag.py
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from datetime import date, datetime
|
|
3
|
+
from typing import Any, Dict, Iterator, List, Tuple, Union
|
|
4
|
+
|
|
5
|
+
from attrs import define, field
|
|
6
|
+
|
|
7
|
+
from exdrf.field import ExField
|
|
8
|
+
from exdrf.field_types.api import (
|
|
9
|
+
FIELD_TYPE_STRING,
|
|
10
|
+
DateTimeField,
|
|
11
|
+
StrField,
|
|
12
|
+
field_type_to_class,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@define
|
|
17
|
+
class VarBag:
|
|
18
|
+
"""A bag of variables for a template.
|
|
19
|
+
|
|
20
|
+
Attributes:
|
|
21
|
+
values: Dictionary of values to be used in the template. This is the
|
|
22
|
+
source of truth for what variables exist.
|
|
23
|
+
_fields: Dictionary mapping field names to ExField objects.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
values: Dict[str, Any] = field(factory=dict)
|
|
27
|
+
_fields: Dict[str, "ExField"] = field(factory=dict, init=False, repr=False)
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def fields(self) -> List["ExField"]:
|
|
31
|
+
"""List of fields, ordered by keys in values."""
|
|
32
|
+
return list(self._fields.values())
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def var_names(self) -> List[str]:
|
|
36
|
+
"""List of variable names."""
|
|
37
|
+
return list(self.values.keys())
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def var_values(self) -> List[str]:
|
|
41
|
+
"""List of variable values."""
|
|
42
|
+
return [self.values[name] for name in self.values.keys()]
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def field_names(self) -> List[str]:
|
|
46
|
+
"""List of field names."""
|
|
47
|
+
return list(self.values.keys())
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def field_values(self) -> List[Any]:
|
|
51
|
+
"""List of field values."""
|
|
52
|
+
return [self.values[name] for name in self.values.keys()]
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def field_count(self) -> int:
|
|
56
|
+
"""Count of fields."""
|
|
57
|
+
return len(self.values)
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def as_field_dict(self) -> Dict[str, Any]:
|
|
61
|
+
"""Return a dictionary mapping field names to values."""
|
|
62
|
+
return dict((name, self.values[name]) for name in self._fields.keys())
|
|
63
|
+
|
|
64
|
+
def add_field(self, field: "ExField", value: Any = None):
|
|
65
|
+
"""Add a field to the bag.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
field: The field to add.
|
|
69
|
+
value: The value to add to the field.
|
|
70
|
+
"""
|
|
71
|
+
self._fields[field.name] = field
|
|
72
|
+
self.values[field.name] = value
|
|
73
|
+
|
|
74
|
+
def add_fields(self, fields: List[Tuple["ExField", Any]]):
|
|
75
|
+
"""Add a list of fields to the bag.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
fields: List of fields to add.
|
|
79
|
+
"""
|
|
80
|
+
for fld, value in fields:
|
|
81
|
+
self._fields[fld.name] = fld
|
|
82
|
+
self.values[fld.name] = value
|
|
83
|
+
|
|
84
|
+
def contains_field(self, name: str) -> bool:
|
|
85
|
+
"""Check if a field exists.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
name: The name of the field to check.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
True if the field exists, False otherwise.
|
|
92
|
+
"""
|
|
93
|
+
return name in self.values
|
|
94
|
+
|
|
95
|
+
def is_field(self, name: str) -> bool:
|
|
96
|
+
"""Check if a value has an associated ExField object.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
name: The name of the value to check.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
True if the value has an associated ExField object, False if it
|
|
103
|
+
is a raw value without a field definition.
|
|
104
|
+
"""
|
|
105
|
+
return name in self._fields
|
|
106
|
+
|
|
107
|
+
def get_field_value(self, name: str) -> Any:
|
|
108
|
+
"""Get the value of a field.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
name: The name of the field.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
The value of the field.
|
|
115
|
+
|
|
116
|
+
Raises:
|
|
117
|
+
KeyError: If the field does not exist.
|
|
118
|
+
"""
|
|
119
|
+
if name not in self.values:
|
|
120
|
+
raise KeyError(f"Key {name} not found")
|
|
121
|
+
if name not in self._fields:
|
|
122
|
+
raise KeyError(f"Key {name} is not a field")
|
|
123
|
+
return self.values[name]
|
|
124
|
+
|
|
125
|
+
def set_field_value(self, name: str, value: Any) -> None:
|
|
126
|
+
"""Set the value of a field.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
name: The name of the field.
|
|
130
|
+
value: The value to set.
|
|
131
|
+
|
|
132
|
+
Raises:
|
|
133
|
+
KeyError: If the field does not exist.
|
|
134
|
+
"""
|
|
135
|
+
if name not in self._fields:
|
|
136
|
+
raise KeyError(f"Key {name} is not a field")
|
|
137
|
+
self.values[name] = value
|
|
138
|
+
|
|
139
|
+
def __contains__(self, key: str) -> bool:
|
|
140
|
+
return key in self.values
|
|
141
|
+
|
|
142
|
+
def __getitem__(self, key: str) -> Any:
|
|
143
|
+
if key not in self.values:
|
|
144
|
+
raise KeyError(f"Key {key} not found")
|
|
145
|
+
return self.values[key]
|
|
146
|
+
|
|
147
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
148
|
+
if key not in self.values:
|
|
149
|
+
raise KeyError(f"Key {key} not found")
|
|
150
|
+
self.values[key] = value
|
|
151
|
+
|
|
152
|
+
def __iter__(self) -> Iterator[str]:
|
|
153
|
+
"""Return an iterator of keys for dictionary unpacking."""
|
|
154
|
+
yield from self.values.keys()
|
|
155
|
+
|
|
156
|
+
def __len__(self) -> int:
|
|
157
|
+
"""Return the number of fields that have values."""
|
|
158
|
+
return len(self.values)
|
|
159
|
+
|
|
160
|
+
def filtered(self, by_name: bool, text: str, exact: bool):
|
|
161
|
+
"""Filter the variable bag based on name or value.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
by_name: If True, filter by field name; if False, filter by value.
|
|
165
|
+
text: The text pattern to search for (supports % and * wildcards).
|
|
166
|
+
exact: If True, match exactly; if False, match anywhere.
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
A new VarBag containing only the filtered fields.
|
|
170
|
+
"""
|
|
171
|
+
if len(text) == 0:
|
|
172
|
+
return self
|
|
173
|
+
|
|
174
|
+
# Convert wildcard pattern to regex pattern
|
|
175
|
+
pattern = text.replace("%", ".*").replace("*", ".*")
|
|
176
|
+
if exact:
|
|
177
|
+
pattern = f"^{pattern}$"
|
|
178
|
+
regex = re.compile(pattern, re.IGNORECASE)
|
|
179
|
+
|
|
180
|
+
result = VarBag()
|
|
181
|
+
for name in self.values.keys():
|
|
182
|
+
search_text = name.lower() if by_name else str(self.values[name]).lower()
|
|
183
|
+
if regex.search(search_text):
|
|
184
|
+
if name in self._fields:
|
|
185
|
+
result._fields[name] = self._fields[name]
|
|
186
|
+
result.values[name] = self.values[name]
|
|
187
|
+
return result
|
|
188
|
+
|
|
189
|
+
def filtered_fields(self, by_name: bool, text: str, exact: bool):
|
|
190
|
+
"""Filter fields based on name or value.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
by_name: If True, filter by field name; if False, filter by value.
|
|
194
|
+
text: The text pattern to search for (supports % and * wildcards).
|
|
195
|
+
exact: If True, match exactly; if False, match anywhere.
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
A new VarBag containing only the filtered fields.
|
|
199
|
+
"""
|
|
200
|
+
if len(text) == 0:
|
|
201
|
+
return self
|
|
202
|
+
|
|
203
|
+
# Convert wildcard pattern to regex pattern
|
|
204
|
+
pattern = text.replace("%", ".*").replace("*", ".*")
|
|
205
|
+
if exact:
|
|
206
|
+
pattern = f"^{pattern}$"
|
|
207
|
+
regex = re.compile(pattern, re.IGNORECASE)
|
|
208
|
+
|
|
209
|
+
result = VarBag()
|
|
210
|
+
for name in self._fields.keys():
|
|
211
|
+
search_text = name.lower() if by_name else str(self.values[name]).lower()
|
|
212
|
+
if regex.search(search_text):
|
|
213
|
+
result._fields[name] = self._fields[name]
|
|
214
|
+
result.values[name] = self.values[name]
|
|
215
|
+
return result
|
|
216
|
+
|
|
217
|
+
def add_now(self):
|
|
218
|
+
"""Add the current date and time to the variable bag."""
|
|
219
|
+
self.add_field(DateTimeField(name="now"), datetime.now())
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def as_dict(self) -> Dict[str, Any]:
|
|
223
|
+
"""Return a dictionary of the variables in the bag and their values."""
|
|
224
|
+
return dict(self.values)
|
|
225
|
+
|
|
226
|
+
def simplify_value(self, value: Any) -> Any:
|
|
227
|
+
"""Convert a value to a simple value.
|
|
228
|
+
|
|
229
|
+
The simple values are:
|
|
230
|
+
- int
|
|
231
|
+
- float
|
|
232
|
+
- bool
|
|
233
|
+
- str
|
|
234
|
+
- list of simple values
|
|
235
|
+
- dict of simple values
|
|
236
|
+
|
|
237
|
+
Classes that are not one of those will be converted to a string
|
|
238
|
+
with the class name.
|
|
239
|
+
"""
|
|
240
|
+
if isinstance(value, (list, tuple)):
|
|
241
|
+
return [self.simplify_value(v) for v in value]
|
|
242
|
+
elif isinstance(value, dict):
|
|
243
|
+
return {k: self.simplify_value(v) for k, v in value.items()}
|
|
244
|
+
elif isinstance(value, (str, int, float, bool)):
|
|
245
|
+
return value
|
|
246
|
+
elif isinstance(value, datetime):
|
|
247
|
+
return value.strftime("%Y-%m-%dT%H:%M:%S")
|
|
248
|
+
elif isinstance(value, date):
|
|
249
|
+
return value.strftime("%Y-%m-%d")
|
|
250
|
+
else:
|
|
251
|
+
return f"<{value.__class__.__name__}>"
|
|
252
|
+
|
|
253
|
+
def to_simple_data(self) -> List[Dict[str, Any]]:
|
|
254
|
+
"""Convert the variable bag to a simple data structure.
|
|
255
|
+
|
|
256
|
+
The result is a list of dictionaries, each containing the name,
|
|
257
|
+
type, and value of a variable.
|
|
258
|
+
|
|
259
|
+
The simple values are:
|
|
260
|
+
- int
|
|
261
|
+
- float
|
|
262
|
+
- bool
|
|
263
|
+
- str
|
|
264
|
+
- list
|
|
265
|
+
- dict
|
|
266
|
+
|
|
267
|
+
Classes that are not one of those will be converted to a string
|
|
268
|
+
with the class name.
|
|
269
|
+
"""
|
|
270
|
+
result = []
|
|
271
|
+
for name in self.values.keys():
|
|
272
|
+
result.append(self.one_to_simple(name))
|
|
273
|
+
return result
|
|
274
|
+
|
|
275
|
+
def one_to_simple(self, name: str) -> Dict[str, Any]:
|
|
276
|
+
fld = self._fields.get(name)
|
|
277
|
+
type_name = fld.type_name if fld else FIELD_TYPE_STRING
|
|
278
|
+
return {
|
|
279
|
+
"name": name,
|
|
280
|
+
"type": type_name,
|
|
281
|
+
"value": self.simplify_value(self.values[name]),
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
def from_simple_data(self, data: Any):
|
|
285
|
+
"""Populate the variable bag from a simple data structure.
|
|
286
|
+
|
|
287
|
+
The simple data structure is a list of dictionaries, each
|
|
288
|
+
containing the name, type, and value of a variable.
|
|
289
|
+
"""
|
|
290
|
+
for item in data:
|
|
291
|
+
self.simple_to_one(item)
|
|
292
|
+
|
|
293
|
+
def simple_to_one(self, item: Dict[str, Any]) -> Tuple[Union["ExField", None], Any]:
|
|
294
|
+
"""Load a single item from a simple data structure into the variable
|
|
295
|
+
bag.
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
A tuple containing the field and the value.
|
|
299
|
+
None, None if the item has no name.
|
|
300
|
+
"""
|
|
301
|
+
type_name = item.get("type", FIELD_TYPE_STRING)
|
|
302
|
+
cls_for_type = field_type_to_class.get(type_name, StrField)
|
|
303
|
+
name = item.get("name", "")
|
|
304
|
+
if not name:
|
|
305
|
+
return None, None
|
|
306
|
+
|
|
307
|
+
if name not in self.values:
|
|
308
|
+
inst = cls_for_type(name=name)
|
|
309
|
+
self._fields[name] = inst
|
|
310
|
+
else:
|
|
311
|
+
inst = self._fields.get(name)
|
|
312
|
+
if inst is None:
|
|
313
|
+
inst = cls_for_type(name=name)
|
|
314
|
+
self._fields[name] = inst
|
|
315
|
+
|
|
316
|
+
value = item.get("value", "")
|
|
317
|
+
self.values[name] = inst.value_from_str(value)
|
|
318
|
+
return inst, value
|
|
319
|
+
|
|
320
|
+
def update(self, other: "VarBag") -> None:
|
|
321
|
+
"""Update this variable bag with the values from another variable bag.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
other: The other variable bag to update from.
|
|
325
|
+
"""
|
|
326
|
+
for name in other._fields.keys():
|
|
327
|
+
self._fields[name] = other._fields[name]
|
|
328
|
+
self.values[name] = other.values[name]
|
exdrf/visitor.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from exdrf.dataset import ExDataset
|
|
5
|
+
from exdrf.field import ExField
|
|
6
|
+
from exdrf.resource import ExResource
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ExVisitor:
|
|
10
|
+
"""Visitor class that can explore datasets, resources and fields."""
|
|
11
|
+
|
|
12
|
+
def visit_dataset(self, dataset: "ExDataset"):
|
|
13
|
+
"""Visit a dataset.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
dataset: The dataset to visit.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
bool: True if the visit should continue, False otherwise.
|
|
20
|
+
"""
|
|
21
|
+
return True
|
|
22
|
+
|
|
23
|
+
def visit_category(self, name: str, level: int, content: dict):
|
|
24
|
+
"""Visit a category.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
name: The key of the category.
|
|
28
|
+
level: The depth level of the category.
|
|
29
|
+
content: The content of the category. This is a dictionary
|
|
30
|
+
where values can be other categories or resources. The key
|
|
31
|
+
is the name of the resource or category.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
bool: True if the visit should continue, False otherwise.
|
|
35
|
+
"""
|
|
36
|
+
return True
|
|
37
|
+
|
|
38
|
+
def visit_resource(self, resource: "ExResource"):
|
|
39
|
+
"""Visit a resource.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
resource: The resource to visit.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
bool: True if the visit should continue, False otherwise.
|
|
46
|
+
"""
|
|
47
|
+
return True
|
|
48
|
+
|
|
49
|
+
def visit_field(self, field: "ExField"):
|
|
50
|
+
"""Visit a field.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
field: The field to visit.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
bool: True if the visit should continue, False otherwise.
|
|
57
|
+
"""
|
|
58
|
+
return True
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: exdrf
|
|
3
|
+
Version: 0.0.1.dev0
|
|
4
|
+
Summary: Describe datasets, resources and their fields.
|
|
5
|
+
Author-email: Nicu Tofan <nicu.tofan@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Operating System :: OS Independent
|
|
8
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Typing :: Typed
|
|
12
|
+
Requires-Python: >=3.12.2
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: attrs>=25.1.0
|
|
15
|
+
Requires-Dist: inflect>=7.5.0
|
|
16
|
+
Requires-Dist: SQLAlchemy>=2.0.38
|
|
17
|
+
Requires-Dist: Unidecode>=1.4.0
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: autoflake; extra == "dev"
|
|
20
|
+
Requires-Dist: black; extra == "dev"
|
|
21
|
+
Requires-Dist: build; extra == "dev"
|
|
22
|
+
Requires-Dist: flake8; extra == "dev"
|
|
23
|
+
Requires-Dist: isort; extra == "dev"
|
|
24
|
+
Requires-Dist: mypy; extra == "dev"
|
|
25
|
+
Requires-Dist: ruff; extra == "dev"
|
|
26
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
27
|
+
Requires-Dist: pyproject-flake8; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-mock; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest; extra == "dev"
|
|
31
|
+
Requires-Dist: twine; extra == "dev"
|
|
32
|
+
Requires-Dist: wheel; extra == "dev"
|
|
33
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
34
|
+
Requires-Dist: click<8.2.0,>=8.1.8; extra == "dev"
|
|
35
|
+
|
|
36
|
+
# Datasets-Resources-Fields
|
|
37
|
+
|
|
38
|
+
The library allows the user to define fields that make up a resource that is
|
|
39
|
+
part of a dataset. The purpose is to construct an unified interface for
|
|
40
|
+
describing these concepts, with supporting libraries for deriving the
|
|
41
|
+
tree from various sources (e.g. SqlAlchemy, Pydantic, etc.) and for
|
|
42
|
+
generating content from the tree.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
exdrf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
exdrf/__version__.py,sha256=wd6FEk1AvxCOeRfZY-CEa3fIKmm0i6E5YP_YSuNubV8,532
|
|
3
|
+
exdrf/api.py,sha256=grjmGw_xnmxLlRZ1IzN6sWa2Emw8XvjjwyReb2ncPX4,1082
|
|
4
|
+
exdrf/constants.py,sha256=wu5RxQz6gZWm_WTvOc1lkL3bE2zD6IXAZpfZc6SBPWY,1580
|
|
5
|
+
exdrf/dataset.py,sha256=HjBkGynj0CZUJI4Sbl0_B2tXbwvl6PfBHE5sQbkSyqA,6889
|
|
6
|
+
exdrf/field.py,sha256=FnLskFULz1LEAOw4cY_Nnau4-BGt247AWaOCUAlTBGI,22086
|
|
7
|
+
exdrf/filter.py,sha256=rCaOZhSggHbHv6E8RaeOV0QiqlaFg7KV-FyUcpvDUnA,22505
|
|
8
|
+
exdrf/filter_dsl.py,sha256=_k1_RCqTTm9XuCyBg9Kaprdex14EZsMM_AL9mj8nB5M,29553
|
|
9
|
+
exdrf/filter_op_catalog.py,sha256=_XrjcJGPAKm1nrFIrZnNszWcOA6IpcYFSw3L3AuKr6w,7349
|
|
10
|
+
exdrf/label_dsl.py,sha256=VJ_dBozDeNml5pAf2jlNVhAOdmg6CGw9Md7bm3p3NsM,20822
|
|
11
|
+
exdrf/moment.py,sha256=3SMlfbd-xBouAWYprVRSA9sCO2Dxy7FJNnN67x25LMg,17881
|
|
12
|
+
exdrf/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
exdrf/py_support.py,sha256=DNQMXG_wTZg3nKSWeIzbAB4liIB4vsCcEBB2hSJ5rrY,530
|
|
14
|
+
exdrf/resource.py,sha256=uM-t3VR-3BOvaggVTA0l4UsBxS3TPa6Z02RvmrZJz8A,33706
|
|
15
|
+
exdrf/sa_fi_item.py,sha256=f5M4Z_h4DYz5xGqOOIpAod_wjAj8Lj-zhzxHriGmr2c,1906
|
|
16
|
+
exdrf/sa_filter_op.py,sha256=zzH3jddknbOtQIo161kc-fu1JHupzoU0__NwKUTUm0I,8810
|
|
17
|
+
exdrf/utils.py,sha256=nwqAdzPveabwBnNpxh2qX4Dp7O02tpb7HoDg_kiDDFk,401
|
|
18
|
+
exdrf/validator.py,sha256=IatkMvcDgj9XLUotj-yL8buvsPcA2XkNCwi72eXjW4c,1253
|
|
19
|
+
exdrf/var_bag.py,sha256=wVAGZv4nL__GRuFs3sUKptai8oFY1MkMpgVFhEVw_dQ,10808
|
|
20
|
+
exdrf/visitor.py,sha256=8Y3v5UjBMxvlenDF1HyUI_XnmogkG77ZrfONf09ot8A,1619
|
|
21
|
+
exdrf/field_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
exdrf/field_types/api.py,sha256=9SjcwsbdRPLlP7WXeR0yrlb9AxMgs1Jm-H1AGsH45mA,3040
|
|
23
|
+
exdrf/field_types/blob_field.py,sha256=NvqITYTiuxZSZ6IiiR_er-pd-YkMLYHunDICyzUIcs0,1222
|
|
24
|
+
exdrf/field_types/bool_field.py,sha256=puDhEJ28M7bLhYaV5xpViiqQOiHrKF86v7-dizU4rt4,1441
|
|
25
|
+
exdrf/field_types/date_field.py,sha256=IGfth56e8zunSruhJG2A1W6B4QMkM0w-HO51wh3CyRg,1435
|
|
26
|
+
exdrf/field_types/date_time.py,sha256=AaDj-lHE47-EN195D3UJ1FQyopFm0RDYFhrMm8Ws6AU,1613
|
|
27
|
+
exdrf/field_types/dur_field.py,sha256=v9dpZ2XOcClKKftWuYd0zpv-hFrapK-b7HR-1bR5stI,1277
|
|
28
|
+
exdrf/field_types/enum_field.py,sha256=mWwC8fQSKT9P_2wOrmdWxXyZgBNc_capjAAlu_zvk-4,1170
|
|
29
|
+
exdrf/field_types/filter_field.py,sha256=YD0iA0t6kpA-4t6vvriEb-uU77AptllpUsOLI0YbHpU,254
|
|
30
|
+
exdrf/field_types/float_field.py,sha256=OexfRPZCd2MUF8BcX1gcLUL0MfPwQRF0reJCJe80688,3231
|
|
31
|
+
exdrf/field_types/float_list.py,sha256=uT6mc0ZT7Hq_iuc4W1qmxkBWH4Ko2b9wCYYcxTIpFVg,515
|
|
32
|
+
exdrf/field_types/formatted.py,sha256=JYjU321orU_sF2yeWe_c-5NCHcGpZ3aSTpyCcCfaBQY,1149
|
|
33
|
+
exdrf/field_types/int_field.py,sha256=gHldpshmqzo5NdXRQLVaGmCGzZZQsbWx0ablLzEm10c,2410
|
|
34
|
+
exdrf/field_types/int_list.py,sha256=XCxXBoMmya0JPN_K2w523TK8SXAfVQnDtz-dSVnDpAs,489
|
|
35
|
+
exdrf/field_types/ref_base.py,sha256=kICJeaejzfEaaDRTM8XqCwBW5MVarVEx4JyWBNmMeps,4543
|
|
36
|
+
exdrf/field_types/ref_m2m.py,sha256=TG0Su3rvLXQUi9gUxM0nkiOfXY0U-T51cRiykNQFoa4,1388
|
|
37
|
+
exdrf/field_types/ref_m2o.py,sha256=ayZN5TnLze43UnNaj5kDZLvYqI2onfeh9UjvyWTzanI,735
|
|
38
|
+
exdrf/field_types/ref_o2m.py,sha256=mPdD1EGvfXeqc2yr_M7ZAiIKrHOtWPF4XCSI0qrk24I,1199
|
|
39
|
+
exdrf/field_types/ref_o2o.py,sha256=9GleYEQ6OM_6JflxjPLK6CJCSmkAxER3UbJU3Bt31i0,1081
|
|
40
|
+
exdrf/field_types/sort_field.py,sha256=L_Od3beme8bY7iWoXQJpXrs-9edNMRao-urJGE2jw2M,459
|
|
41
|
+
exdrf/field_types/str_field.py,sha256=rNbFRNf29BZGqxOSv_bQq9YDiBp8C4KMmKX50a7W0Ao,2916
|
|
42
|
+
exdrf/field_types/str_list.py,sha256=oGBpaDdBrsCoYdU1S0F5S0eMLZ9BO1Lj_nrvB1L6LyI,488
|
|
43
|
+
exdrf/field_types/time_field.py,sha256=sHt4C2OerQygbcFJ4pFIQVvdGZsXVDvaLPszPM74xVo,1471
|
|
44
|
+
exdrf_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
|
+
exdrf_tests/test_dataset.py,sha256=JRU3B0-Owxqq8aS9eanwjmTcbrjUeGNLhCTLuH9smK0,15152
|
|
46
|
+
exdrf_tests/test_field.py,sha256=4P1CS8_0wJ4jq3pgKNdYMOZ2-FTeQlpxZ09GL5AAyOY,2905
|
|
47
|
+
exdrf_tests/test_filter.py,sha256=ZUs-o7GwkEgie3nIUuJTojK-MVoX4-6GhnNMHsLuugw,13705
|
|
48
|
+
exdrf_tests/test_filter_dsl.py,sha256=k1zyTILMO3yTNqd5jI2GQOouWUWNXEe_sLFb5yuxYvA,22087
|
|
49
|
+
exdrf_tests/test_label_dsl.py,sha256=glHYmjzx4JSF4RlB92oX2fxqaNpzFY50Ctd19ewmkig,6573
|
|
50
|
+
exdrf_tests/test_resource.py,sha256=DEOd0gT67NBpMTL_z3eJxxGrurGCZjzGd1WF51-qsKM,3056
|
|
51
|
+
exdrf_tests/test_utils.py,sha256=xB-Z_zziJBdh0itztFELanxoefmFWSxiVb16dv3Vg5o,1345
|
|
52
|
+
exdrf_tests/test_visitor.py,sha256=D2ygbKj7w-QO45L_WWzmoh3TMFJ5wEZevQcZHt4y0XA,933
|
|
53
|
+
exdrf_tests/var_bag_test.py,sha256=EAnlhHj_K5n-UIXKU-IouVOmu9WbuFVSzV8ZbTZAR1o,18872
|
|
54
|
+
exdrf-0.0.1.dev0.dist-info/METADATA,sha256=EcGaHKk3c2ZAvBrneZ1aVqUcjmdEl2x2VPhC8PGZ7iw,1601
|
|
55
|
+
exdrf-0.0.1.dev0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
56
|
+
exdrf-0.0.1.dev0.dist-info/top_level.txt,sha256=WsOz8ThH9m7N2wwPVYmnMt6XqVD6pQ5iU23LOntZzb8,23
|
|
57
|
+
exdrf-0.0.1.dev0.dist-info/RECORD,,
|
exdrf_tests/__init__.py
ADDED
|
File without changes
|