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 CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  """This is the orchestrator workflow engine."""
15
15
 
16
- __version__ = "3.1.2rc1"
16
+ __version__ = "3.1.2rc3"
17
17
 
18
18
  from orchestrator.app import OrchestratorCore
19
19
  from orchestrator.settings import app_settings
@@ -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
- # Check if the token matches
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
- current_step = process.steps[-1]
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=ZP1Jysb045z9lRfVO6EzA1vnZiG_nSFXoDDnIg34onM,1058
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=sdHAuxOsMNzHf3xum-9Lm9FE0OfCm2VcauroOTYn1fw,43051
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=VPNqzogjgK9Y-70b9r-tqPSJD-6PyMj9kOrmhPC__lc,12763
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=pucntLu1f-2ZTgSQG7l3qDX5zQGFhat4-iaq7ecglGo,27618
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.2rc1.dist-info/licenses/LICENSE,sha256=b-aA5OZQuuBATmLKo_mln8CQrDPPhg3ghLzjPjLn4Tg,11409
295
- orchestrator_core-3.1.2rc1.dist-info/WHEEL,sha256=_2ozNFCLWc93bK4WKHCO-eDUENDlo-dgc9cU3qokYO4,82
296
- orchestrator_core-3.1.2rc1.dist-info/METADATA,sha256=y1VUynKBYQow9miuCnXpMg_4VkNQdyODnTBr8X6v-xU,11160
297
- orchestrator_core-3.1.2rc1.dist-info/RECORD,,
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
- [![Downloads](https://pepy.tech/badge/orchestrator-core/month)](https://pepy.tech/project/orchestrator-core)
123
- [![codecov](https://codecov.io/gh/workfloworchestrator/orchestrator-core/branch/main/graph/badge.svg?token=5ANQFI2DHS)](https://codecov.io/gh/workfloworchestrator/orchestrator-core)
124
- [![pypi_version](https://img.shields.io/pypi/v/orchestrator-core?color=%2334D058&label=pypi%20package)](https://pypi.org/project/orchestrator-core)
125
- [![Supported python versions](https://img.shields.io/pypi/pyversions/orchestrator-core.svg?color=%2334D058)](https://pypi.org/project/orchestrator-core)
126
- ![Discord](https://img.shields.io/discord/1295834294270558280?style=flat&logo=discord&label=discord&link=https%3A%2F%2Fdiscord.gg%2FKNgF6gE8)
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
-