|
1 | 1 | import abc |
| 2 | +import importlib |
2 | 3 | from datetime import datetime |
3 | 4 | from pathlib import Path |
4 | 5 | from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union |
5 | 6 |
|
6 | 7 | import pandas |
7 | 8 | import pyarrow |
8 | 9 |
|
| 10 | +from feast import errors |
9 | 11 | from feast.entity import Entity |
10 | 12 | from feast.feature_table import FeatureTable |
11 | 13 | from feast.feature_view import FeatureView |
@@ -135,16 +137,42 @@ def online_read( |
135 | 137 |
|
136 | 138 |
|
137 | 139 | def get_provider(config: RepoConfig, repo_path: Path) -> Provider: |
138 | | - if config.provider == "gcp": |
139 | | - from feast.infra.gcp import GcpProvider |
| 140 | + if "." not in config.provider: |
| 141 | + if config.provider == "gcp": |
| 142 | + from feast.infra.gcp import GcpProvider |
140 | 143 |
|
141 | | - return GcpProvider(config) |
142 | | - elif config.provider == "local": |
143 | | - from feast.infra.local import LocalProvider |
| 144 | + return GcpProvider(config) |
| 145 | + elif config.provider == "local": |
| 146 | + from feast.infra.local import LocalProvider |
144 | 147 |
|
145 | | - return LocalProvider(config, repo_path) |
| 148 | + return LocalProvider(config, repo_path) |
| 149 | + else: |
| 150 | + raise errors.FeastProviderNotImplementedError(config.provider) |
146 | 151 | else: |
147 | | - raise ValueError(config) |
| 152 | + # Split provider into module and class names by finding the right-most dot. |
| 153 | + # For example, provider 'foo.bar.MyProvider' will be parsed into 'foo.bar' and 'MyProvider' |
| 154 | + module_name, class_name = config.provider.rsplit(".", 1) |
| 155 | + |
| 156 | + # Try importing the module that contains the custom provider |
| 157 | + try: |
| 158 | + module = importlib.import_module(module_name) |
| 159 | + except Exception as e: |
| 160 | + # The original exception can be anything - either module not found, |
| 161 | + # or any other kind of error happening during the module import time. |
| 162 | + # So we should include the original error as well in the stack trace. |
| 163 | + raise errors.FeastProviderModuleImportError(module_name) from e |
| 164 | + |
| 165 | + # Try getting the provider class definition |
| 166 | + try: |
| 167 | + ProviderCls = getattr(module, class_name) |
| 168 | + except AttributeError: |
| 169 | + # This can only be one type of error, when class_name attribute does not exist in the module |
| 170 | + # So we don't have to include the original exception here |
| 171 | + raise errors.FeastProviderClassImportError( |
| 172 | + module_name, class_name |
| 173 | + ) from None |
| 174 | + |
| 175 | + return ProviderCls(config, repo_path) |
148 | 176 |
|
149 | 177 |
|
150 | 178 | def _get_requested_feature_views_to_features_dict( |
|
0 commit comments