redis-featureform 3.0.0__tar.gz

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 (166) hide show
  1. redis_featureform-3.0.0/PKG-INFO +448 -0
  2. redis_featureform-3.0.0/README.md +392 -0
  3. redis_featureform-3.0.0/pyproject.toml +233 -0
  4. redis_featureform-3.0.0/src/featureform/__init__.py +335 -0
  5. redis_featureform-3.0.0/src/featureform/_apply_context.py +48 -0
  6. redis_featureform-3.0.0/src/featureform/_apply_wait.py +183 -0
  7. redis_featureform-3.0.0/src/featureform/_generated/__init__.py +1 -0
  8. redis_featureform-3.0.0/src/featureform/_generated/openapi/__init__.py +13 -0
  9. redis_featureform-3.0.0/src/featureform/_generated/openapi/_internal.py +1631 -0
  10. redis_featureform-3.0.0/src/featureform/_generated/openapi/github_com_redislabsdev_featureform_internal_rest_types.py +31 -0
  11. redis_featureform-3.0.0/src/featureform/_generated/openapi/server.py +115 -0
  12. redis_featureform-3.0.0/src/featureform/_generated/openapi/types.py +365 -0
  13. redis_featureform-3.0.0/src/featureform/_generated/proto/__init__.py +1 -0
  14. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/__init__.py +1 -0
  15. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/__init__.py +1 -0
  16. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/apply_pb2.py +66 -0
  17. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/apply_pb2.pyi +463 -0
  18. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/apply_pb2_grpc.py +147 -0
  19. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/apply_pb2_grpc.pyi +82 -0
  20. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/audit_pb2.py +47 -0
  21. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/audit_pb2.pyi +140 -0
  22. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/audit_pb2_grpc.py +97 -0
  23. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/audit_pb2_grpc.pyi +49 -0
  24. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/catalog_pb2.py +60 -0
  25. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/catalog_pb2.pyi +292 -0
  26. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/catalog_pb2_grpc.py +192 -0
  27. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/catalog_pb2_grpc.pyi +88 -0
  28. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/common_pb2.py +44 -0
  29. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/common_pb2.pyi +128 -0
  30. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/common_pb2_grpc.py +24 -0
  31. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/common_pb2_grpc.pyi +20 -0
  32. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/dataframe_pb2.py +67 -0
  33. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/dataframe_pb2.pyi +342 -0
  34. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/dataframe_pb2_grpc.py +97 -0
  35. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/dataframe_pb2_grpc.pyi +49 -0
  36. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/provider_pb2.py +261 -0
  37. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/provider_pb2.pyi +3013 -0
  38. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/provider_pb2_grpc.py +277 -0
  39. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/provider_pb2_grpc.pyi +106 -0
  40. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/rbac_pb2.py +157 -0
  41. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/rbac_pb2.pyi +1281 -0
  42. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/rbac_pb2_grpc.py +1072 -0
  43. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/rbac_pb2_grpc.pyi +260 -0
  44. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/resource_pb2.py +127 -0
  45. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/resource_pb2.pyi +1529 -0
  46. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/resource_pb2_grpc.py +24 -0
  47. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/resource_pb2_grpc.pyi +20 -0
  48. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/resource_service_pb2.py +215 -0
  49. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/resource_service_pb2.pyi +2295 -0
  50. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/resource_service_pb2_grpc.py +1645 -0
  51. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/resource_service_pb2_grpc.pyi +373 -0
  52. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/secret_provider_pb2.py +83 -0
  53. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/secret_provider_pb2.pyi +607 -0
  54. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/secret_provider_pb2_grpc.py +277 -0
  55. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/secret_provider_pb2_grpc.pyi +106 -0
  56. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/serving_pb2.py +112 -0
  57. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/serving_pb2.pyi +783 -0
  58. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/serving_pb2_grpc.py +146 -0
  59. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/serving_pb2_grpc.pyi +76 -0
  60. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/version_pb2.py +45 -0
  61. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/version_pb2.pyi +127 -0
  62. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/version_pb2_grpc.py +146 -0
  63. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/version_pb2_grpc.pyi +76 -0
  64. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/workspace_pb2.py +65 -0
  65. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/workspace_pb2.pyi +296 -0
  66. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/workspace_pb2_grpc.py +322 -0
  67. redis_featureform-3.0.0/src/featureform/_generated/proto/featureform/v2/workspace_pb2_grpc.pyi +124 -0
  68. redis_featureform-3.0.0/src/featureform/_generated/proto/scheduler/__init__.py +1 -0
  69. redis_featureform-3.0.0/src/featureform/_generated/proto/scheduler/v1/__init__.py +1 -0
  70. redis_featureform-3.0.0/src/featureform/_generated/proto/scheduler/v1/scheduler_pb2.py +180 -0
  71. redis_featureform-3.0.0/src/featureform/_generated/proto/scheduler/v1/scheduler_pb2.pyi +1994 -0
  72. redis_featureform-3.0.0/src/featureform/_generated/proto/scheduler/v1/scheduler_pb2_grpc.py +1145 -0
  73. redis_featureform-3.0.0/src/featureform/_generated/proto/scheduler/v1/scheduler_pb2_grpc.pyi +301 -0
  74. redis_featureform-3.0.0/src/featureform/_internal/__init__.py +1 -0
  75. redis_featureform-3.0.0/src/featureform/_internal/http.py +231 -0
  76. redis_featureform-3.0.0/src/featureform/_internal/logging.py +299 -0
  77. redis_featureform-3.0.0/src/featureform/_internal/secret_refs.py +118 -0
  78. redis_featureform-3.0.0/src/featureform/_internal/telemetry/__init__.py +73 -0
  79. redis_featureform-3.0.0/src/featureform/_internal/telemetry/base.py +126 -0
  80. redis_featureform-3.0.0/src/featureform/_internal/telemetry/config.py +71 -0
  81. redis_featureform-3.0.0/src/featureform/_internal/telemetry/noop.py +89 -0
  82. redis_featureform-3.0.0/src/featureform/_internal/telemetry/otel.py +152 -0
  83. redis_featureform-3.0.0/src/featureform/_version.py +39 -0
  84. redis_featureform-3.0.0/src/featureform/auth/__init__.py +21 -0
  85. redis_featureform-3.0.0/src/featureform/auth/runtime.py +125 -0
  86. redis_featureform-3.0.0/src/featureform/auth/token.py +559 -0
  87. redis_featureform-3.0.0/src/featureform/cli/__init__.py +23 -0
  88. redis_featureform-3.0.0/src/featureform/cli/admin_client.py +888 -0
  89. redis_featureform-3.0.0/src/featureform/cli/auth/__init__.py +113 -0
  90. redis_featureform-3.0.0/src/featureform/cli/auth/clock.py +22 -0
  91. redis_featureform-3.0.0/src/featureform/cli/auth/discovery.py +240 -0
  92. redis_featureform-3.0.0/src/featureform/cli/auth/flows.py +130 -0
  93. redis_featureform-3.0.0/src/featureform/cli/auth/fs.py +14 -0
  94. redis_featureform-3.0.0/src/featureform/cli/auth/profiles.py +153 -0
  95. redis_featureform-3.0.0/src/featureform/cli/auth/service.py +575 -0
  96. redis_featureform-3.0.0/src/featureform/cli/auth/session_store.py +311 -0
  97. redis_featureform-3.0.0/src/featureform/cli/auth/types.py +80 -0
  98. redis_featureform-3.0.0/src/featureform/cli/commands/__init__.py +27 -0
  99. redis_featureform-3.0.0/src/featureform/cli/commands/_common.py +23 -0
  100. redis_featureform-3.0.0/src/featureform/cli/commands/_provider_config.py +1173 -0
  101. redis_featureform-3.0.0/src/featureform/cli/commands/apply.py +887 -0
  102. redis_featureform-3.0.0/src/featureform/cli/commands/audit.py +58 -0
  103. redis_featureform-3.0.0/src/featureform/cli/commands/auth.py +437 -0
  104. redis_featureform-3.0.0/src/featureform/cli/commands/catalog.py +116 -0
  105. redis_featureform-3.0.0/src/featureform/cli/commands/config.py +188 -0
  106. redis_featureform-3.0.0/src/featureform/cli/commands/dataframe.py +182 -0
  107. redis_featureform-3.0.0/src/featureform/cli/commands/graph.py +534 -0
  108. redis_featureform-3.0.0/src/featureform/cli/commands/machine_credential.py +142 -0
  109. redis_featureform-3.0.0/src/featureform/cli/commands/provider.py +1222 -0
  110. redis_featureform-3.0.0/src/featureform/cli/commands/rbac.py +445 -0
  111. redis_featureform-3.0.0/src/featureform/cli/commands/scheduler.py +1101 -0
  112. redis_featureform-3.0.0/src/featureform/cli/commands/secret_provider.py +405 -0
  113. redis_featureform-3.0.0/src/featureform/cli/commands/workspace.py +167 -0
  114. redis_featureform-3.0.0/src/featureform/cli/env.py +69 -0
  115. redis_featureform-3.0.0/src/featureform/cli/errors.py +155 -0
  116. redis_featureform-3.0.0/src/featureform/cli/main.py +525 -0
  117. redis_featureform-3.0.0/src/featureform/cli/output/__init__.py +13 -0
  118. redis_featureform-3.0.0/src/featureform/cli/output/base.py +49 -0
  119. redis_featureform-3.0.0/src/featureform/cli/output/json_fmt.py +71 -0
  120. redis_featureform-3.0.0/src/featureform/cli/output/table.py +163 -0
  121. redis_featureform-3.0.0/src/featureform/cli/output/yaml_fmt.py +64 -0
  122. redis_featureform-3.0.0/src/featureform/cli/scheduler_client.py +1281 -0
  123. redis_featureform-3.0.0/src/featureform/cli/utils/__init__.py +5 -0
  124. redis_featureform-3.0.0/src/featureform/cli/utils/context.py +252 -0
  125. redis_featureform-3.0.0/src/featureform/client.py +7961 -0
  126. redis_featureform-3.0.0/src/featureform/config.py +156 -0
  127. redis_featureform-3.0.0/src/featureform/dataframe/__init__.py +12 -0
  128. redis_featureform-3.0.0/src/featureform/dataframe/client.py +787 -0
  129. redis_featureform-3.0.0/src/featureform/dataframe/result.py +288 -0
  130. redis_featureform-3.0.0/src/featureform/dataframe/stream.py +146 -0
  131. redis_featureform-3.0.0/src/featureform/errors.py +867 -0
  132. redis_featureform-3.0.0/src/featureform/py.typed +0 -0
  133. redis_featureform-3.0.0/src/featureform/resources/__init__.py +123 -0
  134. redis_featureform-3.0.0/src/featureform/resources/base.py +256 -0
  135. redis_featureform-3.0.0/src/featureform/resources/dataset.py +319 -0
  136. redis_featureform-3.0.0/src/featureform/resources/entity.py +47 -0
  137. redis_featureform-3.0.0/src/featureform/resources/feature.py +399 -0
  138. redis_featureform-3.0.0/src/featureform/resources/label.py +250 -0
  139. redis_featureform-3.0.0/src/featureform/resources/provider.py +729 -0
  140. redis_featureform-3.0.0/src/featureform/resources/realtime_feature.py +621 -0
  141. redis_featureform-3.0.0/src/featureform/resources/training.py +333 -0
  142. redis_featureform-3.0.0/src/featureform/serving/__init__.py +12 -0
  143. redis_featureform-3.0.0/src/featureform/serving/_decode.py +93 -0
  144. redis_featureform-3.0.0/src/featureform/serving/_metadata.py +99 -0
  145. redis_featureform-3.0.0/src/featureform/serving/_realtime.py +253 -0
  146. redis_featureform-3.0.0/src/featureform/serving/cache.py +190 -0
  147. redis_featureform-3.0.0/src/featureform/serving/client.py +788 -0
  148. redis_featureform-3.0.0/src/featureform/serving/types.py +134 -0
  149. redis_featureform-3.0.0/src/featureform/spark.py +171 -0
  150. redis_featureform-3.0.0/src/featureform/spark_env.py +31 -0
  151. redis_featureform-3.0.0/src/featureform/transport/__init__.py +49 -0
  152. redis_featureform-3.0.0/src/featureform/transport/base.py +42 -0
  153. redis_featureform-3.0.0/src/featureform/transport/grpc.py +760 -0
  154. redis_featureform-3.0.0/src/featureform/transport/rest.py +224 -0
  155. redis_featureform-3.0.0/src/featureform/types/__init__.py +226 -0
  156. redis_featureform-3.0.0/src/featureform/types/_base.py +24 -0
  157. redis_featureform-3.0.0/src/featureform/types/catalog.py +62 -0
  158. redis_featureform-3.0.0/src/featureform/types/entity.py +39 -0
  159. redis_featureform-3.0.0/src/featureform/types/graph.py +487 -0
  160. redis_featureform-3.0.0/src/featureform/types/patch.py +14 -0
  161. redis_featureform-3.0.0/src/featureform/types/provider.py +1098 -0
  162. redis_featureform-3.0.0/src/featureform/types/resource.py +407 -0
  163. redis_featureform-3.0.0/src/featureform/types/secret.py +232 -0
  164. redis_featureform-3.0.0/src/featureform/types/secret_provider.py +206 -0
  165. redis_featureform-3.0.0/src/featureform/types/workspace.py +54 -0
  166. redis_featureform-3.0.0/src/featureform/version.py +228 -0
