moose-lib 0.6.18__py3-none-any.whl → 0.6.20__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.
Potentially problematic release.
This version of moose-lib might be problematic. Click here for more details.
- moose_lib/__init__.py +0 -2
- moose_lib/dmv2/__init__.py +2 -0
- moose_lib/dmv2/workflow.py +16 -11
- moose_lib/main.py +33 -44
- {moose_lib-0.6.18.dist-info → moose_lib-0.6.20.dist-info}/METADATA +1 -1
- {moose_lib-0.6.18.dist-info → moose_lib-0.6.20.dist-info}/RECORD +8 -9
- moose_lib/tasks.py +0 -45
- {moose_lib-0.6.18.dist-info → moose_lib-0.6.20.dist-info}/WHEEL +0 -0
- {moose_lib-0.6.18.dist-info → moose_lib-0.6.20.dist-info}/top_level.txt +0 -0
moose_lib/__init__.py
CHANGED
moose_lib/dmv2/__init__.py
CHANGED
|
@@ -65,6 +65,7 @@ from .materialized_view import (
|
|
|
65
65
|
)
|
|
66
66
|
|
|
67
67
|
from .workflow import (
|
|
68
|
+
TaskContext,
|
|
68
69
|
TaskConfig,
|
|
69
70
|
Task,
|
|
70
71
|
WorkflowConfig,
|
|
@@ -140,6 +141,7 @@ __all__ = [
|
|
|
140
141
|
'MaterializedView',
|
|
141
142
|
|
|
142
143
|
# Workflow
|
|
144
|
+
'TaskContext',
|
|
143
145
|
'TaskConfig',
|
|
144
146
|
'Task',
|
|
145
147
|
'WorkflowConfig',
|
moose_lib/dmv2/workflow.py
CHANGED
|
@@ -11,16 +11,17 @@ from pydantic import BaseModel
|
|
|
11
11
|
from .types import TypedMooseResource, T_none, U_none
|
|
12
12
|
from ._registry import _workflows
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
@dataclasses.dataclass
|
|
15
|
+
class TaskContext(Generic[T_none]):
|
|
16
|
+
"""Context object passed to task handlers.
|
|
17
|
+
|
|
18
|
+
- When a task declares an input model `T`, `input` is of type `T` (not Optional).
|
|
19
|
+
- For no-input tasks (`T` is `None`), `input` is exactly `None`.
|
|
20
|
+
"""
|
|
21
|
+
state: Dict[str, Any]
|
|
22
|
+
input: T_none
|
|
23
|
+
|
|
24
|
+
type TaskRunFunc[T_none, U_none] = Callable[[TaskContext[T_none]], Union[U_none, Awaitable[U_none]]]
|
|
24
25
|
|
|
25
26
|
@dataclasses.dataclass
|
|
26
27
|
class TaskConfig(Generic[T_none, U_none]):
|
|
@@ -28,12 +29,16 @@ class TaskConfig(Generic[T_none, U_none]):
|
|
|
28
29
|
|
|
29
30
|
Attributes:
|
|
30
31
|
run: The handler function that executes the task logic.
|
|
32
|
+
Signature: run(context: TaskContext[T]) -> U
|
|
31
33
|
on_complete: Optional list of tasks to run after this task completes.
|
|
32
|
-
|
|
34
|
+
on_cancel: Optional function to call when the task is cancelled.
|
|
35
|
+
Signature: on_cancel(context: TaskContext[T]) -> None
|
|
36
|
+
timeout: Optional timeout string (e.g. "5m", "1h", "never").
|
|
33
37
|
retries: Optional number of retry attempts.
|
|
34
38
|
"""
|
|
35
39
|
run: TaskRunFunc[T_none, U_none]
|
|
36
40
|
on_complete: Optional[list["Task[U_none, Any]"]] = None
|
|
41
|
+
on_cancel: Optional[Callable[[TaskContext[T_none]], Union[None, Awaitable[None]]]] = None
|
|
37
42
|
timeout: Optional[str] = None
|
|
38
43
|
retries: Optional[int] = None
|
|
39
44
|
|
moose_lib/main.py
CHANGED
|
@@ -220,7 +220,7 @@ class QueryClient:
|
|
|
220
220
|
|
|
221
221
|
|
|
222
222
|
class WorkflowClient:
|
|
223
|
-
"""Client for interacting with Temporal workflows.
|
|
223
|
+
"""Client for interacting with Temporal DMv2 workflows.
|
|
224
224
|
|
|
225
225
|
Args:
|
|
226
226
|
temporal_client: An instance of the Temporal client.
|
|
@@ -228,8 +228,6 @@ class WorkflowClient:
|
|
|
228
228
|
|
|
229
229
|
def __init__(self, temporal_client: TemporalClient):
|
|
230
230
|
self.temporal_client = temporal_client
|
|
231
|
-
self.configs = self.load_consolidated_configs()
|
|
232
|
-
print(f"WorkflowClient - configs: {self.configs}")
|
|
233
231
|
|
|
234
232
|
# Test workflow executor in rust if this changes significantly
|
|
235
233
|
def execute(self, name: str, input_data: Any) -> Dict[str, Any]:
|
|
@@ -278,42 +276,43 @@ class WorkflowClient:
|
|
|
278
276
|
run_timeout = self.parse_timeout_to_timedelta(config['timeout_str'])
|
|
279
277
|
|
|
280
278
|
print(
|
|
281
|
-
f"WorkflowClient - starting
|
|
279
|
+
f"WorkflowClient - starting DMv2 workflow: {name} with retry policy: {retry_policy} and timeout: {run_timeout}")
|
|
282
280
|
|
|
283
281
|
# Start workflow with appropriate args
|
|
284
|
-
workflow_args = self._build_workflow_args(name, processed_input
|
|
282
|
+
workflow_args = self._build_workflow_args(name, processed_input)
|
|
283
|
+
|
|
284
|
+
# Handle "never" timeout by omitting run_timeout parameter
|
|
285
|
+
workflow_kwargs = {
|
|
286
|
+
"args": workflow_args,
|
|
287
|
+
"id": workflow_id,
|
|
288
|
+
"task_queue": "python-script-queue",
|
|
289
|
+
"id_conflict_policy": WorkflowIDConflictPolicy.FAIL,
|
|
290
|
+
"id_reuse_policy": WorkflowIDReusePolicy.ALLOW_DUPLICATE,
|
|
291
|
+
"retry_policy": retry_policy,
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if run_timeout is not None:
|
|
295
|
+
workflow_kwargs["run_timeout"] = run_timeout
|
|
285
296
|
|
|
286
297
|
workflow_handle = await self.temporal_client.start_workflow(
|
|
287
298
|
"ScriptWorkflow",
|
|
288
|
-
|
|
289
|
-
id=workflow_id,
|
|
290
|
-
task_queue="python-script-queue",
|
|
291
|
-
id_conflict_policy=WorkflowIDConflictPolicy.FAIL,
|
|
292
|
-
id_reuse_policy=WorkflowIDReusePolicy.ALLOW_DUPLICATE,
|
|
293
|
-
retry_policy=retry_policy,
|
|
294
|
-
run_timeout=run_timeout
|
|
299
|
+
**workflow_kwargs
|
|
295
300
|
)
|
|
296
301
|
|
|
297
302
|
return workflow_id, workflow_handle.result_run_id
|
|
298
303
|
|
|
299
304
|
def _get_workflow_config(self, name: str) -> Dict[str, Any]:
|
|
300
|
-
"""Extract workflow configuration from DMv2
|
|
305
|
+
"""Extract workflow configuration from DMv2 workflow."""
|
|
301
306
|
from moose_lib.dmv2 import get_workflow
|
|
302
307
|
|
|
303
308
|
dmv2_workflow = get_workflow(name)
|
|
304
|
-
if dmv2_workflow is
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
config = self.configs.get(name, {})
|
|
312
|
-
return {
|
|
313
|
-
'retry_count': config.get('retries', 3),
|
|
314
|
-
'timeout_str': config.get('timeout', "1h"),
|
|
315
|
-
'is_dmv2': False
|
|
316
|
-
}
|
|
309
|
+
if dmv2_workflow is None:
|
|
310
|
+
raise ValueError(f"DMv2 workflow '{name}' not found")
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
'retry_count': dmv2_workflow.config.retries or 3,
|
|
314
|
+
'timeout_str': dmv2_workflow.config.timeout or "1h",
|
|
315
|
+
}
|
|
317
316
|
|
|
318
317
|
def _process_input_data(self, name: str, input_data: Any) -> tuple[Any, str]:
|
|
319
318
|
"""Process input data and generate workflow ID."""
|
|
@@ -339,26 +338,16 @@ class WorkflowClient:
|
|
|
339
338
|
|
|
340
339
|
return input_data, workflow_id
|
|
341
340
|
|
|
342
|
-
def _build_workflow_args(self, name: str, input_data: Any
|
|
343
|
-
"""Build workflow arguments
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
else:
|
|
347
|
-
return [f"{os.getcwd()}/app/scripts/{name}", input_data]
|
|
341
|
+
def _build_workflow_args(self, name: str, input_data: Any) -> list:
|
|
342
|
+
"""Build workflow arguments for DMv2 workflow."""
|
|
343
|
+
return [{"workflow_name": name, "execution_mode": "start"}, input_data]
|
|
344
|
+
|
|
348
345
|
|
|
349
|
-
# TODO: Remove when workflows dmv1 is removed
|
|
350
|
-
def load_consolidated_configs(self):
|
|
351
|
-
try:
|
|
352
|
-
file_path = os.path.join(os.getcwd(), ".moose", "workflow_configs.json")
|
|
353
|
-
with open(file_path, 'r') as file:
|
|
354
|
-
data = json.load(file)
|
|
355
|
-
config_map = {config['name']: config for config in data}
|
|
356
|
-
return config_map
|
|
357
|
-
except Exception as e:
|
|
358
|
-
print(f"Could not load configs for workflows v1: {e}")
|
|
359
346
|
|
|
360
|
-
def parse_timeout_to_timedelta(self, timeout_str: str) -> timedelta:
|
|
361
|
-
if timeout_str
|
|
347
|
+
def parse_timeout_to_timedelta(self, timeout_str: str) -> Optional[timedelta]:
|
|
348
|
+
if timeout_str == "never":
|
|
349
|
+
return None # Unlimited execution timeout
|
|
350
|
+
elif timeout_str.endswith('h'):
|
|
362
351
|
return timedelta(hours=int(timeout_str[:-1]))
|
|
363
352
|
elif timeout_str.endswith('m'):
|
|
364
353
|
return timedelta(minutes=int(timeout_str[:-1]))
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
moose_lib/__init__.py,sha256=
|
|
1
|
+
moose_lib/__init__.py,sha256=LiUdVqmtASPqbMF53dXVZzCdU1jtFVx62_tiSbW65a0,162
|
|
2
2
|
moose_lib/blocks.py,sha256=_wdvC2NC_Y3MMEnB71WTgWbeQ--zPNHk19xjToJW0C0,3185
|
|
3
3
|
moose_lib/commons.py,sha256=FUpRv8D3-LeGcjhcqtDyiimz5izwpCq53h50ydxC_uA,3711
|
|
4
4
|
moose_lib/data_models.py,sha256=PgoFXTzf4C66FlKUowMT4VOrwSRR9_bk36P43ub4LzU,10274
|
|
5
5
|
moose_lib/dmv2-serializer.py,sha256=CL_Pvvg8tJOT8Qk6hywDNzY8MYGhMVdTOw8arZi3jng,49
|
|
6
6
|
moose_lib/internal.py,sha256=UYF42oFujLH1g9GDo_HdP-AYipKTf_lReyVi6qs945A,14397
|
|
7
|
-
moose_lib/main.py,sha256=
|
|
7
|
+
moose_lib/main.py,sha256=XcVX_sTnt5QbrPXKNLCKZGCvpFpE8oiqSG2S1So9ztI,16713
|
|
8
8
|
moose_lib/query_param.py,sha256=kxcR09BMIsEg4o2qetjKrVu1YFRaLfMEzwzyGsKUpvA,6474
|
|
9
|
-
moose_lib/tasks.py,sha256=6MXA0j7nhvQILAJVTQHCAsquwrSOi2zAevghAc_7kXs,1554
|
|
10
9
|
moose_lib/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
10
|
moose_lib/clients/redis_client.py,sha256=UBCdxwgZpIOIOy2EnPyxJIAYjw_qmNwGsJQCQ66SxUI,8117
|
|
12
11
|
moose_lib/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
12
|
moose_lib/config/config_file.py,sha256=NyjY6YFraBel7vBk18lLkpGaPR1viKMAEv4ZldyfLIA,2585
|
|
14
13
|
moose_lib/config/runtime.py,sha256=gF1wrUCbp0MxRU92k0vyItvWX2x6P1FuBRzM61nJE_U,2776
|
|
15
|
-
moose_lib/dmv2/__init__.py,sha256=
|
|
14
|
+
moose_lib/dmv2/__init__.py,sha256=3DVAtNMZUoP94CMJBFhuXfYEQXDbQUNKSgg9XnKqae0,2768
|
|
16
15
|
moose_lib/dmv2/_registry.py,sha256=RweMQWHSvhxgSceZ5mfd0NGnJ-49VZORbaFmw-O0bFY,611
|
|
17
16
|
moose_lib/dmv2/consumption.py,sha256=KJV9MKgrnVLIRhlFVZMDhTsXvOaZoMiHk4hnRePdPWA,8745
|
|
18
17
|
moose_lib/dmv2/ingest_api.py,sha256=Snek9NGwaJl_BuImSWGtQq91m9D3AJ4qBoGiKZ-9yTQ,2323
|
|
@@ -25,14 +24,14 @@ moose_lib/dmv2/sql_resource.py,sha256=kUZoGqxhZMHMthtBZGYJBxTFjXkspXiWLXhJRYXgGU
|
|
|
25
24
|
moose_lib/dmv2/stream.py,sha256=jiUWBsjFalLLP63mikOxyHRdieiDAlzf9lXfLye-Wjc,10761
|
|
26
25
|
moose_lib/dmv2/types.py,sha256=5FsB0HLHFkYB-8cjJ0rtRUjqahVA-ToLr2JXT1lFiss,3276
|
|
27
26
|
moose_lib/dmv2/view.py,sha256=fVbfbJgc2lvhjpGvpfKcFUqZqxKuLD4X59jdupxIe94,1350
|
|
28
|
-
moose_lib/dmv2/workflow.py,sha256=
|
|
27
|
+
moose_lib/dmv2/workflow.py,sha256=_FY4-VRo7uWxRtoipxGSo04qzBb4pbP30iQei1W0Ios,6287
|
|
29
28
|
moose_lib/streaming/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
29
|
moose_lib/streaming/streaming_function_runner.py,sha256=toide6mpUIuHWv75Iv8PmKL6HlsPnBB2XRq2aIjOWBY,23421
|
|
31
30
|
tests/__init__.py,sha256=0Gh4yzPkkC3TzBGKhenpMIxJcRhyrrCfxLSfpTZnPMQ,53
|
|
32
31
|
tests/conftest.py,sha256=ZVJNbnr4DwbcqkTmePW6U01zAzE6QD0kNAEZjPG1f4s,169
|
|
33
32
|
tests/test_moose.py,sha256=mBsx_OYWmL8ppDzL_7Bd7xR6qf_i3-pCIO3wm2iQNaA,2136
|
|
34
33
|
tests/test_redis_client.py,sha256=d9_MLYsJ4ecVil_jPB2gW3Q5aWnavxmmjZg2uYI3LVo,3256
|
|
35
|
-
moose_lib-0.6.
|
|
36
|
-
moose_lib-0.6.
|
|
37
|
-
moose_lib-0.6.
|
|
38
|
-
moose_lib-0.6.
|
|
34
|
+
moose_lib-0.6.20.dist-info/METADATA,sha256=5oRl34L_r8CXqY2lKc__Tx2CX3M4pcQcbQCuojDbAS4,730
|
|
35
|
+
moose_lib-0.6.20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
36
|
+
moose_lib-0.6.20.dist-info/top_level.txt,sha256=XEns2-4aCmGp2XjJAeEH9TAUcGONLnSLy6ycT9FSJh8,16
|
|
37
|
+
moose_lib-0.6.20.dist-info/RECORD,,
|
moose_lib/tasks.py
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
from functools import wraps
|
|
2
|
-
from typing import TypeVar, Callable, Any
|
|
3
|
-
from .commons import Logger
|
|
4
|
-
import asyncio
|
|
5
|
-
|
|
6
|
-
T = TypeVar('T')
|
|
7
|
-
|
|
8
|
-
def task(func: Callable[..., T] = None, *, retries: int = 3) -> Callable[..., T]:
|
|
9
|
-
"""Decorator to mark a function as a Moose task
|
|
10
|
-
|
|
11
|
-
Args:
|
|
12
|
-
func: The function to decorate
|
|
13
|
-
retries: Number of times to retry the task if it fails
|
|
14
|
-
"""
|
|
15
|
-
def validate_result(result: Any) -> None:
|
|
16
|
-
"""Ensure proper return format"""
|
|
17
|
-
if not isinstance(result, dict):
|
|
18
|
-
raise ValueError("Task must return a dictionary with 'task' and 'data' keys")
|
|
19
|
-
if "task" not in result or "data" not in result:
|
|
20
|
-
raise ValueError("Task result must contain 'task' and 'data' keys")
|
|
21
|
-
|
|
22
|
-
def decorator(f: Callable[..., T]) -> Callable[..., T]:
|
|
23
|
-
if asyncio.iscoroutinefunction(f):
|
|
24
|
-
@wraps(f)
|
|
25
|
-
async def wrapper(*args, **kwargs) -> T:
|
|
26
|
-
result = await f(*args, **kwargs)
|
|
27
|
-
validate_result(result)
|
|
28
|
-
return result
|
|
29
|
-
else:
|
|
30
|
-
@wraps(f)
|
|
31
|
-
def wrapper(*args, **kwargs) -> T:
|
|
32
|
-
result = f(*args, **kwargs)
|
|
33
|
-
validate_result(result)
|
|
34
|
-
return result
|
|
35
|
-
|
|
36
|
-
# Add the markers to the wrapper
|
|
37
|
-
wrapper._is_moose_task = True
|
|
38
|
-
wrapper._retries = retries
|
|
39
|
-
wrapper.logger = Logger(is_moose_task=True)
|
|
40
|
-
return wrapper
|
|
41
|
-
|
|
42
|
-
# Handle both @task and @task() syntax
|
|
43
|
-
if func is None:
|
|
44
|
-
return decorator
|
|
45
|
-
return decorator(func)
|
|
File without changes
|
|
File without changes
|