moose-lib 0.6.63__tar.gz → 0.6.64__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.
Potentially problematic release.
This version of moose-lib might be problematic. Click here for more details.
- {moose_lib-0.6.63 → moose_lib-0.6.64}/PKG-INFO +1 -1
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/ingest_pipeline.py +8 -6
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/stream.py +33 -6
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/streaming/streaming_function_runner.py +4 -2
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib.egg-info/PKG-INFO +1 -1
- {moose_lib-0.6.63 → moose_lib-0.6.64}/README.md +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/__init__.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/blocks.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/clients/__init__.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/clients/redis_client.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/commons.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/config/__init__.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/config/config_file.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/config/runtime.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/data_models.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/__init__.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/_registry.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/consumption.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/ingest_api.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/life_cycle.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/materialized_view.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/olap_table.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/registry.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/sql_resource.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/types.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/view.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2/workflow.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/dmv2_serializer.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/internal.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/main.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/query_param.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/streaming/__init__.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/utilities/__init__.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib/utilities/sql.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib.egg-info/SOURCES.txt +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib.egg-info/dependency_links.txt +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib.egg-info/requires.txt +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/moose_lib.egg-info/top_level.txt +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/setup.cfg +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/setup.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/tests/__init__.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/tests/conftest.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/tests/test_moose.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/tests/test_redis_client.py +0 -0
- {moose_lib-0.6.63 → moose_lib-0.6.64}/tests/test_s3queue_config.py +0 -0
|
@@ -132,22 +132,24 @@ class IngestPipeline(TypedMooseResource, Generic[T]):
|
|
|
132
132
|
table_config.version = config.version
|
|
133
133
|
table_config.metadata = table_metadata
|
|
134
134
|
self.table = OlapTable(name, table_config, t=self._t)
|
|
135
|
+
if config.dead_letter_queue:
|
|
136
|
+
dlq_stream_config = StreamConfig() if config.dead_letter_queue is True else config.dead_letter_queue
|
|
137
|
+
if config.version:
|
|
138
|
+
dlq_stream_config.version = config.version
|
|
139
|
+
dlq_stream_config.metadata = stream_metadata
|
|
140
|
+
self.dead_letter_queue = DeadLetterQueue(f"{name}DeadLetterQueue", dlq_stream_config, t=self._t)
|
|
135
141
|
if config.stream:
|
|
136
142
|
stream_config = (config.stream if isinstance(config.stream, StreamConfig) else
|
|
137
143
|
StreamConfig(life_cycle=config.life_cycle))
|
|
138
144
|
if config.table and stream_config.destination is not None:
|
|
139
145
|
raise ValueError("The destination of the stream should be the table created in the IngestPipeline")
|
|
140
146
|
stream_config.destination = self.table
|
|
147
|
+
if self.dead_letter_queue is not None:
|
|
148
|
+
stream_config.default_dead_letter_queue = self.dead_letter_queue
|
|
141
149
|
if config.version:
|
|
142
150
|
stream_config.version = config.version
|
|
143
151
|
stream_config.metadata = stream_metadata
|
|
144
152
|
self.stream = Stream(name, stream_config, t=self._t)
|
|
145
|
-
if config.dead_letter_queue:
|
|
146
|
-
stream_config = StreamConfig() if config.dead_letter_queue is True else config.dead_letter_queue
|
|
147
|
-
if config.version:
|
|
148
|
-
stream_config.version = config.version
|
|
149
|
-
stream_config.metadata = stream_metadata
|
|
150
|
-
self.dead_letter_queue = DeadLetterQueue(f"{name}DeadLetterQueue", stream_config, t=self._t)
|
|
151
153
|
if config.ingest:
|
|
152
154
|
if self.stream is None:
|
|
153
155
|
raise ValueError("Ingest API needs a stream to write to.")
|
|
@@ -15,6 +15,7 @@ from .olap_table import OlapTable
|
|
|
15
15
|
from ._registry import _streams
|
|
16
16
|
from .life_cycle import LifeCycle
|
|
17
17
|
|
|
18
|
+
|
|
18
19
|
class StreamConfig(BaseModel):
|
|
19
20
|
"""Configuration for data streams (e.g., Redpanda topics).
|
|
20
21
|
|
|
@@ -25,6 +26,7 @@ class StreamConfig(BaseModel):
|
|
|
25
26
|
version: Optional version string for tracking configuration changes.
|
|
26
27
|
metadata: Optional metadata for the stream.
|
|
27
28
|
life_cycle: Determines how changes in code will propagate to the resources.
|
|
29
|
+
default_dead_letter_queue: default dead letter queue used by transforms/consumers
|
|
28
30
|
"""
|
|
29
31
|
parallelism: int = 1
|
|
30
32
|
retention_period: int = 60 * 60 * 24 * 7 # 7 days
|
|
@@ -32,6 +34,10 @@ class StreamConfig(BaseModel):
|
|
|
32
34
|
version: Optional[str] = None
|
|
33
35
|
metadata: Optional[dict] = None
|
|
34
36
|
life_cycle: Optional[LifeCycle] = None
|
|
37
|
+
default_dead_letter_queue: "Optional[DeadLetterQueue]" = None
|
|
38
|
+
# allow DeadLetterQueue
|
|
39
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
40
|
+
|
|
35
41
|
|
|
36
42
|
class TransformConfig(BaseModel):
|
|
37
43
|
"""Configuration for stream transformations.
|
|
@@ -45,6 +51,7 @@ class TransformConfig(BaseModel):
|
|
|
45
51
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
46
52
|
metadata: Optional[dict] = None
|
|
47
53
|
|
|
54
|
+
|
|
48
55
|
class ConsumerConfig(BaseModel):
|
|
49
56
|
"""Configuration for stream consumers.
|
|
50
57
|
|
|
@@ -56,18 +63,21 @@ class ConsumerConfig(BaseModel):
|
|
|
56
63
|
dead_letter_queue: "Optional[DeadLetterQueue]" = None
|
|
57
64
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
58
65
|
|
|
66
|
+
|
|
59
67
|
@dataclasses.dataclass
|
|
60
68
|
class _RoutedMessage:
|
|
61
69
|
"""Internal class representing a message routed to a specific stream."""
|
|
62
70
|
destination: "Stream[Any]"
|
|
63
71
|
values: ZeroOrMany[Any]
|
|
64
72
|
|
|
73
|
+
|
|
65
74
|
@dataclasses.dataclass
|
|
66
75
|
class ConsumerEntry(Generic[T]):
|
|
67
76
|
"""Internal class representing a consumer with its configuration."""
|
|
68
77
|
consumer: Callable[[T], None]
|
|
69
78
|
config: ConsumerConfig
|
|
70
79
|
|
|
80
|
+
|
|
71
81
|
@dataclasses.dataclass
|
|
72
82
|
class TransformEntry(Generic[T]):
|
|
73
83
|
"""Internal class representing a transformation with its configuration."""
|
|
@@ -75,6 +85,7 @@ class TransformEntry(Generic[T]):
|
|
|
75
85
|
transformation: Callable[[T], ZeroOrMany[Any]]
|
|
76
86
|
config: TransformConfig
|
|
77
87
|
|
|
88
|
+
|
|
78
89
|
class Stream(TypedMooseResource, Generic[T]):
|
|
79
90
|
"""Represents a data stream (e.g., a Redpanda topic) typed with a Pydantic model.
|
|
80
91
|
|
|
@@ -98,14 +109,16 @@ class Stream(TypedMooseResource, Generic[T]):
|
|
|
98
109
|
transformations: dict[str, list[TransformEntry[T]]]
|
|
99
110
|
consumers: list[ConsumerEntry[T]]
|
|
100
111
|
_multipleTransformations: Optional[Callable[[T], list[_RoutedMessage]]] = None
|
|
112
|
+
default_dead_letter_queue: "Optional[DeadLetterQueue[T]]" = None
|
|
101
113
|
|
|
102
|
-
def __init__(self, name: str, config: StreamConfig =
|
|
114
|
+
def __init__(self, name: str, config: "StreamConfig" = None, **kwargs):
|
|
103
115
|
super().__init__()
|
|
104
116
|
self._set_type(name, self._get_type(kwargs))
|
|
105
|
-
self.config = config
|
|
106
|
-
self.metadata = config.metadata
|
|
117
|
+
self.config = config if config is not None else StreamConfig()
|
|
118
|
+
self.metadata = self.config.metadata
|
|
107
119
|
self.consumers = []
|
|
108
120
|
self.transformations = {}
|
|
121
|
+
self.default_dead_letter_queue = self.config.default_dead_letter_queue
|
|
109
122
|
_streams[name] = self
|
|
110
123
|
|
|
111
124
|
def add_transform(self, destination: "Stream[U]", transformation: Callable[[T], ZeroOrMany[U]],
|
|
@@ -121,6 +134,12 @@ class Stream(TypedMooseResource, Generic[T]):
|
|
|
121
134
|
config: Optional configuration, primarily for setting a version.
|
|
122
135
|
"""
|
|
123
136
|
config = config or TransformConfig()
|
|
137
|
+
if (
|
|
138
|
+
self.default_dead_letter_queue is not None
|
|
139
|
+
and config.dead_letter_queue is None
|
|
140
|
+
):
|
|
141
|
+
config = config.model_copy()
|
|
142
|
+
config.dead_letter_queue = self.default_dead_letter_queue
|
|
124
143
|
if destination.name in self.transformations:
|
|
125
144
|
existing_transforms = self.transformations[destination.name]
|
|
126
145
|
# Check if a transform with this version already exists
|
|
@@ -142,6 +161,12 @@ class Stream(TypedMooseResource, Generic[T]):
|
|
|
142
161
|
config: Optional configuration, primarily for setting a version.
|
|
143
162
|
"""
|
|
144
163
|
config = config or ConsumerConfig()
|
|
164
|
+
if (
|
|
165
|
+
self.default_dead_letter_queue is not None
|
|
166
|
+
and config.dead_letter_queue is None
|
|
167
|
+
):
|
|
168
|
+
config = config.model_copy()
|
|
169
|
+
config.dead_letter_queue = self.default_dead_letter_queue
|
|
145
170
|
has_version = any(c.config.version == config.version for c in self.consumers)
|
|
146
171
|
if not has_version:
|
|
147
172
|
self.consumers.append(ConsumerEntry(consumer=consumer, config=config))
|
|
@@ -191,6 +216,7 @@ class Stream(TypedMooseResource, Generic[T]):
|
|
|
191
216
|
"""
|
|
192
217
|
self._multipleTransformations = transformation
|
|
193
218
|
|
|
219
|
+
|
|
194
220
|
class DeadLetterModel(BaseModel, Generic[T]):
|
|
195
221
|
"""Model for dead letter queue messages.
|
|
196
222
|
|
|
@@ -213,6 +239,7 @@ class DeadLetterModel(BaseModel, Generic[T]):
|
|
|
213
239
|
def as_typed(self) -> T:
|
|
214
240
|
return self._t.model_validate(self.original_record)
|
|
215
241
|
|
|
242
|
+
|
|
216
243
|
class DeadLetterQueue(Stream, Generic[T]):
|
|
217
244
|
"""A specialized Stream for handling failed records.
|
|
218
245
|
|
|
@@ -225,7 +252,7 @@ class DeadLetterQueue(Stream, Generic[T]):
|
|
|
225
252
|
|
|
226
253
|
_model_type: type[T]
|
|
227
254
|
|
|
228
|
-
def __init__(self, name: str, config: StreamConfig =
|
|
255
|
+
def __init__(self, name: str, config: "StreamConfig" = None, **kwargs):
|
|
229
256
|
"""Initialize a new DeadLetterQueue.
|
|
230
257
|
|
|
231
258
|
Args:
|
|
@@ -234,7 +261,7 @@ class DeadLetterQueue(Stream, Generic[T]):
|
|
|
234
261
|
"""
|
|
235
262
|
self._model_type = self._get_type(kwargs)
|
|
236
263
|
kwargs["t"] = DeadLetterModel[self._model_type]
|
|
237
|
-
super().__init__(name, config, **kwargs)
|
|
264
|
+
super().__init__(name, config if config is not None else StreamConfig(), **kwargs)
|
|
238
265
|
|
|
239
266
|
def add_transform(self, destination: Stream[U], transformation: Callable[[DeadLetterModel[T]], ZeroOrMany[U]],
|
|
240
267
|
config: TransformConfig = None):
|
|
@@ -258,4 +285,4 @@ class DeadLetterQueue(Stream, Generic[T]):
|
|
|
258
285
|
record._t = self._model_type
|
|
259
286
|
return transformation(record)
|
|
260
287
|
|
|
261
|
-
super().set_multi_transform(wrapped_transform)
|
|
288
|
+
super().set_multi_transform(wrapped_transform)
|
|
@@ -328,6 +328,8 @@ def create_producer() -> Optional[KafkaProducer]:
|
|
|
328
328
|
Returns:
|
|
329
329
|
Configured KafkaProducer instance
|
|
330
330
|
"""
|
|
331
|
+
max_request_size = KafkaProducer.DEFAULT_CONFIG['max_request_size'] if target_topic is None \
|
|
332
|
+
else target_topic.max_message_bytes
|
|
331
333
|
if sasl_config['mechanism'] is not None:
|
|
332
334
|
return KafkaProducer(
|
|
333
335
|
bootstrap_servers=broker,
|
|
@@ -335,13 +337,13 @@ def create_producer() -> Optional[KafkaProducer]:
|
|
|
335
337
|
sasl_plain_password=sasl_config['password'],
|
|
336
338
|
sasl_mechanism=sasl_config['mechanism'],
|
|
337
339
|
security_protocol=args.security_protocol,
|
|
338
|
-
max_request_size=
|
|
340
|
+
max_request_size=max_request_size
|
|
339
341
|
)
|
|
340
342
|
log("No sasl mechanism specified. Using default producer.")
|
|
341
343
|
return KafkaProducer(
|
|
342
344
|
bootstrap_servers=broker,
|
|
343
345
|
max_in_flight_requests_per_connection=1,
|
|
344
|
-
max_request_size=
|
|
346
|
+
max_request_size=max_request_size
|
|
345
347
|
)
|
|
346
348
|
|
|
347
349
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|