@@ -0,0 +1,448 @@
1
+ Metadata-Version: 2.3
2
+ Name: redis-featureform
3
+ Version: 3.0.0
4
+ Summary: Python SDK and ff CLI for Redis Feature Form
5
+ Author: Simba Khadder
6
+ Author-email: Simba Khadder <simba.khadder@redis.com>
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Typing :: Typed
15
+ Requires-Dist: cloudpickle>=3.0.0
16
+ Requires-Dist: httpx>=0.27.0
17
+ Requires-Dist: keyring>=25.0.0
18
+ Requires-Dist: packaging>=24.0
19
+ Requires-Dist: pydantic>=2.0.0
20
+ Requires-Dist: structlog>=24.0.0
21
+ Requires-Dist: typer>=0.12.0
22
+ Requires-Dist: rich>=13.0.0
23
+ Requires-Dist: pyyaml>=6.0.0
24
+ Requires-Dist: grpcio>=1.60.0
25
+ Requires-Dist: grpcio-health-checking>=1.60.0
26
+ Requires-Dist: protobuf>=4.25.0
27
+ Requires-Dist: pyarrow>=17.0.0
28
+ Requires-Dist: pandas>=2.3.3
29
+ Requires-Dist: tomli>=2.0.0 ; python_full_version < '3.11'
30
+ Requires-Dist: pytest>=9.0.3 ; extra == 'dev'
31
+ Requires-Dist: pytest-cov>=4.1.0 ; extra == 'dev'
32
+ Requires-Dist: pytest-asyncio>=0.23.0 ; extra == 'dev'
33
+ Requires-Dist: pytest-httpx>=0.30.0 ; extra == 'dev'
34
+ Requires-Dist: psycopg[binary]>=3.2.0 ; extra == 'dev'
35
+ Requires-Dist: snowflake-connector-python>=3.12.0 ; extra == 'dev'
36
+ Requires-Dist: requests>=2.33.0 ; extra == 'dev'
37
+ Requires-Dist: redis>=5.0.0 ; extra == 'dev'
38
+ Requires-Dist: schemathesis>=4 ; extra == 'dev'
39
+ Requires-Dist: polars>=1.30.0 ; extra == 'dev'
40
+ Requires-Dist: schemathesis>=4 ; extra == 'dev'
41
+ Requires-Dist: ruff>=0.8.0 ; extra == 'dev'
42
+ Requires-Dist: mypy>=1.8.0 ; extra == 'dev'
43
+ Requires-Dist: pyright>=1.1.350 ; extra == 'dev'
44
+ Requires-Dist: datamodel-code-generator>=0.55.0 ; extra == 'dev'
45
+ Requires-Dist: opentelemetry-api>=1.20.0 ; extra == 'otel'
46
+ Requires-Dist: opentelemetry-sdk>=1.20.0 ; extra == 'otel'
47
+ Requires-Dist: pyspark>=3.5,<5 ; extra == 'pyspark'
48
+ Requires-Python: >=3.10
49
+ Project-URL: Documentation, https://redis.io/docs/latest/develop/ai/featureform/
50
+ Project-URL: Overview, https://redis.io/docs/latest/develop/ai/featureform/overview/
51
+ Project-URL: Quickstart, https://redis.io/docs/latest/develop/ai/featureform/quickstart/
52
+ Provides-Extra: dev
53
+ Provides-Extra: otel
54
+ Provides-Extra: pyspark
55
+ Description-Content-Type: text/markdown
56
+
57
+ # Redis Feature Form Python SDK
58
+
59
+ `redis-featureform` is the Python SDK and `ff` CLI for Redis Feature Form.
60
+
61
+ Redis Feature Form gives data and ML teams a declarative workflow for defining
62
+ providers, datasets, transformations, entities, features, labels, training sets,
63
+ and feature views in Python while keeping existing offline data systems in place.
64
+ Redis is the low-latency online store for feature serving.
65
+
66
+ Install from PyPI as `redis-featureform`, then import it in Python as
67
+ `featureform`.
68
+
69
+ Official Redis Feature Form docs:
70
+
71
+ - Overview: `https://redis.io/docs/latest/develop/ai/featureform/overview/`
72
+ - Quickstart: `https://redis.io/docs/latest/develop/ai/featureform/quickstart/`
73
+ - Documentation hub: `https://redis.io/docs/latest/develop/ai/featureform/`
74
+
75
+ ## Install
76
+
77
+ ```bash
78
+ pip install redis-featureform
79
+ ```
80
+
81
+ Optional extras:
82
+
83
+ ```bash
84
+ pip install "redis-featureform[otel]"
85
+ pip install "redis-featureform[pyspark]"
86
+ ```
87
+
88
+ ## What Redis Feature Form Does
89
+
90
+ Redis Feature Form helps you:
91
+
92
+ - register offline systems and Redis as providers
93
+ - define feature engineering resources as Python code
94
+ - submit a complete resource graph into a workspace with `ff apply` or `client.apply()`
95
+ - inspect the resulting plan before execution
96
+ - query datasets and training sets over Arrow Flight
97
+ - serve online feature values from Redis-backed feature views
98
+
99
+ ## Core Workflow
100
+
101
+ The Redis Feature Form workflow is:
102
+
103
+ 1. Create a workspace.
104
+ 2. Register providers for offline systems and the Redis online store.
105
+ 3. Author resources in Python.
106
+ 4. Apply or merge the resource graph into the workspace.
107
+ 5. Let Redis Feature Form plan and run the required execution work.
108
+ 6. Query offline results for training or fetch online features for inference.
109
+
110
+ ## Core Concepts
111
+
112
+ - Workspace: logical boundary for a Redis Feature Form resource graph
113
+ - Provider: connection to an external system such as Postgres, Snowflake, Spark, S3, Iceberg, or Redis
114
+ - Resource: Python declaration of an entity, dataset, transformation, feature, label, training set, or feature view
115
+ - Apply: single-shot workspace update that submits one combined resource set, computes a delta, and optionally runs an apply job
116
+ - Merge: apply strategy that preserves omitted resources already present in the workspace
117
+ - Execution mode: planning mode for runtime work, currently `NORMAL`, `UPDATE`, or `FULL_REMATERIALIZE`
118
+ - Training set: offline, model-ready dataset composed from features and labels
119
+ - Feature view: online-serving surface backed by Redis for inference-time lookup
120
+
121
+ ## Connect And Register Providers
122
+
123
+ The CLI is usually the fastest way to bootstrap Redis Feature Form resources:
124
+
125
+ ```bash
126
+ ff --server https://api.example.com --transport rest auth login
127
+
128
+ ff --server https://api.example.com --transport rest \
129
+ workspace create fraud-detection
130
+
131
+ ff --server https://api.example.com --transport rest \
132
+ provider register analytics-postgres \
133
+ --workspace fraud-detection \
134
+ --type postgres \
135
+ --pg-host postgres.example.com \
136
+ --pg-port 5432 \
137
+ --pg-database analytics \
138
+ --pg-user ff_user \
139
+ --pg-password-secret env:PG_PASSWORD
140
+
141
+ ff --server https://api.example.com --transport rest \
142
+ provider register online-store \
143
+ --workspace fraud-detection \
144
+ --type redis \
145
+ --redis-host redis.example.com \
146
+ --redis-port 6379
147
+ ```
148
+
149
+ Providers are registered separately from apply. Resource definitions then refer
150
+ to those provider names when you define datasets, transformations, training sets,
151
+ and Redis-backed feature views.
152
+
153
+ ## What `ff apply` Does
154
+
155
+ `ff apply` is the main authoring workflow in Redis Feature Form.
156
+
157
+ At a high level it:
158
+
159
+ 1. loads one Python entry file or package directory
160
+ 2. collects resources from either an explicit `resources = [...]` list or the global registry
161
+ 3. serializes the full resource graph into one request for one workspace
162
+ 4. compares the submitted graph with the current workspace graph
163
+ 5. returns a dry-run plan or commits the new version and optionally waits for the apply job
164
+
165
+ `ff apply` is graph-wide. It does not patch one object at a time.
166
+
167
+ ### Example Apply File
168
+
169
+ ```python
170
+ from datetime import timedelta
171
+
172
+ import featureform as ff
173
+ from featureform.types.resource import FeatureView, MaterializationEngine, TrainingSetType
174
+
175
+ postgres = ff.get_postgres("analytics-postgres")
176
+
177
+ customer = ff.Entity(
178
+ name="customer",
179
+ description="Customer entity for fraud models",
180
+ )
181
+
182
+ transactions = postgres.dataset(
183
+ name="transactions",
184
+ schema="public",
185
+ table="transactions",
186
+ timestamp_column="event_ts",
187
+ description="Raw payment events",
188
+ )
189
+
190
+
191
+ @postgres.sql_transformation(
192
+ name="customer_daily_rollups",
193
+ description="Daily transaction totals per customer",
194
+ inputs=[transactions],
195
+ )
196
+ def customer_daily_rollups() -> str:
197
+ return """
198
+ SELECT
199
+ customer_id,
200
+ date_trunc('day', event_ts) AS event_day,
201
+ SUM(amount) AS total_amount,
202
+ COUNT(*) AS transaction_count
203
+ FROM {{transactions}}
204
+ GROUP BY 1, 2
205
+ """
206
+
207
+
208
+ customer_amount_7d = (
209
+ ff.Feature(name="customer_amount_7d")
210
+ .from_dataset(
211
+ customer_daily_rollups,
212
+ entity="customer",
213
+ entity_column="customer_id",
214
+ value="total_amount",
215
+ timestamp="event_day",
216
+ )
217
+ .with_provider("analytics-postgres")
218
+ .aggregate(function=ff.AggregateFunction.SUM, window=timedelta(days=7))
219
+ )
220
+
221
+ fraud_label = (
222
+ ff.Label()
223
+ .from_dataset(transactions)
224
+ .value("is_fraud")
225
+ .timestamp("event_ts")
226
+ .entity("customer", column="customer_id")
227
+ .build()
228
+ )
229
+
230
+ fraud_training = ff.TrainingSet(
231
+ name="fraud_training",
232
+ provider="analytics-postgres",
233
+ features=[customer_amount_7d],
234
+ label=fraud_label,
235
+ type=TrainingSetType.STATIC,
236
+ )
237
+
238
+ customer_features = FeatureView(
239
+ name="customer_features",
240
+ entity="customer",
241
+ features=[customer_amount_7d.name],
242
+ inference_store="online-store",
243
+ materialization_engine=MaterializationEngine.K8S,
244
+ )
245
+
246
+ resources = [
247
+ customer,
248
+ transactions,
249
+ customer_daily_rollups,
250
+ customer_amount_7d,
251
+ fraud_label,
252
+ fraud_training,
253
+ customer_features,
254
+ ]
255
+ ```
256
+
257
+ ## Apply Strategies And Execution Modes
258
+
259
+ Redis Feature Form now exposes apply strategy and execution mode as separate axes.
260
+
261
+ Apply strategies:
262
+
263
+ - default apply: submitted resources replace the desired graph for the workspace
264
+ - merge: submitted resources merge into the workspace and omitted resources are retained
265
+
266
+ Execution modes:
267
+
268
+ - `NORMAL`: standard diff-based planning
269
+ - `UPDATE`: revisit the target graph in update mode
270
+ - `FULL_REMATERIALIZE`: revisit the target graph in full-rematerialize mode
271
+
272
+ That means combinations such as these are valid:
273
+
274
+ - apply + normal
275
+ - apply + update
276
+ - apply + full rematerialize
277
+ - merge + normal
278
+ - merge + update
279
+ - merge + full rematerialize
280
+
281
+ ### Apply From The CLI
282
+
283
+ Preview the graph delta without changing the workspace:
284
+
285
+ ```bash
286
+ ff --server https://api.example.com --transport rest \
287
+ apply -f resources.py --workspace fraud-detection --plan
288
+ ```
289
+
290
+ Apply the submitted graph and wait for completion:
291
+
292
+ ```bash
293
+ ff --server https://api.example.com --transport rest \
294
+ apply -f resources.py \
295
+ --workspace fraud-detection \
296
+ --message "initial fraud pipeline" \
297
+ --wait --wait-for finished
298
+ ```
299
+
300
+ Merge into the existing workspace instead of replacing omitted resources:
301
+
302
+ ```bash
303
+ ff --server https://api.example.com --transport rest \
304
+ apply -f resources.py \
305
+ --workspace fraud-detection \
306
+ --merge \
307
+ --wait --wait-for finished
308
+ ```
309
+
310
+ Run a plan in update mode:
311
+
312
+ ```bash
313
+ ff --server https://api.example.com --transport rest \
314
+ apply -f resources.py \
315
+ --workspace fraud-detection \
316
+ --plan \
317
+ --update
318
+ ```
319
+
320
+ Request a merge with full rematerialization semantics:
321
+
322
+ ```bash
323
+ ff --server https://api.example.com --transport rest \
324
+ apply -f resources.py \
325
+ --workspace fraud-detection \
326
+ --merge \
327
+ --full-rematerialize
328
+ ```
329
+
330
+ Useful flags:
331
+
332
+ - `--plan`: show what would change without applying
333
+ - `--merge`: keep omitted resources already present in the workspace
334
+ - `--update`: use update execution mode
335
+ - `--full-rematerialize`: use full rematerialization execution mode
336
+ - `--wait --wait-for finished`: block until the apply job completes and the workspace version is visible
337
+
338
+ ### Apply From Python
339
+
340
+ Use `client.apply()` for standard apply semantics:
341
+
342
+ ```python
343
+ import os
344
+
345
+ import featureform as ff
346
+ import resources
347
+
348
+ client = ff.Client(
349
+ base_url="grpc.example.com:443",
350
+ transport="grpc",
351
+ token=os.environ["FEATUREFORM_TOKEN"],
352
+ )
353
+
354
+ result = client.apply(
355
+ resources=resources.resources,
356
+ workspace="fraud-detection",
357
+ message="initial fraud pipeline",
358
+ wait=True,
359
+ )
360
+
361
+ print(result.version)
362
+ for change in result.changes:
363
+ print(change.resource_type, change.resource_name, change.action)
364
+ ```
365
+
366
+ Use execution mode directly from Python:
367
+
368
+ ```python
369
+ plan = client.apply(
370
+ resources=resources.resources,
371
+ workspace="fraud-detection",
372
+ dry_run=True,
373
+ execution_mode="UPDATE",
374
+ )
375
+ ```
376
+
377
+ Use merge semantics without deleting omitted resources:
378
+
379
+ ```python
380
+ result = client.merge(
381
+ resources=resources.resources,
382
+ workspace="fraud-detection",
383
+ execution_mode="FULL_REMATERIALIZE",
384
+ wait=True,
385
+ )
386
+ ```
387
+
388
+ If `resources` is omitted, `client.apply(...)` and `client.merge(...)` use the
389
+ global resource registry. That works well when definition modules register
390
+ resources during import.
391
+
392
+ ## Query Offline Data
393
+
394
+ Use Arrow Flight helpers to pull datasets, training sets, or feature-view
395
+ snapshots into pandas or stream them incrementally.
396
+
397
+ ```python
398
+ training = client.query_training_set(
399
+ "fraud_training",
400
+ workspace="fraud-detection",
401
+ flight_server="grpc.example.com:9090",
402
+ ).to_pandas()
403
+
404
+ print(training.head())
405
+ ```
406
+
407
+ You can also query datasets directly:
408
+
409
+ ```python
410
+ transactions = client.query_dataset(
411
+ "transactions",
412
+ workspace="fraud-detection",
413
+ limit=1000,
414
+ ).to_pandas()
415
+ ```
416
+
417
+ ## Serve Online Features From Redis
418
+
419
+ Once a feature view is materialized, Redis Feature Form serves online values from
420
+ Redis with `client.serve(...)`.
421
+
422
+ ```python
423
+ features = client.serve(
424
+ "customer_features",
425
+ entity="customer_123",
426
+ workspace="fraud-detection",
427
+ )
428
+
429
+ print(features["customer_amount_7d"])
430
+ ```
431
+
432
+ Batch serving is supported as well:
433
+
434
+ ```python
435
+ result = client.serve(
436
+ "customer_features",
437
+ entities=["customer_123", "customer_456"],
438
+ workspace="fraud-detection",
439
+ return_type="pandas",
440
+ )
441
+ ```
442
+
443
+ ## Package Surface
444
+
445
+ - `featureform.Client`: client for workspaces, providers, apply and merge, offline queries, and online serving
446
+ - `ff`: CLI for auth, apply, workspace, provider, catalog, graph, scheduler, and RBAC operations
447
+ - `featureform.resources`: typed resource DSL for authoring Redis Feature Form resource graphs
448
+ - `featureform.types`: request and response models used by the client surface