apache-hamilton 1.90.0.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.
- apache_hamilton-1.90.0.dev0.dist-info/METADATA +407 -0
- apache_hamilton-1.90.0.dev0.dist-info/RECORD +151 -0
- apache_hamilton-1.90.0.dev0.dist-info/WHEEL +4 -0
- apache_hamilton-1.90.0.dev0.dist-info/entry_points.txt +9 -0
- apache_hamilton-1.90.0.dev0.dist-info/licenses/DISCLAIMER +10 -0
- apache_hamilton-1.90.0.dev0.dist-info/licenses/LICENSE +228 -0
- apache_hamilton-1.90.0.dev0.dist-info/licenses/NOTICE +5 -0
- hamilton/__init__.py +24 -0
- hamilton/ad_hoc_utils.py +132 -0
- hamilton/async_driver.py +465 -0
- hamilton/base.py +466 -0
- hamilton/caching/__init__.py +16 -0
- hamilton/caching/adapter.py +1475 -0
- hamilton/caching/cache_key.py +70 -0
- hamilton/caching/fingerprinting.py +287 -0
- hamilton/caching/stores/__init__.py +16 -0
- hamilton/caching/stores/base.py +242 -0
- hamilton/caching/stores/file.py +140 -0
- hamilton/caching/stores/memory.py +297 -0
- hamilton/caching/stores/sqlite.py +282 -0
- hamilton/caching/stores/utils.py +40 -0
- hamilton/cli/__init__.py +16 -0
- hamilton/cli/__main__.py +328 -0
- hamilton/cli/commands.py +126 -0
- hamilton/cli/logic.py +338 -0
- hamilton/common/__init__.py +76 -0
- hamilton/contrib/__init__.py +41 -0
- hamilton/data_quality/__init__.py +16 -0
- hamilton/data_quality/base.py +198 -0
- hamilton/data_quality/default_validators.py +560 -0
- hamilton/data_quality/pandera_validators.py +121 -0
- hamilton/dataflows/__init__.py +726 -0
- hamilton/dataflows/template/README.md +25 -0
- hamilton/dataflows/template/__init__.py +54 -0
- hamilton/dataflows/template/author.md +28 -0
- hamilton/dataflows/template/requirements.txt +0 -0
- hamilton/dataflows/template/tags.json +7 -0
- hamilton/dataflows/template/valid_configs.jsonl +1 -0
- hamilton/dev_utils/__init__.py +16 -0
- hamilton/dev_utils/deprecation.py +204 -0
- hamilton/driver.py +2112 -0
- hamilton/execution/__init__.py +16 -0
- hamilton/execution/debugging_utils.py +56 -0
- hamilton/execution/executors.py +502 -0
- hamilton/execution/graph_functions.py +421 -0
- hamilton/execution/grouping.py +430 -0
- hamilton/execution/state.py +539 -0
- hamilton/experimental/__init__.py +27 -0
- hamilton/experimental/databackend.py +61 -0
- hamilton/experimental/decorators/__init__.py +16 -0
- hamilton/experimental/decorators/parameterize_frame.py +233 -0
- hamilton/experimental/h_async.py +29 -0
- hamilton/experimental/h_cache.py +413 -0
- hamilton/experimental/h_dask.py +28 -0
- hamilton/experimental/h_databackends.py +174 -0
- hamilton/experimental/h_ray.py +28 -0
- hamilton/experimental/h_spark.py +32 -0
- hamilton/function_modifiers/README +40 -0
- hamilton/function_modifiers/__init__.py +121 -0
- hamilton/function_modifiers/adapters.py +900 -0
- hamilton/function_modifiers/base.py +859 -0
- hamilton/function_modifiers/configuration.py +310 -0
- hamilton/function_modifiers/delayed.py +202 -0
- hamilton/function_modifiers/dependencies.py +246 -0
- hamilton/function_modifiers/expanders.py +1230 -0
- hamilton/function_modifiers/macros.py +1634 -0
- hamilton/function_modifiers/metadata.py +434 -0
- hamilton/function_modifiers/recursive.py +908 -0
- hamilton/function_modifiers/validation.py +289 -0
- hamilton/function_modifiers_base.py +31 -0
- hamilton/graph.py +1153 -0
- hamilton/graph_types.py +264 -0
- hamilton/graph_utils.py +41 -0
- hamilton/htypes.py +450 -0
- hamilton/io/__init__.py +32 -0
- hamilton/io/data_adapters.py +216 -0
- hamilton/io/default_data_loaders.py +224 -0
- hamilton/io/materialization.py +500 -0
- hamilton/io/utils.py +158 -0
- hamilton/lifecycle/__init__.py +67 -0
- hamilton/lifecycle/api.py +833 -0
- hamilton/lifecycle/base.py +1130 -0
- hamilton/lifecycle/default.py +802 -0
- hamilton/log_setup.py +47 -0
- hamilton/models.py +92 -0
- hamilton/node.py +449 -0
- hamilton/plugins/README.md +48 -0
- hamilton/plugins/__init__.py +16 -0
- hamilton/plugins/dask_extensions.py +47 -0
- hamilton/plugins/dlt_extensions.py +161 -0
- hamilton/plugins/geopandas_extensions.py +49 -0
- hamilton/plugins/h_dask.py +331 -0
- hamilton/plugins/h_ddog.py +522 -0
- hamilton/plugins/h_diskcache.py +163 -0
- hamilton/plugins/h_experiments/__init__.py +22 -0
- hamilton/plugins/h_experiments/__main__.py +62 -0
- hamilton/plugins/h_experiments/cache.py +39 -0
- hamilton/plugins/h_experiments/data_model.py +68 -0
- hamilton/plugins/h_experiments/hook.py +219 -0
- hamilton/plugins/h_experiments/server.py +375 -0
- hamilton/plugins/h_kedro.py +152 -0
- hamilton/plugins/h_logging.py +454 -0
- hamilton/plugins/h_mcp/__init__.py +28 -0
- hamilton/plugins/h_mcp/__main__.py +33 -0
- hamilton/plugins/h_mcp/_helpers.py +129 -0
- hamilton/plugins/h_mcp/_templates.py +417 -0
- hamilton/plugins/h_mcp/server.py +328 -0
- hamilton/plugins/h_mlflow.py +335 -0
- hamilton/plugins/h_narwhals.py +134 -0
- hamilton/plugins/h_openlineage.py +400 -0
- hamilton/plugins/h_opentelemetry.py +167 -0
- hamilton/plugins/h_pandas.py +257 -0
- hamilton/plugins/h_pandera.py +117 -0
- hamilton/plugins/h_polars.py +304 -0
- hamilton/plugins/h_polars_lazyframe.py +282 -0
- hamilton/plugins/h_pyarrow.py +56 -0
- hamilton/plugins/h_pydantic.py +127 -0
- hamilton/plugins/h_ray.py +242 -0
- hamilton/plugins/h_rich.py +142 -0
- hamilton/plugins/h_schema.py +493 -0
- hamilton/plugins/h_slack.py +100 -0
- hamilton/plugins/h_spark.py +1380 -0
- hamilton/plugins/h_threadpool.py +125 -0
- hamilton/plugins/h_tqdm.py +122 -0
- hamilton/plugins/h_vaex.py +129 -0
- hamilton/plugins/huggingface_extensions.py +236 -0
- hamilton/plugins/ibis_extensions.py +93 -0
- hamilton/plugins/jupyter_magic.py +622 -0
- hamilton/plugins/kedro_extensions.py +117 -0
- hamilton/plugins/lightgbm_extensions.py +99 -0
- hamilton/plugins/matplotlib_extensions.py +108 -0
- hamilton/plugins/mlflow_extensions.py +216 -0
- hamilton/plugins/numpy_extensions.py +105 -0
- hamilton/plugins/pandas_extensions.py +1763 -0
- hamilton/plugins/plotly_extensions.py +150 -0
- hamilton/plugins/polars_extensions.py +71 -0
- hamilton/plugins/polars_implementations.py +25 -0
- hamilton/plugins/polars_lazyframe_extensions.py +302 -0
- hamilton/plugins/polars_post_1_0_0_extensions.py +877 -0
- hamilton/plugins/polars_pre_1_0_0_extension.py +836 -0
- hamilton/plugins/pydantic_extensions.py +98 -0
- hamilton/plugins/pyspark_pandas_extensions.py +47 -0
- hamilton/plugins/sklearn_plot_extensions.py +129 -0
- hamilton/plugins/spark_extensions.py +105 -0
- hamilton/plugins/vaex_extensions.py +51 -0
- hamilton/plugins/xgboost_extensions.py +91 -0
- hamilton/plugins/yaml_extensions.py +89 -0
- hamilton/registry.py +254 -0
- hamilton/settings.py +18 -0
- hamilton/telemetry.py +50 -0
- hamilton/version.py +18 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
|
12
|
+
# software distributed under the License is distributed on an
|
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
# KIND, either express or implied. See the License for the
|
|
15
|
+
# specific language governing permissions and limitations
|
|
16
|
+
# under the License.
|
|
17
|
+
|
|
18
|
+
import abc
|
|
19
|
+
import dataclasses
|
|
20
|
+
import enum
|
|
21
|
+
import inspect
|
|
22
|
+
import logging
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class DataValidationError(Exception):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class DataValidationLevel(enum.Enum):
|
|
33
|
+
WARN = "warn"
|
|
34
|
+
FAIL = "fail"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclasses.dataclass
|
|
38
|
+
class ValidationResult:
|
|
39
|
+
passes: bool # Whether or not this passed the validation
|
|
40
|
+
message: str # Error message or success message
|
|
41
|
+
diagnostics: dict[str, Any] = dataclasses.field(
|
|
42
|
+
default_factory=dict
|
|
43
|
+
) # Any extra diagnostics information needed, free-form
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class DataValidator(abc.ABC):
|
|
47
|
+
"""Base class for a data quality operator. This will be used by the `data_quality` operator"""
|
|
48
|
+
|
|
49
|
+
def __init__(self, importance: str):
|
|
50
|
+
self._importance = DataValidationLevel(importance)
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def importance(self) -> DataValidationLevel:
|
|
54
|
+
return self._importance
|
|
55
|
+
|
|
56
|
+
@abc.abstractmethod
|
|
57
|
+
def applies_to(self, datatype: type[type]) -> bool:
|
|
58
|
+
"""Whether or not this data validator can apply to the specified dataset
|
|
59
|
+
|
|
60
|
+
:param datatype:
|
|
61
|
+
:return: True if it can be run on the specified type, false otherwise
|
|
62
|
+
"""
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
@abc.abstractmethod
|
|
66
|
+
def description(self) -> str:
|
|
67
|
+
"""Gives a description of this validator. E.G.
|
|
68
|
+
`Checks whether the entire dataset lies between 0 and 1.`
|
|
69
|
+
Note it should be able to access internal state (E.G. constructor arguments).
|
|
70
|
+
:return: The description of the validator as a string
|
|
71
|
+
"""
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
@abc.abstractmethod
|
|
76
|
+
def name(cls) -> str:
|
|
77
|
+
"""Returns the name for this validator."""
|
|
78
|
+
|
|
79
|
+
@abc.abstractmethod
|
|
80
|
+
def validate(self, dataset: Any) -> ValidationResult:
|
|
81
|
+
"""Actually performs the validation. Note when you
|
|
82
|
+
|
|
83
|
+
:param dataset: dataset to validate
|
|
84
|
+
:return: The result of validation
|
|
85
|
+
"""
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class AsyncDataValidator(DataValidator, abc.ABC):
|
|
90
|
+
"""Base class for an async data quality operator. Use this when validation requires async operations
|
|
91
|
+
(e.g. async database queries, async API calls). Must be used with AsyncDriver."""
|
|
92
|
+
|
|
93
|
+
@abc.abstractmethod
|
|
94
|
+
async def validate(self, dataset: Any) -> ValidationResult:
|
|
95
|
+
"""Asynchronously performs the validation.
|
|
96
|
+
|
|
97
|
+
:param dataset: dataset to validate
|
|
98
|
+
:return: The result of validation
|
|
99
|
+
"""
|
|
100
|
+
pass
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def is_async_validator(validator: DataValidator) -> bool:
|
|
104
|
+
"""Checks whether a validator's validate method is a coroutine function.
|
|
105
|
+
|
|
106
|
+
:param validator: The validator to check
|
|
107
|
+
:return: True if the validator's validate method is async
|
|
108
|
+
"""
|
|
109
|
+
return inspect.iscoroutinefunction(validator.validate)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def act_warn(node_name: str, validation_result: ValidationResult, validator: DataValidator):
|
|
113
|
+
"""This is the current default for acting on the validation result when you want to warn.
|
|
114
|
+
Note that we might move this at some point -- we'll want to make it configurable. But for now, this
|
|
115
|
+
seems like a fine place to put it.
|
|
116
|
+
|
|
117
|
+
:param node_name: the name of the node we are validating.
|
|
118
|
+
:param validation_result: the result
|
|
119
|
+
:param validator: the validator object.
|
|
120
|
+
"""
|
|
121
|
+
if not validation_result.passes:
|
|
122
|
+
logger.warning(_create_error_string(node_name, validation_result, validator))
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _create_error_string(node_name, validation_result, validator):
|
|
126
|
+
return (
|
|
127
|
+
f"[{node_name}:{validator.name()}] validator failed. Message was: {validation_result.message}. "
|
|
128
|
+
f"Diagnostic information is: {validation_result.diagnostics}."
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def act_fail_bulk(node_name: str, failures: list[tuple[ValidationResult, DataValidator]]):
|
|
133
|
+
"""This is the current default for acting on the validation result when you want to fail.
|
|
134
|
+
Note that we might move this at some point -- we'll want to make it configurable. But for now, this
|
|
135
|
+
seems like a fine place to put it.
|
|
136
|
+
:param node_name: the name of the node we are validating.
|
|
137
|
+
:param failures: list of tuples of (validation_result, validator)
|
|
138
|
+
:raises DataValidationError: if there are errors detected.
|
|
139
|
+
"""
|
|
140
|
+
error_messages = []
|
|
141
|
+
for validation_result, validator in failures:
|
|
142
|
+
if not validation_result.passes:
|
|
143
|
+
message = f"{_create_error_string(node_name, validation_result, validator)}\n"
|
|
144
|
+
logger.error(message) # log here so things print nicely at least
|
|
145
|
+
error_messages.append(message)
|
|
146
|
+
if error_messages:
|
|
147
|
+
raise DataValidationError(error_messages)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class BaseDefaultValidator(DataValidator, abc.ABC):
|
|
151
|
+
"""Base class for a default validator.
|
|
152
|
+
These are all validators that utilize a single argument to be passed to the decorator check_output.
|
|
153
|
+
check_output can thus delegate to multiple of these. This is an internal abstraction to allow for easy
|
|
154
|
+
creation of validators.
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
def __init__(self, importance: str):
|
|
158
|
+
super(BaseDefaultValidator, self).__init__(importance)
|
|
159
|
+
|
|
160
|
+
@classmethod
|
|
161
|
+
@abc.abstractmethod
|
|
162
|
+
def applies_to(cls, datatype: type[type]) -> bool:
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
@abc.abstractmethod
|
|
166
|
+
def description(self) -> str:
|
|
167
|
+
pass
|
|
168
|
+
|
|
169
|
+
@abc.abstractmethod
|
|
170
|
+
def validate(self, data: Any) -> ValidationResult:
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
@classmethod
|
|
174
|
+
@abc.abstractmethod
|
|
175
|
+
def arg(cls) -> str:
|
|
176
|
+
"""Yields a string that represents this validator's argument.
|
|
177
|
+
@check_output() will be passed a series of kwargs, each one of which will correspond to
|
|
178
|
+
one of these default validators. Note that we have the limitation of allowing just a single
|
|
179
|
+
argument.
|
|
180
|
+
|
|
181
|
+
:return: The argument that this needs.
|
|
182
|
+
"""
|
|
183
|
+
pass
|
|
184
|
+
|
|
185
|
+
@classmethod
|
|
186
|
+
def name(cls) -> str:
|
|
187
|
+
return f"{cls.arg()}_validator"
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class AsyncBaseDefaultValidator(BaseDefaultValidator, abc.ABC):
|
|
191
|
+
"""Base class for an async default validator.
|
|
192
|
+
Async variant of BaseDefaultValidator for validators that require async operations.
|
|
193
|
+
Must be used with AsyncDriver.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
@abc.abstractmethod
|
|
197
|
+
async def validate(self, data: Any) -> ValidationResult:
|
|
198
|
+
pass
|