From 2a53f32e785839e9826c4a933b6649064161e72b Mon Sep 17 00:00:00 2001 From: Stefan Krawczyk Date: Mon, 24 Jun 2024 16:52:19 -0700 Subject: [PATCH 1/4] Example showing inline data saver & loaders This is a proof of concept. What needs to be actually done: 1. ideally we expand/wrap the function with the dataloader type appropriately, to mirror the current process (I think that's what we want). I made them classes to make it easy to add from_X functions to create the metadata. Otherwise I don't type the metadata dictionaries -- so maybe we should do that / provide a way to push people to putting standard things in it. Otherwise I think this is more ergonomic for most people getting started. --- .../using_types/def simple_etl.py | 37 +++++++++ .../using_types/simple_etl.png | Bin 0 -> 30150 bytes hamilton/execution/graph_functions.py | 14 +++- hamilton/htypes.py | 72 ++++++++++++++++++ hamilton/node.py | 32 +++++++- ui/sdk/src/hamilton_sdk/tracking/stats.py | 23 +++++- 6 files changed, 170 insertions(+), 8 deletions(-) create mode 100644 examples/materialization/using_types/def simple_etl.py create mode 100644 examples/materialization/using_types/simple_etl.png diff --git a/examples/materialization/using_types/def simple_etl.py b/examples/materialization/using_types/def simple_etl.py new file mode 100644 index 000000000..a9f99c791 --- /dev/null +++ b/examples/materialization/using_types/def simple_etl.py @@ -0,0 +1,37 @@ +import pandas as pd +from sklearn import datasets + +from hamilton.htypes import DataLoaderMetadata, DataSaverMetadata + + +def raw_data() -> tuple[pd.DataFrame, DataLoaderMetadata]: + data = datasets.load_digits() + df = pd.DataFrame(data.data, columns=[f"feature_{i}" for i in range(data.data.shape[1])]) + return df, DataLoaderMetadata.from_dataframe(df) + + +def transformed_data(raw_data: pd.DataFrame) -> pd.DataFrame: + return raw_data + + +def saved_data(transformed_data: pd.DataFrame, filepath: str) -> DataSaverMetadata: + transformed_data.to_csv(filepath) + return DataSaverMetadata.from_file_and_dataframe(filepath, transformed_data) + + +if __name__ == "__main__": + import __main__ as simple_etl + from hamilton_sdk import adapters + + from hamilton import driver + + tracker = adapters.HamiltonTracker( + project_id=7, # modify this as needed + username="elijah@dagworks.io", + dag_name="my_version_of_the_dag", + tags={"environment": "DEV", "team": "MY_TEAM", "version": "X"}, + ) + dr = driver.Builder().with_config({}).with_modules(simple_etl).with_adapters(tracker).build() + dr.display_all_functions("simple_etl.png") + + dr.execute(["saved_data"], inputs={"filepath": "data.csv"}) diff --git a/examples/materialization/using_types/simple_etl.png b/examples/materialization/using_types/simple_etl.png new file mode 100644 index 0000000000000000000000000000000000000000..3c84b2f9f29ab17749332dcf8ff339028ae3da1a GIT binary patch literal 30150 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 DdTXfi literal 0 HcmV?d00001 diff --git a/hamilton/execution/graph_functions.py b/hamilton/execution/graph_functions.py index dfadbbf90..edeb5fb51 100644 --- a/hamilton/execution/graph_functions.py +++ b/hamilton/execution/graph_functions.py @@ -3,6 +3,7 @@ from typing import Any, Collection, Dict, List, Optional, Set, Tuple from hamilton import node +from hamilton.htypes import DataLoaderMetadata from hamilton.lifecycle.base import LifecycleAdapterSet logger = logging.getLogger(__name__) @@ -218,7 +219,18 @@ def dfs_traverse( except Exception as e: pre_node_execute_errored = True raise e - + # this is a hack + # if one of the kwargs is a tuple[Value, DataLoaderMetadata] we need to unpack it + kwargs = { + k: ( + v[0] + if isinstance(v, tuple) + and len(v) == 2 + and isinstance(v[1], DataLoaderMetadata) + else v + ) + for k, v in kwargs.items() + } if adapter.does_method("do_node_execute", is_async=False): result = adapter.call_lifecycle_method_sync( "do_node_execute", diff --git a/hamilton/htypes.py b/hamilton/htypes.py index 2aac81920..317e16ac4 100644 --- a/hamilton/htypes.py +++ b/hamilton/htypes.py @@ -383,3 +383,75 @@ def check_instance(obj: Any, type_: Any) -> bool: # If the type is not a generic type, just use isinstance return isinstance(obj, type_) + + +from io import BytesIO +from pathlib import Path +from typing import Any, BinaryIO, Literal, TextIO + + +class DataSaverMetadata: + + def __init__(self, metadata: dict): + self.value: dict = metadata + + @classmethod + def from_file_and_dataframe( + cls, file: Union[str, TextIO, BytesIO, Path, BinaryIO, bytes], dataframe: Any + ) -> "DataSaverMetadata": + from hamilton.io import utils as io_utils # here due to circular import + + metadata = io_utils.get_file_and_dataframe_metadata(file, dataframe) + return DataSaverMetadata(metadata) + + @classmethod + def from_file( + cls, file: Union[str, TextIO, BytesIO, Path, BinaryIO, bytes] + ) -> "DataSaverMetadata": + from hamilton.io import utils as io_utils # here due to circular import + + metadata = io_utils.get_file_metadata(file) + return DataSaverMetadata(metadata) + + @classmethod + def from_dataframe(cls, dataframe: Any) -> "DataSaverMetadata": + from hamilton.io import utils as io_utils # here due to circular import + + metadata = io_utils.get_dataframe_metadata(dataframe) + return DataSaverMetadata(metadata) + + def to_dict(self) -> dict: + return self.value + + +class DataLoaderMetadata: + def __init__(self, metadata: dict): + self.value: dict = metadata + + @classmethod + def from_file_and_dataframe( + cls, file: Union[str, TextIO, BytesIO, Path, BinaryIO, bytes], dataframe: Any + ) -> "DataLoaderMetadata": + from hamilton.io import utils as io_utils # here due to circular import + + metadata = io_utils.get_file_and_dataframe_metadata(file, dataframe) + return DataLoaderMetadata(metadata) + + @classmethod + def from_file( + cls, file: Union[str, TextIO, BytesIO, Path, BinaryIO, bytes] + ) -> "DataLoaderMetadata": + from hamilton.io import utils as io_utils # here due to circular import + + metadata = io_utils.get_file_metadata(file) + return DataLoaderMetadata(metadata) + + @classmethod + def from_dataframe(cls, dataframe: Any) -> "DataLoaderMetadata": + from hamilton.io import utils as io_utils # here due to circular import + + metadata = io_utils.get_dataframe_metadata(dataframe) + return DataLoaderMetadata(metadata) + + def to_dict(self) -> dict: + return self.value diff --git a/hamilton/node.py b/hamilton/node.py index 4d4a4a764..4cc59e056 100644 --- a/hamilton/node.py +++ b/hamilton/node.py @@ -6,7 +6,7 @@ import typing_inspect -from hamilton.htypes import Collect, Parallelizable +from hamilton.htypes import Collect, DataLoaderMetadata, DataSaverMetadata, Parallelizable """ Module that contains the primitive components of the graph. @@ -266,19 +266,45 @@ def from_fn(fn: Callable, name: str = None) -> "Node": return_type = typing.get_type_hints(fn, **type_hint_kwargs).get("return") if return_type is None: raise ValueError(f"Missing type hint for return value in function {fn.__qualname__}.") + module = inspect.getmodule(fn).__name__ + tags = {"module": module} + node_source = NodeType.STANDARD # TODO - extract this into a function + clean up! if typing_inspect.is_generic_type(return_type): if typing_inspect.get_origin(return_type) == Parallelizable: node_source = NodeType.EXPAND + elif return_type == DataSaverMetadata: + tags.update( + { + "hamilton.data_saver": True, + "hamilton.data_saver.sink": fn.__name__, + "hamilton.data_saver.classname": fn.__name__, + } + ) + # check for tuple[DataLoaderMetadata, Any], or Tuple[DataLoaderMetadata, Any] + elif ( + typing_inspect.get_origin(return_type) == tuple + and len(return_type.__args__) == 2 + and return_type.__args__[1] == DataLoaderMetadata + ): + tags.update( + { + "hamilton.data_loader": True, + "hamilton.data_loader.has_metadata": True, + "hamilton.data_loader.source": fn.__name__, + "hamilton.data_loader.classname": fn.__name__, + } + ) + # make return types match -- TODO: actually do the right data loader thing + return_type = return_type.__args__[0] for parameter in inspect.signature(fn).parameters.values(): hint = parameter.annotation if typing_inspect.is_generic_type(hint): if typing_inspect.get_origin(hint) == Collect: node_source = NodeType.COLLECT break - module = inspect.getmodule(fn).__name__ - tags = {"module": module} + if hasattr(fn, "__config_decorated__"): tags["hamilton.config"] = ",".join(fn.__config_decorated__) return Node( diff --git a/ui/sdk/src/hamilton_sdk/tracking/stats.py b/ui/sdk/src/hamilton_sdk/tracking/stats.py index 0b968e27f..5938d686b 100644 --- a/ui/sdk/src/hamilton_sdk/tracking/stats.py +++ b/ui/sdk/src/hamilton_sdk/tracking/stats.py @@ -5,6 +5,8 @@ import pandas as pd from hamilton_sdk.tracking import sql_utils +from hamilton.htypes import DataLoaderMetadata, DataSaverMetadata + StatsType = Dict[str, Any] @@ -44,6 +46,13 @@ def compute_stats_primitives(result, node_name: str, node_tags: dict) -> StatsTy } +@compute_stats.register(DataSaverMetadata) +def compute_state_saver( + result: DataSaverMetadata, node_name: str, node_tags: dict +) -> Dict[str, Any]: + return compute_stats_dict(result.to_dict(), node_name, node_tags) + + @compute_stats.register(dict) def compute_stats_dict(result: dict, node_name: str, node_tags: dict) -> StatsType: """call summary stats on the values in the dict""" @@ -96,14 +105,20 @@ def compute_stats_dict(result: dict, node_name: str, node_tags: dict) -> StatsTy @compute_stats.register(tuple) def compute_stats_tuple(result: tuple, node_name: str, node_tags: dict) -> StatsType: if "hamilton.data_loader" in node_tags and node_tags["hamilton.data_loader"] is True: - # assumption it's a tuple - if isinstance(result[1], dict): + # assumption it's a tuple -- HACK to get metadata for dataloadermetadata -- TODO: create actual nodes. + if isinstance(result[1], dict) or isinstance(result[1], DataLoaderMetadata): try: # double check that it's JSON serializable - raw_data = json.dumps(result[1]) + raw_data = ( + json.dumps(result[1]) + if isinstance(result[1], dict) + else json.dumps(result[1].to_dict()) + ) _metadata = json.loads(raw_data) except Exception: - _metadata = str(result[1]) + _metadata = ( + str(result[1]) if isinstance(result[1], dict) else str(result[1].to_dict()) + ) if len(_metadata) > 1000: _metadata = _metadata[:1000] + "..." else: From 984d6cb8d2d5b743f10308525e88ee46d2cc985d Mon Sep 17 00:00:00 2001 From: Stefan Krawczyk Date: Mon, 24 Jun 2024 17:01:16 -0700 Subject: [PATCH 2/4] Adds notebook -- proving it works --- .../using_types/notebook.ipynb | 175 ++++++++++++++++++ .../using_types/simple_etl.png | Bin 30150 -> 30787 bytes .../{def simple_etl.py => simple_etl.py} | 0 3 files changed, 175 insertions(+) create mode 100644 examples/materialization/using_types/notebook.ipynb rename examples/materialization/using_types/{def simple_etl.py => simple_etl.py} (100%) diff --git a/examples/materialization/using_types/notebook.ipynb b/examples/materialization/using_types/notebook.ipynb new file mode 100644 index 000000000..e46ba15fd --- /dev/null +++ b/examples/materialization/using_types/notebook.ipynb @@ -0,0 +1,175 @@ +{ + "cells": [ + { + "cell_type": "code", + "id": "initial_id", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-06-25T00:00:13.662458Z", + "start_time": "2024-06-25T00:00:06.982077Z" + } + }, + "source": "%load_ext hamilton.plugins.jupyter_magic\n", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/stefankrawczyk/.pyenv/versions/knowledge_retrieval-py39/lib/python3.9/site-packages/pyspark/pandas/__init__.py:50: UserWarning: 'PYARROW_IGNORE_TIMEZONE' environment variable was not set. It is required to set this environment variable to '1' in both driver and executor sides if you use pyarrow>=2.0.0. pandas-on-Spark will set it for you but it does not work if there is a Spark context already launched.\n", + " warnings.warn(\n" + ] + } + ], + "execution_count": 1 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-25T00:00:25.003646Z", + "start_time": "2024-06-25T00:00:24.322577Z" + } + }, + "cell_type": "code", + "source": [ + "%%cell_to_module simple_etl --display\n", + "import pandas as pd\n", + "from sklearn import datasets\n", + "\n", + "from hamilton.htypes import DataLoaderMetadata, DataSaverMetadata\n", + "\n", + "\n", + "def raw_data() -> tuple[pd.DataFrame, DataLoaderMetadata]:\n", + " data = datasets.load_digits()\n", + " df = pd.DataFrame(data.data, columns=[f\"feature_{i}\" for i in range(data.data.shape[1])])\n", + " return df, DataLoaderMetadata.from_dataframe(df)\n", + "\n", + "\n", + "def transformed_data(raw_data: pd.DataFrame) -> pd.DataFrame:\n", + " return raw_data\n", + "\n", + "\n", + "def saved_data(transformed_data: pd.DataFrame, filepath: str) -> DataSaverMetadata:\n", + " transformed_data.to_csv(filepath)\n", + " return DataSaverMetadata.from_file_and_dataframe(filepath, transformed_data)\n" + ], + "id": "efd6c1b2417bb9cf", + "outputs": [ + { + "data": { + "image/svg+xml": "\n\n\n\n\n\n\n\ncluster__legend\n\nLegend\n\n\n\nraw_data\n\nraw_data\nDataFrame\n\n\n\ntransformed_data\n\ntransformed_data\nDataFrame\n\n\n\nraw_data->transformed_data\n\n\n\n\n\nsaved_data\n\n\nsaved_data\nsaved_data\n\n\n\ntransformed_data->saved_data\n\n\n\n\n\n_saved_data_inputs\n\nfilepath\nstr\n\n\n\n_saved_data_inputs->saved_data\n\n\n\n\n\ninput\n\ninput\n\n\n\nfunction\n\nfunction\n\n\n\nmaterializer\n\n\nmaterializer\n\n\n\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 2 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-25T00:00:37.889540Z", + "start_time": "2024-06-25T00:00:35.994131Z" + } + }, + "cell_type": "code", + "source": [ + "from hamilton_sdk import adapters\n", + "\n", + "from hamilton import driver\n", + "\n", + "tracker = adapters.HamiltonTracker(\n", + " project_id=7, # modify this as needed\n", + " username=\"elijah@dagworks.io\",\n", + " dag_name=\"my_version_of_the_dag\",\n", + " tags={\"environment\": \"DEV\", \"team\": \"MY_TEAM\", \"version\": \"X\"},\n", + ")\n", + "dr = driver.Builder().with_config({}).with_modules(simple_etl).with_adapters(tracker).build()\n", + "dr.display_all_functions()" + ], + "id": "e9252f2a09228330", + "outputs": [ + { + "data": { + "image/svg+xml": "\n\n\n\n\n\n\n\ncluster__legend\n\nLegend\n\n\n\nraw_data\n\nraw_data\nDataFrame\n\n\n\ntransformed_data\n\ntransformed_data\nDataFrame\n\n\n\nraw_data->transformed_data\n\n\n\n\n\nsaved_data\n\n\nsaved_data\nsaved_data\n\n\n\ntransformed_data->saved_data\n\n\n\n\n\n_saved_data_inputs\n\nfilepath\nstr\n\n\n\n_saved_data_inputs->saved_data\n\n\n\n\n\ninput\n\ninput\n\n\n\nfunction\n\nfunction\n\n\n\nmaterializer\n\n\nmaterializer\n\n\n\n", + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 3 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-06-25T00:00:53.746596Z", + "start_time": "2024-06-25T00:00:52.320439Z" + } + }, + "cell_type": "code", + "source": "dr.execute([\"saved_data\"], inputs={\"filepath\": \"data.csv\"})", + "id": "86c0d0f7da9a472b", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n", + "Capturing execution run. Results can be found at http://localhost:8241/dashboard/project/7/runs/25\n", + "\n", + "\n", + "Captured execution run. Results can be found at http://localhost:8241/dashboard/project/7/runs/25\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "{'saved_data': }" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 4 + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": "", + "id": "e108601ca3a88aab" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/materialization/using_types/simple_etl.png b/examples/materialization/using_types/simple_etl.png index 3c84b2f9f29ab17749332dcf8ff339028ae3da1a..e83cef032149b7b68ea806117ec6efc102e3dc90 100644 GIT binary patch literal 30787 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 EA8{A5GXMYp literal 30150 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 DdTXfi diff --git a/examples/materialization/using_types/def simple_etl.py b/examples/materialization/using_types/simple_etl.py similarity index 100% rename from examples/materialization/using_types/def simple_etl.py rename to examples/materialization/using_types/simple_etl.py From 794c2c4fc259238b6e83cd027b7999e835efa588 Mon Sep 17 00:00:00 2001 From: Stefan Krawczyk Date: Fri, 12 Jul 2024 17:22:47 -0600 Subject: [PATCH 3/4] Adds loader and saver decorators They enable one to annotate a function as loading or saving data and then having that metadata available for capture. This also removes older code -- hopefully all of it... --- examples/materialization/using_types/run.py | 23 ++++ .../using_types/simple_etl.png | Bin 30787 -> 37494 bytes .../materialization/using_types/simple_etl.py | 33 ++---- hamilton/execution/graph_functions.py | 13 --- hamilton/function_modifiers/__init__.py | 2 + hamilton/function_modifiers/adapters.py | 1 - hamilton/function_modifiers/macros.py | 105 ++++++++++++++++++ hamilton/graph.py | 4 +- hamilton/htypes.py | 72 ------------ hamilton/node.py | 26 +---- .../src/hamilton_sdk/tracking/pandas_stats.py | 4 +- ui/sdk/src/hamilton_sdk/tracking/stats.py | 13 +-- 12 files changed, 149 insertions(+), 147 deletions(-) create mode 100644 examples/materialization/using_types/run.py diff --git a/examples/materialization/using_types/run.py b/examples/materialization/using_types/run.py new file mode 100644 index 000000000..973c910b0 --- /dev/null +++ b/examples/materialization/using_types/run.py @@ -0,0 +1,23 @@ +import simple_etl +from hamilton_sdk import adapters + +from hamilton import driver + +tracker = adapters.HamiltonTracker( + project_id=7, # modify this as needed + username="elijah@dagworks.io", + dag_name="my_version_of_the_dag", + tags={"environment": "DEV", "team": "MY_TEAM", "version": "X"}, +) # note this slows down execution because there's 60 columns. +# 30 columns adds about a 1 second. +# 60 is therefore 2 seconds. + +dr = driver.Builder().with_config({}).with_modules(simple_etl).with_adapters(tracker).build() +dr.display_all_functions("simple_etl.png") + +import time + +start = time.time() +print(start) +dr.execute(["saved_data"], inputs={"filepath": "data.csv"}) +print(time.time() - start) diff --git a/examples/materialization/using_types/simple_etl.png b/examples/materialization/using_types/simple_etl.png index e83cef032149b7b68ea806117ec6efc102e3dc90..13c5cafd2f0162394cef58aa2ee812f3bcf75c48 100644 GIT binary patch literal 37494 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 ONkT+MxKK#P=l=k>GlkXw literal 30787 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 EA8{A5GXMYp diff --git a/examples/materialization/using_types/simple_etl.py b/examples/materialization/using_types/simple_etl.py index a9f99c791..d14c266d8 100644 --- a/examples/materialization/using_types/simple_etl.py +++ b/examples/materialization/using_types/simple_etl.py @@ -1,37 +1,24 @@ import pandas as pd from sklearn import datasets -from hamilton.htypes import DataLoaderMetadata, DataSaverMetadata +from hamilton.function_modifiers import loader, saver +from hamilton.io import utils as io_utils -def raw_data() -> tuple[pd.DataFrame, DataLoaderMetadata]: +@loader() +def raw_data() -> tuple[pd.DataFrame, dict]: data = datasets.load_digits() df = pd.DataFrame(data.data, columns=[f"feature_{i}" for i in range(data.data.shape[1])]) - return df, DataLoaderMetadata.from_dataframe(df) + metadata = io_utils.get_dataframe_metadata(df) + return df, metadata def transformed_data(raw_data: pd.DataFrame) -> pd.DataFrame: return raw_data -def saved_data(transformed_data: pd.DataFrame, filepath: str) -> DataSaverMetadata: +@saver() +def saved_data(transformed_data: pd.DataFrame, filepath: str) -> dict: transformed_data.to_csv(filepath) - return DataSaverMetadata.from_file_and_dataframe(filepath, transformed_data) - - -if __name__ == "__main__": - import __main__ as simple_etl - from hamilton_sdk import adapters - - from hamilton import driver - - tracker = adapters.HamiltonTracker( - project_id=7, # modify this as needed - username="elijah@dagworks.io", - dag_name="my_version_of_the_dag", - tags={"environment": "DEV", "team": "MY_TEAM", "version": "X"}, - ) - dr = driver.Builder().with_config({}).with_modules(simple_etl).with_adapters(tracker).build() - dr.display_all_functions("simple_etl.png") - - dr.execute(["saved_data"], inputs={"filepath": "data.csv"}) + metadata = io_utils.get_file_and_dataframe_metadata(filepath, transformed_data) + return metadata diff --git a/hamilton/execution/graph_functions.py b/hamilton/execution/graph_functions.py index edeb5fb51..3a86d8b60 100644 --- a/hamilton/execution/graph_functions.py +++ b/hamilton/execution/graph_functions.py @@ -3,7 +3,6 @@ from typing import Any, Collection, Dict, List, Optional, Set, Tuple from hamilton import node -from hamilton.htypes import DataLoaderMetadata from hamilton.lifecycle.base import LifecycleAdapterSet logger = logging.getLogger(__name__) @@ -219,18 +218,6 @@ def dfs_traverse( except Exception as e: pre_node_execute_errored = True raise e - # this is a hack - # if one of the kwargs is a tuple[Value, DataLoaderMetadata] we need to unpack it - kwargs = { - k: ( - v[0] - if isinstance(v, tuple) - and len(v) == 2 - and isinstance(v[1], DataLoaderMetadata) - else v - ) - for k, v in kwargs.items() - } if adapter.does_method("do_node_execute", is_async=False): result = adapter.call_lifecycle_method_sync( "do_node_execute", diff --git a/hamilton/function_modifiers/__init__.py b/hamilton/function_modifiers/__init__.py index 1f52edcb2..a1baf34e0 100644 --- a/hamilton/function_modifiers/__init__.py +++ b/hamilton/function_modifiers/__init__.py @@ -92,3 +92,5 @@ # materialization stuff load_from = adapters.load_from save_to = adapters.save_to +loader = macros.loader +saver = macros.saver diff --git a/hamilton/function_modifiers/adapters.py b/hamilton/function_modifiers/adapters.py index 0fe712f90..48c4d9480 100644 --- a/hamilton/function_modifiers/adapters.py +++ b/hamilton/function_modifiers/adapters.py @@ -265,7 +265,6 @@ def filter_function(_inject_parameter=inject_parameter, **kwargs): def inject_nodes( self, params: Dict[str, Type[Type]], config: Dict[str, Any], fn: Callable ) -> Tuple[Collection[node.Node], Dict[str, str]]: - pass """Generates two nodes: 1. A node that loads the data from the data source, and returns that + metadata 2. A node that takes the data from the data source, injects it into, and runs, the function. diff --git a/hamilton/function_modifiers/macros.py b/hamilton/function_modifiers/macros.py index d855448cf..89e745070 100644 --- a/hamilton/function_modifiers/macros.py +++ b/hamilton/function_modifiers/macros.py @@ -5,6 +5,7 @@ from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union import pandas as pd +import typing_inspect from hamilton import models, node from hamilton.dev_utils.deprecation import deprecated @@ -12,6 +13,7 @@ from hamilton.function_modifiers.configuration import ConfigResolver from hamilton.function_modifiers.delayed import resolve as delayed_resolve from hamilton.function_modifiers.dependencies import ( + InvalidDecoratorException, LiteralDependency, SingleDependency, UpstreamDependency, @@ -870,3 +872,106 @@ def optional_config(self) -> Dict[str, Any]: # # def __init__(self, *transforms: Applicable, collapse=False): # super(flow, self).__init__(*transforms, collapse=collapse, _chain=False) + + +class loader(base.NodeCreator): + """Class to capture metadata.""" + + # def __init__(self, og_function: Callable): + # self.og_function = og_function + # super(loader,self).__init__() + + def validate(self, fn: Callable): + print("called validate loader") + return_annotation = inspect.signature(fn).return_annotation + if return_annotation is inspect.Signature.empty: + raise InvalidDecoratorException( + f"Function: {fn.__qualname__} must have a return annotation." + ) + # check that the type is a tuple[TYPE, dict]: + if not typing_inspect.is_tuple_type(return_annotation): + raise InvalidDecoratorException(f"Function: {fn.__qualname__} must return a tuple.") + if len(typing_inspect.get_args(return_annotation)) != 2: + raise InvalidDecoratorException( + f"Function: {fn.__qualname__} must return a tuple of length 2." + ) + if not typing_inspect.get_args(return_annotation)[1] == dict: + raise InvalidDecoratorException( + f"Function: {fn.__qualname__} must return a tuple of type (SOME_TYPE, dict)." + ) + + def generate_nodes(self, fn: Callable, config) -> List[node.Node]: + """ + Generates two nodes. + The first one is just the fn - with a slightly different name, + the second one uses the proper function name, but only returns + the first part of the tuple that the first returns. + We have to add tags appropriately. + :param fn: + :param config: + :return: + """ + _name = "loader" + og_node = node.Node.from_fn(fn, name=_name) + new_tags = og_node.tags.copy() + new_tags.update( + { + "hamilton.data_loader": True, + "hamilton.data_loader.has_metadata": True, + "hamilton.data_loader.source": f"{fn.__name__}", + "hamilton.data_loader.classname": f"{fn.__name__}()", + "hamilton.data_loader.node": _name, + } + ) + + def filter_function(**kwargs): + return kwargs[f"{fn.__name__}.{_name}"][0] + + filter_node = node.Node( + name=fn.__name__, # use original function name + callabl=filter_function, + typ=typing_inspect.get_args(og_node.type)[0], + input_types={f"{fn.__name__}.{_name}": og_node.type}, + tags={ + "hamilton.data_loader": True, + "hamilton.data_loader.has_metadata": False, + "hamilton.data_loader.source": f"{fn.__name__}", + "hamilton.data_loader.classname": f"{fn.__name__}()", + "hamilton.data_loader.node": fn.__name__, + }, + ) + + return [og_node.copy_with(tags=new_tags, namespace=(fn.__name__,)), filter_node] + + +class saver(base.NodeCreator): + """Class to capture metadata.""" + + def validate(self, fn: Callable): + print("called validate") + return_annotation = inspect.signature(fn).return_annotation + if return_annotation is inspect.Signature.empty: + raise InvalidDecoratorException( + f"Function: {fn.__qualname__} must have a return annotation." + ) + # check that the return type is a dict + if return_annotation not in (dict, Dict): + raise InvalidDecoratorException(f"Function: {fn.__qualname__} must return a dict.") + + def generate_nodes(self, fn: Callable, config) -> List[node.Node]: + """ + All this does is add tags + :param fn: + :param config: + :return: + """ + og_node = node.Node.from_fn(fn) + new_tags = og_node.tags.copy() + new_tags.update( + { + "hamilton.data_saver": True, + "hamilton.data_saver.sink": f"{og_node.name}", + "hamilton.data_saver.classname": f"{fn.__name__}()", + } + ) + return [og_node.copy_with(tags=new_tags)] diff --git a/hamilton/graph.py b/hamilton/graph.py index 56edacff7..5847ef6a2 100644 --- a/hamilton/graph.py +++ b/hamilton/graph.py @@ -500,7 +500,9 @@ def _get_legend( node_style.update(**modifier_style) seen_node_types.add("materializer") - if n.tags.get("hamilton.data_loader") and "load_data." in n.name: + if n.tags.get("hamilton.data_loader") and ( + "load_data." in n.name or "loader" == n.tags.get("hamilton.data_loader.node") + ): materializer_type = n.tags["hamilton.data_loader.classname"] label = _get_node_label(n, type_string=materializer_type) modifier_style = _get_function_modifier_style("materializer") diff --git a/hamilton/htypes.py b/hamilton/htypes.py index 317e16ac4..2aac81920 100644 --- a/hamilton/htypes.py +++ b/hamilton/htypes.py @@ -383,75 +383,3 @@ def check_instance(obj: Any, type_: Any) -> bool: # If the type is not a generic type, just use isinstance return isinstance(obj, type_) - - -from io import BytesIO -from pathlib import Path -from typing import Any, BinaryIO, Literal, TextIO - - -class DataSaverMetadata: - - def __init__(self, metadata: dict): - self.value: dict = metadata - - @classmethod - def from_file_and_dataframe( - cls, file: Union[str, TextIO, BytesIO, Path, BinaryIO, bytes], dataframe: Any - ) -> "DataSaverMetadata": - from hamilton.io import utils as io_utils # here due to circular import - - metadata = io_utils.get_file_and_dataframe_metadata(file, dataframe) - return DataSaverMetadata(metadata) - - @classmethod - def from_file( - cls, file: Union[str, TextIO, BytesIO, Path, BinaryIO, bytes] - ) -> "DataSaverMetadata": - from hamilton.io import utils as io_utils # here due to circular import - - metadata = io_utils.get_file_metadata(file) - return DataSaverMetadata(metadata) - - @classmethod - def from_dataframe(cls, dataframe: Any) -> "DataSaverMetadata": - from hamilton.io import utils as io_utils # here due to circular import - - metadata = io_utils.get_dataframe_metadata(dataframe) - return DataSaverMetadata(metadata) - - def to_dict(self) -> dict: - return self.value - - -class DataLoaderMetadata: - def __init__(self, metadata: dict): - self.value: dict = metadata - - @classmethod - def from_file_and_dataframe( - cls, file: Union[str, TextIO, BytesIO, Path, BinaryIO, bytes], dataframe: Any - ) -> "DataLoaderMetadata": - from hamilton.io import utils as io_utils # here due to circular import - - metadata = io_utils.get_file_and_dataframe_metadata(file, dataframe) - return DataLoaderMetadata(metadata) - - @classmethod - def from_file( - cls, file: Union[str, TextIO, BytesIO, Path, BinaryIO, bytes] - ) -> "DataLoaderMetadata": - from hamilton.io import utils as io_utils # here due to circular import - - metadata = io_utils.get_file_metadata(file) - return DataLoaderMetadata(metadata) - - @classmethod - def from_dataframe(cls, dataframe: Any) -> "DataLoaderMetadata": - from hamilton.io import utils as io_utils # here due to circular import - - metadata = io_utils.get_dataframe_metadata(dataframe) - return DataLoaderMetadata(metadata) - - def to_dict(self) -> dict: - return self.value diff --git a/hamilton/node.py b/hamilton/node.py index 4cc59e056..2c6e5c73f 100644 --- a/hamilton/node.py +++ b/hamilton/node.py @@ -6,7 +6,7 @@ import typing_inspect -from hamilton.htypes import Collect, DataLoaderMetadata, DataSaverMetadata, Parallelizable +from hamilton.htypes import Collect, Parallelizable """ Module that contains the primitive components of the graph. @@ -274,30 +274,6 @@ def from_fn(fn: Callable, name: str = None) -> "Node": if typing_inspect.is_generic_type(return_type): if typing_inspect.get_origin(return_type) == Parallelizable: node_source = NodeType.EXPAND - elif return_type == DataSaverMetadata: - tags.update( - { - "hamilton.data_saver": True, - "hamilton.data_saver.sink": fn.__name__, - "hamilton.data_saver.classname": fn.__name__, - } - ) - # check for tuple[DataLoaderMetadata, Any], or Tuple[DataLoaderMetadata, Any] - elif ( - typing_inspect.get_origin(return_type) == tuple - and len(return_type.__args__) == 2 - and return_type.__args__[1] == DataLoaderMetadata - ): - tags.update( - { - "hamilton.data_loader": True, - "hamilton.data_loader.has_metadata": True, - "hamilton.data_loader.source": fn.__name__, - "hamilton.data_loader.classname": fn.__name__, - } - ) - # make return types match -- TODO: actually do the right data loader thing - return_type = return_type.__args__[0] for parameter in inspect.signature(fn).parameters.values(): hint = parameter.annotation if typing_inspect.is_generic_type(hint): diff --git a/ui/sdk/src/hamilton_sdk/tracking/pandas_stats.py b/ui/sdk/src/hamilton_sdk/tracking/pandas_stats.py index f190b8b08..e6ec8c86a 100644 --- a/ui/sdk/src/hamilton_sdk/tracking/pandas_stats.py +++ b/ui/sdk/src/hamilton_sdk/tracking/pandas_stats.py @@ -44,7 +44,9 @@ def _compute_stats(df: pd.DataFrame) -> Dict[str, Dict[str, Any]]: def execute_col( target_output: str, col: pd.Series, name: Union[str, int], position: int ) -> Dict[str, Any]: - """Get stats on a column.""" + """Get stats on a column. + TODO: profile this and see where we can speed things up. + """ try: res = dr.execute( [target_output], inputs={"col": col, "name": name, "position": position} diff --git a/ui/sdk/src/hamilton_sdk/tracking/stats.py b/ui/sdk/src/hamilton_sdk/tracking/stats.py index 5938d686b..44f5a5c3e 100644 --- a/ui/sdk/src/hamilton_sdk/tracking/stats.py +++ b/ui/sdk/src/hamilton_sdk/tracking/stats.py @@ -5,8 +5,6 @@ import pandas as pd from hamilton_sdk.tracking import sql_utils -from hamilton.htypes import DataLoaderMetadata, DataSaverMetadata - StatsType = Dict[str, Any] @@ -46,13 +44,6 @@ def compute_stats_primitives(result, node_name: str, node_tags: dict) -> StatsTy } -@compute_stats.register(DataSaverMetadata) -def compute_state_saver( - result: DataSaverMetadata, node_name: str, node_tags: dict -) -> Dict[str, Any]: - return compute_stats_dict(result.to_dict(), node_name, node_tags) - - @compute_stats.register(dict) def compute_stats_dict(result: dict, node_name: str, node_tags: dict) -> StatsType: """call summary stats on the values in the dict""" @@ -105,8 +96,8 @@ def compute_stats_dict(result: dict, node_name: str, node_tags: dict) -> StatsTy @compute_stats.register(tuple) def compute_stats_tuple(result: tuple, node_name: str, node_tags: dict) -> StatsType: if "hamilton.data_loader" in node_tags and node_tags["hamilton.data_loader"] is True: - # assumption it's a tuple -- HACK to get metadata for dataloadermetadata -- TODO: create actual nodes. - if isinstance(result[1], dict) or isinstance(result[1], DataLoaderMetadata): + # assumption it's a tuple + if isinstance(result[1], dict): try: # double check that it's JSON serializable raw_data = ( From 3868da629a3f7ed5a129a796104b7721c063215c Mon Sep 17 00:00:00 2001 From: elijahbenizzy Date: Mon, 15 Jul 2024 14:53:09 -0700 Subject: [PATCH 4/4] perf profiling --- examples/materialization/using_types/run.py | 7 +++++- .../using_types/simple_etl.png | Bin 37494 -> 37846 bytes .../materialization/using_types/simple_etl.py | 21 ++++++++++++++++++ .../hamilton_sdk/tracking/pandas_col_stats.py | 16 +++---------- .../src/hamilton_sdk/tracking/pandas_stats.py | 8 +++++++ 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/examples/materialization/using_types/run.py b/examples/materialization/using_types/run.py index 973c910b0..eec65a491 100644 --- a/examples/materialization/using_types/run.py +++ b/examples/materialization/using_types/run.py @@ -1,10 +1,15 @@ +import logging + import simple_etl from hamilton_sdk import adapters from hamilton import driver +from hamilton.log_setup import setup_logging + +setup_logging(logging.DEBUG) tracker = adapters.HamiltonTracker( - project_id=7, # modify this as needed + project_id=15, # modify this as needed username="elijah@dagworks.io", dag_name="my_version_of_the_dag", tags={"environment": "DEV", "team": "MY_TEAM", "version": "X"}, diff --git a/examples/materialization/using_types/simple_etl.png b/examples/materialization/using_types/simple_etl.png index 13c5cafd2f0162394cef58aa2ee812f3bcf75c48..a6595a2ed86cc1f6e531a960cdb90f9790f24253 100644 GIT binary patch literal 37846 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 DBA6*u literal 37494 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 ONkT+MxKK#P=l=k>GlkXw diff --git a/examples/materialization/using_types/simple_etl.py b/examples/materialization/using_types/simple_etl.py index d14c266d8..73ae688a1 100644 --- a/examples/materialization/using_types/simple_etl.py +++ b/examples/materialization/using_types/simple_etl.py @@ -1,8 +1,17 @@ +from hamilton.telemetry import disable_telemetry + +disable_telemetry() +import logging + import pandas as pd from sklearn import datasets +from hamilton import node from hamilton.function_modifiers import loader, saver from hamilton.io import utils as io_utils +from hamilton.log_setup import setup_logging + +setup_logging(logging.INFO) @loader() @@ -22,3 +31,15 @@ def saved_data(transformed_data: pd.DataFrame, filepath: str) -> dict: transformed_data.to_csv(filepath) metadata = io_utils.get_file_and_dataframe_metadata(filepath, transformed_data) return metadata + + +if __name__ == "__main__": + import time + + from hamilton_sdk.tracking import runs + + df, metadata = raw_data() + t1 = time.time() + stats = runs.process_result(df, node.Node.from_fn(raw_data)) + t2 = time.time() + print(t2 - t1) diff --git a/ui/sdk/src/hamilton_sdk/tracking/pandas_col_stats.py b/ui/sdk/src/hamilton_sdk/tracking/pandas_col_stats.py index c59a92da5..a013b1cad 100644 --- a/ui/sdk/src/hamilton_sdk/tracking/pandas_col_stats.py +++ b/ui/sdk/src/hamilton_sdk/tracking/pandas_col_stats.py @@ -1,5 +1,6 @@ from typing import Dict, List, Union +import numpy as np import pandas as pd from hamilton_sdk.tracking import dataframe_stats as dfs @@ -45,19 +46,8 @@ def quantiles(col: pd.Series, quantile_cuts: List[float]) -> Dict[float, float]: def histogram(col: pd.Series, num_hist_bins: int = 10) -> Dict[str, int]: - try: - hist_counts = ( - col.value_counts( - bins=num_hist_bins, - ) - .sort_index() - .to_dict() - ) - except ValueError: - return {} - except AttributeError: - return {} - return {str(interval): interval_value for interval, interval_value in hist_counts.items()} + hist, bins = np.histogram(col, bins=num_hist_bins) + return {str(interval): interval_value for interval, interval_value in zip(bins, hist)} def numeric_column_stats( diff --git a/ui/sdk/src/hamilton_sdk/tracking/pandas_stats.py b/ui/sdk/src/hamilton_sdk/tracking/pandas_stats.py index e6ec8c86a..a0763448f 100644 --- a/ui/sdk/src/hamilton_sdk/tracking/pandas_stats.py +++ b/ui/sdk/src/hamilton_sdk/tracking/pandas_stats.py @@ -1,3 +1,4 @@ +import logging from typing import Any, Dict, Union import pandas as pd @@ -12,7 +13,11 @@ - for object types we should :shrug: """ + dr = driver.Builder().with_modules(pcs).with_config({"config_key": "config_value"}).build() +logger = logging.getLogger(__name__) + +import time def _compute_stats(df: pd.DataFrame) -> Dict[str, Dict[str, Any]]: @@ -48,9 +53,12 @@ def execute_col( TODO: profile this and see where we can speed things up. """ try: + t1 = time.time() res = dr.execute( [target_output], inputs={"col": col, "name": name, "position": position} ) + + logger.info(f"Computed stats for column {name}, time taken was {time.time() - t1}") res = res[target_output].to_dict() except Exception: # minimum that we want -- ideally we have hamilton handle errors and do best effort.