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.
Files changed (151) hide show
  1. apache_hamilton-1.90.0.dev0.dist-info/METADATA +407 -0
  2. apache_hamilton-1.90.0.dev0.dist-info/RECORD +151 -0
  3. apache_hamilton-1.90.0.dev0.dist-info/WHEEL +4 -0
  4. apache_hamilton-1.90.0.dev0.dist-info/entry_points.txt +9 -0
  5. apache_hamilton-1.90.0.dev0.dist-info/licenses/DISCLAIMER +10 -0
  6. apache_hamilton-1.90.0.dev0.dist-info/licenses/LICENSE +228 -0
  7. apache_hamilton-1.90.0.dev0.dist-info/licenses/NOTICE +5 -0
  8. hamilton/__init__.py +24 -0
  9. hamilton/ad_hoc_utils.py +132 -0
  10. hamilton/async_driver.py +465 -0
  11. hamilton/base.py +466 -0
  12. hamilton/caching/__init__.py +16 -0
  13. hamilton/caching/adapter.py +1475 -0
  14. hamilton/caching/cache_key.py +70 -0
  15. hamilton/caching/fingerprinting.py +287 -0
  16. hamilton/caching/stores/__init__.py +16 -0
  17. hamilton/caching/stores/base.py +242 -0
  18. hamilton/caching/stores/file.py +140 -0
  19. hamilton/caching/stores/memory.py +297 -0
  20. hamilton/caching/stores/sqlite.py +282 -0
  21. hamilton/caching/stores/utils.py +40 -0
  22. hamilton/cli/__init__.py +16 -0
  23. hamilton/cli/__main__.py +328 -0
  24. hamilton/cli/commands.py +126 -0
  25. hamilton/cli/logic.py +338 -0
  26. hamilton/common/__init__.py +76 -0
  27. hamilton/contrib/__init__.py +41 -0
  28. hamilton/data_quality/__init__.py +16 -0
  29. hamilton/data_quality/base.py +198 -0
  30. hamilton/data_quality/default_validators.py +560 -0
  31. hamilton/data_quality/pandera_validators.py +121 -0
  32. hamilton/dataflows/__init__.py +726 -0
  33. hamilton/dataflows/template/README.md +25 -0
  34. hamilton/dataflows/template/__init__.py +54 -0
  35. hamilton/dataflows/template/author.md +28 -0
  36. hamilton/dataflows/template/requirements.txt +0 -0
  37. hamilton/dataflows/template/tags.json +7 -0
  38. hamilton/dataflows/template/valid_configs.jsonl +1 -0
  39. hamilton/dev_utils/__init__.py +16 -0
  40. hamilton/dev_utils/deprecation.py +204 -0
  41. hamilton/driver.py +2112 -0
  42. hamilton/execution/__init__.py +16 -0
  43. hamilton/execution/debugging_utils.py +56 -0
  44. hamilton/execution/executors.py +502 -0
  45. hamilton/execution/graph_functions.py +421 -0
  46. hamilton/execution/grouping.py +430 -0
  47. hamilton/execution/state.py +539 -0
  48. hamilton/experimental/__init__.py +27 -0
  49. hamilton/experimental/databackend.py +61 -0
  50. hamilton/experimental/decorators/__init__.py +16 -0
  51. hamilton/experimental/decorators/parameterize_frame.py +233 -0
  52. hamilton/experimental/h_async.py +29 -0
  53. hamilton/experimental/h_cache.py +413 -0
  54. hamilton/experimental/h_dask.py +28 -0
  55. hamilton/experimental/h_databackends.py +174 -0
  56. hamilton/experimental/h_ray.py +28 -0
  57. hamilton/experimental/h_spark.py +32 -0
  58. hamilton/function_modifiers/README +40 -0
  59. hamilton/function_modifiers/__init__.py +121 -0
  60. hamilton/function_modifiers/adapters.py +900 -0
  61. hamilton/function_modifiers/base.py +859 -0
  62. hamilton/function_modifiers/configuration.py +310 -0
  63. hamilton/function_modifiers/delayed.py +202 -0
  64. hamilton/function_modifiers/dependencies.py +246 -0
  65. hamilton/function_modifiers/expanders.py +1230 -0
  66. hamilton/function_modifiers/macros.py +1634 -0
  67. hamilton/function_modifiers/metadata.py +434 -0
  68. hamilton/function_modifiers/recursive.py +908 -0
  69. hamilton/function_modifiers/validation.py +289 -0
  70. hamilton/function_modifiers_base.py +31 -0
  71. hamilton/graph.py +1153 -0
  72. hamilton/graph_types.py +264 -0
  73. hamilton/graph_utils.py +41 -0
  74. hamilton/htypes.py +450 -0
  75. hamilton/io/__init__.py +32 -0
  76. hamilton/io/data_adapters.py +216 -0
  77. hamilton/io/default_data_loaders.py +224 -0
  78. hamilton/io/materialization.py +500 -0
  79. hamilton/io/utils.py +158 -0
  80. hamilton/lifecycle/__init__.py +67 -0
  81. hamilton/lifecycle/api.py +833 -0
  82. hamilton/lifecycle/base.py +1130 -0
  83. hamilton/lifecycle/default.py +802 -0
  84. hamilton/log_setup.py +47 -0
  85. hamilton/models.py +92 -0
  86. hamilton/node.py +449 -0
  87. hamilton/plugins/README.md +48 -0
  88. hamilton/plugins/__init__.py +16 -0
  89. hamilton/plugins/dask_extensions.py +47 -0
  90. hamilton/plugins/dlt_extensions.py +161 -0
  91. hamilton/plugins/geopandas_extensions.py +49 -0
  92. hamilton/plugins/h_dask.py +331 -0
  93. hamilton/plugins/h_ddog.py +522 -0
  94. hamilton/plugins/h_diskcache.py +163 -0
  95. hamilton/plugins/h_experiments/__init__.py +22 -0
  96. hamilton/plugins/h_experiments/__main__.py +62 -0
  97. hamilton/plugins/h_experiments/cache.py +39 -0
  98. hamilton/plugins/h_experiments/data_model.py +68 -0
  99. hamilton/plugins/h_experiments/hook.py +219 -0
  100. hamilton/plugins/h_experiments/server.py +375 -0
  101. hamilton/plugins/h_kedro.py +152 -0
  102. hamilton/plugins/h_logging.py +454 -0
  103. hamilton/plugins/h_mcp/__init__.py +28 -0
  104. hamilton/plugins/h_mcp/__main__.py +33 -0
  105. hamilton/plugins/h_mcp/_helpers.py +129 -0
  106. hamilton/plugins/h_mcp/_templates.py +417 -0
  107. hamilton/plugins/h_mcp/server.py +328 -0
  108. hamilton/plugins/h_mlflow.py +335 -0
  109. hamilton/plugins/h_narwhals.py +134 -0
  110. hamilton/plugins/h_openlineage.py +400 -0
  111. hamilton/plugins/h_opentelemetry.py +167 -0
  112. hamilton/plugins/h_pandas.py +257 -0
  113. hamilton/plugins/h_pandera.py +117 -0
  114. hamilton/plugins/h_polars.py +304 -0
  115. hamilton/plugins/h_polars_lazyframe.py +282 -0
  116. hamilton/plugins/h_pyarrow.py +56 -0
  117. hamilton/plugins/h_pydantic.py +127 -0
  118. hamilton/plugins/h_ray.py +242 -0
  119. hamilton/plugins/h_rich.py +142 -0
  120. hamilton/plugins/h_schema.py +493 -0
  121. hamilton/plugins/h_slack.py +100 -0
  122. hamilton/plugins/h_spark.py +1380 -0
  123. hamilton/plugins/h_threadpool.py +125 -0
  124. hamilton/plugins/h_tqdm.py +122 -0
  125. hamilton/plugins/h_vaex.py +129 -0
  126. hamilton/plugins/huggingface_extensions.py +236 -0
  127. hamilton/plugins/ibis_extensions.py +93 -0
  128. hamilton/plugins/jupyter_magic.py +622 -0
  129. hamilton/plugins/kedro_extensions.py +117 -0
  130. hamilton/plugins/lightgbm_extensions.py +99 -0
  131. hamilton/plugins/matplotlib_extensions.py +108 -0
  132. hamilton/plugins/mlflow_extensions.py +216 -0
  133. hamilton/plugins/numpy_extensions.py +105 -0
  134. hamilton/plugins/pandas_extensions.py +1763 -0
  135. hamilton/plugins/plotly_extensions.py +150 -0
  136. hamilton/plugins/polars_extensions.py +71 -0
  137. hamilton/plugins/polars_implementations.py +25 -0
  138. hamilton/plugins/polars_lazyframe_extensions.py +302 -0
  139. hamilton/plugins/polars_post_1_0_0_extensions.py +877 -0
  140. hamilton/plugins/polars_pre_1_0_0_extension.py +836 -0
  141. hamilton/plugins/pydantic_extensions.py +98 -0
  142. hamilton/plugins/pyspark_pandas_extensions.py +47 -0
  143. hamilton/plugins/sklearn_plot_extensions.py +129 -0
  144. hamilton/plugins/spark_extensions.py +105 -0
  145. hamilton/plugins/vaex_extensions.py +51 -0
  146. hamilton/plugins/xgboost_extensions.py +91 -0
  147. hamilton/plugins/yaml_extensions.py +89 -0
  148. hamilton/registry.py +254 -0
  149. hamilton/settings.py +18 -0
  150. hamilton/telemetry.py +50 -0
  151. hamilton/version.py +18 -0
