redis-featureform 3.0.0__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.
- featureform/__init__.py +335 -0
- featureform/_apply_context.py +48 -0
- featureform/_apply_wait.py +183 -0
- featureform/_generated/__init__.py +1 -0
- featureform/_generated/openapi/__init__.py +13 -0
- featureform/_generated/openapi/_internal.py +1631 -0
- featureform/_generated/openapi/github_com_redislabsdev_featureform_internal_rest_types.py +31 -0
- featureform/_generated/openapi/server.py +115 -0
- featureform/_generated/openapi/types.py +365 -0
- featureform/_generated/proto/__init__.py +1 -0
- featureform/_generated/proto/featureform/__init__.py +1 -0
- featureform/_generated/proto/featureform/v2/__init__.py +1 -0
- featureform/_generated/proto/featureform/v2/apply_pb2.py +66 -0
- featureform/_generated/proto/featureform/v2/apply_pb2.pyi +463 -0
- featureform/_generated/proto/featureform/v2/apply_pb2_grpc.py +147 -0
- featureform/_generated/proto/featureform/v2/apply_pb2_grpc.pyi +82 -0
- featureform/_generated/proto/featureform/v2/audit_pb2.py +47 -0
- featureform/_generated/proto/featureform/v2/audit_pb2.pyi +140 -0
- featureform/_generated/proto/featureform/v2/audit_pb2_grpc.py +97 -0
- featureform/_generated/proto/featureform/v2/audit_pb2_grpc.pyi +49 -0
- featureform/_generated/proto/featureform/v2/catalog_pb2.py +60 -0
- featureform/_generated/proto/featureform/v2/catalog_pb2.pyi +292 -0
- featureform/_generated/proto/featureform/v2/catalog_pb2_grpc.py +192 -0
- featureform/_generated/proto/featureform/v2/catalog_pb2_grpc.pyi +88 -0
- featureform/_generated/proto/featureform/v2/common_pb2.py +44 -0
- featureform/_generated/proto/featureform/v2/common_pb2.pyi +128 -0
- featureform/_generated/proto/featureform/v2/common_pb2_grpc.py +24 -0
- featureform/_generated/proto/featureform/v2/common_pb2_grpc.pyi +20 -0
- featureform/_generated/proto/featureform/v2/dataframe_pb2.py +67 -0
- featureform/_generated/proto/featureform/v2/dataframe_pb2.pyi +342 -0
- featureform/_generated/proto/featureform/v2/dataframe_pb2_grpc.py +97 -0
- featureform/_generated/proto/featureform/v2/dataframe_pb2_grpc.pyi +49 -0
- featureform/_generated/proto/featureform/v2/provider_pb2.py +261 -0
- featureform/_generated/proto/featureform/v2/provider_pb2.pyi +3013 -0
- featureform/_generated/proto/featureform/v2/provider_pb2_grpc.py +277 -0
- featureform/_generated/proto/featureform/v2/provider_pb2_grpc.pyi +106 -0
- featureform/_generated/proto/featureform/v2/rbac_pb2.py +157 -0
- featureform/_generated/proto/featureform/v2/rbac_pb2.pyi +1281 -0
- featureform/_generated/proto/featureform/v2/rbac_pb2_grpc.py +1072 -0
- featureform/_generated/proto/featureform/v2/rbac_pb2_grpc.pyi +260 -0
- featureform/_generated/proto/featureform/v2/resource_pb2.py +127 -0
- featureform/_generated/proto/featureform/v2/resource_pb2.pyi +1529 -0
- featureform/_generated/proto/featureform/v2/resource_pb2_grpc.py +24 -0
- featureform/_generated/proto/featureform/v2/resource_pb2_grpc.pyi +20 -0
- featureform/_generated/proto/featureform/v2/resource_service_pb2.py +215 -0
- featureform/_generated/proto/featureform/v2/resource_service_pb2.pyi +2295 -0
- featureform/_generated/proto/featureform/v2/resource_service_pb2_grpc.py +1645 -0
- featureform/_generated/proto/featureform/v2/resource_service_pb2_grpc.pyi +373 -0
- featureform/_generated/proto/featureform/v2/secret_provider_pb2.py +83 -0
- featureform/_generated/proto/featureform/v2/secret_provider_pb2.pyi +607 -0
- featureform/_generated/proto/featureform/v2/secret_provider_pb2_grpc.py +277 -0
- featureform/_generated/proto/featureform/v2/secret_provider_pb2_grpc.pyi +106 -0
- featureform/_generated/proto/featureform/v2/serving_pb2.py +112 -0
- featureform/_generated/proto/featureform/v2/serving_pb2.pyi +783 -0
- featureform/_generated/proto/featureform/v2/serving_pb2_grpc.py +146 -0
- featureform/_generated/proto/featureform/v2/serving_pb2_grpc.pyi +76 -0
- featureform/_generated/proto/featureform/v2/version_pb2.py +45 -0
- featureform/_generated/proto/featureform/v2/version_pb2.pyi +127 -0
- featureform/_generated/proto/featureform/v2/version_pb2_grpc.py +146 -0
- featureform/_generated/proto/featureform/v2/version_pb2_grpc.pyi +76 -0
- featureform/_generated/proto/featureform/v2/workspace_pb2.py +65 -0
- featureform/_generated/proto/featureform/v2/workspace_pb2.pyi +296 -0
- featureform/_generated/proto/featureform/v2/workspace_pb2_grpc.py +322 -0
- featureform/_generated/proto/featureform/v2/workspace_pb2_grpc.pyi +124 -0
- featureform/_generated/proto/scheduler/__init__.py +1 -0
- featureform/_generated/proto/scheduler/v1/__init__.py +1 -0
- featureform/_generated/proto/scheduler/v1/scheduler_pb2.py +180 -0
- featureform/_generated/proto/scheduler/v1/scheduler_pb2.pyi +1994 -0
- featureform/_generated/proto/scheduler/v1/scheduler_pb2_grpc.py +1145 -0
- featureform/_generated/proto/scheduler/v1/scheduler_pb2_grpc.pyi +301 -0
- featureform/_internal/__init__.py +1 -0
- featureform/_internal/http.py +231 -0
- featureform/_internal/logging.py +299 -0
- featureform/_internal/secret_refs.py +118 -0
- featureform/_internal/telemetry/__init__.py +73 -0
- featureform/_internal/telemetry/base.py +126 -0
- featureform/_internal/telemetry/config.py +71 -0
- featureform/_internal/telemetry/noop.py +89 -0
- featureform/_internal/telemetry/otel.py +152 -0
- featureform/_version.py +39 -0
- featureform/auth/__init__.py +21 -0
- featureform/auth/runtime.py +125 -0
- featureform/auth/token.py +559 -0
- featureform/cli/__init__.py +23 -0
- featureform/cli/admin_client.py +888 -0
- featureform/cli/auth/__init__.py +113 -0
- featureform/cli/auth/clock.py +22 -0
- featureform/cli/auth/discovery.py +240 -0
- featureform/cli/auth/flows.py +130 -0
- featureform/cli/auth/fs.py +14 -0
- featureform/cli/auth/profiles.py +153 -0
- featureform/cli/auth/service.py +575 -0
- featureform/cli/auth/session_store.py +311 -0
- featureform/cli/auth/types.py +80 -0
- featureform/cli/commands/__init__.py +27 -0
- featureform/cli/commands/_common.py +23 -0
- featureform/cli/commands/_provider_config.py +1173 -0
- featureform/cli/commands/apply.py +887 -0
- featureform/cli/commands/audit.py +58 -0
- featureform/cli/commands/auth.py +437 -0
- featureform/cli/commands/catalog.py +116 -0
- featureform/cli/commands/config.py +188 -0
- featureform/cli/commands/dataframe.py +182 -0
- featureform/cli/commands/graph.py +534 -0
- featureform/cli/commands/machine_credential.py +142 -0
- featureform/cli/commands/provider.py +1222 -0
- featureform/cli/commands/rbac.py +445 -0
- featureform/cli/commands/scheduler.py +1101 -0
- featureform/cli/commands/secret_provider.py +405 -0
- featureform/cli/commands/workspace.py +167 -0
- featureform/cli/env.py +69 -0
- featureform/cli/errors.py +155 -0
- featureform/cli/main.py +525 -0
- featureform/cli/output/__init__.py +13 -0
- featureform/cli/output/base.py +49 -0
- featureform/cli/output/json_fmt.py +71 -0
- featureform/cli/output/table.py +163 -0
- featureform/cli/output/yaml_fmt.py +64 -0
- featureform/cli/scheduler_client.py +1281 -0
- featureform/cli/utils/__init__.py +5 -0
- featureform/cli/utils/context.py +252 -0
- featureform/client.py +7961 -0
- featureform/config.py +156 -0
- featureform/dataframe/__init__.py +12 -0
- featureform/dataframe/client.py +787 -0
- featureform/dataframe/result.py +288 -0
- featureform/dataframe/stream.py +146 -0
- featureform/errors.py +867 -0
- featureform/py.typed +0 -0
- featureform/resources/__init__.py +123 -0
- featureform/resources/base.py +256 -0
- featureform/resources/dataset.py +319 -0
- featureform/resources/entity.py +47 -0
- featureform/resources/feature.py +399 -0
- featureform/resources/label.py +250 -0
- featureform/resources/provider.py +729 -0
- featureform/resources/realtime_feature.py +621 -0
- featureform/resources/training.py +333 -0
- featureform/serving/__init__.py +12 -0
- featureform/serving/_decode.py +93 -0
- featureform/serving/_metadata.py +99 -0
- featureform/serving/_realtime.py +253 -0
- featureform/serving/cache.py +190 -0
- featureform/serving/client.py +788 -0
- featureform/serving/types.py +134 -0
- featureform/spark.py +171 -0
- featureform/spark_env.py +31 -0
- featureform/transport/__init__.py +49 -0
- featureform/transport/base.py +42 -0
- featureform/transport/grpc.py +760 -0
- featureform/transport/rest.py +224 -0
- featureform/types/__init__.py +226 -0
- featureform/types/_base.py +24 -0
- featureform/types/catalog.py +62 -0
- featureform/types/entity.py +39 -0
- featureform/types/graph.py +487 -0
- featureform/types/patch.py +14 -0
- featureform/types/provider.py +1098 -0
- featureform/types/resource.py +407 -0
- featureform/types/secret.py +232 -0
- featureform/types/secret_provider.py +206 -0
- featureform/types/workspace.py +54 -0
- featureform/version.py +228 -0
- redis_featureform-3.0.0.dist-info/METADATA +448 -0
- redis_featureform-3.0.0.dist-info/RECORD +167 -0
- redis_featureform-3.0.0.dist-info/WHEEL +4 -0
- redis_featureform-3.0.0.dist-info/entry_points.txt +3 -0
featureform/__init__.py
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
"""Featureform Python client library.
|
|
2
|
+
|
|
3
|
+
Enterprise-grade Python client for Featureform v2 API.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from featureform._apply_context import get_active_apply_client, get_active_apply_workspace_id
|
|
7
|
+
from featureform._apply_wait import ApplyWaitError, WaitTarget
|
|
8
|
+
from featureform._internal.logging import (
|
|
9
|
+
LogLevel,
|
|
10
|
+
configure_logging,
|
|
11
|
+
current_request_id,
|
|
12
|
+
get_logger,
|
|
13
|
+
request_id_context,
|
|
14
|
+
temporary_log_level,
|
|
15
|
+
)
|
|
16
|
+
from featureform._internal.telemetry import TelemetryConfig
|
|
17
|
+
from featureform._version import resolve_version
|
|
18
|
+
from featureform.client import (
|
|
19
|
+
ApplyResult,
|
|
20
|
+
ApplyWaitResult,
|
|
21
|
+
Client,
|
|
22
|
+
GraphClientBase,
|
|
23
|
+
GRPCGraphClient,
|
|
24
|
+
PingResult,
|
|
25
|
+
PlannedJob,
|
|
26
|
+
PlannedTask,
|
|
27
|
+
ProviderClient,
|
|
28
|
+
ResourceChange,
|
|
29
|
+
RESTGraphClient,
|
|
30
|
+
SecretProviderClient,
|
|
31
|
+
WorkspaceClient,
|
|
32
|
+
)
|
|
33
|
+
from featureform.config import Config
|
|
34
|
+
from featureform.errors import (
|
|
35
|
+
AlreadyExistsError,
|
|
36
|
+
ConnectionError,
|
|
37
|
+
DataframeFallbackError,
|
|
38
|
+
DataframePlanResolutionError,
|
|
39
|
+
FeatureformError,
|
|
40
|
+
FlightFallbackUnavailableError,
|
|
41
|
+
InternalError,
|
|
42
|
+
InvalidArgumentError,
|
|
43
|
+
NotFoundError,
|
|
44
|
+
ProviderWorkspaceMismatchError,
|
|
45
|
+
SparkExecutionError,
|
|
46
|
+
TimeoutError,
|
|
47
|
+
ValidationError,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# New DSL resource classes
|
|
51
|
+
from featureform.resources import (
|
|
52
|
+
AggregateFeature,
|
|
53
|
+
AttributeFeature,
|
|
54
|
+
Dataset,
|
|
55
|
+
EnvSecretProvider,
|
|
56
|
+
Feature,
|
|
57
|
+
FeatureBuilder,
|
|
58
|
+
FeatureInput,
|
|
59
|
+
FeatureResource,
|
|
60
|
+
FeatureView,
|
|
61
|
+
FunctionNormalizerDetails,
|
|
62
|
+
IcebergPrimaryDataset,
|
|
63
|
+
IcebergProvider,
|
|
64
|
+
K8sSecretProvider,
|
|
65
|
+
Label,
|
|
66
|
+
LabelBuilder,
|
|
67
|
+
LabelResource,
|
|
68
|
+
PostgresPrimaryDataset,
|
|
69
|
+
PostgresProvider,
|
|
70
|
+
PostgresTransformedDataset,
|
|
71
|
+
PrimaryDataset,
|
|
72
|
+
RealtimeFeature,
|
|
73
|
+
RealtimeInput,
|
|
74
|
+
RedisClusterProvider,
|
|
75
|
+
RedisProvider,
|
|
76
|
+
Resource,
|
|
77
|
+
ResourceRegistry,
|
|
78
|
+
S3Provider,
|
|
79
|
+
SecretProviderBase,
|
|
80
|
+
SerializerDetails,
|
|
81
|
+
SnowflakePrimaryDataset,
|
|
82
|
+
SnowflakeProvider,
|
|
83
|
+
SnowflakeTransformedDataset,
|
|
84
|
+
SparkProvider,
|
|
85
|
+
SparkTransformedDataset,
|
|
86
|
+
TrainingSet,
|
|
87
|
+
TransformedDataset,
|
|
88
|
+
VaultSecretProvider,
|
|
89
|
+
postgres_sql_transformation,
|
|
90
|
+
realtime_feature,
|
|
91
|
+
spark_sql_transformation,
|
|
92
|
+
)
|
|
93
|
+
from featureform.resources import Provider as ProviderBase
|
|
94
|
+
from featureform.resources.entity import Entity
|
|
95
|
+
from featureform.spark import DataframeExecutionInfo, SparkOptions, get_execution_info
|
|
96
|
+
from featureform.types import (
|
|
97
|
+
CLEAR,
|
|
98
|
+
AWSSecretRef,
|
|
99
|
+
AWSSecretsManagerSecretConfig,
|
|
100
|
+
AzureSecretRef,
|
|
101
|
+
CreateWorkspaceRequest,
|
|
102
|
+
DynamoDBConfig,
|
|
103
|
+
EnvSecretConfig,
|
|
104
|
+
EnvSecretRef,
|
|
105
|
+
GCPSecretRef,
|
|
106
|
+
K8sSecretRef,
|
|
107
|
+
KafkaConfig,
|
|
108
|
+
KubernetesSecretConfig,
|
|
109
|
+
PostgresConfig,
|
|
110
|
+
Provider,
|
|
111
|
+
ProviderConfig,
|
|
112
|
+
ProviderType,
|
|
113
|
+
RedisConfig,
|
|
114
|
+
RegisterProviderRequest,
|
|
115
|
+
RegisterSecretProviderRequest,
|
|
116
|
+
S3Config,
|
|
117
|
+
SecretProvider,
|
|
118
|
+
SecretProviderConfig,
|
|
119
|
+
SecretProviderType,
|
|
120
|
+
SecretRef,
|
|
121
|
+
SnowflakeConfig,
|
|
122
|
+
SparkKerberosConfig,
|
|
123
|
+
SparkProviderConfig,
|
|
124
|
+
UpdateProviderRequest,
|
|
125
|
+
UpdateSecretProviderRequest,
|
|
126
|
+
UpdateWorkspaceRequest,
|
|
127
|
+
VaultSecretConfig,
|
|
128
|
+
VaultSecretRef,
|
|
129
|
+
Workspace,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Type helpers from types.resource
|
|
133
|
+
from featureform.types.resource import (
|
|
134
|
+
AggregateFunction,
|
|
135
|
+
FeatureLag,
|
|
136
|
+
IcebergConfig,
|
|
137
|
+
IcebergTableLocation,
|
|
138
|
+
MaterializationEngine,
|
|
139
|
+
PostgresDatasetConfig,
|
|
140
|
+
ScalarType,
|
|
141
|
+
SparkEnv,
|
|
142
|
+
SparkExecutionDefaults,
|
|
143
|
+
SparkJobConfig,
|
|
144
|
+
TableLocation,
|
|
145
|
+
TrainingSetType,
|
|
146
|
+
ValueType,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
__version__ = resolve_version()
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def get_postgres(name: str) -> PostgresProvider:
|
|
153
|
+
"""Resolve a registered Postgres provider within an active apply context.
|
|
154
|
+
|
|
155
|
+
Use this in resource files loaded by ``ff apply`` when you want method-style
|
|
156
|
+
authoring such as ``postgres.dataset(...)`` or ``@postgres.sql_transformation(...)``.
|
|
157
|
+
Outside apply, use ``client.get_postgres(...)`` instead.
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
client = get_active_apply_client()
|
|
161
|
+
workspace_id = get_active_apply_workspace_id()
|
|
162
|
+
if client is None:
|
|
163
|
+
raise InvalidArgumentError(
|
|
164
|
+
"ff.get_postgres() requires an active apply context. Use client.get_postgres() "
|
|
165
|
+
"outside resource-file apply flows."
|
|
166
|
+
)
|
|
167
|
+
return client.get_postgres(name, workspace=workspace_id)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def get_provider(name: str) -> ProviderBase:
|
|
171
|
+
"""Resolve a registered provider within an active apply context.
|
|
172
|
+
|
|
173
|
+
Outside apply, use ``client.get_provider(...)`` instead.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
client = get_active_apply_client()
|
|
177
|
+
workspace_id = get_active_apply_workspace_id()
|
|
178
|
+
if client is None:
|
|
179
|
+
raise InvalidArgumentError(
|
|
180
|
+
"ff.get_provider() requires an active apply context. Use client.get_provider() "
|
|
181
|
+
"outside resource-file apply flows."
|
|
182
|
+
)
|
|
183
|
+
return client.get_provider(name, workspace=workspace_id)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
__all__ = [
|
|
187
|
+
# Version
|
|
188
|
+
"__version__",
|
|
189
|
+
# Client
|
|
190
|
+
"ApplyResult",
|
|
191
|
+
"ApplyWaitError",
|
|
192
|
+
"ApplyWaitResult",
|
|
193
|
+
"Client",
|
|
194
|
+
"GRPCGraphClient",
|
|
195
|
+
"GraphClientBase",
|
|
196
|
+
"PingResult",
|
|
197
|
+
"PlannedJob",
|
|
198
|
+
"PlannedTask",
|
|
199
|
+
"ProviderClient",
|
|
200
|
+
"RESTGraphClient",
|
|
201
|
+
"ResourceChange",
|
|
202
|
+
"SecretProviderClient",
|
|
203
|
+
"WaitTarget",
|
|
204
|
+
"WorkspaceClient",
|
|
205
|
+
# Config
|
|
206
|
+
"Config",
|
|
207
|
+
"CLEAR",
|
|
208
|
+
# Logging
|
|
209
|
+
"LogLevel",
|
|
210
|
+
"configure_logging",
|
|
211
|
+
"current_request_id",
|
|
212
|
+
"get_logger",
|
|
213
|
+
"request_id_context",
|
|
214
|
+
"temporary_log_level",
|
|
215
|
+
# Telemetry
|
|
216
|
+
"TelemetryConfig",
|
|
217
|
+
# Errors
|
|
218
|
+
"AlreadyExistsError",
|
|
219
|
+
"ConnectionError",
|
|
220
|
+
"DataframeFallbackError",
|
|
221
|
+
"DataframePlanResolutionError",
|
|
222
|
+
"FeatureformError",
|
|
223
|
+
"FlightFallbackUnavailableError",
|
|
224
|
+
"get_postgres",
|
|
225
|
+
"get_provider",
|
|
226
|
+
"InternalError",
|
|
227
|
+
"InvalidArgumentError",
|
|
228
|
+
"NotFoundError",
|
|
229
|
+
"ProviderWorkspaceMismatchError",
|
|
230
|
+
"SparkExecutionError",
|
|
231
|
+
"TimeoutError",
|
|
232
|
+
"ValidationError",
|
|
233
|
+
# New DSL - Base
|
|
234
|
+
"Resource",
|
|
235
|
+
"ResourceRegistry",
|
|
236
|
+
# New DSL - Secrets
|
|
237
|
+
"SecretProviderBase",
|
|
238
|
+
"EnvSecretProvider",
|
|
239
|
+
"VaultSecretProvider",
|
|
240
|
+
"K8sSecretProvider",
|
|
241
|
+
"EnvSecretRef",
|
|
242
|
+
"AWSSecretRef",
|
|
243
|
+
"GCPSecretRef",
|
|
244
|
+
"AzureSecretRef",
|
|
245
|
+
"VaultSecretRef",
|
|
246
|
+
"K8sSecretRef",
|
|
247
|
+
"SecretRef",
|
|
248
|
+
# New DSL - Providers (NOT Resources - registered separately)
|
|
249
|
+
"IcebergProvider",
|
|
250
|
+
"PostgresProvider",
|
|
251
|
+
"SnowflakeProvider",
|
|
252
|
+
"ProviderBase",
|
|
253
|
+
"RedisProvider",
|
|
254
|
+
"RedisClusterProvider",
|
|
255
|
+
"S3Provider",
|
|
256
|
+
"SparkProvider",
|
|
257
|
+
"SparkOptions",
|
|
258
|
+
"get_execution_info",
|
|
259
|
+
"postgres_sql_transformation",
|
|
260
|
+
"spark_sql_transformation",
|
|
261
|
+
# New DSL - Entity
|
|
262
|
+
"Entity",
|
|
263
|
+
# New DSL - Datasets
|
|
264
|
+
"Dataset",
|
|
265
|
+
"IcebergPrimaryDataset",
|
|
266
|
+
"PostgresPrimaryDataset",
|
|
267
|
+
"PostgresTransformedDataset",
|
|
268
|
+
"PrimaryDataset",
|
|
269
|
+
"SnowflakePrimaryDataset",
|
|
270
|
+
"SnowflakeTransformedDataset",
|
|
271
|
+
"SparkTransformedDataset",
|
|
272
|
+
"TransformedDataset",
|
|
273
|
+
# New DSL - Features (builder pattern)
|
|
274
|
+
"Feature",
|
|
275
|
+
"FeatureBuilder",
|
|
276
|
+
"FeatureResource",
|
|
277
|
+
"FeatureInput",
|
|
278
|
+
"AttributeFeature",
|
|
279
|
+
"AggregateFeature",
|
|
280
|
+
"FunctionNormalizerDetails",
|
|
281
|
+
# New DSL - Labels (builder pattern)
|
|
282
|
+
"Label",
|
|
283
|
+
"LabelBuilder",
|
|
284
|
+
"LabelResource",
|
|
285
|
+
"RealtimeFeature",
|
|
286
|
+
"RealtimeInput",
|
|
287
|
+
"SerializerDetails",
|
|
288
|
+
"realtime_feature",
|
|
289
|
+
# New DSL - Training
|
|
290
|
+
"FeatureView",
|
|
291
|
+
"TrainingSet",
|
|
292
|
+
# Type helpers
|
|
293
|
+
"AggregateFunction",
|
|
294
|
+
"FeatureLag",
|
|
295
|
+
"IcebergConfig",
|
|
296
|
+
"IcebergTableLocation",
|
|
297
|
+
"MaterializationEngine",
|
|
298
|
+
"PostgresDatasetConfig",
|
|
299
|
+
"ScalarType",
|
|
300
|
+
"SparkEnv",
|
|
301
|
+
"SparkExecutionDefaults",
|
|
302
|
+
"SparkJobConfig",
|
|
303
|
+
"DataframeExecutionInfo",
|
|
304
|
+
"TableLocation",
|
|
305
|
+
"TrainingSetType",
|
|
306
|
+
"ValueType",
|
|
307
|
+
# Workspace Types
|
|
308
|
+
"CreateWorkspaceRequest",
|
|
309
|
+
"UpdateWorkspaceRequest",
|
|
310
|
+
"Workspace",
|
|
311
|
+
# Provider Types (legacy)
|
|
312
|
+
"KafkaConfig",
|
|
313
|
+
"PostgresConfig",
|
|
314
|
+
"Provider",
|
|
315
|
+
"ProviderConfig",
|
|
316
|
+
"ProviderType",
|
|
317
|
+
"DynamoDBConfig",
|
|
318
|
+
"RedisConfig",
|
|
319
|
+
"RegisterProviderRequest",
|
|
320
|
+
"S3Config",
|
|
321
|
+
"SparkKerberosConfig",
|
|
322
|
+
"SparkProviderConfig",
|
|
323
|
+
"SnowflakeConfig",
|
|
324
|
+
"UpdateProviderRequest",
|
|
325
|
+
# SecretProvider Types
|
|
326
|
+
"AWSSecretsManagerSecretConfig",
|
|
327
|
+
"EnvSecretConfig",
|
|
328
|
+
"KubernetesSecretConfig",
|
|
329
|
+
"RegisterSecretProviderRequest",
|
|
330
|
+
"SecretProvider",
|
|
331
|
+
"SecretProviderConfig",
|
|
332
|
+
"SecretProviderType",
|
|
333
|
+
"UpdateSecretProviderRequest",
|
|
334
|
+
"VaultSecretConfig",
|
|
335
|
+
]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Apply-time provider resolution context for resource files."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterator
|
|
6
|
+
from contextlib import contextmanager
|
|
7
|
+
from contextvars import ContextVar
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
from uuid import UUID
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from featureform.client import Client
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
_active_client: ContextVar[Client | None] = ContextVar(
|
|
16
|
+
"featureform_active_apply_client",
|
|
17
|
+
default=None,
|
|
18
|
+
)
|
|
19
|
+
_active_workspace_id: ContextVar[UUID | None] = ContextVar(
|
|
20
|
+
"featureform_active_apply_workspace_id",
|
|
21
|
+
default=None,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@contextmanager
|
|
26
|
+
def apply_resolution_context(
|
|
27
|
+
*,
|
|
28
|
+
client: Client | None,
|
|
29
|
+
workspace_id: UUID | None,
|
|
30
|
+
) -> Iterator[None]:
|
|
31
|
+
"""Temporarily expose the active apply client/workspace to resource files."""
|
|
32
|
+
client_token = _active_client.set(client)
|
|
33
|
+
workspace_token = _active_workspace_id.set(workspace_id)
|
|
34
|
+
try:
|
|
35
|
+
yield
|
|
36
|
+
finally:
|
|
37
|
+
_active_client.reset(client_token)
|
|
38
|
+
_active_workspace_id.reset(workspace_token)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_active_apply_client() -> Client | None:
|
|
42
|
+
"""Return the active apply client, if any."""
|
|
43
|
+
return _active_client.get()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_active_apply_workspace_id() -> UUID | None:
|
|
47
|
+
"""Return the active apply workspace ID, if any."""
|
|
48
|
+
return _active_workspace_id.get()
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""Shared apply wait helpers for CLI and Python client flows."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import time
|
|
6
|
+
from collections.abc import Callable, Mapping
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import Any, cast
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class WaitTarget(str, Enum):
|
|
12
|
+
"""Wait target options for apply jobs."""
|
|
13
|
+
|
|
14
|
+
RUNNING = "running"
|
|
15
|
+
FINISHED = "finished"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
TERMINAL_JOB_STATUSES = {"COMPLETED", "COMPLETED_WITH_WARNINGS", "FAILED", "CANCELED"}
|
|
19
|
+
SUCCESSFUL_TERMINAL_JOB_STATUSES = {"COMPLETED", "COMPLETED_WITH_WARNINGS"}
|
|
20
|
+
FAILED_JOB_STATUSES = {"FAILED", "CANCELED"}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ApplyWaitError(Exception):
|
|
24
|
+
"""Raised when apply wait semantics fail or time out."""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ApplyWaitTimeoutError(ApplyWaitError):
|
|
28
|
+
"""Raised when apply waiting exceeds the allotted timeout."""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ApplyJobVisibilityTimeoutError(ApplyWaitTimeoutError):
|
|
32
|
+
"""Timed out before the scheduler job became visible."""
|
|
33
|
+
|
|
34
|
+
def __init__(self, job_id: str) -> None:
|
|
35
|
+
super().__init__(f"Timed out waiting for job '{job_id}' to become visible.")
|
|
36
|
+
self.job_id = job_id
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ApplyJobStateTimeoutError(ApplyWaitTimeoutError):
|
|
40
|
+
"""Timed out before the scheduler job reached the requested wait target."""
|
|
41
|
+
|
|
42
|
+
def __init__(self, job_id: str, wait_for: WaitTarget, last_status: str) -> None:
|
|
43
|
+
super().__init__(
|
|
44
|
+
f"Timed out waiting for job '{job_id}' to reach {wait_for.value}. "
|
|
45
|
+
f"Last status: {last_status}."
|
|
46
|
+
)
|
|
47
|
+
self.job_id = job_id
|
|
48
|
+
self.wait_for = wait_for
|
|
49
|
+
self.last_status = last_status
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ApplyJobFailedError(ApplyWaitError):
|
|
53
|
+
"""Apply job reached a failed terminal state."""
|
|
54
|
+
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
job_id: str,
|
|
58
|
+
status: str,
|
|
59
|
+
*,
|
|
60
|
+
detail: str | None = None,
|
|
61
|
+
job: dict[str, Any] | None = None,
|
|
62
|
+
) -> None:
|
|
63
|
+
message = f"Apply job '{job_id}' finished with status {status}."
|
|
64
|
+
if detail:
|
|
65
|
+
message = f"{message} {detail}"
|
|
66
|
+
super().__init__(message)
|
|
67
|
+
self.job_id = job_id
|
|
68
|
+
self.status = status
|
|
69
|
+
self.detail = detail
|
|
70
|
+
self.job = job
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class ApplyJobFetchError(ApplyWaitError):
|
|
74
|
+
"""Fetching scheduler job state failed."""
|
|
75
|
+
|
|
76
|
+
def __init__(self, job_id: str, detail: str | None = None) -> None:
|
|
77
|
+
message = f"Failed to fetch apply job '{job_id}'."
|
|
78
|
+
if detail:
|
|
79
|
+
message = f"{message} {detail}"
|
|
80
|
+
super().__init__(message)
|
|
81
|
+
self.job_id = job_id
|
|
82
|
+
self.detail = detail
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class ApplyWorkspaceVersionTimeoutError(ApplyWaitTimeoutError):
|
|
86
|
+
"""Timed out waiting for the applied workspace version to become visible."""
|
|
87
|
+
|
|
88
|
+
def __init__(self, workspace_id: object, minimum: int, last_seen: int) -> None:
|
|
89
|
+
super().__init__(
|
|
90
|
+
f"Timed out waiting for workspace '{workspace_id}' to reach applied version "
|
|
91
|
+
f"{minimum}. Last seen version: {last_seen}."
|
|
92
|
+
)
|
|
93
|
+
self.workspace_id = workspace_id
|
|
94
|
+
self.minimum = minimum
|
|
95
|
+
self.last_seen = last_seen
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def summarize_failed_job(job: Mapping[str, object]) -> str | None:
|
|
99
|
+
"""Build a concise failure summary from scheduler job data."""
|
|
100
|
+
parts: list[str] = []
|
|
101
|
+
|
|
102
|
+
job_error_value: object = job.get("error_message")
|
|
103
|
+
job_error = str(job_error_value or "").strip()
|
|
104
|
+
if job_error:
|
|
105
|
+
parts.append(f"job error: {job_error}")
|
|
106
|
+
|
|
107
|
+
tasks_value: object = job.get("tasks")
|
|
108
|
+
if isinstance(tasks_value, list):
|
|
109
|
+
failed_task = next(
|
|
110
|
+
(
|
|
111
|
+
task
|
|
112
|
+
for task in tasks_value
|
|
113
|
+
if isinstance(task, Mapping)
|
|
114
|
+
and str(cast(Mapping[str, object], task).get("status", "")).upper() == "FAILED"
|
|
115
|
+
),
|
|
116
|
+
None,
|
|
117
|
+
)
|
|
118
|
+
if isinstance(failed_task, Mapping):
|
|
119
|
+
task = cast(Mapping[str, object], failed_task)
|
|
120
|
+
task_def_id_value: object = task.get("task_def_id")
|
|
121
|
+
task_id_value: object = task.get("id")
|
|
122
|
+
task_error_value: object = task.get("error_message")
|
|
123
|
+
task_label = str(task_def_id_value or task_id_value or "").strip()
|
|
124
|
+
task_error = str(task_error_value or "").strip()
|
|
125
|
+
if task_label:
|
|
126
|
+
summary = f"failed task: {task_label}"
|
|
127
|
+
if task_error:
|
|
128
|
+
summary = f"{summary}; error: {task_error}"
|
|
129
|
+
parts.append(summary)
|
|
130
|
+
|
|
131
|
+
if not parts:
|
|
132
|
+
return None
|
|
133
|
+
return " ".join(parts)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def wait_target_reached(status: str, wait_for: WaitTarget) -> bool:
|
|
137
|
+
"""Return whether the current job status satisfies the wait target."""
|
|
138
|
+
if wait_for == WaitTarget.RUNNING:
|
|
139
|
+
return status == "RUNNING" or status in SUCCESSFUL_TERMINAL_JOB_STATUSES
|
|
140
|
+
return status in TERMINAL_JOB_STATUSES
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def wait_for_job(
|
|
144
|
+
*,
|
|
145
|
+
get_job: Callable[[str], dict[str, Any]],
|
|
146
|
+
job_id: str,
|
|
147
|
+
wait_for: WaitTarget,
|
|
148
|
+
timeout_seconds: float,
|
|
149
|
+
poll_interval_seconds: float,
|
|
150
|
+
is_not_found_error: Callable[[Exception], bool] | None = None,
|
|
151
|
+
monotonic_fn: Callable[[], float] = time.monotonic,
|
|
152
|
+
sleep_fn: Callable[[float], None] = time.sleep,
|
|
153
|
+
) -> dict[str, Any]:
|
|
154
|
+
"""Poll the scheduler until a job reaches the requested state."""
|
|
155
|
+
deadline = monotonic_fn() + timeout_seconds
|
|
156
|
+
|
|
157
|
+
while True:
|
|
158
|
+
try:
|
|
159
|
+
job = get_job(job_id)
|
|
160
|
+
except Exception as exc:
|
|
161
|
+
if is_not_found_error is not None and is_not_found_error(exc):
|
|
162
|
+
if monotonic_fn() >= deadline:
|
|
163
|
+
raise ApplyJobVisibilityTimeoutError(job_id) from None
|
|
164
|
+
sleep_fn(poll_interval_seconds)
|
|
165
|
+
continue
|
|
166
|
+
raise
|
|
167
|
+
|
|
168
|
+
raw_status = job.get("status")
|
|
169
|
+
status = str(raw_status).upper().strip() if raw_status not in (None, "") else "UNKNOWN"
|
|
170
|
+
if status in FAILED_JOB_STATUSES:
|
|
171
|
+
raise ApplyJobFailedError(
|
|
172
|
+
job_id,
|
|
173
|
+
status,
|
|
174
|
+
detail=summarize_failed_job(job),
|
|
175
|
+
job=job,
|
|
176
|
+
)
|
|
177
|
+
if wait_target_reached(status, wait_for):
|
|
178
|
+
return job
|
|
179
|
+
|
|
180
|
+
if monotonic_fn() >= deadline:
|
|
181
|
+
raise ApplyJobStateTimeoutError(job_id, wait_for, status)
|
|
182
|
+
|
|
183
|
+
sleep_fn(poll_interval_seconds)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Generated code from protobuf and OpenAPI."""
|