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.
Files changed (90) hide show
  1. ccflow/__init__.py +11 -0
  2. ccflow/arrow.py +198 -0
  3. ccflow/base.py +830 -0
  4. ccflow/callable.py +545 -0
  5. ccflow/context.py +203 -0
  6. ccflow/enums.py +136 -0
  7. ccflow/evaluators/__init__.py +1 -0
  8. ccflow/evaluators/common.py +221 -0
  9. ccflow/examples/__init__.py +0 -0
  10. ccflow/examples/example.parquet +0 -0
  11. ccflow/exttypes/__init__.py +9 -0
  12. ccflow/exttypes/arrow.py +123 -0
  13. ccflow/exttypes/exprtk.py +60 -0
  14. ccflow/exttypes/frequency.py +56 -0
  15. ccflow/exttypes/jinja.py +43 -0
  16. ccflow/exttypes/pandas.py +165 -0
  17. ccflow/exttypes/polars.py +77 -0
  18. ccflow/exttypes/pydantic_numpy/__init__.py +2 -0
  19. ccflow/exttypes/pydantic_numpy/ndarray.py +73 -0
  20. ccflow/exttypes/pydantic_numpy/ndtypes.py +220 -0
  21. ccflow/exttypes/pyobjectpath.py +97 -0
  22. ccflow/models/__init__.py +0 -0
  23. ccflow/object_config.py +90 -0
  24. ccflow/publisher.py +49 -0
  25. ccflow/publishers/__init__.py +2 -0
  26. ccflow/publishers/composite.py +127 -0
  27. ccflow/publishers/file.py +192 -0
  28. ccflow/py.typed +0 -0
  29. ccflow/result/__init__.py +2 -0
  30. ccflow/result/dict.py +13 -0
  31. ccflow/result/generic.py +28 -0
  32. ccflow/result/numpy.py +16 -0
  33. ccflow/result/pandas.py +23 -0
  34. ccflow/result/pyarrow.py +67 -0
  35. ccflow/result/xarray.py +24 -0
  36. ccflow/serialization.py +59 -0
  37. ccflow/tests/__init__.py +0 -0
  38. ccflow/tests/config/conf.yaml +28 -0
  39. ccflow/tests/config/conf_out_of_order.yaml +23 -0
  40. ccflow/tests/config/conf_sub.yaml +30 -0
  41. ccflow/tests/conftest.py +0 -0
  42. ccflow/tests/enums/__init__.py +0 -0
  43. ccflow/tests/enums/test_enums.py +108 -0
  44. ccflow/tests/enums/test_pydantic.py +113 -0
  45. ccflow/tests/evaluators/__init__.py +0 -0
  46. ccflow/tests/evaluators/test_common.py +406 -0
  47. ccflow/tests/evaluators/util.py +116 -0
  48. ccflow/tests/exttypes/__init__.py +0 -0
  49. ccflow/tests/exttypes/test_arrow.py +182 -0
  50. ccflow/tests/exttypes/test_exprtk.py +58 -0
  51. ccflow/tests/exttypes/test_frequency.py +71 -0
  52. ccflow/tests/exttypes/test_jinja.py +28 -0
  53. ccflow/tests/exttypes/test_pandas.py +130 -0
  54. ccflow/tests/exttypes/test_polars.py +56 -0
  55. ccflow/tests/exttypes/test_pydantic_numpy.py +132 -0
  56. ccflow/tests/exttypes/test_pyobjectpath.py +64 -0
  57. ccflow/tests/publishers/test_composite.py +246 -0
  58. ccflow/tests/publishers/test_file.py +164 -0
  59. ccflow/tests/result/__init__.py +0 -0
  60. ccflow/tests/result/test_dict.py +9 -0
  61. ccflow/tests/result/test_generic.py +41 -0
  62. ccflow/tests/result/test_numpy.py +24 -0
  63. ccflow/tests/result/test_pandas.py +22 -0
  64. ccflow/tests/result/test_pyarrow.py +38 -0
  65. ccflow/tests/result/test_xarray.py +30 -0
  66. ccflow/tests/test_arrow.py +188 -0
  67. ccflow/tests/test_base.py +139 -0
  68. ccflow/tests/test_base_registry.py +594 -0
  69. ccflow/tests/test_base_serialize.py +234 -0
  70. ccflow/tests/test_callable.py +378 -0
  71. ccflow/tests/test_context.py +190 -0
  72. ccflow/tests/test_decorator.py +293 -0
  73. ccflow/tests/test_evaluator.py +34 -0
  74. ccflow/tests/test_import.py +32 -0
  75. ccflow/tests/test_lazy_result.py +41 -0
  76. ccflow/tests/test_object_config.py +96 -0
  77. ccflow/tests/test_validators.py +40 -0
  78. ccflow/tests/utils/__init__.py +0 -0
  79. ccflow/tests/utils/test_arrow.py +97 -0
  80. ccflow/tests/utils/test_chunker.py +109 -0
  81. ccflow/utils/__init__.py +3 -0
  82. ccflow/utils/arrow.py +87 -0
  83. ccflow/utils/chunker.py +49 -0
  84. ccflow/utils/core.py +39 -0
  85. ccflow/utils/tokenize.py +2 -0
  86. ccflow/validators.py +52 -0
  87. ccflow-0.0.1.dist-info/METADATA +324 -0
  88. ccflow-0.0.1.dist-info/RECORD +90 -0
  89. ccflow-0.0.1.dist-info/WHEEL +4 -0
  90. ccflow-0.0.1.dist-info/licenses/LICENSE +201 -0
ccflow/__init__.py ADDED
@@ -0,0 +1,11 @@
1
+ __version__ = "0.0.1"
2
+
3
+ from .arrow import *
4
+ from .base import *
5
+ from .callable import *
6
+ from .context import *
7
+ from .enums import Enum
8
+ from .exttypes import *
9
+ from .object_config import *
10
+ from .publisher import *
11
+ from .result import *
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 []