moose-lib 0.6.148.dev3442438466__py3-none-any.whl → 0.6.283__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 (59) hide show
  1. moose_lib/__init__.py +34 -3
  2. moose_lib/blocks.py +416 -52
  3. moose_lib/clients/redis_client.py +26 -14
  4. moose_lib/commons.py +37 -30
  5. moose_lib/config/config_file.py +5 -1
  6. moose_lib/config/runtime.py +73 -34
  7. moose_lib/data_models.py +331 -61
  8. moose_lib/dmv2/__init__.py +69 -73
  9. moose_lib/dmv2/_registry.py +2 -1
  10. moose_lib/dmv2/_source_capture.py +37 -0
  11. moose_lib/dmv2/consumption.py +55 -32
  12. moose_lib/dmv2/ingest_api.py +9 -2
  13. moose_lib/dmv2/ingest_pipeline.py +35 -16
  14. moose_lib/dmv2/life_cycle.py +3 -1
  15. moose_lib/dmv2/materialized_view.py +24 -14
  16. moose_lib/dmv2/moose_model.py +165 -0
  17. moose_lib/dmv2/olap_table.py +299 -151
  18. moose_lib/dmv2/registry.py +18 -3
  19. moose_lib/dmv2/sql_resource.py +16 -8
  20. moose_lib/dmv2/stream.py +75 -23
  21. moose_lib/dmv2/types.py +14 -8
  22. moose_lib/dmv2/view.py +13 -6
  23. moose_lib/dmv2/web_app.py +11 -6
  24. moose_lib/dmv2/web_app_helpers.py +5 -1
  25. moose_lib/dmv2/workflow.py +37 -9
  26. moose_lib/internal.py +340 -56
  27. moose_lib/main.py +87 -56
  28. moose_lib/query_builder.py +18 -5
  29. moose_lib/query_param.py +54 -20
  30. moose_lib/secrets.py +122 -0
  31. moose_lib/streaming/streaming_function_runner.py +233 -117
  32. moose_lib/utilities/sql.py +0 -1
  33. {moose_lib-0.6.148.dev3442438466.dist-info → moose_lib-0.6.283.dist-info}/METADATA +18 -1
  34. moose_lib-0.6.283.dist-info/RECORD +63 -0
  35. tests/__init__.py +1 -1
  36. tests/conftest.py +6 -5
  37. tests/test_backward_compatibility.py +85 -0
  38. tests/test_cluster_validation.py +85 -0
  39. tests/test_codec.py +75 -0
  40. tests/test_column_formatting.py +80 -0
  41. tests/test_fixedstring.py +43 -0
  42. tests/test_iceberg_config.py +105 -0
  43. tests/test_int_types.py +211 -0
  44. tests/test_kafka_config.py +141 -0
  45. tests/test_materialized.py +74 -0
  46. tests/test_metadata.py +37 -0
  47. tests/test_moose.py +21 -30
  48. tests/test_moose_model.py +153 -0
  49. tests/test_olap_table_moosemodel.py +89 -0
  50. tests/test_olap_table_versioning.py +52 -58
  51. tests/test_query_builder.py +97 -9
  52. tests/test_redis_client.py +10 -3
  53. tests/test_s3queue_config.py +211 -110
  54. tests/test_secrets.py +239 -0
  55. tests/test_simple_aggregate.py +42 -40
  56. tests/test_web_app.py +11 -5
  57. moose_lib-0.6.148.dev3442438466.dist-info/RECORD +0 -47
  58. {moose_lib-0.6.148.dev3442438466.dist-info → moose_lib-0.6.283.dist-info}/WHEEL +0 -0
  59. {moose_lib-0.6.148.dev3442438466.dist-info → moose_lib-0.6.283.dist-info}/top_level.txt +0 -0
@@ -15,6 +15,10 @@ from .types import (
15
15
  ZeroOrMany,
16
16
  )
17
17
 
