orchestrator-core 3.1.2rc1__py3-none-any.whl → 3.1.2rc3__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.
- orchestrator/__init__.py +1 -1
- orchestrator/api/api_v1/endpoints/processes.py +23 -0
- orchestrator/services/processes.py +71 -9
- orchestrator/workflow.py +1 -0
- orchestrator_core-3.1.2rc3.dist-info/METADATA +116 -0
- {orchestrator_core-3.1.2rc1.dist-info → orchestrator_core-3.1.2rc3.dist-info}/RECORD +8 -8
- orchestrator_core-3.1.2rc1.dist-info/METADATA +0 -321
- {orchestrator_core-3.1.2rc1.dist-info → orchestrator_core-3.1.2rc3.dist-info}/WHEEL +0 -0
- {orchestrator_core-3.1.2rc1.dist-info → orchestrator_core-3.1.2rc3.dist-info}/licenses/LICENSE +0 -0
orchestrator/__init__.py
CHANGED
|
@@ -58,6 +58,7 @@ from orchestrator.services.processes import (
|
|
|
58
58
|
load_process,
|
|
59
59
|
resume_process,
|
|
60
60
|
start_process,
|
|
61
|
+
update_awaiting_process_progress,
|
|
61
62
|
)
|
|
62
63
|
from orchestrator.services.settings import get_engine_settings
|
|
63
64
|
from orchestrator.settings import app_settings
|
|
@@ -197,6 +198,28 @@ def continue_awaiting_process_endpoint(
|
|
|
197
198
|
raise_status(HTTPStatus.NOT_FOUND, str(e))
|
|
198
199
|
|
|
199
200
|
|
|
201
|
+
@router.post(
|
|
202
|
+
"/{process_id}/callback/{token}/progress",
|
|
203
|
+
response_model=None,
|
|
204
|
+
status_code=HTTPStatus.OK,
|
|
205
|
+
dependencies=[Depends(check_global_lock, use_cache=False)],
|
|
206
|
+
)
|
|
207
|
+
def update_progress_on_awaiting_process_endpoint(
|
|
208
|
+
process_id: UUID,
|
|
209
|
+
token: str,
|
|
210
|
+
data: str | State = Body(...),
|
|
211
|
+
) -> None:
|
|
212
|
+
process = _get_process(process_id)
|
|
213
|
+
|
|
214
|
+
if process.last_status != ProcessStatus.AWAITING_CALLBACK:
|
|
215
|
+
raise_status(HTTPStatus.CONFLICT, "This process is not in an awaiting state.")
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
update_awaiting_process_progress(process, token=token, data=data)
|
|
219
|
+
except AssertionError as exc:
|
|
220
|
+
raise_status(HTTPStatus.NOT_FOUND, str(exc))
|
|
221
|
+
|
|
222
|
+
|
|
200
223
|
@router.put(
|
|
201
224
|
"/resume-all", response_model=ProcessResumeAllSchema, dependencies=[Depends(check_global_lock, use_cache=False)]
|
|
202
225
|
)
|
|
@@ -43,9 +43,10 @@ from orchestrator.targets import Target
|
|
|
43
43
|
from orchestrator.types import BroadcastFunc
|
|
44
44
|
from orchestrator.utils.datetime import nowtz
|
|
45
45
|
from orchestrator.utils.errors import error_state_to_dict
|
|
46
|
-
from orchestrator.websocket import broadcast_invalidate_status_counts
|
|
46
|
+
from orchestrator.websocket import broadcast_invalidate_status_counts, broadcast_process_update_to_websocket
|
|
47
47
|
from orchestrator.workflow import (
|
|
48
48
|
CALLBACK_TOKEN_KEY,
|
|
49
|
+
DEFAULT_CALLBACK_PROGRESS_KEY,
|
|
49
50
|
Failed,
|
|
50
51
|
ProcessStat,
|
|
51
52
|
ProcessStatus,
|
|
@@ -566,6 +567,39 @@ def resume_process(
|
|
|
566
567
|
return resume_func(process, user_inputs=user_inputs, user=user, broadcast_func=broadcast_func)
|
|
567
568
|
|
|
568
569
|
|
|
570
|
+
def ensure_correct_callback_token(pstat: ProcessStat, *, token: str) -> None:
|
|
571
|
+
"""Ensure that a callback token matches the expected value in state.
|
|
572
|
+
|
|
573
|
+
Args:
|
|
574
|
+
pstat: ProcessStat of process.
|
|
575
|
+
token: The token which was generated for the process.
|
|
576
|
+
|
|
577
|
+
Raises:
|
|
578
|
+
AssertionError: if the supplied token does not match the generated process token.
|
|
579
|
+
|
|
580
|
+
"""
|
|
581
|
+
state = pstat.state.unwrap()
|
|
582
|
+
|
|
583
|
+
# Check if the token matches
|
|
584
|
+
token_from_state = state.get(CALLBACK_TOKEN_KEY)
|
|
585
|
+
if token != token_from_state:
|
|
586
|
+
raise AssertionError("Invalid token")
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
def replace_current_step_state(process: ProcessTable, *, new_state: State) -> None:
|
|
590
|
+
"""Replace the state of the current step in a process.
|
|
591
|
+
|
|
592
|
+
Args:
|
|
593
|
+
process: Process from database
|
|
594
|
+
new_state: The new state
|
|
595
|
+
|
|
596
|
+
"""
|
|
597
|
+
current_step = process.steps[-1]
|
|
598
|
+
current_step.state = new_state
|
|
599
|
+
db.session.add(current_step)
|
|
600
|
+
db.session.commit()
|
|
601
|
+
|
|
602
|
+
|
|
569
603
|
def continue_awaiting_process(
|
|
570
604
|
process: ProcessTable,
|
|
571
605
|
*,
|
|
@@ -589,10 +623,7 @@ def continue_awaiting_process(
|
|
|
589
623
|
pstat = load_process(process)
|
|
590
624
|
state = pstat.state.unwrap()
|
|
591
625
|
|
|
592
|
-
|
|
593
|
-
token_from_state = state.get(CALLBACK_TOKEN_KEY)
|
|
594
|
-
if token != token_from_state:
|
|
595
|
-
raise AssertionError("Invalid token")
|
|
626
|
+
ensure_correct_callback_token(pstat, token=token)
|
|
596
627
|
|
|
597
628
|
# We need to pass the callback data to the worker executor. Currently, this is not supported.
|
|
598
629
|
# Therefore, we update the step state in the db and kick-off resume_workflow
|
|
@@ -600,16 +631,47 @@ def continue_awaiting_process(
|
|
|
600
631
|
result_key = state.get("__callback_result_key", "callback_result")
|
|
601
632
|
state = {**state, result_key: input_data}
|
|
602
633
|
|
|
603
|
-
|
|
604
|
-
current_step.state = state
|
|
605
|
-
db.session.add(current_step)
|
|
606
|
-
db.session.commit()
|
|
634
|
+
replace_current_step_state(process, new_state=state)
|
|
607
635
|
|
|
608
636
|
# Continue the workflow
|
|
609
637
|
resume_func = get_execution_context()["resume"]
|
|
610
638
|
return resume_func(process, broadcast_func=broadcast_func)
|
|
611
639
|
|
|
612
640
|
|
|
641
|
+
def update_awaiting_process_progress(
|
|
642
|
+
process: ProcessTable,
|
|
643
|
+
*,
|
|
644
|
+
token: str,
|
|
645
|
+
data: str | State,
|
|
646
|
+
) -> UUID:
|
|
647
|
+
"""Update progress for a process awaiting data from a callback.
|
|
648
|
+
|
|
649
|
+
Args:
|
|
650
|
+
process: Process from database
|
|
651
|
+
token: The token which was generated for the process. This must match.
|
|
652
|
+
data: Progress data posted to the callback
|
|
653
|
+
|
|
654
|
+
Returns:
|
|
655
|
+
process id
|
|
656
|
+
|
|
657
|
+
Raises:
|
|
658
|
+
AssertionError: if the supplied token does not match the generated process token.
|
|
659
|
+
|
|
660
|
+
"""
|
|
661
|
+
pstat = load_process(process)
|
|
662
|
+
|
|
663
|
+
ensure_correct_callback_token(pstat, token=token)
|
|
664
|
+
|
|
665
|
+
state = pstat.state.unwrap()
|
|
666
|
+
progress_key = state.get(DEFAULT_CALLBACK_PROGRESS_KEY, "callback_progress")
|
|
667
|
+
state = {**state, progress_key: data} | {"__remove_keys": [progress_key]}
|
|
668
|
+
|
|
669
|
+
replace_current_step_state(process, new_state=state)
|
|
670
|
+
broadcast_process_update_to_websocket(process.process_id)
|
|
671
|
+
|
|
672
|
+
return process.process_id
|
|
673
|
+
|
|
674
|
+
|
|
613
675
|
async def _async_resume_processes(
|
|
614
676
|
processes: Sequence[ProcessTable],
|
|
615
677
|
user_name: str,
|
orchestrator/workflow.py
CHANGED
|
@@ -69,6 +69,7 @@ step_log_fn_var: contextvars.ContextVar[StepLogFuncInternal] = contextvars.Conte
|
|
|
69
69
|
|
|
70
70
|
DEFAULT_CALLBACK_ROUTE_KEY = "callback_route"
|
|
71
71
|
CALLBACK_TOKEN_KEY = "__callback_token" # noqa: S105
|
|
72
|
+
DEFAULT_CALLBACK_PROGRESS_KEY = "callback_progress" # noqa: S105
|
|
72
73
|
|
|
73
74
|
|
|
74
75
|
@runtime_checkable
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: orchestrator-core
|
|
3
|
+
Version: 3.1.2rc3
|
|
4
|
+
Summary: This is the orchestrator workflow engine.
|
|
5
|
+
Requires-Python: >=3.11,<3.14
|
|
6
|
+
Classifier: Intended Audience :: Information Technology
|
|
7
|
+
Classifier: Intended Audience :: System Administrators
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python
|
|
11
|
+
Classifier: Topic :: Internet
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
15
|
+
Classifier: Topic :: Software Development
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
18
|
+
Classifier: Environment :: Web Environment
|
|
19
|
+
Classifier: Framework :: AsyncIO
|
|
20
|
+
Classifier: Framework :: FastAPI
|
|
21
|
+
Classifier: Intended Audience :: Developers
|
|
22
|
+
Classifier: Intended Audience :: Telecommunications Industry
|
|
23
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
24
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
28
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
29
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: alembic==1.15.1
|
|
32
|
+
Requires-Dist: anyio>=3.7.0
|
|
33
|
+
Requires-Dist: click==8.*
|
|
34
|
+
Requires-Dist: deprecated
|
|
35
|
+
Requires-Dist: deepmerge==2.0
|
|
36
|
+
Requires-Dist: fastapi~=0.115.2
|
|
37
|
+
Requires-Dist: fastapi-etag==0.4.0
|
|
38
|
+
Requires-Dist: more-itertools~=10.6.0
|
|
39
|
+
Requires-Dist: itsdangerous
|
|
40
|
+
Requires-Dist: Jinja2==3.1.6
|
|
41
|
+
Requires-Dist: orjson==3.10.15
|
|
42
|
+
Requires-Dist: psycopg[binary]==3.2.6
|
|
43
|
+
Requires-Dist: pydantic[email]~=2.8.2
|
|
44
|
+
Requires-Dist: pydantic-settings~=2.8.0
|
|
45
|
+
Requires-Dist: python-dateutil==2.8.2
|
|
46
|
+
Requires-Dist: python-rapidjson>=1.18,<1.21
|
|
47
|
+
Requires-Dist: pytz==2025.1
|
|
48
|
+
Requires-Dist: redis==5.1.1
|
|
49
|
+
Requires-Dist: schedule==1.1.0
|
|
50
|
+
Requires-Dist: sentry-sdk[fastapi]~=2.22.0
|
|
51
|
+
Requires-Dist: SQLAlchemy==2.0.39
|
|
52
|
+
Requires-Dist: SQLAlchemy-Utils==0.41.2
|
|
53
|
+
Requires-Dist: structlog
|
|
54
|
+
Requires-Dist: typer==0.15.2
|
|
55
|
+
Requires-Dist: uvicorn[standard]~=0.34.0
|
|
56
|
+
Requires-Dist: nwa-stdlib~=1.9.0
|
|
57
|
+
Requires-Dist: oauth2-lib~=2.4.0
|
|
58
|
+
Requires-Dist: tabulate==0.9.0
|
|
59
|
+
Requires-Dist: strawberry-graphql>=0.246.2
|
|
60
|
+
Requires-Dist: pydantic-forms~=1.4.0
|
|
61
|
+
Requires-Dist: celery~=5.4.0 ; extra == "celery"
|
|
62
|
+
Requires-Dist: toml ; extra == "dev"
|
|
63
|
+
Requires-Dist: bumpversion ; extra == "dev"
|
|
64
|
+
Requires-Dist: mypy_extensions ; extra == "dev"
|
|
65
|
+
Requires-Dist: pre-commit ; extra == "dev"
|
|
66
|
+
Requires-Dist: pydocstyle ; extra == "dev"
|
|
67
|
+
Requires-Dist: python-dotenv ; extra == "dev"
|
|
68
|
+
Requires-Dist: watchdog ; extra == "dev"
|
|
69
|
+
Requires-Dist: mkdocs ; extra == "doc"
|
|
70
|
+
Requires-Dist: mkdocs-material[imaging] ; extra == "doc"
|
|
71
|
+
Requires-Dist: mkdocs-render-swagger-plugin ; extra == "doc"
|
|
72
|
+
Requires-Dist: mkdocs-include-markdown-plugin ; extra == "doc"
|
|
73
|
+
Requires-Dist: mkdocstrings[python] ; extra == "doc"
|
|
74
|
+
Requires-Dist: mkdocs-open-in-new-tab ; extra == "doc"
|
|
75
|
+
Requires-Dist: mkdocs-macros-plugin ; extra == "doc"
|
|
76
|
+
Requires-Dist: mkdocs-embed-external-markdown ; extra == "doc"
|
|
77
|
+
Requires-Dist: apache-license-check ; extra == "test"
|
|
78
|
+
Requires-Dist: black ; extra == "test"
|
|
79
|
+
Requires-Dist: blinker ; extra == "test"
|
|
80
|
+
Requires-Dist: deepdiff ; extra == "test"
|
|
81
|
+
Requires-Dist: dirty-equals ; extra == "test"
|
|
82
|
+
Requires-Dist: jsonref ; extra == "test"
|
|
83
|
+
Requires-Dist: mypy==1.9 ; extra == "test"
|
|
84
|
+
Requires-Dist: pyinstrument ; extra == "test"
|
|
85
|
+
Requires-Dist: pytest==8.3.5 ; extra == "test"
|
|
86
|
+
Requires-Dist: pytest-asyncio==0.21.2 ; extra == "test"
|
|
87
|
+
Requires-Dist: pytest-codspeed ; extra == "test"
|
|
88
|
+
Requires-Dist: pytest-cov ; extra == "test"
|
|
89
|
+
Requires-Dist: pytest-httpx ; extra == "test"
|
|
90
|
+
Requires-Dist: pytest-xdist ; extra == "test"
|
|
91
|
+
Requires-Dist: requests-mock ; extra == "test"
|
|
92
|
+
Requires-Dist: ruff ; extra == "test"
|
|
93
|
+
Requires-Dist: sqlalchemy[mypy] ; extra == "test"
|
|
94
|
+
Requires-Dist: urllib3-mock ; extra == "test"
|
|
95
|
+
Requires-Dist: types-Deprecated ; extra == "test"
|
|
96
|
+
Requires-Dist: types-Jinja2 ; extra == "test"
|
|
97
|
+
Requires-Dist: types-aiofiles ; extra == "test"
|
|
98
|
+
Requires-Dist: types-certifi ; extra == "test"
|
|
99
|
+
Requires-Dist: types-click ; extra == "test"
|
|
100
|
+
Requires-Dist: types-itsdangerous ; extra == "test"
|
|
101
|
+
Requires-Dist: types-orjson ; extra == "test"
|
|
102
|
+
Requires-Dist: types-python-dateutil ; extra == "test"
|
|
103
|
+
Requires-Dist: types-pytz ; extra == "test"
|
|
104
|
+
Requires-Dist: types-redis ; extra == "test"
|
|
105
|
+
Requires-Dist: types-requests ; extra == "test"
|
|
106
|
+
Requires-Dist: types-setuptools ; extra == "test"
|
|
107
|
+
Requires-Dist: types-tabulate ; extra == "test"
|
|
108
|
+
Requires-Dist: types-toml ; extra == "test"
|
|
109
|
+
Requires-Dist: types-ujson ; extra == "test"
|
|
110
|
+
Requires-Dist: types-PyYAML ; extra == "test"
|
|
111
|
+
Project-URL: Documentation, https://workfloworchestrator.org/orchestrator-core/
|
|
112
|
+
Project-URL: Source, https://github.com/workfloworchestrator/orchestrator-core
|
|
113
|
+
Provides-Extra: celery
|
|
114
|
+
Provides-Extra: dev
|
|
115
|
+
Provides-Extra: doc
|
|
116
|
+
Provides-Extra: test
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
orchestrator/__init__.py,sha256=
|
|
1
|
+
orchestrator/__init__.py,sha256=SRujUPF8rKeTg1Ixeu8yyiXCPAlFG-1XYRWLEWtP0SQ,1058
|
|
2
2
|
orchestrator/app.py,sha256=8GMzoHjdR0bkgRBCejiG8nIUjeo43f12I3WNNZ89pKE,11659
|
|
3
3
|
orchestrator/exception_handlers.py,sha256=UsW3dw8q0QQlNLcV359bIotah8DYjMsj2Ts1LfX4ClY,1268
|
|
4
4
|
orchestrator/log_config.py,sha256=1tPRX5q65e57a6a_zEii_PFK8SzWT0mnA5w2sKg4hh8,1853
|
|
@@ -8,7 +8,7 @@ orchestrator/settings.py,sha256=lrNKPtJMxZtbEZcUZ1MDGEpIDCJv_swWVoVJvwcooCY,4614
|
|
|
8
8
|
orchestrator/targets.py,sha256=q_IMCdVUUYWcyKHqyls38fJPveJDBNfSzMKj_U2hLsk,768
|
|
9
9
|
orchestrator/types.py,sha256=4vDeL5teRnugXoet3O2dMv8WwTsEyimrIfzagx9jQRo,15451
|
|
10
10
|
orchestrator/version.py,sha256=b58e08lxs47wUNXv0jXFO_ykpksmytuzEXD4La4W-NQ,1366
|
|
11
|
-
orchestrator/workflow.py,sha256=
|
|
11
|
+
orchestrator/workflow.py,sha256=eQEmi7IwnipDuwCmv1ipYWJbmOuxSG0_nH0-DMfUJog,43117
|
|
12
12
|
orchestrator/api/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n8XzmLU,571
|
|
13
13
|
orchestrator/api/error_handling.py,sha256=YrPCxSa-DSa9KwqIMlXI-KGBGnbGIW5ukOPiikUH9E4,1502
|
|
14
14
|
orchestrator/api/helpers.py,sha256=s0QRHYw8AvEmlkmRhuEzz9xixaZKUF3YuPzUVHkcoXk,6933
|
|
@@ -17,7 +17,7 @@ orchestrator/api/api_v1/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n
|
|
|
17
17
|
orchestrator/api/api_v1/api.py,sha256=Q_Yh9w_SBoyx06jV_kf6leGFrAMXoGjF8UikIAie_us,2858
|
|
18
18
|
orchestrator/api/api_v1/endpoints/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n8XzmLU,571
|
|
19
19
|
orchestrator/api/api_v1/endpoints/health.py,sha256=iaxs1XX1_250_gKNsspuULCV2GEMBjbtjsmfQTOvMAI,1284
|
|
20
|
-
orchestrator/api/api_v1/endpoints/processes.py,sha256=
|
|
20
|
+
orchestrator/api/api_v1/endpoints/processes.py,sha256=l85OZ-gs6YeVjFVsGhq6z_Hwkl-oY5YUagXlgzyivx8,13481
|
|
21
21
|
orchestrator/api/api_v1/endpoints/product_blocks.py,sha256=kZ6ywIOsS_S2qGq7RvZ4KzjvaS1LmwbGWR37AKRvWOw,2146
|
|
22
22
|
orchestrator/api/api_v1/endpoints/products.py,sha256=BfFtwu9dZXEQbtKxYj9icc73GKGvAGMR5ytyf41nQlQ,3081
|
|
23
23
|
orchestrator/api/api_v1/endpoints/resource_types.py,sha256=gGyuaDyOD0TAVoeFGaGmjDGnQ8eQQArOxKrrk4MaDzA,2145
|
|
@@ -248,7 +248,7 @@ orchestrator/services/celery.py,sha256=DHruqocnORNZUca9WDIti9GXYk9Q38BFyeJy7-N7l
|
|
|
248
248
|
orchestrator/services/fixed_inputs.py,sha256=kyz7s2HLzyDulvcq-ZqefTw1om86COvyvTjz0_5CmgI,876
|
|
249
249
|
orchestrator/services/input_state.py,sha256=HF7wl9fWdaAW8pdCCqbuYoKyNj8dY0g8Ff8vXis8z5A,2211
|
|
250
250
|
orchestrator/services/process_broadcast_thread.py,sha256=D44YbjF8mRqGuznkRUV4SoRn1J0lfy_x1H508GnSVlU,4649
|
|
251
|
-
orchestrator/services/processes.py,sha256=
|
|
251
|
+
orchestrator/services/processes.py,sha256=NuxNHaaXc2IlLhMp0rf9-EPgsDjybDCfglQd9wBhOP0,29405
|
|
252
252
|
orchestrator/services/products.py,sha256=w6b6sSA3MstmbM_YN8xWEvkb_YnuCQFph48wYU3_Lx4,1935
|
|
253
253
|
orchestrator/services/resource_types.py,sha256=_QBy_JOW_X3aSTqH0CuLrq4zBJL0p7Q-UDJUcuK2_qc,884
|
|
254
254
|
orchestrator/services/settings.py,sha256=u-834F4KWloXS8zi7R9mp-D3cjl-rbVjKJRU35IqhXo,2723
|
|
@@ -291,7 +291,7 @@ orchestrator/workflows/tasks/resume_workflows.py,sha256=R0I3jxGToiqDr5mF3YjDd6dN
|
|
|
291
291
|
orchestrator/workflows/tasks/validate_product_type.py,sha256=5FwhRQyMNgtys5DM846EIIY0uXKvnSYy3Orf7lOg0DA,3176
|
|
292
292
|
orchestrator/workflows/tasks/validate_products.py,sha256=5uXX7MXMDDP13cXRvfLDNvvCp4nG7zLQBm_IYdf8BSs,8513
|
|
293
293
|
orchestrator/workflows/translations/en-GB.json,sha256=ST53HxkphFLTMjFHonykDBOZ7-P_KxksktZU3GbxLt0,846
|
|
294
|
-
orchestrator_core-3.1.
|
|
295
|
-
orchestrator_core-3.1.
|
|
296
|
-
orchestrator_core-3.1.
|
|
297
|
-
orchestrator_core-3.1.
|
|
294
|
+
orchestrator_core-3.1.2rc3.dist-info/licenses/LICENSE,sha256=b-aA5OZQuuBATmLKo_mln8CQrDPPhg3ghLzjPjLn4Tg,11409
|
|
295
|
+
orchestrator_core-3.1.2rc3.dist-info/WHEEL,sha256=_2ozNFCLWc93bK4WKHCO-eDUENDlo-dgc9cU3qokYO4,82
|
|
296
|
+
orchestrator_core-3.1.2rc3.dist-info/METADATA,sha256=jh6W7fea4ZKjoqBM-q5LM_zvE5F1mgHEwV2_O2qO-mk,4993
|
|
297
|
+
orchestrator_core-3.1.2rc3.dist-info/RECORD,,
|
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: orchestrator-core
|
|
3
|
-
Version: 3.1.2rc1
|
|
4
|
-
Summary: This is the orchestrator workflow engine.
|
|
5
|
-
Author-email: SURF <automation-beheer@surf.nl>
|
|
6
|
-
Requires-Python: >=3.11,<3.14
|
|
7
|
-
Description-Content-Type: text/markdown
|
|
8
|
-
License-Expression: Apache-2.0
|
|
9
|
-
Classifier: Intended Audience :: Information Technology
|
|
10
|
-
Classifier: Intended Audience :: System Administrators
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Programming Language :: Python
|
|
14
|
-
Classifier: Topic :: Internet
|
|
15
|
-
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
16
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
-
Classifier: Topic :: Software Development :: Libraries
|
|
18
|
-
Classifier: Topic :: Software Development
|
|
19
|
-
Classifier: Typing :: Typed
|
|
20
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
21
|
-
Classifier: Environment :: Web Environment
|
|
22
|
-
Classifier: Framework :: AsyncIO
|
|
23
|
-
Classifier: Framework :: FastAPI
|
|
24
|
-
Classifier: Intended Audience :: Developers
|
|
25
|
-
Classifier: Intended Audience :: Telecommunications Industry
|
|
26
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
27
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
28
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
29
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
30
|
-
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
31
|
-
Classifier: Topic :: Internet :: WWW/HTTP
|
|
32
|
-
License-File: LICENSE
|
|
33
|
-
Requires-Dist: alembic==1.15.1
|
|
34
|
-
Requires-Dist: anyio>=3.7.0
|
|
35
|
-
Requires-Dist: click==8.*
|
|
36
|
-
Requires-Dist: deprecated
|
|
37
|
-
Requires-Dist: deepmerge==2.0
|
|
38
|
-
Requires-Dist: fastapi~=0.115.2
|
|
39
|
-
Requires-Dist: fastapi-etag==0.4.0
|
|
40
|
-
Requires-Dist: more-itertools~=10.6.0
|
|
41
|
-
Requires-Dist: itsdangerous
|
|
42
|
-
Requires-Dist: Jinja2==3.1.6
|
|
43
|
-
Requires-Dist: orjson==3.10.15
|
|
44
|
-
Requires-Dist: psycopg[binary]==3.2.6
|
|
45
|
-
Requires-Dist: pydantic[email]~=2.10.6
|
|
46
|
-
Requires-Dist: pydantic-settings~=2.8.0
|
|
47
|
-
Requires-Dist: python-dateutil==2.8.2
|
|
48
|
-
Requires-Dist: python-rapidjson>=1.18,<1.21
|
|
49
|
-
Requires-Dist: pytz==2025.1
|
|
50
|
-
Requires-Dist: redis==5.1.1
|
|
51
|
-
Requires-Dist: schedule==1.1.0
|
|
52
|
-
Requires-Dist: sentry-sdk[fastapi]~=2.22.0
|
|
53
|
-
Requires-Dist: SQLAlchemy==2.0.39
|
|
54
|
-
Requires-Dist: SQLAlchemy-Utils==0.41.2
|
|
55
|
-
Requires-Dist: structlog
|
|
56
|
-
Requires-Dist: typer==0.15.2
|
|
57
|
-
Requires-Dist: uvicorn[standard]~=0.34.0
|
|
58
|
-
Requires-Dist: nwa-stdlib~=1.9.0
|
|
59
|
-
Requires-Dist: oauth2-lib~=2.4.0
|
|
60
|
-
Requires-Dist: tabulate==0.9.0
|
|
61
|
-
Requires-Dist: strawberry-graphql>=0.246.2
|
|
62
|
-
Requires-Dist: pydantic-forms~=1.4.0
|
|
63
|
-
Requires-Dist: celery~=5.4.0 ; extra == "celery"
|
|
64
|
-
Requires-Dist: toml ; extra == "dev"
|
|
65
|
-
Requires-Dist: bumpversion ; extra == "dev"
|
|
66
|
-
Requires-Dist: mypy_extensions ; extra == "dev"
|
|
67
|
-
Requires-Dist: pre-commit ; extra == "dev"
|
|
68
|
-
Requires-Dist: pydocstyle ; extra == "dev"
|
|
69
|
-
Requires-Dist: python-dotenv ; extra == "dev"
|
|
70
|
-
Requires-Dist: watchdog ; extra == "dev"
|
|
71
|
-
Requires-Dist: mkdocs ; extra == "doc"
|
|
72
|
-
Requires-Dist: mkdocs-material[imaging] ; extra == "doc"
|
|
73
|
-
Requires-Dist: mkdocs-render-swagger-plugin ; extra == "doc"
|
|
74
|
-
Requires-Dist: mkdocs-include-markdown-plugin ; extra == "doc"
|
|
75
|
-
Requires-Dist: mkdocstrings[python] ; extra == "doc"
|
|
76
|
-
Requires-Dist: mkdocs-open-in-new-tab ; extra == "doc"
|
|
77
|
-
Requires-Dist: mkdocs-macros-plugin ; extra == "doc"
|
|
78
|
-
Requires-Dist: mkdocs-embed-external-markdown ; extra == "doc"
|
|
79
|
-
Requires-Dist: apache-license-check ; extra == "test"
|
|
80
|
-
Requires-Dist: black ; extra == "test"
|
|
81
|
-
Requires-Dist: blinker ; extra == "test"
|
|
82
|
-
Requires-Dist: deepdiff ; extra == "test"
|
|
83
|
-
Requires-Dist: dirty-equals ; extra == "test"
|
|
84
|
-
Requires-Dist: jsonref ; extra == "test"
|
|
85
|
-
Requires-Dist: mypy==1.9 ; extra == "test"
|
|
86
|
-
Requires-Dist: pyinstrument ; extra == "test"
|
|
87
|
-
Requires-Dist: pytest==8.3.5 ; extra == "test"
|
|
88
|
-
Requires-Dist: pytest-asyncio==0.21.2 ; extra == "test"
|
|
89
|
-
Requires-Dist: pytest-codspeed ; extra == "test"
|
|
90
|
-
Requires-Dist: pytest-cov ; extra == "test"
|
|
91
|
-
Requires-Dist: pytest-httpx ; extra == "test"
|
|
92
|
-
Requires-Dist: pytest-xdist ; extra == "test"
|
|
93
|
-
Requires-Dist: requests-mock ; extra == "test"
|
|
94
|
-
Requires-Dist: ruff ; extra == "test"
|
|
95
|
-
Requires-Dist: sqlalchemy[mypy] ; extra == "test"
|
|
96
|
-
Requires-Dist: urllib3-mock ; extra == "test"
|
|
97
|
-
Requires-Dist: types-Deprecated ; extra == "test"
|
|
98
|
-
Requires-Dist: types-Jinja2 ; extra == "test"
|
|
99
|
-
Requires-Dist: types-aiofiles ; extra == "test"
|
|
100
|
-
Requires-Dist: types-certifi ; extra == "test"
|
|
101
|
-
Requires-Dist: types-click ; extra == "test"
|
|
102
|
-
Requires-Dist: types-itsdangerous ; extra == "test"
|
|
103
|
-
Requires-Dist: types-orjson ; extra == "test"
|
|
104
|
-
Requires-Dist: types-python-dateutil ; extra == "test"
|
|
105
|
-
Requires-Dist: types-pytz ; extra == "test"
|
|
106
|
-
Requires-Dist: types-redis ; extra == "test"
|
|
107
|
-
Requires-Dist: types-requests ; extra == "test"
|
|
108
|
-
Requires-Dist: types-setuptools ; extra == "test"
|
|
109
|
-
Requires-Dist: types-tabulate ; extra == "test"
|
|
110
|
-
Requires-Dist: types-toml ; extra == "test"
|
|
111
|
-
Requires-Dist: types-ujson ; extra == "test"
|
|
112
|
-
Requires-Dist: types-PyYAML ; extra == "test"
|
|
113
|
-
Project-URL: documentation, https://workfloworchestrator.org/orchestrator-core/
|
|
114
|
-
Project-URL: releasenotes, https://github.com/workfloworchestrator/orchestrator-core/releases
|
|
115
|
-
Project-URL: source, https://github.com/workfloworchestrator/orchestrator-core
|
|
116
|
-
Provides-Extra: celery
|
|
117
|
-
Provides-Extra: dev
|
|
118
|
-
Provides-Extra: doc
|
|
119
|
-
Provides-Extra: test
|
|
120
|
-
|
|
121
|
-
# Orchestrator-Core
|
|
122
|
-
[](https://pepy.tech/project/orchestrator-core)
|
|
123
|
-
[](https://codecov.io/gh/workfloworchestrator/orchestrator-core)
|
|
124
|
-
[](https://pypi.org/project/orchestrator-core)
|
|
125
|
-
[](https://pypi.org/project/orchestrator-core)
|
|
126
|
-

|
|
127
|
-
|
|
128
|
-
<p style="text-align: center"><em>Production ready Orchestration Framework to manage product lifecycle and workflows. Easy to use, Built on top of FastAPI</em></p>
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
## Documentation
|
|
132
|
-
Can be found [here](https://workfloworchestrator.org/orchestrator-core/)
|
|
133
|
-
|
|
134
|
-
## Usage
|
|
135
|
-
This project can be installed as follows:
|
|
136
|
-
|
|
137
|
-
#### Step 1:
|
|
138
|
-
Install the core.
|
|
139
|
-
```shell
|
|
140
|
-
pip install orchestrator-core
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
#### Step 2:
|
|
144
|
-
Create a postgres database:
|
|
145
|
-
```shell
|
|
146
|
-
createuser -sP nwa
|
|
147
|
-
createdb orchestrator-core -O nwa
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
#### Step 3 (optional):
|
|
151
|
-
When using multiple workers, you will need a redis server for live updates with websockets.
|
|
152
|
-
|
|
153
|
-
By default it will use memory which works with only one worker.
|
|
154
|
-
```shell
|
|
155
|
-
export WEBSOCKET_BROADCASTER_URL="memory://"
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
For the redis connection you need to set the env variable with the connection url.
|
|
159
|
-
```shell
|
|
160
|
-
export WEBSOCKET_BROADCASTER_URL="redis://localhost:6379"
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
Websockets can also be turned off with:
|
|
165
|
-
```shell
|
|
166
|
-
export ENABLE_WEBSOCKETS=False
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
If you want to use pickle for CACHE serialization you will need to set the `CACHE_HMAC_SECRET`:
|
|
170
|
-
```shell
|
|
171
|
-
export CACHE_HMAC_SECRET="SOMESECRET"
|
|
172
|
-
```
|
|
173
|
-
**NOTE**: The key can be any length. However, the recommended size is 1024 bits.
|
|
174
|
-
|
|
175
|
-
#### Step 4:
|
|
176
|
-
Create a `main.py` file.
|
|
177
|
-
|
|
178
|
-
```python
|
|
179
|
-
from orchestrator import OrchestratorCore
|
|
180
|
-
from orchestrator.cli.main import app as core_cli
|
|
181
|
-
from orchestrator.settings import AppSettings
|
|
182
|
-
|
|
183
|
-
app = OrchestratorCore(base_settings=AppSettings())
|
|
184
|
-
|
|
185
|
-
if __name__ == "__main__":
|
|
186
|
-
core_cli()
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
#### Step 5 (Optional):
|
|
190
|
-
OrchestratorCore comes with a graphql interface that can to be registered after you create your OrchestratorApp.
|
|
191
|
-
If you add it after registering your `SUBSCRIPTION_MODEL_REGISTRY` it will automatically create graphql types for them.
|
|
192
|
-
More info can be found in `docs/architecture/application/graphql.md`
|
|
193
|
-
|
|
194
|
-
example:
|
|
195
|
-
```python
|
|
196
|
-
from orchestrator import OrchestratorCore
|
|
197
|
-
from orchestrator.settings import AppSettings
|
|
198
|
-
|
|
199
|
-
app = OrchestratorCore(base_settings=AppSettings())
|
|
200
|
-
# register SUBSCRIPTION_MODEL_REGISTRY
|
|
201
|
-
app.register_graphql()
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
#### Step 6:
|
|
205
|
-
Initialize the migration environment.
|
|
206
|
-
```shell
|
|
207
|
-
PYTHONPATH=. python main.py db init
|
|
208
|
-
PYTHONPATH=. python main.py db upgrade heads
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### Step 7:
|
|
212
|
-
Profit :)
|
|
213
|
-
|
|
214
|
-
Authentication and authorization are default enabled, to disable set `OAUTH2_ACTIVE` and `OAUTH2_AUTHORIZATION_ACTIVE` to `False`.
|
|
215
|
-
|
|
216
|
-
```shell
|
|
217
|
-
uvicorn --reload --host 127.0.0.1 --port 8080 main:app
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Visit [http://127.0.0.1:8080/api/redoc](http://127.0.0.1:8080/api/redoc) to view the api documentation.
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
## Setting up a development environment
|
|
224
|
-
|
|
225
|
-
To add features to the repository follow the following procedure to setup a working development environment.
|
|
226
|
-
|
|
227
|
-
### Installation (Development standalone)
|
|
228
|
-
Install the project and its dependencies to develop on the code.
|
|
229
|
-
|
|
230
|
-
#### Step 1 - install flit:
|
|
231
|
-
|
|
232
|
-
```shell
|
|
233
|
-
python3 -m venv venv
|
|
234
|
-
source venv/bin/activate
|
|
235
|
-
pip install flit
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
#### Step 2 - install the development code:
|
|
239
|
-
|
|
240
|
-
!!! danger
|
|
241
|
-
Make sure to use the flit binary that is installed in your environment. You can check the correct
|
|
242
|
-
path by running
|
|
243
|
-
```shell
|
|
244
|
-
which flit
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
To be sure that the packages will be installed against the correct venv you can also prepend the python interpreter
|
|
248
|
-
that you want to use:
|
|
249
|
-
|
|
250
|
-
```shell
|
|
251
|
-
flit install --deps develop --symlink --python venv/bin/python
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
### Running tests
|
|
256
|
-
Run the unit-test suite to verify a correct setup.
|
|
257
|
-
|
|
258
|
-
#### Step 1 - Create a database
|
|
259
|
-
|
|
260
|
-
```shell
|
|
261
|
-
createuser -sP nwa
|
|
262
|
-
createdb orchestrator-core-test -O nwa
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
#### Step 2 - Run tests
|
|
266
|
-
```shell
|
|
267
|
-
pytest test/unit_tests
|
|
268
|
-
```
|
|
269
|
-
or with xdist:
|
|
270
|
-
|
|
271
|
-
```shell
|
|
272
|
-
pytest -n auto test/unit_tests
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
If you do not encounter any failures in the test, you should be able to develop features in the orchestrator-core.
|
|
276
|
-
|
|
277
|
-
### Installation (Development symlinked into orchestrator SURF)
|
|
278
|
-
|
|
279
|
-
If you are working on a project that already uses the `orchestrator-core` and you want to test your new core features
|
|
280
|
-
against it, you can use some `flit` magic to symlink the dev version of the core to your project. It will
|
|
281
|
-
automatically replace the pypi dep with a symlink to the development version
|
|
282
|
-
of the core and update/downgrade all required packages in your own orchestrator project.
|
|
283
|
-
|
|
284
|
-
#### Step 1 - install flit:
|
|
285
|
-
|
|
286
|
-
```shell
|
|
287
|
-
python - m venv venv
|
|
288
|
-
source venv/bin/activate
|
|
289
|
-
pip install flit
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### Step 2 - symlink the core to your own project
|
|
293
|
-
|
|
294
|
-
```shell
|
|
295
|
-
flit install --deps develop --symlink --python /path/to/a/orchestrator-project/venv/bin/python
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
So if you have the core and your own orchestrator project repo in the same folder and the main project folder is
|
|
299
|
-
`orchestrator` and you want to use relative links, this will be last step:
|
|
300
|
-
|
|
301
|
-
```shell
|
|
302
|
-
flit install --deps develop --symlink --python ../orchestrator/venv/bin/python
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
# Increasing the version number for a (pre) release.
|
|
306
|
-
|
|
307
|
-
When your PR is accepted you will get a version number.
|
|
308
|
-
|
|
309
|
-
You can do the necessary change with a clean, e.g. every change committed, branch:
|
|
310
|
-
|
|
311
|
-
```shell
|
|
312
|
-
bumpversion patch --new-version 0.4.1-rc3
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
### Changing the Core database schema
|
|
316
|
-
When you would like to change the core database schema, execute the following steps.
|
|
317
|
-
|
|
318
|
-
- Create the new model `orchestrator/database/models.py`
|
|
319
|
-
- `cd orchestrator/migrations`
|
|
320
|
-
- `alembic revision --autogenerate -m "Name of the migratioin"`
|
|
321
|
-
|
|
File without changes
|
{orchestrator_core-3.1.2rc1.dist-info → orchestrator_core-3.1.2rc3.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|