Skip to content

Commit 8870433

Browse files
committed
wip
Signed-off-by: Yves Bastide <yves@botify.com>
1 parent fd4551a commit 8870433

File tree

8 files changed

+806
-668
lines changed

8 files changed

+806
-668
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ repos:
1414
- --maxkb=1024
1515
- repo: https://github.com/astral-sh/uv-pre-commit
1616
# uv version.
17-
rev: 0.5.24
17+
rev: 0.6.6
1818
hooks:
1919
# Keep uv.lock up to date.
2020
- id: uv-lock
2121

2222
- repo: https://github.com/astral-sh/ruff-pre-commit
2323
# Ruff version.
24-
rev: v0.9.3
24+
rev: v0.11.0
2525
hooks:
2626
# Run the linter.
2727
- id: ruff

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ dependencies = [
4646
"click",
4747
"psutil",
4848
"pytz",
49+
"typer>=0.15.2",
4950
]
5051

5152
[project.urls]
@@ -92,7 +93,7 @@ exclude = ["*~"]
9293
[dependency-groups]
9394
dev = [
9495
"boto3-stubs[s3,swf]",
95-
"cffi==v1.17.0rc1; python_full_version=='3.13.0b4'", # via cryptography via moto, secretstorage
96+
"cffi==v1.17.1; python_full_version=='3.13.0b4'", # via cryptography via moto, secretstorage
9697
"flaky",
9798
"hatch",
9899
"invoke",

simpleflow/cli/__init__.py

Whitespace-only changes.

simpleflow/cli/workflow.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
from __future__ import annotations
2+
3+
import json
4+
from datetime import datetime
5+
from enum import Enum
6+
from typing import Any
7+
8+
import typer
9+
from typing_extensions import Annotated
10+
11+
from simpleflow.command import get_progression_callback, get_workflow_type, with_format
12+
from simpleflow.swf import helpers
13+
from simpleflow.swf.mapper.models import WorkflowExecution
14+
from simpleflow.swf.utils import set_workflow_class_name
15+
from simpleflow.utils import import_from_module
16+
17+
18+
class Status(str, Enum):
19+
open = "open"
20+
closed = "closed"
21+
22+
23+
class CloseStatus(str, Enum):
24+
completed = "completed"
25+
failed = "failed"
26+
canceled = "canceled"
27+
terminated = "terminated"
28+
continued_as_new = "continued_as_new"
29+
30+
31+
app = typer.Typer(no_args_is_help=True)
32+
33+
TIMESTAMP_FORMATS = [
34+
"%Y-%m-%d",
35+
"%Y-%m-%dT%H:%M:%S%z",
36+
"%Y-%m-%d %H:%M:%S%z",
37+
"%Y-%m-%dT%H:%M:%S",
38+
"%Y-%m-%d %H:%M:%S",
39+
]
40+
41+
42+
@app.command()
43+
def filter(
44+
ctx: typer.Context,
45+
domain: Annotated[str, typer.Argument(envvar="SWF_DOMAIN")],
46+
status: Annotated[Status, typer.Option("--status", "-s")] = Status.open,
47+
tag: str | None = None,
48+
workflow_id: str | None = None,
49+
run_id: str | None = None,
50+
workflow_type: str | None = None,
51+
workflow_type_version: str | None = None,
52+
close_status: CloseStatus | None = None,
53+
started_since: int = 1,
54+
from_date: Annotated[datetime, typer.Option(formats=TIMESTAMP_FORMATS)] | None = None,
55+
to_date: Annotated[datetime, typer.Option(formats=TIMESTAMP_FORMATS)] | None = None,
56+
):
57+
"""
58+
Filter workflow executions.
59+
"""
60+
status = status.upper()
61+
kwargs: dict[str, Any] = {}
62+
if status == WorkflowExecution.STATUS_OPEN:
63+
if from_date:
64+
kwargs["oldest_date"] = from_date
65+
kwargs["latest_date"] = to_date
66+
else:
67+
kwargs["oldest_date"] = started_since
68+
else:
69+
if from_date:
70+
kwargs["start_oldest_date"] = from_date
71+
kwargs["start_latest_date"] = to_date
72+
else:
73+
kwargs["start_oldest_date"] = started_since
74+
75+
if close_status and status != WorkflowExecution.STATUS_CLOSED:
76+
raise Exception("Closed status not supported for non-closed workflows.")
77+
elif close_status:
78+
kwargs["close_status"] = close_status.upper()
79+
80+
print(
81+
with_format(ctx.parent)(helpers.filter_workflow_executions)(
82+
domain,
83+
status=status.upper(),
84+
tag=tag,
85+
workflow_id=workflow_id,
86+
workflow_type_name=workflow_type,
87+
workflow_type_version=workflow_type_version,
88+
callback=get_progression_callback("executionInfos"),
89+
**kwargs,
90+
)
91+
)
92+
93+
94+
@app.command()
95+
def start(
96+
ctx: typer.Context,
97+
workflow: str,
98+
domain: Annotated[str, typer.Argument(envvar="SWF_DOMAIN")],
99+
input: Annotated[str, typer.Option("--input", "-i", help="input JSON")] | None = None,
100+
):
101+
"""
102+
Start a workflow.
103+
"""
104+
workflow_class = import_from_module(workflow)
105+
wf_input: dict[str, Any] = {}
106+
if input is not None:
107+
json_input = json.loads(input)
108+
if isinstance(json_input, list):
109+
wf_input = {"args": json_input, "kwargs": {}}
110+
elif isinstance(json_input, dict) and ("args" not in json_input or "kwargs" not in json_input):
111+
wf_input = {"args": [], "kwargs": json_input}
112+
else:
113+
wf_input = json_input
114+
workflow_type = get_workflow_type(domain, workflow_class)
115+
set_workflow_class_name(wf_input, workflow_class)
116+
execution = workflow_type.start_execution(
117+
# workflow_id=workflow_id,
118+
# task_list=task_list or workflow_class.task_list,
119+
# execution_timeout=execution_timeout,
120+
input=wf_input,
121+
# tag_list=tags,
122+
# decision_tasks_timeout=decision_tasks_timeout,
123+
)
124+
125+
def get_infos():
126+
return ["workflow_id", "run_id"], [[execution.workflow_id, execution.run_id]]
127+
128+
print(with_format(ctx.parent)(get_infos)())
129+
130+
131+
if __name__ == "__main__":
132+
# from click.core import Command
133+
#
134+
# parent = typer.Context(command=Command(name="main"))
135+
# parent.params["format"] = "json"
136+
# filter(
137+
# ctx=typer.Context(
138+
# command=Command(name="filter"), parent=typer.Context(command=Command(name="main"), parent=parent)
139+
# ),
140+
# domain="TestDomain",
141+
# )
142+
app()

simpleflow/command.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,9 +271,14 @@ def restart_workflow(domain: str, workflow_id: str, run_id: str | None):
271271

272272

273273
def with_format(ctx):
274+
with_header = ctx.parent.params.get("header")
275+
fmt = ctx.parent.params.get("format") or pretty.DEFAULT_FORMAT
276+
if fmt == "prettyjson":
277+
with_header = True
278+
fmt = "json"
274279
return pretty.formatted(
275-
with_header=ctx.parent.params["header"],
276-
fmt=ctx.parent.params["format"] or pretty.DEFAULT_FORMAT,
280+
with_header=with_header,
281+
fmt=fmt,
277282
)
278283

279284

simpleflow/main.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/usr/bin/env python3
2+
from __future__ import annotations
3+
4+
from enum import Enum
5+
6+
import typer
7+
from typing_extensions import Annotated
8+
9+
from simpleflow.cli import workflow
10+
11+
app = typer.Typer(
12+
# add_completion=False,
13+
no_args_is_help=True,
14+
context_settings={"help_option_names": ["--help", "-h"]},
15+
)
16+
17+
app.add_typer(workflow.app, name="workflow", help="Manage workflows")
18+
19+
20+
class Format(str, Enum):
21+
json = "json"
22+
prettyjson = "prettyjson"
23+
csv = "csv"
24+
tsv = "tsv"
25+
tabular = "tabular"
26+
human = "human"
27+
28+
29+
@app.callback()
30+
def main(
31+
ctx: typer.Context,
32+
format: Annotated[Format, typer.Option("--format", "-f", envvar="SIMPLEFLOW_FORMAT")] = Format.json,
33+
):
34+
ctx.params["format"] = format.lower()
35+
36+
37+
# @app.command()
38+
# def main(name: str):
39+
# print(f"Hello {name}")
40+
#
41+
#
42+
# def run(function: Callable[..., Any]) -> None:
43+
# app = Typer(
44+
# # add_completion=False
45+
# )
46+
# app.command(context_settings={"help_option_names": ["-h", "--help"]})(function)
47+
# app()
48+
49+
50+
if __name__ == "__main__":
51+
app()
52+
# run(main)

simpleflow/swf/mapper/models/workflow.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ def start_execution(
251251
:param decision_tasks_timeout: maximum duration of decision tasks
252252
for this workflow execution
253253
"""
254-
workflow_id = workflow_id or f"{self.name}-{self.version}-{time.time():d}"
254+
workflow_id = workflow_id or f"{self.name}-{self.version}-{int(time.time())}"
255255
task_list = task_list or self.task_list
256256
child_policy = child_policy or self.child_policy
257257
if child_policy not in CHILD_POLICIES:

0 commit comments

Comments
 (0)