18
+ from .moose_model import (
19
+ MooseModel,
20
+ )
21
+
18
22
  from .olap_table import (
19
23
  OlapConfig,
20
24
  OlapTable,
@@ -114,88 +118,80 @@ from .registry import (
114
118
 
115
119
  __all__ = [
116
120
  # Types
117
- 'BaseTypedResource',
118
- 'TypedMooseResource',
119
- 'Columns',
120
- 'T',
121
- 'U',
122
- 'T_none',
123
- 'U_none',
124
- 'ZeroOrMany',
125
-
121
+ "BaseTypedResource",
122
+ "TypedMooseResource",
123
+ "Columns",
124
+ "MooseModel",
125
+ "T",
126
+ "U",
127
+ "T_none",
128
+ "U_none",
129
+ "ZeroOrMany",
126
130
  # OLAP Tables
127
- 'OlapConfig',
128
- 'OlapTable',
129
- 'InsertOptions',
130
-
131
+ "OlapConfig",
132
+ "OlapTable",
133
+ "InsertOptions",
131
134
  # Streams
132
- 'StreamConfig',
133
- 'TransformConfig',
134
- 'ConsumerConfig',
135
- 'Stream',
136
- 'DeadLetterModel',
137
- 'DeadLetterQueue',
138
- 'SubjectLatest',
139
- 'SubjectVersion',
140
- 'SchemaById',
141
- 'KafkaSchemaConfig',
142
-
135
+ "StreamConfig",
136
+ "TransformConfig",
137
+ "ConsumerConfig",
138
+ "Stream",
139
+ "DeadLetterModel",
140
+ "DeadLetterQueue",
141
+ "SubjectLatest",
142
+ "SubjectVersion",
143
+ "SchemaById",
144
+ "KafkaSchemaConfig",
143
145
  # Ingestion
144
- 'IngestConfig',
145
- 'IngestConfigWithDestination',
146
- 'IngestPipelineConfig',
147
- 'IngestApi',
148
- 'IngestPipeline',
149
-
146
+ "IngestConfig",
147
+ "IngestConfigWithDestination",
148
+ "IngestPipelineConfig",
149
+ "IngestApi",
150
+ "IngestPipeline",
150
151
  # Consumption
151
- 'ApiConfig',
152
- 'Api',
153
- 'get_moose_base_url',
154
- 'set_moose_base_url',
152
+ "ApiConfig",
153
+ "Api",
154
+ "get_moose_base_url",
155
+ "set_moose_base_url",
155
156
  # Backward compatibility aliases (deprecated)
156
- 'ConsumptionApi',
157
- 'EgressConfig',
158
-
157
+ "ConsumptionApi",
158
+ "EgressConfig",
159
159
  # SQL
160
- 'SqlResource',
161
- 'View',
162
- 'MaterializedViewOptions',
163
- 'MaterializedView',
164
-
160
+ "SqlResource",
161
+ "View",
162
+ "MaterializedViewOptions",
163
+ "MaterializedView",
165
164
  # Workflow
166
- 'TaskContext',
167
- 'TaskConfig',
168
- 'Task',
169
- 'WorkflowConfig',
170
- 'Workflow',
171
-
165
+ "TaskContext",
166
+ "TaskConfig",
167
+ "Task",
168
+ "WorkflowConfig",
169
+ "Workflow",
172
170
  # Lifecycle
173
- 'LifeCycle',
174
-
171
+ "LifeCycle",
175
172
  # WebApp
176
- 'WebApp',
177
- 'WebAppConfig',
178
- 'WebAppMetadata',
179
- 'ApiUtil',
180
- 'get_moose_utils',
181
- 'get_moose_dependency',
182
-
173
+ "WebApp",
174
+ "WebAppConfig",
175
+ "WebAppMetadata",
176
+ "ApiUtil",
177
+ "get_moose_utils",
178
+ "get_moose_dependency",
183
179
  # Registry
184
- 'get_tables',
185
- 'get_table',
186
- 'get_streams',
187
- 'get_stream',
188
- 'get_ingest_apis',
189
- 'get_ingest_api',
190
- 'get_apis',
191
- 'get_api',
192
- 'get_sql_resources',
193
- 'get_sql_resource',
194
- 'get_workflows',
195
- 'get_workflow',
196
- 'get_web_apps',
197
- 'get_web_app',
180
+ "get_tables",
181
+ "get_table",
182
+ "get_streams",
183
+ "get_stream",
184
+ "get_ingest_apis",
185
+ "get_ingest_api",
186
+ "get_apis",
187
+ "get_api",
188
+ "get_sql_resources",
189
+ "get_sql_resource",
190
+ "get_workflows",
191
+ "get_workflow",
192
+ "get_web_apps",
193
+ "get_web_app",
198
194
  # Backward compatibility aliases (deprecated)
199
- 'get_consumption_apis',
200
- 'get_consumption_api',
195
+ "get_consumption_apis",
196
+ "get_consumption_api",
201
197
  ]
@@ -4,6 +4,7 @@ Internal registry dictionaries for Moose Data Model v2 (dmv2) resources.
4
4
  This module maintains the raw dictionaries that store all registered resources.
5
5
  It has no imports from other dmv2 modules to avoid circular dependencies.
6
6
  """
7
+
7
8
  from typing import Dict, Any
8
9
 
9
10
  # Global registries for all resource types
@@ -17,4 +18,4 @@ _api_name_aliases: Dict[str, Any] = {}
17
18
  _api_path_map: Dict[str, Any] = {}
18
19
  _sql_resources: Dict[str, Any] = {}
19
20
  _workflows: Dict[str, Any] = {}
20
- _web_apps: Dict[str, Any] = {}
21
+ _web_apps: Dict[str, Any] = {}
@@ -0,0 +1,37 @@
1
+ """
2
+ Utilities for capturing source file information from the call stack.
3
+
4
+ This module provides functions to extract source file paths from Python's
5
+ call stack, filtering out internal library paths.
6
+ """
7
+
8
+ from typing import Optional
9
+ import inspect
10
+
11
+
12
+ def get_source_file_from_stack() -> Optional[str]:
13
+ """Extract the source file path from the call stack, skipping internal modules.
14
+
15
+ Returns the first file path that is not from internal moose_lib modules,
16
+ site-packages, or special Python frames.
17
+
18
+ Returns:
19
+ The absolute path to the user's source file, or None if not found.
20
+ """
21
+ try:
22
+ # Get the current call stack
23
+ stack = inspect.stack()
24
+ # Start from index 1 to skip this function itself
25
+ for frame_info in stack[1:]:
26
+ filename = frame_info.filename
27
+ # Skip internal modules and site-packages
28
+ if (
29
+ "site-packages" not in filename
30
+ and "moose_lib" not in filename
31
+ and "<" not in filename # Skip special frames like <frozen importlib>
32
+ ):
33
+ return filename
34
+ except Exception:
35
+ # If anything goes wrong, just return None
36
+ pass
37
+ return None
@@ -4,6 +4,7 @@ API definitions for Moose Data Model v2 (dmv2).
4
4
  This module provides classes for defining and configuring APIs
5
5
  that allow querying data through user-defined functions.
6
6
  """
7
+
7
8
  import os
8
9
  from typing import Any, Callable, Optional, Tuple, Generic
9
10
 
@@ -17,13 +18,14 @@ from ._registry import _apis, _api_name_aliases, _api_path_map
17
18
  # Global base URL configuration
18
19
  _global_base_url: Optional[str] = None
19
20
 
21
+
20
22
  def _generate_api_key(name: str, version: Optional[str] = None) -> str:
21
23
  return f"{name}:{version}" if version else name
22
24
 
23
25
 
24
26
  def set_moose_base_url(url: str) -> None:
25
27
  """Set the global base URL for API calls.
26
-
28
+
27
29
  Args:
28
30
  url: The base URL to use for API calls
29
31
  """
@@ -33,14 +35,14 @@ def set_moose_base_url(url: str) -> None:
33
35
 
34
36
  def get_moose_base_url() -> Optional[str]:
35
37
  """Get the configured base URL from global setting or environment variable.
36
-
38
+
37
39
  Returns:
38
40
  The base URL if configured, None otherwise
39
41
  """
40
42
  # Priority: programmatically set > environment variable
41
43
  if _global_base_url:
42
44
  return _global_base_url
43
- return os.getenv('MOOSE_BASE_URL')
45
+ return os.getenv("MOOSE_BASE_URL")
44
46
 
45
47
 
46
48
  class ApiConfig(BaseModel):
@@ -51,6 +53,7 @@ class ApiConfig(BaseModel):
51
53
  path: Optional custom path for the API endpoint. If not specified, defaults to the API name.
52
54
  metadata: Optional metadata for the API.
53
55
  """
56
+
54
57
  version: Optional[str] = None
55
58
  path: Optional[str] = None
56
59
  metadata: Optional[dict] = None
@@ -78,6 +81,7 @@ class Api(BaseTypedResource, Generic[U]):
78
81
  model_type (type[T]): The Pydantic model for the input/query parameters.
79
82
  return_type (type[U]): The Pydantic model for the response body.
80
83
  """
84
+
81
85
  config: ApiConfig
82
86
  query_function: Callable[..., U]
83
87
  _u: type[U]
@@ -85,7 +89,9 @@ class Api(BaseTypedResource, Generic[U]):
85
89
  def __class_getitem__(cls, items):
86
90
  # Handle two type parameters
87
91
  if not isinstance(items, tuple) or len(items) != 2:
88
- raise ValueError(f"Use `{cls.__name__}[T, U](name='...')` to supply both input and output types")
92
+ raise ValueError(
93
+ f"Use `{cls.__name__}[T, U](name='...')` to supply both input and output types"
94
+ )
89
95
  input_type, output_type = items
90
96
 
91
97
  def curried_constructor(*args, **kwargs):
@@ -93,19 +99,23 @@ class Api(BaseTypedResource, Generic[U]):
93
99
 
94
100
  return curried_constructor
95
101
 
96
- def __init__(self, name: str, query_function: Callable[..., U], config: ApiConfig = None, version: str = None, **kwargs):
102
+ def __init__(
103
+ self,
104
+ name: str,
105
+ query_function: Callable[..., U],
106
+ config: ApiConfig = None,
107
+ version: str = None,
108
+ **kwargs,
109
+ ):
97
110
  super().__init__()
98
111
  self._set_type(name, self._get_type(kwargs))
99
-
112
+
100
113
  # Handle config and version parameters properly
101
114
  if config is not None:
102
115
  # If config is provided, use it as base
103
116
  if version is not None:
104
117
  # If version is also provided, update the config's version
105
- self.config = ApiConfig(
106
- version=version,
107
- metadata=config.metadata
108
- )
118
+ self.config = ApiConfig(version=version, metadata=config.metadata)
109
119
  else:
110
120
  # Use the provided config as-is
111
121
  self.config = config
@@ -117,7 +127,7 @@ class Api(BaseTypedResource, Generic[U]):
117
127
  self.config = ApiConfig()
118
128
 
119
129
  self.query_function = query_function
120
- self.metadata = getattr(self.config, 'metadata', {}) or {}
130
+ self.metadata = getattr(self.config, "metadata", {}) or {}
121
131
  key = _generate_api_key(name, self.config.version)
122
132
 
123
133
  # Check for duplicate registration
@@ -143,13 +153,15 @@ class Api(BaseTypedResource, Generic[U]):
143
153
  else:
144
154
  # For versioned APIs, check if version is already in the path
145
155
  path_ends_with_version = (
146
- self.config.path.endswith(f"/{self.config.version}") or
147
- self.config.path == self.config.version or
148
- (self.config.path.endswith(self.config.version) and
149
- len(self.config.path) > len(self.config.version) and
150
- self.config.path[-(len(self.config.version) + 1)] == '/')
156
+ self.config.path.endswith(f"/{self.config.version}")
157
+ or self.config.path == self.config.version
158
+ or (
159
+ self.config.path.endswith(self.config.version)
160
+ and len(self.config.path) > len(self.config.version)
161
+ and self.config.path[-(len(self.config.version) + 1)] == "/"
162
+ )
151
163
  )
152
-
164
+
153
165
  if path_ends_with_version:
154
166
  # Path already contains version, check for collision
155
167
  if self.config.path in _api_path_map:
@@ -161,8 +173,10 @@ class Api(BaseTypedResource, Generic[U]):
161
173
  _api_path_map[self.config.path] = self
162
174
  else:
163
175
  # Path doesn't contain version, register with version appended
164
- path_with_version = f"{self.config.path.rstrip('/')}/{self.config.version}"
165
-
176
+ path_with_version = (
177
+ f"{self.config.path.rstrip('/')}/{self.config.version}"
178
+ )
179
+
166
180
  # Check for collision on versioned path
167
181
  if path_with_version in _api_path_map:
168
182
  existing = _api_path_map[path_with_version]
@@ -171,7 +185,7 @@ class Api(BaseTypedResource, Generic[U]):
171
185
  f'this path is already used by API "{existing.name}"'
172
186
  )
173
187
  _api_path_map[path_with_version] = self
174
-
188
+
175
189
  # Also register the unversioned path if not already claimed
176
190
  # (This is intentionally more permissive - first API gets the unversioned path)
177
191
  if self.config.path not in _api_path_map:
@@ -209,9 +223,11 @@ class Api(BaseTypedResource, Generic[U]):
209
223
 
210
224
  @classmethod
211
225
  def _get_type(cls, keyword_args: dict):
212
- t = keyword_args.get('t')
226
+ t = keyword_args.get("t")
213
227
  if not isinstance(t, tuple) or len(t) != 2:
214
- raise ValueError(f"Use `{cls.__name__}[T, U](name='...')` to supply both input and output types")
228
+ raise ValueError(
229
+ f"Use `{cls.__name__}[T, U](name='...')` to supply both input and output types"
230
+ )
215
231
 
216
232
  input_type, output_type = t
217
233
  if not isinstance(input_type, type) or not issubclass(input_type, BaseModel):
@@ -237,21 +253,22 @@ class Api(BaseTypedResource, Generic[U]):
237
253
  A dictionary representing the JSON schema.
238
254
  """
239
255
  from pydantic.type_adapter import TypeAdapter
256
+
240
257
  return TypeAdapter(self.return_type()).json_schema(
241
- ref_template='#/components/schemas/{model}'
258
+ ref_template="#/components/schemas/{model}"
242
259
  )
243
260
 
244
261
  def call(self, params: T, base_url: Optional[str] = None) -> U:
245
262
  """Call the API with the given parameters.
246
-
263
+
247
264
  Args:
248
265
  params: Parameters matching the input model T
249
266
  base_url: Optional base URL override. If not provided, uses the global
250
267
  base URL set via set_base_url() or MOOSE_BASE_URL environment variable.
251
-
268
+
252
269
  Returns:
253
270
  Response data matching the output model U
254
-
271
+
255
272
  Raises:
256
273
  ValueError: If no base URL is configured
257
274
  """
@@ -268,11 +285,13 @@ class Api(BaseTypedResource, Generic[U]):
268
285
  # Check if the custom path already contains the version
269
286
  if self.config.version:
270
287
  path_ends_with_version = (
271
- self.config.path.endswith(f"/{self.config.version}") or
272
- self.config.path == self.config.version or
273
- (self.config.path.endswith(self.config.version) and
274
- len(self.config.path) > len(self.config.version) and
275
- self.config.path[-(len(self.config.version) + 1)] == '/')
288
+ self.config.path.endswith(f"/{self.config.version}")
289
+ or self.config.path == self.config.version
290
+ or (
291
+ self.config.path.endswith(self.config.version)
292
+ and len(self.config.path) > len(self.config.version)
293
+ and self.config.path[-(len(self.config.version) + 1)] == "/"
294
+ )
276
295
  )
277
296
  if path_ends_with_version:
278
297
  path = self.config.path
@@ -282,7 +301,11 @@ class Api(BaseTypedResource, Generic[U]):
282
301
  path = self.config.path
283
302
  else:
284
303
  # Default to name with optional version
285
- path = self.name if not self.config.version else f"{self.name}/{self.config.version}"
304
+ path = (
305
+ self.name
306
+ if not self.config.version
307
+ else f"{self.name}/{self.config.version}"
308
+ )
286
309
  url = f"{effective_base_url.rstrip('/')}/api/{path}"
287
310
 
288
311
  # Convert Pydantic model to dictionary
@@ -4,6 +4,7 @@ Ingestion API definitions for Moose Data Model v2 (dmv2).
4
4
  This module provides classes for defining and configuring ingestion APIs
5
5
  that receive data and send it to streams.
6
6
  """
7
+
7
8
  import dataclasses
8
9
  from typing import Any, Optional, Generic
9
10
  from pydantic import BaseModel
@@ -12,6 +13,7 @@ from .types import TypedMooseResource, T
12
13
  from .stream import Stream, DeadLetterQueue
13
14
  from ._registry import _ingest_apis
14
15
 
16
+
15
17
  class IngestConfig(BaseModel):
16
18
  """Basic configuration for an ingestion point.
17
19
 
@@ -20,10 +22,12 @@ class IngestConfig(BaseModel):
20
22
  path: Optional custom path for the ingestion endpoint.
21
23
  metadata: Optional metadata for the ingestion point.
22
24
  """
25
+
23
26
  version: Optional[str] = None
24
27
  path: Optional[str] = None
25
28
  metadata: Optional[dict] = None
26
29
 
30
+
27
31
  @dataclasses.dataclass
28
32
  class IngestConfigWithDestination[T: BaseModel]:
29
33
  """Ingestion configuration that includes the mandatory destination stream.
@@ -35,12 +39,14 @@ class IngestConfigWithDestination[T: BaseModel]:
35
39
  path: Optional custom path for the ingestion endpoint.
36
40
  metadata: Optional metadata for the ingestion configuration.
37
41
  """
42
+
38
43
  destination: Stream[T]
39
44
  dead_letter_queue: Optional[DeadLetterQueue[T]] = None
40
45
  version: Optional[str] = None
41
46
  path: Optional[str] = None
42
47
  metadata: Optional[dict] = None
43
48
 
49
+
44
50
  class IngestApi(TypedMooseResource, Generic[T]):
45
51
  """Represents an Ingestion API endpoint typed with a Pydantic model.
46
52
 
@@ -59,11 +65,12 @@ class IngestApi(TypedMooseResource, Generic[T]):
59
65
  name (str): The name of the API.
60
66
  model_type (type[T]): The Pydantic model associated with this API's input.
61
67
  """
68
+
62
69
  config: IngestConfigWithDestination[T]
63
70
 
64
71
  def __init__(self, name: str, config: IngestConfigWithDestination[T], **kwargs):
65
72
  super().__init__()
66
73
  self._set_type(name, self._get_type(kwargs))
67
74
  self.config = config
68
- self.metadata = getattr(config, 'metadata', None)
69
- _ingest_apis[name] = self
75
+ self.metadata = getattr(config, "metadata", None)
76
+ _ingest_apis[name] = self
@@ -4,6 +4,7 @@ Ingestion Pipeline definitions for Moose Data Model v2 (dmv2).
4
4
  This module provides classes for defining and configuring complete ingestion pipelines,
5
5
  which combine tables, streams, and ingestion APIs into a single cohesive unit.
6
6
  """
7
+
7
8
  import warnings
8
9
  from typing import Any, Optional, Generic, TypeVar
9
10
  from pydantic import BaseModel, model_validator
@@ -14,6 +15,7 @@ from .stream import Stream, StreamConfig, DeadLetterQueue
14
15
  from .ingest_api import IngestApi, IngestConfig, IngestConfigWithDestination
15
16
  from .life_cycle import LifeCycle
16
17
 
18
+
17
19
  class IngestPipelineConfig(BaseModel):
18
20
  """Configuration for creating a complete ingestion pipeline.
19
21
 
@@ -31,6 +33,7 @@ class IngestPipelineConfig(BaseModel):
31
33
  metadata: Optional metadata for the ingestion pipeline.
32
34
  life_cycle: Determines how changes in code will propagate to the resources.
33
35
  """
36
+
34
37
  table: bool | OlapConfig = True
35
38
  stream: bool | StreamConfig = True
36
39
  ingest_api: bool | IngestConfig = True
@@ -39,30 +42,31 @@ class IngestPipelineConfig(BaseModel):
39
42
  path: Optional[str] = None
40
43
  metadata: Optional[dict] = None
41
44
  life_cycle: Optional[LifeCycle] = None
42
-
45
+
43
46
  # Legacy support - will be removed in future version
44
47
  ingest: Optional[bool | IngestConfig] = None
45
-
46
- @model_validator(mode='before')
48
+
49
+ @model_validator(mode="before")
47
50
  @classmethod
48
51
  def handle_legacy_ingest_param(cls, data):
49
52
  """Handle backwards compatibility for the deprecated 'ingest' parameter."""
50
- if isinstance(data, dict) and 'ingest' in data:
53
+ if isinstance(data, dict) and "ingest" in data:
51
54
  warnings.warn(
52
55
  "The 'ingest' parameter is deprecated and will be removed in a future version. "
53
56
  "Please use 'ingest_api' instead.",
54
57
  DeprecationWarning,
55
- stacklevel=3
58
+ stacklevel=3,
56
59
  )
57
60
  # Make a copy first to avoid mutating the original dictionary
58
61
  data = data.copy()
59
62
  # If ingest_api is not explicitly set, use the ingest value
60
- if 'ingest_api' not in data:
61
- data['ingest_api'] = data['ingest']
63
+ if "ingest_api" not in data:
64
+ data["ingest_api"] = data["ingest"]
62
65
  # Remove the legacy parameter
63
- del data['ingest']
66
+ del data["ingest"]
64
67
  return data
65
68
 
69
+
66
70
  class IngestPipeline(TypedMooseResource, Generic[T]):
67
71
  """Creates and configures a linked Table, Stream, and Ingest API pipeline.
68
72
 
@@ -84,6 +88,7 @@ class IngestPipeline(TypedMooseResource, Generic[T]):
84
88
  name (str): The base name of the pipeline.
85
89
  model_type (type[T]): The Pydantic model associated with this pipeline.
86
90
  """
91
+
87
92
  table: Optional[OlapTable[T]] = None
88
93
  stream: Optional[Stream[T]] = None
89
94
  ingest_api: Optional[IngestApi[T]] = None
@@ -150,23 +155,37 @@ class IngestPipeline(TypedMooseResource, Generic[T]):
150
155
  stream_metadata = config.metadata
151
156
  ingest_metadata = config.metadata
152
157
  if config.table:
153
- table_config = (config.table if isinstance(config.table, OlapConfig) else
154
- OlapConfig(life_cycle=config.life_cycle))
158
+ table_config = (
159
+ config.table
160
+ if isinstance(config.table, OlapConfig)
161
+ else OlapConfig(life_cycle=config.life_cycle)
162
+ )
155
163
  if config.version:
156
164
  table_config.version = config.version
157
165
  table_config.metadata = table_metadata
158
166
  self.table = OlapTable(name, table_config, t=self._t)
159
167
  if config.dead_letter_queue:
160
- dlq_stream_config = StreamConfig() if config.dead_letter_queue is True else config.dead_letter_queue
168
+ dlq_stream_config = (
169
+ StreamConfig()
170
+ if config.dead_letter_queue is True
171
+ else config.dead_letter_queue
172
+ )
161
173
  if config.version:
162
174
  dlq_stream_config.version = config.version
163
175
  dlq_stream_config.metadata = stream_metadata
164
- self.dead_letter_queue = DeadLetterQueue(f"{name}DeadLetterQueue", dlq_stream_config, t=self._t)
176
+ self.dead_letter_queue = DeadLetterQueue(
177
+ f"{name}DeadLetterQueue", dlq_stream_config, t=self._t
178
+ )
165
179
  if config.stream:
166
- stream_config = (config.stream if isinstance(config.stream, StreamConfig) else
167
- StreamConfig(life_cycle=config.life_cycle))
180
+ stream_config = (
181
+ config.stream
182
+ if isinstance(config.stream, StreamConfig)
183
+ else StreamConfig(life_cycle=config.life_cycle)
184
+ )
168
185
  if config.table and stream_config.destination is not None:
169
- raise ValueError("The destination of the stream should be the table created in the IngestPipeline")
186
+ raise ValueError(
187
+ "The destination of the stream should be the table created in the IngestPipeline"
188
+ )
170
189
  stream_config.destination = self.table
171
190
  if self.dead_letter_queue is not None:
172
191
  stream_config.default_dead_letter_queue = self.dead_letter_queue
@@ -189,4 +208,4 @@ class IngestPipeline(TypedMooseResource, Generic[T]):
189
208
  ingest_config_dict["dead_letter_queue"] = self.dead_letter_queue
190
209
  ingest_config_dict["metadata"] = ingest_metadata
191
210
  ingest_config = IngestConfigWithDestination(**ingest_config_dict)
192
- self.ingest_api = IngestApi(name, ingest_config, t=self._t)
211
+ self.ingest_api = IngestApi(name, ingest_config, t=self._t)
@@ -4,8 +4,10 @@ Lifecycle management definitions for Moose Data Model v2 (dmv2).
4
4
  This module defines how Moose manages the lifecycle of database resources
5
5
  when your code changes.
6
6
  """
7
+
7
8
  from enum import Enum
8
9
 
10
+
9
11
  class LifeCycle(Enum):
10
12
  """Defines how Moose manages the lifecycle of database resources when your code changes.
11
13
 
@@ -29,4 +31,4 @@ class LifeCycle(Enum):
29
31
  """External management - no automatic changes.
30
32
  Moose will not modify the database resources. You are responsible for managing
31
33
  the schema and ensuring it matches your code definitions manually.
32
- """
34
+ """