@@ -0,0 +1,140 @@
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 inspect
19
+ import shutil
20
+ from pathlib import Path
21
+ from typing import Any
22
+
23
+ try:
24
+ from typing import override
25
+ except ImportError:
26
+ override = lambda x: x # noqa E731
27
+
28
+ from hamilton.io.data_adapters import DataLoader, DataSaver
29
+
30
+ from .base import ResultStore, StoredResult
31
+
32
+
33
+ class FileResultStore(ResultStore):
34
+ def __init__(self, path: str, create_dir: bool = True) -> None:
35
+ self.path = Path(path)
36
+ self.create_dir = create_dir
37
+
38
+ if self.create_dir:
39
+ self.path.mkdir(exist_ok=True, parents=True)
40
+
41
+ def __getstate__(self) -> dict:
42
+ """Serialize the `__init__` kwargs to pass in Parallelizable branches
43
+ when using multiprocessing.
44
+ """
45
+ return {"path": str(self.path)}
46
+
47
+ @staticmethod
48
+ def _write_result(file_path: Path, stored_result: StoredResult) -> None:
49
+ file_path.write_bytes(stored_result.save())
50
+
51
+ @staticmethod
52
+ def _load_result_from_path(path: Path) -> StoredResult | None:
53
+ try:
54
+ data = path.read_bytes()
55
+ return StoredResult.load(data)
56
+ except FileNotFoundError:
57
+ return None
58
+
59
+ def _path_from_data_version(self, data_version: str) -> Path:
60
+ return self.path.joinpath(data_version)
61
+
62
+ def _materialized_path(self, data_version: str, saver_cls: DataSaver) -> Path:
63
+ # TODO allow a more flexible mechanism to specify file path extension
64
+ return self._path_from_data_version(data_version).with_suffix(f".{saver_cls.name()}")
65
+
66
+ @override
67
+ def exists(self, data_version: str) -> bool:
68
+ result_path = self._path_from_data_version(data_version)
69
+ return result_path.exists()
70
+
71
+ @override
72
+ def set(
73
+ self,
74
+ data_version: str,
75
+ result: Any,
76
+ saver_cls: DataSaver | None = None,
77
+ loader_cls: DataLoader | None = None,
78
+ ) -> None:
79
+ # != operator on boolean is XOR
80
+ if bool(saver_cls is not None) != bool(loader_cls is not None):
81
+ raise ValueError(
82
+ "Must pass both `saver` and `loader` or neither. Currently received: "
83
+ f"`saver`: `{saver_cls}`; `loader`: `{loader_cls}`"
84
+ )
85
+
86
+ if saver_cls is not None:
87
+ # materialized_path
88
+ materialized_path = self._materialized_path(data_version, saver_cls)
89
+ saver_argspec = inspect.getfullargspec(saver_cls.__init__)
90
+ loader_argspec = inspect.getfullargspec(loader_cls.__init__)
91
+ if "file" in saver_argspec.args:
92
+ saver = saver_cls(file=str(materialized_path.absolute()))
93
+ elif "path" in saver_argspec.args:
94
+ saver = saver_cls(path=str(materialized_path.absolute()))
95
+ else:
96
+ raise ValueError(
97
+ f"Saver [{saver_cls.name()}] must have either `file` or `path` as an argument."
98
+ )
99
+ if "file" in loader_argspec.args:
100
+ loader = loader_cls(file=str(materialized_path.absolute()))
101
+ elif "path" in loader_argspec.args:
102
+ loader = loader_cls(path=str(materialized_path.absolute()))
103
+ else:
104
+ raise ValueError(
105
+ f"Loader [{loader_cls.name()}] must have either `file` or `path` as an argument."
106
+ )
107
+ else:
108
+ saver = None
109
+ loader = None
110
+
111
+ self.path.mkdir(exist_ok=True)
112
+ result_path = self._path_from_data_version(data_version)
113
+ stored_result = StoredResult.new(value=result, saver=saver, loader=loader)
114
+ self._write_result(result_path, stored_result)
115
+
116
+ @override
117
+ def get(self, data_version: str) -> Any | None:
118
+ result_path = self._path_from_data_version(data_version)
119
+ stored_result = self._load_result_from_path(result_path)
120
+
121
+ if stored_result is None:
122
+ return None
123
+
124
+ return stored_result.value
125
+
126
+ @override
127
+ def delete(self, data_version: str) -> None:
128
+ result_path = self._path_from_data_version(data_version)
129
+ result_path.unlink(missing_ok=True)
130
+
131
+ @override
132
+ def delete_all(self) -> None:
133
+ shutil.rmtree(self.path)
134
+ self.path.mkdir(exist_ok=True)
135
+
136
+ def delete_expired(self) -> None:
137
+ for file_path in self.path.iterdir():
138
+ stored_result = self._load_result_from_path(file_path)
139
+ if stored_result and stored_result.expired:
140
+ file_path.unlink(missing_ok=True)
@@ -0,0 +1,297 @@
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
+ from collections.abc import Sequence
19
+ from typing import Any
20
+
21
+ try:
22
+ from typing import override
23
+ except ImportError:
24
+ override = lambda x: x # noqa E731
25
+
26
+ from hamilton.caching.cache_key import decode_key
27
+
28
+ from .base import MetadataStore, ResultStore, StoredResult
29
+ from .file import FileResultStore
30
+ from .sqlite import SQLiteMetadataStore
31
+
32
+
33
+ class InMemoryMetadataStore(MetadataStore):
34
+ def __init__(self) -> None:
35
+ self._data_versions: dict[str, str] = {} # {cache_key: data_version}
36
+ self._cache_keys_by_run: dict[str, list[str]] = {} # {run_id: [cache_key]}
37
+ self._run_ids: list[str] = []
38
+
39
+ @override
40
+ def __len__(self) -> int:
41
+ """Number of unique ``cache_key`` values."""
42
+ return len(self._data_versions.keys())
43
+
44
+ @override
45
+ def exists(self, cache_key: str) -> bool:
46
+ """Indicate if ``cache_key`` exists and it can retrieve a ``data_version``."""
47
+ return cache_key in self._data_versions.keys()
48
+
49
+ @override
50
+ def initialize(self, run_id: str) -> None:
51
+ """Set up and log the beginning of the run."""
52
+ self._cache_keys_by_run[run_id] = []
53
+ self._run_ids.append(run_id)
54
+
55
+ @override
56
+ def set(self, cache_key: str, data_version: str, run_id: str, **kwargs) -> Any | None:
57
+ """Set the ``data_version`` for ``cache_key`` and associate it with the ``run_id``."""
58
+ self._data_versions[cache_key] = data_version
59
+ self._cache_keys_by_run[run_id].append(cache_key)
60
+
61
+ @override
62
+ def get(self, cache_key: str) -> str | None:
63
+ """Retrieve the ``data_version`` for ``cache_key``."""
64
+ return self._data_versions.get(cache_key, None)
65
+
66
+ @override
67
+ def delete(self, cache_key: str) -> None:
68
+ """Delete the ``data_version`` for ``cache_key``."""
69
+ del self._data_versions[cache_key]
70
+
71
+ @override
72
+ def delete_all(self) -> None:
73
+ """Delete all stored metadata."""
74
+ self._data_versions.clear()
75
+
76
+ def persist_to(self, metadata_store: MetadataStore | None = None) -> None:
77
+ """Persist in-memory metadata using another MetadataStore implementation.
78
+
79
+ :param metadata_store: MetadataStore implementation to use for persistence.
80
+ If None, a SQLiteMetadataStore is created with the default path "./.hamilton_cache".
81
+
82
+ .. code-block:: python
83
+
84
+ from hamilton import driver
85
+ from hamilton.caching.stores.sqlite import SQLiteMetadataStore
86
+ from hamilton.caching.stores.memory import InMemoryMetadataStore
87
+ import my_dataflow
88
+
89
+ dr = (
90
+ driver.Builder()
91
+ .with_modules(my_dataflow)
92
+ .with_cache(metadata_store=InMemoryMetadataStore())
93
+ .build()
94
+ )
95
+
96
+ # execute the Driver several time. This will populate the in-memory metadata store
97
+ dr.execute(...)
98
+
99
+ # persist to disk in-memory metadata
100
+ dr.cache.metadata_store.persist_to(SQLiteMetadataStore(path="./.hamilton_cache"))
101
+
102
+ """
103
+ if metadata_store is None:
104
+ metadata_store = SQLiteMetadataStore(path="./.hamilton_cache")
105
+
106
+ for run_id in self._run_ids:
107
+ metadata_store.initialize(run_id)
108
+
109
+ for run_id, cache_keys in self._cache_keys_by_run.items():
110
+ for cache_key in cache_keys:
111
+ data_version = self._data_versions[cache_key]
112
+ metadata_store.set(
113
+ cache_key=cache_key,
114
+ data_version=data_version,
115
+ run_id=run_id,
116
+ )
117
+
118
+ @classmethod
119
+ def load_from(cls, metadata_store: MetadataStore) -> "InMemoryMetadataStore":
120
+ """Load in-memory metadata from another MetadataStore instance.
121
+
122
+ :param metadata_store: MetadataStore instance to load from.
123
+ :return: InMemoryMetadataStore copy of the ``metadata_store``.
124
+
125
+ .. code-block:: python
126
+
127
+ from hamilton import driver
128
+ from hamilton.caching.stores.sqlite import SQLiteMetadataStore
129
+ from hamilton.caching.stores.memory import InMemoryMetadataStore
130
+ import my_dataflow
131
+
132
+ sqlite_metadata_store = SQLiteMetadataStore(path="./.hamilton_cache")
133
+ in_memory_metadata_store = InMemoryMetadataStore.load_from(sqlite_metadata_store)
134
+
135
+ # create the Driver with the in-memory metadata store
136
+ dr = (
137
+ driver.Builder()
138
+ .with_modules(my_dataflow)
139
+ .with_cache(metadata_store=in_memory_metadata_store)
140
+ .build()
141
+ )
142
+
143
+ """
144
+ in_memory_metadata_store = InMemoryMetadataStore()
145
+
146
+ for run_id in metadata_store.get_run_ids():
147
+ in_memory_metadata_store.initialize(run_id)
148
+
149
+ for node_metadata in metadata_store.get_run(run_id):
150
+ in_memory_metadata_store.set(
151
+ cache_key=node_metadata["cache_key"],
152
+ data_version=node_metadata["data_version"],
153
+ run_id=run_id,
154
+ )
155
+
156
+ return in_memory_metadata_store
157
+
158
+ @override
159
+ def get_run_ids(self) -> list[str]:
160
+ """Return a list of all ``run_id`` values stored."""
161
+ return self._run_ids
162
+
163
+ @override
164
+ def get_run(self, run_id: str) -> list[dict[str, str]]:
165
+ """Return a list of node metadata associated with a run."""
166
+ if self._cache_keys_by_run.get(run_id, None) is None:
167
+ raise IndexError(f"Run ID not found: {run_id}")
168
+
169
+ nodes_metadata = []
170
+ for cache_key in self._cache_keys_by_run[run_id]:
171
+ decoded_key = decode_key(cache_key)
172
+ nodes_metadata.append(
173
+ dict(
174
+ cache_key=cache_key,
175
+ data_version=self._data_versions[cache_key],
176
+ node_name=decoded_key["node_name"],
177
+ code_version=decoded_key["code_version"],
178
+ dependencies_data_versions=decoded_key["dependencies_data_versions"],
179
+ )
180
+ )
181
+
182
+ return nodes_metadata
183
+
184
+
185
+ class InMemoryResultStore(ResultStore):
186
+ def __init__(self, persist_on_exit: bool = False) -> None:
187
+ self._results: dict[str, StoredResult] = {} # {data_version: result}
188
+
189
+ @override
190
+ def exists(self, data_version: str) -> bool:
191
+ return data_version in self._results.keys()
192
+
193
+ # TODO handle materialization
194
+ @override
195
+ def set(self, data_version: str, result: Any, **kwargs) -> None:
196
+ self._results[data_version] = StoredResult.new(value=result)
197
+
198
+ @override
199
+ def get(self, data_version: str) -> Any | None:
200
+ stored_result = self._results.get(data_version, None)
201
+ if stored_result is None:
202
+ return None
203
+
204
+ return stored_result.value
205
+
206
+ @override
207
+ def delete(self, data_version: str) -> None:
208
+ del self._results[data_version]
209
+
210
+ @override
211
+ def delete_all(self) -> None:
212
+ self._results.clear()
213
+
214
+ def delete_expired(self) -> None:
215
+ to_delete = [
216
+ data_version
217
+ for data_version, stored_result in self._results.items()
218
+ if stored_result.expired
219
+ ]
220
+
221
+ # first collect keys then delete because you can delete from dictionary
222
+ # as you iterate through it
223
+ for data_version in to_delete:
224
+ self.delete(data_version)
225
+
226
+ def persist_to(self, result_store: ResultStore | None = None) -> None:
227
+ """Persist in-memory results using another ``ResultStore`` implementation.
228
+
229
+ :param result_store: ResultStore implementation to use for persistence.
230
+ If None, a FileResultStore is created with the default path "./.hamilton_cache".
231
+ """
232
+ if result_store is None:
233
+ result_store = FileResultStore(path="./.hamilton_cache")
234
+
235
+ for data_version, stored_result in self._results.items():
236
+ result_store.set(data_version, stored_result.value)
237
+
238
+ @classmethod
239
+ def load_from(
240
+ cls,
241
+ result_store: ResultStore,
242
+ metadata_store: MetadataStore | None = None,
243
+ data_versions: Sequence[str] | None = None,
244
+ ) -> "InMemoryResultStore":
245
+ """Load in-memory results from another ResultStore instance.
246
+
247
+ Since result stores do not store an index of their keys, you must provide a
248
+ ``MetadataStore`` instance or a list of ``data_version`` for which results
249
+ should be loaded in memory.
250
+
251
+ :param result_store: ``ResultStore`` instance to load results from.
252
+ :param metadata_store: ``MetadataStore`` instance from which all ``data_version`` are retrieved.
253
+ :return: InMemoryResultStore copy of the ``result_store``.
254
+
255
+ .. code-block:: python
256
+
257
+ from hamilton import driver
258
+ from hamilton.caching.stores.sqlite import SQLiteMetadataStore
259
+ from hamilton.caching.stores.memory import InMemoryMetadataStore
260
+ import my_dataflow
261
+
262
+ sqlite_metadata_store = SQLiteMetadataStore(path="./.hamilton_cache")
263
+ in_memory_metadata_store = InMemoryMetadataStore.load_from(sqlite_metadata_store)
264
+
265
+ # create the Driver with the in-memory metadata store
266
+ dr = (
267
+ driver.Builder()
268
+ .with_modules(my_dataflow)
269
+ .with_cache(metadata_store=in_memory_metadata_store)
270
+ .build()
271
+ )
272
+
273
+
274
+ """
275
+ if metadata_store is None and data_versions is None:
276
+ raise ValueError(
277
+ "A `metadata_store` or `data_versions` must be provided to load results."
278
+ )
279
+
280
+ in_memory_result_store = InMemoryResultStore()
281
+
282
+ data_versions_to_retrieve = set()
283
+ if data_versions is not None:
284
+ data_versions_to_retrieve.update(data_versions)
285
+
286
+ if metadata_store is not None:
287
+ for run_id in metadata_store.get_run_ids():
288
+ for node_metadata in metadata_store.get_run(run_id):
289
+ data_versions_to_retrieve.add(node_metadata["data_version"])
290
+
291
+ for data_version in data_versions_to_retrieve:
292
+ # TODO disambiguate "result is None" from the sentinel value when `data_version`
293
+ # is not found in `result_store`.
294
+ result = result_store.get(data_version)
295
+ in_memory_result_store.set(data_version, result)
296
+
297
+ return in_memory_result_store