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
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,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ dist
2
+ exdrf
3
+ exdrf_tests
File without changes