ccflow 0.0.1__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.
- ccflow/__init__.py +11 -0
- ccflow/arrow.py +198 -0
- ccflow/base.py +830 -0
- ccflow/callable.py +545 -0
- ccflow/context.py +203 -0
- ccflow/enums.py +136 -0
- ccflow/evaluators/__init__.py +1 -0
- ccflow/evaluators/common.py +221 -0
- ccflow/examples/__init__.py +0 -0
- ccflow/examples/example.parquet +0 -0
- ccflow/exttypes/__init__.py +9 -0
- ccflow/exttypes/arrow.py +123 -0
- ccflow/exttypes/exprtk.py +60 -0
- ccflow/exttypes/frequency.py +56 -0
- ccflow/exttypes/jinja.py +43 -0
- ccflow/exttypes/pandas.py +165 -0
- ccflow/exttypes/polars.py +77 -0
- ccflow/exttypes/pydantic_numpy/__init__.py +2 -0
- ccflow/exttypes/pydantic_numpy/ndarray.py +73 -0
- ccflow/exttypes/pydantic_numpy/ndtypes.py +220 -0
- ccflow/exttypes/pyobjectpath.py +97 -0
- ccflow/models/__init__.py +0 -0
- ccflow/object_config.py +90 -0
- ccflow/publisher.py +49 -0
- ccflow/publishers/__init__.py +2 -0
- ccflow/publishers/composite.py +127 -0
- ccflow/publishers/file.py +192 -0
- ccflow/py.typed +0 -0
- ccflow/result/__init__.py +2 -0
- ccflow/result/dict.py +13 -0
- ccflow/result/generic.py +28 -0
- ccflow/result/numpy.py +16 -0
- ccflow/result/pandas.py +23 -0
- ccflow/result/pyarrow.py +67 -0
- ccflow/result/xarray.py +24 -0
- ccflow/serialization.py +59 -0
- ccflow/tests/__init__.py +0 -0
- ccflow/tests/config/conf.yaml +28 -0
- ccflow/tests/config/conf_out_of_order.yaml +23 -0
- ccflow/tests/config/conf_sub.yaml +30 -0
- ccflow/tests/conftest.py +0 -0
- ccflow/tests/enums/__init__.py +0 -0
- ccflow/tests/enums/test_enums.py +108 -0
- ccflow/tests/enums/test_pydantic.py +113 -0
- ccflow/tests/evaluators/__init__.py +0 -0
- ccflow/tests/evaluators/test_common.py +406 -0
- ccflow/tests/evaluators/util.py +116 -0
- ccflow/tests/exttypes/__init__.py +0 -0
- ccflow/tests/exttypes/test_arrow.py +182 -0
- ccflow/tests/exttypes/test_exprtk.py +58 -0
- ccflow/tests/exttypes/test_frequency.py +71 -0
- ccflow/tests/exttypes/test_jinja.py +28 -0
- ccflow/tests/exttypes/test_pandas.py +130 -0
- ccflow/tests/exttypes/test_polars.py +56 -0
- ccflow/tests/exttypes/test_pydantic_numpy.py +132 -0
- ccflow/tests/exttypes/test_pyobjectpath.py +64 -0
- ccflow/tests/publishers/test_composite.py +246 -0
- ccflow/tests/publishers/test_file.py +164 -0
- ccflow/tests/result/__init__.py +0 -0
- ccflow/tests/result/test_dict.py +9 -0
- ccflow/tests/result/test_generic.py +41 -0
- ccflow/tests/result/test_numpy.py +24 -0
- ccflow/tests/result/test_pandas.py +22 -0
- ccflow/tests/result/test_pyarrow.py +38 -0
- ccflow/tests/result/test_xarray.py +30 -0
- ccflow/tests/test_arrow.py +188 -0
- ccflow/tests/test_base.py +139 -0
- ccflow/tests/test_base_registry.py +594 -0
- ccflow/tests/test_base_serialize.py +234 -0
- ccflow/tests/test_callable.py +378 -0
- ccflow/tests/test_context.py +190 -0
- ccflow/tests/test_decorator.py +293 -0
- ccflow/tests/test_evaluator.py +34 -0
- ccflow/tests/test_import.py +32 -0
- ccflow/tests/test_lazy_result.py +41 -0
- ccflow/tests/test_object_config.py +96 -0
- ccflow/tests/test_validators.py +40 -0
- ccflow/tests/utils/__init__.py +0 -0
- ccflow/tests/utils/test_arrow.py +97 -0
- ccflow/tests/utils/test_chunker.py +109 -0
- ccflow/utils/__init__.py +3 -0
- ccflow/utils/arrow.py +87 -0
- ccflow/utils/chunker.py +49 -0
- ccflow/utils/core.py +39 -0
- ccflow/utils/tokenize.py +2 -0
- ccflow/validators.py +52 -0
- ccflow-0.0.1.dist-info/METADATA +324 -0
- ccflow-0.0.1.dist-info/RECORD +90 -0
- ccflow-0.0.1.dist-info/WHEEL +4 -0
- ccflow-0.0.1.dist-info/licenses/LICENSE +201 -0
ccflow/__init__.py
ADDED
ccflow/arrow.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""This modules holds BaseModels that facilitate working with Arrow classes.
|
|
2
|
+
Note that arrow related extension types are in exttypes.arrow.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import abc
|
|
6
|
+
from datetime import date, datetime, time
|
|
7
|
+
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
|
|
8
|
+
|
|
9
|
+
import pyarrow as pa
|
|
10
|
+
from pydantic import Field, model_validator
|
|
11
|
+
|
|
12
|
+
from .base import BaseModel
|
|
13
|
+
from .exttypes import JinjaTemplate, PyArrowDatatype, PyObjectPath
|
|
14
|
+
from .object_config import ObjectConfig
|
|
15
|
+
|
|
16
|
+
__all__ = (
|
|
17
|
+
"ArrowSchemaModel",
|
|
18
|
+
"ArrowPartitioning",
|
|
19
|
+
"ArrowDateFilter",
|
|
20
|
+
"ArrowDatetimeFilter",
|
|
21
|
+
"ArrowFilter",
|
|
22
|
+
"ArrowTimeFilter",
|
|
23
|
+
"ArrowTemplateFilter",
|
|
24
|
+
"ArrowFileSystem",
|
|
25
|
+
"ArrowLocalFileSystem",
|
|
26
|
+
"ArrowS3FileSystem",
|
|
27
|
+
"render_filters",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ArrowFilter(BaseModel):
|
|
32
|
+
"""Wrapping of pyarrow filter tuples as a ccflow BaseModel.
|
|
33
|
+
|
|
34
|
+
Allows for better typing of filters in configs for pyarrow file reads.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
key: str
|
|
38
|
+
op: str
|
|
39
|
+
value: Any
|
|
40
|
+
|
|
41
|
+
def tuple(self) -> Tuple:
|
|
42
|
+
"""Convert the filter back to a tuple"""
|
|
43
|
+
return self.key, self.op, self.value
|
|
44
|
+
|
|
45
|
+
@model_validator(mode="before")
|
|
46
|
+
def _validate_fields(cls, v, info):
|
|
47
|
+
if isinstance(v, (list, tuple)):
|
|
48
|
+
key, op, value = v
|
|
49
|
+
return dict(key=key, op=op, value=value)
|
|
50
|
+
return v
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ArrowDateFilter(ArrowFilter):
|
|
54
|
+
"""An ArrowFilter where value is validated as a date"""
|
|
55
|
+
|
|
56
|
+
value: date
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ArrowDatetimeFilter(ArrowFilter):
|
|
60
|
+
"""An ArrowFilter where value is validated as a datetime"""
|
|
61
|
+
|
|
62
|
+
value: datetime
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class ArrowTimeFilter(ArrowFilter):
|
|
66
|
+
"""An ArrowFilter where value is validated as a time"""
|
|
67
|
+
|
|
68
|
+
value: time
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class ArrowTemplateFilter(ArrowFilter):
|
|
72
|
+
"""An ArrowFilter where value is validated as a Jinja template"""
|
|
73
|
+
|
|
74
|
+
value: JinjaTemplate
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _render_filter(f, template_args):
|
|
78
|
+
if isinstance(f, ArrowTemplateFilter):
|
|
79
|
+
return (f.key, f.op, f.value.template.render(**template_args))
|
|
80
|
+
else:
|
|
81
|
+
return f.tuple()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def render_filters(
|
|
85
|
+
filters: Union[List[ArrowFilter], List[List[ArrowFilter]]],
|
|
86
|
+
template_args: Dict[str, Any],
|
|
87
|
+
) -> Union[List[ArrowFilter], List[List[ArrowFilter]]]:
|
|
88
|
+
"""Fill in template arguments in a list of filters, and return the standard Arrow form.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
filters: The collection of filters to render.
|
|
92
|
+
template_args: The template arguments for the filters
|
|
93
|
+
"""
|
|
94
|
+
if isinstance(filters[0], ArrowFilter):
|
|
95
|
+
return [_render_filter(f, template_args) for f in filters]
|
|
96
|
+
else:
|
|
97
|
+
return [[_render_filter(f, template_args) for f in flist] for flist in filters]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class ArrowFileSystem(ObjectConfig, abc.ABC):
|
|
101
|
+
"""Wrapping of pyarrow.fs.Filesystem as a generic ObjectConfig.
|
|
102
|
+
|
|
103
|
+
See https://arrow.apache.org/docs/python/filesystems.html
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class ArrowLocalFileSystem(ArrowFileSystem):
|
|
108
|
+
"""Wrapping of pyarrow.fs.LocalFilesystem as a generic ObjectConfig.
|
|
109
|
+
|
|
110
|
+
See https://arrow.apache.org/docs/python/generated/pyarrow.fs.LocalFileSystem.html
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
_LOCAL_FILE_SYSTEM = PyObjectPath("pyarrow.fs.LocalFileSystem")
|
|
114
|
+
|
|
115
|
+
object_type: Literal[_LOCAL_FILE_SYSTEM] = _LOCAL_FILE_SYSTEM
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class ArrowS3FileSystem(ArrowFileSystem):
|
|
119
|
+
"""Wrapping of pyarrow.fs.S3FileSystem as a generic ObjectConfig.
|
|
120
|
+
|
|
121
|
+
See https://arrow.apache.org/docs/python/generated/pyarrow.fs.S3FileSystem.html"""
|
|
122
|
+
|
|
123
|
+
_S3_FILE_SYSTEM = PyObjectPath("pyarrow.fs.S3FileSystem")
|
|
124
|
+
|
|
125
|
+
object_type: Literal[_S3_FILE_SYSTEM] = _S3_FILE_SYSTEM
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class ArrowSchemaModel(BaseModel):
|
|
129
|
+
"""Wrapping of pyarrow.Schema as a ccflow BaseModel."""
|
|
130
|
+
|
|
131
|
+
fields: Dict[str, PyArrowDatatype]
|
|
132
|
+
metadata: Optional[Dict[bytes, bytes]] = None
|
|
133
|
+
|
|
134
|
+
@model_validator(mode="before")
|
|
135
|
+
def _validate_fields(cls, values, info):
|
|
136
|
+
if isinstance(values, dict) and "fields" in values:
|
|
137
|
+
values["fields"] = dict(values["fields"])
|
|
138
|
+
return values
|
|
139
|
+
|
|
140
|
+
@model_validator(mode="wrap")
|
|
141
|
+
def _schema_validator(cls, v, handler, info):
|
|
142
|
+
if isinstance(v, pa.Schema):
|
|
143
|
+
v = dict(
|
|
144
|
+
fields={name: v.field(name).type for name in v.names},
|
|
145
|
+
metadata=v.metadata,
|
|
146
|
+
)
|
|
147
|
+
return handler(v)
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def schema(self) -> pa.Schema:
|
|
151
|
+
if isinstance(self.fields, Dict):
|
|
152
|
+
return pa.schema(
|
|
153
|
+
{k: v.datatype if isinstance(v, PyArrowDatatype) else v for k, v in self.fields.items()},
|
|
154
|
+
self.metadata,
|
|
155
|
+
)
|
|
156
|
+
if isinstance(self.fields, List):
|
|
157
|
+
return pa.schema(
|
|
158
|
+
[(k, v.datatype if isinstance(v, PyArrowDatatype) else v) for (k, v) in self.fields],
|
|
159
|
+
self.metadata,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def object(self) -> pa.Schema:
|
|
164
|
+
"""Alias to schema method as it's more consistent with other object wrappings"""
|
|
165
|
+
return self.schema
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class ArrowPartitioning(BaseModel):
|
|
169
|
+
"""Wrapping of pyarrow.dataset.Partitioning as a ccflow BaseModel.
|
|
170
|
+
|
|
171
|
+
See https://arrow.apache.org/docs/python/generated/pyarrow.dataset.partitioning.html
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
arrow_schema: Optional[ArrowSchemaModel] = Field(None, alias="schema")
|
|
175
|
+
field_names: Optional[List[str]] = None
|
|
176
|
+
flavor: Optional[str] = None
|
|
177
|
+
dictionaries: Optional[Dict[str, Any]] = None
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def object(self): # -> Union[ds.Partitioning, ds.PartitioningFactory]:
|
|
181
|
+
"""Return the underlying pyarrow dataset Partitioning object"""
|
|
182
|
+
import pyarrow.dataset as ds # Heavy import, only import if used.
|
|
183
|
+
|
|
184
|
+
return ds.partitioning(
|
|
185
|
+
schema=self.arrow_schema.schema if self.arrow_schema else None,
|
|
186
|
+
field_names=self.field_names,
|
|
187
|
+
flavor=self.flavor,
|
|
188
|
+
dictionaries=self.dictionaries,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def get_partition_columns(self) -> List[str]:
|
|
192
|
+
"""Return the list of partition columns"""
|
|
193
|
+
if self.arrow_schema:
|
|
194
|
+
return self.arrow_schema.object.names
|
|
195
|
+
elif self.field_names:
|
|
196
|
+
return self.field_names
|
|
197
|
+
else:
|
|
198
|
+
return []
|