orchestrator-core 4.1.0rc2__py3-none-any.whl → 4.2.0rc1__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 +4 -1
- orchestrator/api/api_v1/endpoints/subscriptions.py +25 -2
- orchestrator/cli/generator/templates/create_product.j2 +1 -2
- orchestrator/db/models.py +6 -3
- orchestrator/graphql/schemas/process.py +21 -2
- orchestrator/graphql/schemas/product.py +8 -9
- orchestrator/graphql/schemas/workflow.py +9 -0
- orchestrator/graphql/types.py +7 -1
- orchestrator/migrations/versions/schema/2025-07-01_93fc5834c7e5_changed_timestamping_fields_in_process_steps.py +65 -0
- orchestrator/migrations/versions/schema/2025-07-04_4b58e336d1bf_deprecating_workflow_target_in_.py +30 -0
- orchestrator/schemas/process.py +5 -1
- orchestrator/services/processes.py +11 -2
- orchestrator/utils/enrich_process.py +4 -2
- orchestrator/workflow.py +7 -2
- orchestrator/workflows/modify_note.py +1 -1
- orchestrator/workflows/steps.py +14 -8
- orchestrator/workflows/utils.py +3 -3
- orchestrator_core-4.2.0rc1.dist-info/METADATA +167 -0
- {orchestrator_core-4.1.0rc2.dist-info → orchestrator_core-4.2.0rc1.dist-info}/RECORD +22 -20
- orchestrator_core-4.1.0rc2.dist-info/METADATA +0 -118
- {orchestrator_core-4.1.0rc2.dist-info → orchestrator_core-4.2.0rc1.dist-info}/WHEEL +0 -0
- {orchestrator_core-4.1.0rc2.dist-info → orchestrator_core-4.2.0rc1.dist-info}/licenses/LICENSE +0 -0
orchestrator/__init__.py
CHANGED
|
@@ -158,6 +158,9 @@ def delete(process_id: UUID) -> None:
|
|
|
158
158
|
if not process:
|
|
159
159
|
raise_status(HTTPStatus.NOT_FOUND)
|
|
160
160
|
|
|
161
|
+
if not process.is_task:
|
|
162
|
+
raise_status(HTTPStatus.BAD_REQUEST)
|
|
163
|
+
|
|
161
164
|
db.session.delete(db.session.get(ProcessTable, process_id))
|
|
162
165
|
db.session.commit()
|
|
163
166
|
|
|
@@ -270,7 +273,7 @@ def update_progress_on_awaiting_process_endpoint(
|
|
|
270
273
|
@router.put(
|
|
271
274
|
"/resume-all", response_model=ProcessResumeAllSchema, dependencies=[Depends(check_global_lock, use_cache=False)]
|
|
272
275
|
)
|
|
273
|
-
async def
|
|
276
|
+
async def resume_all_processes_endpoint(request: Request, user: str = Depends(user_name)) -> dict[str, int]:
|
|
274
277
|
"""Retry all task processes in status Failed, Waiting, API Unavailable or Inconsistent Data.
|
|
275
278
|
|
|
276
279
|
The retry is started in the background, returning status 200 and number of processes in message.
|
|
@@ -47,10 +47,12 @@ from orchestrator.services.subscriptions import (
|
|
|
47
47
|
subscription_workflows,
|
|
48
48
|
)
|
|
49
49
|
from orchestrator.settings import app_settings
|
|
50
|
+
from orchestrator.targets import Target
|
|
50
51
|
from orchestrator.types import SubscriptionLifecycle
|
|
51
52
|
from orchestrator.utils.deprecation_logger import deprecated_endpoint
|
|
52
53
|
from orchestrator.utils.get_subscription_dict import get_subscription_dict
|
|
53
54
|
from orchestrator.websocket import sync_invalidate_subscription_cache
|
|
55
|
+
from orchestrator.workflows import get_workflow
|
|
54
56
|
|
|
55
57
|
router = APIRouter()
|
|
56
58
|
|
|
@@ -100,6 +102,25 @@ def _filter_statuses(filter_statuses: str | None = None) -> list[str]:
|
|
|
100
102
|
return statuses
|
|
101
103
|
|
|
102
104
|
|
|
105
|
+
def _authorized_subscription_workflows(
|
|
106
|
+
subscription: SubscriptionTable, current_user: OIDCUserModel | None
|
|
107
|
+
) -> dict[str, list[dict[str, list[Any] | str]]]:
|
|
108
|
+
subscription_workflows_dict = subscription_workflows(subscription)
|
|
109
|
+
|
|
110
|
+
for workflow_target in Target.values():
|
|
111
|
+
for workflow_dict in subscription_workflows_dict[workflow_target.lower()]:
|
|
112
|
+
workflow = get_workflow(workflow_dict["name"])
|
|
113
|
+
if not workflow:
|
|
114
|
+
continue
|
|
115
|
+
if (
|
|
116
|
+
not workflow.authorize_callback(current_user) # The current user isn't allowed to run this workflow
|
|
117
|
+
and "reason" not in workflow_dict # and there isn't already a reason why this workflow cannot run
|
|
118
|
+
):
|
|
119
|
+
workflow_dict["reason"] = "subscription.insufficient_workflow_permissions"
|
|
120
|
+
|
|
121
|
+
return subscription_workflows_dict
|
|
122
|
+
|
|
123
|
+
|
|
103
124
|
@router.get(
|
|
104
125
|
"/domain-model/{subscription_id}",
|
|
105
126
|
response_model=SubscriptionDomainModelSchema | None,
|
|
@@ -169,7 +190,9 @@ def subscriptions_search(
|
|
|
169
190
|
description="This endpoint is deprecated and will be removed in a future release. Please use the GraphQL query",
|
|
170
191
|
dependencies=[Depends(deprecated_endpoint)],
|
|
171
192
|
)
|
|
172
|
-
def subscription_workflows_by_id(
|
|
193
|
+
def subscription_workflows_by_id(
|
|
194
|
+
subscription_id: UUID, current_user: OIDCUserModel | None = Depends(authenticate)
|
|
195
|
+
) -> dict[str, list[dict[str, list[Any] | str]]]:
|
|
173
196
|
subscription = db.session.get(
|
|
174
197
|
SubscriptionTable,
|
|
175
198
|
subscription_id,
|
|
@@ -181,7 +204,7 @@ def subscription_workflows_by_id(subscription_id: UUID) -> dict[str, list[dict[s
|
|
|
181
204
|
if not subscription:
|
|
182
205
|
raise_status(HTTPStatus.NOT_FOUND)
|
|
183
206
|
|
|
184
|
-
return
|
|
207
|
+
return _authorized_subscription_workflows(subscription, current_user)
|
|
185
208
|
|
|
186
209
|
|
|
187
210
|
@router.put("/{subscription_id}/set_in_sync", response_model=None, status_code=HTTPStatus.OK)
|
|
@@ -11,7 +11,6 @@ from pydantic_forms.types import FormGenerator, State, UUIDstr
|
|
|
11
11
|
|
|
12
12
|
from orchestrator.forms import FormPage
|
|
13
13
|
from orchestrator.forms.validators import Divider, Label, CustomerId, MigrationSummary
|
|
14
|
-
from orchestrator.targets import Target
|
|
15
14
|
from orchestrator.types import SubscriptionLifecycle
|
|
16
15
|
from orchestrator.workflow import StepList, begin, step
|
|
17
16
|
from orchestrator.workflows.steps import store_process_subscription
|
|
@@ -119,6 +118,6 @@ def create_{{ product.variable }}() -> StepList:
|
|
|
119
118
|
return (
|
|
120
119
|
begin
|
|
121
120
|
>> construct_{{ product.variable }}_model
|
|
122
|
-
>> store_process_subscription(
|
|
121
|
+
>> store_process_subscription()
|
|
123
122
|
# TODO add provision step(s)
|
|
124
123
|
)
|
orchestrator/db/models.py
CHANGED
|
@@ -117,7 +117,7 @@ class ProcessTable(BaseModel):
|
|
|
117
117
|
is_task = mapped_column(Boolean, nullable=False, server_default=text("false"), index=True)
|
|
118
118
|
|
|
119
119
|
steps = relationship(
|
|
120
|
-
"ProcessStepTable", cascade="delete", passive_deletes=True, order_by="asc(ProcessStepTable.
|
|
120
|
+
"ProcessStepTable", cascade="delete", passive_deletes=True, order_by="asc(ProcessStepTable.completed_at)"
|
|
121
121
|
)
|
|
122
122
|
input_states = relationship("InputStateTable", cascade="delete", order_by="desc(InputStateTable.input_time)")
|
|
123
123
|
process_subscriptions = relationship("ProcessSubscriptionTable", back_populates="process", passive_deletes=True)
|
|
@@ -141,7 +141,8 @@ class ProcessStepTable(BaseModel):
|
|
|
141
141
|
status = mapped_column(String(50), nullable=False)
|
|
142
142
|
state = mapped_column(pg.JSONB(), nullable=False)
|
|
143
143
|
created_by = mapped_column(String(255), nullable=True)
|
|
144
|
-
|
|
144
|
+
completed_at = mapped_column(UtcTimestamp, server_default=text("statement_timestamp()"), nullable=False)
|
|
145
|
+
started_at = mapped_column(UtcTimestamp, server_default=text("statement_timestamp()"), nullable=False)
|
|
145
146
|
commit_hash = mapped_column(String(40), nullable=True, default=GIT_COMMIT_HASH)
|
|
146
147
|
|
|
147
148
|
|
|
@@ -154,7 +155,9 @@ class ProcessSubscriptionTable(BaseModel):
|
|
|
154
155
|
)
|
|
155
156
|
subscription_id = mapped_column(UUIDType, ForeignKey("subscriptions.subscription_id"), nullable=False, index=True)
|
|
156
157
|
created_at = mapped_column(UtcTimestamp, server_default=text("current_timestamp()"), nullable=False)
|
|
157
|
-
|
|
158
|
+
|
|
159
|
+
# FIXME: workflow_target is already stored in the workflow table, this column should get removed in a later release.
|
|
160
|
+
workflow_target = mapped_column(String(255), nullable=True)
|
|
158
161
|
|
|
159
162
|
process = relationship("ProcessTable", back_populates="process_subscriptions")
|
|
160
163
|
subscription = relationship("SubscriptionTable", back_populates="processes")
|
|
@@ -6,14 +6,17 @@ from strawberry.federation.schema_directives import Key
|
|
|
6
6
|
from strawberry.scalars import JSON
|
|
7
7
|
|
|
8
8
|
from oauth2_lib.strawberry import authenticated_field
|
|
9
|
+
from orchestrator.api.api_v1.endpoints.processes import get_auth_callbacks, get_current_steps
|
|
9
10
|
from orchestrator.db import ProcessTable, ProductTable, db
|
|
10
11
|
from orchestrator.graphql.pagination import EMPTY_PAGE, Connection
|
|
11
12
|
from orchestrator.graphql.schemas.customer import CustomerType
|
|
12
13
|
from orchestrator.graphql.schemas.helpers import get_original_model
|
|
13
14
|
from orchestrator.graphql.schemas.product import ProductType
|
|
14
|
-
from orchestrator.graphql.types import GraphqlFilter, GraphqlSort, OrchestratorInfo
|
|
15
|
+
from orchestrator.graphql.types import FormUserPermissionsType, GraphqlFilter, GraphqlSort, OrchestratorInfo
|
|
15
16
|
from orchestrator.schemas.process import ProcessSchema, ProcessStepSchema
|
|
17
|
+
from orchestrator.services.processes import load_process
|
|
16
18
|
from orchestrator.settings import app_settings
|
|
19
|
+
from orchestrator.workflows import get_workflow
|
|
17
20
|
|
|
18
21
|
if TYPE_CHECKING:
|
|
19
22
|
from orchestrator.graphql.schemas.subscription import SubscriptionInterface
|
|
@@ -29,7 +32,11 @@ class ProcessStepType:
|
|
|
29
32
|
name: strawberry.auto
|
|
30
33
|
status: strawberry.auto
|
|
31
34
|
created_by: strawberry.auto
|
|
32
|
-
executed: strawberry.auto
|
|
35
|
+
executed: strawberry.auto = strawberry.field(
|
|
36
|
+
deprecation_reason="Deprecated, use 'started' and 'completed' for step start and completion times"
|
|
37
|
+
)
|
|
38
|
+
started: strawberry.auto
|
|
39
|
+
completed: strawberry.auto
|
|
33
40
|
commit_hash: strawberry.auto
|
|
34
41
|
state: JSON | None
|
|
35
42
|
state_delta: JSON | None
|
|
@@ -74,6 +81,18 @@ class ProcessType:
|
|
|
74
81
|
shortcode=app_settings.DEFAULT_CUSTOMER_SHORTCODE,
|
|
75
82
|
)
|
|
76
83
|
|
|
84
|
+
@strawberry.field(description="Returns user permissions for operations on this process") # type: ignore
|
|
85
|
+
def user_permissions(self, info: OrchestratorInfo) -> FormUserPermissionsType:
|
|
86
|
+
oidc_user = info.context.get_current_user
|
|
87
|
+
workflow = get_workflow(self.workflow_name)
|
|
88
|
+
process = load_process(db.session.get(ProcessTable, self.process_id)) # type: ignore[arg-type]
|
|
89
|
+
auth_resume, auth_retry = get_auth_callbacks(get_current_steps(process), workflow) # type: ignore[arg-type]
|
|
90
|
+
|
|
91
|
+
return FormUserPermissionsType(
|
|
92
|
+
retryAllowed=auth_retry and auth_retry(oidc_user), # type: ignore[arg-type]
|
|
93
|
+
resumeAllowed=auth_resume and auth_resume(oidc_user), # type: ignore[arg-type]
|
|
94
|
+
)
|
|
95
|
+
|
|
77
96
|
@authenticated_field(description="Returns list of subscriptions of the process") # type: ignore
|
|
78
97
|
async def subscriptions(
|
|
79
98
|
self,
|
|
@@ -52,21 +52,20 @@ class ProductType:
|
|
|
52
52
|
return await resolve_subscriptions(info, filter_by_with_related_subscriptions, sort_by, first, after)
|
|
53
53
|
|
|
54
54
|
@strawberry.field(description="Returns list of all nested productblock names") # type: ignore
|
|
55
|
-
async def
|
|
56
|
-
|
|
55
|
+
async def all_product_block_names(self) -> list[str]:
|
|
57
56
|
model = get_original_model(self, ProductTable)
|
|
58
57
|
|
|
59
|
-
def
|
|
58
|
+
def get_names(product_blocks: list[ProductBlockTable], visited: set) -> Iterable[str]:
|
|
60
59
|
for product_block in product_blocks:
|
|
60
|
+
if product_block.product_block_id in visited:
|
|
61
|
+
continue
|
|
62
|
+
visited.add(product_block.product_block_id)
|
|
61
63
|
yield product_block.name
|
|
62
|
-
|
|
63
64
|
if product_block.depends_on:
|
|
64
|
-
yield from
|
|
65
|
-
|
|
66
|
-
names: list[str] = list(get_all_pb_names(model.product_blocks))
|
|
67
|
-
names.sort()
|
|
65
|
+
yield from get_names(product_block.depends_on, visited)
|
|
68
66
|
|
|
69
|
-
|
|
67
|
+
names = set(get_names(model.product_blocks, set()))
|
|
68
|
+
return sorted(names)
|
|
70
69
|
|
|
71
70
|
@strawberry.field(description="Return product blocks") # type: ignore
|
|
72
71
|
async def product_blocks(self) -> list[Annotated["ProductBlock", strawberry.lazy(".product_block")]]:
|
|
@@ -5,6 +5,7 @@ import strawberry
|
|
|
5
5
|
from orchestrator.config.assignee import Assignee
|
|
6
6
|
from orchestrator.db import WorkflowTable
|
|
7
7
|
from orchestrator.graphql.schemas.helpers import get_original_model
|
|
8
|
+
from orchestrator.graphql.types import OrchestratorInfo
|
|
8
9
|
from orchestrator.schemas import StepSchema, WorkflowSchema
|
|
9
10
|
from orchestrator.workflows import get_workflow
|
|
10
11
|
|
|
@@ -30,3 +31,11 @@ class Workflow:
|
|
|
30
31
|
@strawberry.field(description="Return all steps for this workflow") # type: ignore
|
|
31
32
|
def steps(self) -> list[Step]:
|
|
32
33
|
return [Step(name=step.name, assignee=step.assignee) for step in get_workflow(self.name).steps] # type: ignore
|
|
34
|
+
|
|
35
|
+
@strawberry.field(description="Return whether the currently logged-in used is allowed to start this workflow") # type: ignore
|
|
36
|
+
def is_allowed(self, info: OrchestratorInfo) -> bool:
|
|
37
|
+
oidc_user = info.context.get_current_user
|
|
38
|
+
workflow_table = get_original_model(self, WorkflowTable)
|
|
39
|
+
workflow = get_workflow(workflow_table.name)
|
|
40
|
+
|
|
41
|
+
return workflow.authorize_callback(oidc_user) # type: ignore
|
orchestrator/graphql/types.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2022-
|
|
1
|
+
# Copyright 2022-2025 SURF, GÉANT.
|
|
2
2
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
3
|
# you may not use this file except in compliance with the License.
|
|
4
4
|
# You may obtain a copy of the License at
|
|
@@ -132,6 +132,12 @@ SCALAR_OVERRIDES: ScalarOverrideType = {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
|
|
135
|
+
@strawberry.type(description="User permissions on a specific process")
|
|
136
|
+
class FormUserPermissionsType:
|
|
137
|
+
retryAllowed: bool
|
|
138
|
+
resumeAllowed: bool
|
|
139
|
+
|
|
140
|
+
|
|
135
141
|
@strawberry.type(description="Generic class to capture errors")
|
|
136
142
|
class MutationError:
|
|
137
143
|
message: str = strawberry.field(description="Error message")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Changed timestamping fields in process_steps.
|
|
2
|
+
|
|
3
|
+
Revision ID: 93fc5834c7e5
|
|
4
|
+
Revises: 4b58e336d1bf
|
|
5
|
+
Create Date: 2025-07-01 14:20:44.755694
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
from alembic import op
|
|
11
|
+
|
|
12
|
+
from orchestrator import db
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision = "93fc5834c7e5"
|
|
16
|
+
down_revision = "4b58e336d1bf"
|
|
17
|
+
branch_labels = None
|
|
18
|
+
depends_on = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade() -> None:
|
|
22
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
23
|
+
op.add_column(
|
|
24
|
+
"process_steps",
|
|
25
|
+
sa.Column(
|
|
26
|
+
"started_at",
|
|
27
|
+
db.UtcTimestamp(timezone=True),
|
|
28
|
+
server_default=sa.text("statement_timestamp()"),
|
|
29
|
+
nullable=False,
|
|
30
|
+
),
|
|
31
|
+
)
|
|
32
|
+
op.alter_column("process_steps", "executed_at", new_column_name="completed_at")
|
|
33
|
+
# conn = op.get_bind()
|
|
34
|
+
# sa.select
|
|
35
|
+
# ### end Alembic commands ###
|
|
36
|
+
# Backfill started_at field correctly using proper aliasing
|
|
37
|
+
op.execute(
|
|
38
|
+
"""
|
|
39
|
+
WITH backfill_started_at AS (
|
|
40
|
+
SELECT
|
|
41
|
+
ps1.stepid,
|
|
42
|
+
COALESCE(prev.completed_at, p.started_at) AS new_started_at
|
|
43
|
+
FROM process_steps ps1
|
|
44
|
+
JOIN processes p ON ps1.pid = p.pid
|
|
45
|
+
LEFT JOIN LATERAL (
|
|
46
|
+
SELECT ps2.completed_at
|
|
47
|
+
FROM process_steps ps2
|
|
48
|
+
WHERE ps2.pid = ps1.pid AND ps2.completed_at < ps1.completed_at
|
|
49
|
+
ORDER BY ps2.completed_at DESC
|
|
50
|
+
LIMIT 1
|
|
51
|
+
) prev ON true
|
|
52
|
+
)
|
|
53
|
+
UPDATE process_steps
|
|
54
|
+
SET started_at = b.new_started_at
|
|
55
|
+
FROM backfill_started_at b
|
|
56
|
+
WHERE process_steps.stepid = b.stepid;
|
|
57
|
+
"""
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def downgrade() -> None:
|
|
62
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
63
|
+
op.drop_column("process_steps", "started_at")
|
|
64
|
+
op.alter_column("process_steps", "completed_at", new_column_name="executed_at")
|
|
65
|
+
# ### end Alembic commands ###
|
orchestrator/migrations/versions/schema/2025-07-04_4b58e336d1bf_deprecating_workflow_target_in_.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Deprecating workflow target in ProcessSubscriptionTable.
|
|
2
|
+
|
|
3
|
+
Revision ID: 4b58e336d1bf
|
|
4
|
+
Revises: 161918133bec
|
|
5
|
+
Create Date: 2025-07-04 15:27:23.814954
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
from alembic import op
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = "4b58e336d1bf"
|
|
14
|
+
down_revision = "161918133bec"
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade() -> None:
|
|
20
|
+
op.alter_column("processes_subscriptions", "workflow_target", existing_type=sa.VARCHAR(length=255), nullable=True)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def downgrade() -> None:
|
|
24
|
+
op.alter_column(
|
|
25
|
+
"processes_subscriptions",
|
|
26
|
+
"workflow_target",
|
|
27
|
+
existing_type=sa.VARCHAR(length=255),
|
|
28
|
+
nullable=False,
|
|
29
|
+
existing_server_default=sa.text("'CREATE'::character varying"),
|
|
30
|
+
)
|
orchestrator/schemas/process.py
CHANGED
|
@@ -49,7 +49,11 @@ class ProcessStepSchema(OrchestratorBaseModel):
|
|
|
49
49
|
name: str
|
|
50
50
|
status: str
|
|
51
51
|
created_by: str | None = None
|
|
52
|
-
executed: datetime | None =
|
|
52
|
+
executed: datetime | None = Field(
|
|
53
|
+
None, deprecated="Deprecated, use 'started' and 'completed' for step start and completion times"
|
|
54
|
+
)
|
|
55
|
+
started: datetime | None = None
|
|
56
|
+
completed: datetime | None = None
|
|
53
57
|
commit_hash: str | None = None
|
|
54
58
|
state: dict[str, Any] | None = None
|
|
55
59
|
state_delta: dict[str, Any] | None = None
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
from collections.abc import Callable, Sequence
|
|
14
14
|
from concurrent.futures.thread import ThreadPoolExecutor
|
|
15
|
+
from datetime import datetime
|
|
15
16
|
from functools import partial
|
|
16
17
|
from http import HTTPStatus
|
|
17
18
|
from typing import Any
|
|
@@ -19,6 +20,7 @@ from uuid import UUID, uuid4
|
|
|
19
20
|
|
|
20
21
|
import structlog
|
|
21
22
|
from deepmerge.merger import Merger
|
|
23
|
+
from pytz import utc
|
|
22
24
|
from sqlalchemy import delete, select
|
|
23
25
|
from sqlalchemy.exc import SQLAlchemyError
|
|
24
26
|
from sqlalchemy.orm import joinedload
|
|
@@ -206,6 +208,10 @@ def _get_current_step_to_update(
|
|
|
206
208
|
finally:
|
|
207
209
|
step_state.pop("__remove_keys", None)
|
|
208
210
|
|
|
211
|
+
# We don't have __last_step_started in __remove_keys because the way __remove_keys is populated appears like it would overwrite
|
|
212
|
+
# what's put there in the step decorator in certain cases (step groups and callback steps)
|
|
213
|
+
step_start_time = step_state.pop("__last_step_started_at", None)
|
|
214
|
+
|
|
209
215
|
if process_state.isfailed() or process_state.iswaiting():
|
|
210
216
|
if (
|
|
211
217
|
last_db_step is not None
|
|
@@ -216,7 +222,7 @@ def _get_current_step_to_update(
|
|
|
216
222
|
):
|
|
217
223
|
state_ex_info = {
|
|
218
224
|
"retries": last_db_step.state.get("retries", 0) + 1,
|
|
219
|
-
"
|
|
225
|
+
"completed_at": last_db_step.state.get("completed_at", []) + [str(last_db_step.completed_at)],
|
|
220
226
|
}
|
|
221
227
|
|
|
222
228
|
# write new state info and execution date
|
|
@@ -236,10 +242,13 @@ def _get_current_step_to_update(
|
|
|
236
242
|
state=step_state,
|
|
237
243
|
created_by=stat.current_user,
|
|
238
244
|
)
|
|
245
|
+
# Since the Start step does not have a __last_step_started_at in it's state, we effectively assume it is instantaneous.
|
|
246
|
+
now = nowtz()
|
|
247
|
+
current_step.started_at = datetime.fromtimestamp(step_start_time or now.timestamp(), tz=utc)
|
|
239
248
|
|
|
240
249
|
# Always explicitly set this instead of leaving it to the database to prevent failing tests
|
|
241
250
|
# Test will fail if multiple steps have the same timestamp
|
|
242
|
-
current_step.
|
|
251
|
+
current_step.completed_at = now
|
|
243
252
|
return current_step
|
|
244
253
|
|
|
245
254
|
|
|
@@ -57,7 +57,9 @@ def enrich_step_details(step: ProcessStepTable, previous_step: ProcessStepTable
|
|
|
57
57
|
|
|
58
58
|
return {
|
|
59
59
|
"name": step.name,
|
|
60
|
-
"executed": step.
|
|
60
|
+
"executed": step.completed_at.timestamp(),
|
|
61
|
+
"started": step.started_at.timestamp(),
|
|
62
|
+
"completed": step.completed_at.timestamp(),
|
|
61
63
|
"status": step.status,
|
|
62
64
|
"state": step.state,
|
|
63
65
|
"created_by": step.created_by,
|
|
@@ -103,7 +105,7 @@ def enrich_process(process: ProcessTable, p_stat: ProcessStat | None = None) ->
|
|
|
103
105
|
"is_task": process.is_task,
|
|
104
106
|
"workflow_id": process.workflow_id,
|
|
105
107
|
"workflow_name": process.workflow.name,
|
|
106
|
-
"workflow_target": process.
|
|
108
|
+
"workflow_target": process.workflow.target,
|
|
107
109
|
"failed_reason": process.failed_reason,
|
|
108
110
|
"created_by": process.created_by,
|
|
109
111
|
"started_at": process.started_at,
|
orchestrator/workflow.py
CHANGED
|
@@ -46,6 +46,7 @@ from orchestrator.services.settings import get_engine_settings
|
|
|
46
46
|
from orchestrator.targets import Target
|
|
47
47
|
from orchestrator.types import ErrorDict, StepFunc
|
|
48
48
|
from orchestrator.utils.auth import Authorizer
|
|
49
|
+
from orchestrator.utils.datetime import nowtz
|
|
49
50
|
from orchestrator.utils.docs import make_workflow_doc
|
|
50
51
|
from orchestrator.utils.errors import error_state_to_dict
|
|
51
52
|
from orchestrator.utils.state import form_inject_args, inject_args
|
|
@@ -381,11 +382,13 @@ def step_group(name: str, steps: StepList, extract_form: bool = True) -> Step:
|
|
|
381
382
|
p = p.map(lambda s: s | {"__replace_last_state": True})
|
|
382
383
|
return step_log_fn(step_, p)
|
|
383
384
|
|
|
385
|
+
step_group_start_time = nowtz().timestamp()
|
|
384
386
|
process: Process = Success(initial_state)
|
|
385
387
|
process = _exec_steps(step_list, process, dblogstep)
|
|
386
|
-
|
|
387
388
|
# Add instruction to replace state of last sub step before returning process _exec_steps higher in the call tree
|
|
388
|
-
return process.map(
|
|
389
|
+
return process.map(
|
|
390
|
+
lambda s: s | {"__replace_last_state": True, "__last_step_started_at": step_group_start_time}
|
|
391
|
+
)
|
|
389
392
|
|
|
390
393
|
# Make sure we return a form is a sub step has a form
|
|
391
394
|
form = next((sub_step.form for sub_step in steps if sub_step.form), None) if extract_form else None
|
|
@@ -1454,6 +1457,8 @@ def _exec_steps(steps: StepList, starting_process: Process, dblogstep: StepLogFu
|
|
|
1454
1457
|
"Not executing Step as the workflow engine is Paused. Process will remain in state 'running'"
|
|
1455
1458
|
)
|
|
1456
1459
|
return process
|
|
1460
|
+
|
|
1461
|
+
process = process.map(lambda s: s | {"__last_step_started_at": nowtz().timestamp()})
|
|
1457
1462
|
step_result_process = process.execute_step(step)
|
|
1458
1463
|
except Exception as e:
|
|
1459
1464
|
consolelogger.error("An exception occurred while executing the workflow step.")
|
|
@@ -53,4 +53,4 @@ def store_subscription_note(subscription_id: UUIDstr, note: str) -> State:
|
|
|
53
53
|
|
|
54
54
|
@workflow("Modify Note", initial_input_form=wrap_modify_initial_input_form(initial_input_form), target=Target.MODIFY)
|
|
55
55
|
def modify_note() -> StepList:
|
|
56
|
-
return init >> store_process_subscription(
|
|
56
|
+
return init >> store_process_subscription() >> store_subscription_note >> done
|
orchestrator/workflows/steps.py
CHANGED
|
@@ -23,6 +23,7 @@ from orchestrator.services.subscriptions import get_subscription
|
|
|
23
23
|
from orchestrator.targets import Target
|
|
24
24
|
from orchestrator.types import SubscriptionLifecycle
|
|
25
25
|
from orchestrator.utils.json import to_serializable
|
|
26
|
+
from orchestrator.websocket import sync_invalidate_subscription_cache
|
|
26
27
|
from orchestrator.workflow import Step, step
|
|
27
28
|
from pydantic_forms.types import State, UUIDstr
|
|
28
29
|
|
|
@@ -33,6 +34,7 @@ logger = structlog.get_logger(__name__)
|
|
|
33
34
|
def resync(subscription: SubscriptionModel) -> State:
|
|
34
35
|
"""Transition a subscription to in sync."""
|
|
35
36
|
subscription.insync = True
|
|
37
|
+
sync_invalidate_subscription_cache(subscription.subscription_id)
|
|
36
38
|
return {"subscription": subscription}
|
|
37
39
|
|
|
38
40
|
|
|
@@ -93,6 +95,7 @@ def unsync(subscription_id: UUIDstr, __old_subscriptions__: dict | None = None)
|
|
|
93
95
|
if not subscription.insync:
|
|
94
96
|
raise ValueError("Subscription is already out of sync, cannot continue!")
|
|
95
97
|
subscription.insync = False
|
|
98
|
+
sync_invalidate_subscription_cache(subscription.subscription_id)
|
|
96
99
|
|
|
97
100
|
return {"subscription": subscription, "__old_subscriptions__": subscription_backup}
|
|
98
101
|
|
|
@@ -105,20 +108,23 @@ def unsync_unchecked(subscription_id: UUIDstr) -> State:
|
|
|
105
108
|
return {"subscription": subscription}
|
|
106
109
|
|
|
107
110
|
|
|
108
|
-
def store_process_subscription_relationship(
|
|
109
|
-
process_id
|
|
110
|
-
) -> ProcessSubscriptionTable:
|
|
111
|
-
process_subscription = ProcessSubscriptionTable(
|
|
112
|
-
process_id=process_id, subscription_id=subscription_id, workflow_target=workflow_target
|
|
113
|
-
)
|
|
111
|
+
def store_process_subscription_relationship(process_id: UUIDstr, subscription_id: UUIDstr) -> ProcessSubscriptionTable:
|
|
112
|
+
process_subscription = ProcessSubscriptionTable(process_id=process_id, subscription_id=subscription_id)
|
|
114
113
|
db.session.add(process_subscription)
|
|
115
114
|
return process_subscription
|
|
116
115
|
|
|
117
116
|
|
|
118
|
-
def store_process_subscription(workflow_target: Target) -> Step:
|
|
117
|
+
def store_process_subscription(workflow_target: Target | None = None) -> Step:
|
|
118
|
+
if workflow_target:
|
|
119
|
+
deprecation_warning = (
|
|
120
|
+
"Providing a workflow target to function store_process_subscription() is deprecated. "
|
|
121
|
+
"This information is already stored in the workflow table."
|
|
122
|
+
)
|
|
123
|
+
logger.warning(deprecation_warning)
|
|
124
|
+
|
|
119
125
|
@step("Create Process Subscription relation")
|
|
120
126
|
def _store_process_subscription(process_id: UUIDstr, subscription_id: UUIDstr) -> None:
|
|
121
|
-
store_process_subscription_relationship(process_id, subscription_id
|
|
127
|
+
store_process_subscription_relationship(process_id, subscription_id)
|
|
122
128
|
|
|
123
129
|
return _store_process_subscription
|
|
124
130
|
|
orchestrator/workflows/utils.py
CHANGED
|
@@ -265,7 +265,7 @@ def modify_workflow(
|
|
|
265
265
|
def _modify_workflow(f: Callable[[], StepList]) -> Workflow:
|
|
266
266
|
steplist = (
|
|
267
267
|
init
|
|
268
|
-
>> store_process_subscription(
|
|
268
|
+
>> store_process_subscription()
|
|
269
269
|
>> unsync
|
|
270
270
|
>> f()
|
|
271
271
|
>> (additional_steps or StepList())
|
|
@@ -311,7 +311,7 @@ def terminate_workflow(
|
|
|
311
311
|
def _terminate_workflow(f: Callable[[], StepList]) -> Workflow:
|
|
312
312
|
steplist = (
|
|
313
313
|
init
|
|
314
|
-
>> store_process_subscription(
|
|
314
|
+
>> store_process_subscription()
|
|
315
315
|
>> unsync
|
|
316
316
|
>> f()
|
|
317
317
|
>> (additional_steps or StepList())
|
|
@@ -348,7 +348,7 @@ def validate_workflow(description: str) -> Callable[[Callable[[], StepList]], Wo
|
|
|
348
348
|
"""
|
|
349
349
|
|
|
350
350
|
def _validate_workflow(f: Callable[[], StepList]) -> Workflow:
|
|
351
|
-
steplist = init >> store_process_subscription(
|
|
351
|
+
steplist = init >> store_process_subscription() >> unsync_unchecked >> f() >> resync >> done
|
|
352
352
|
|
|
353
353
|
return make_workflow(f, description, validate_initial_input_form_generator, Target.VALIDATE, steplist)
|
|
354
354
|
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: orchestrator-core
|
|
3
|
+
Version: 4.2.0rc1
|
|
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: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Environment :: Web Environment
|
|
11
|
+
Classifier: Framework :: AsyncIO
|
|
12
|
+
Classifier: Framework :: FastAPI
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Information Technology
|
|
15
|
+
Classifier: Intended Audience :: System Administrators
|
|
16
|
+
Classifier: Intended Audience :: Telecommunications Industry
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python
|
|
24
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
25
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
26
|
+
Classifier: Topic :: Internet
|
|
27
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
28
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
29
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
30
|
+
Classifier: Topic :: Software Development
|
|
31
|
+
Classifier: Typing :: Typed
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Requires-Dist: alembic==1.16.1
|
|
34
|
+
Requires-Dist: anyio>=3.7.0
|
|
35
|
+
Requires-Dist: click==8.*
|
|
36
|
+
Requires-Dist: deepmerge==2.0
|
|
37
|
+
Requires-Dist: deprecated>=1.2.18
|
|
38
|
+
Requires-Dist: fastapi~=0.115.2
|
|
39
|
+
Requires-Dist: fastapi-etag==0.4.0
|
|
40
|
+
Requires-Dist: itsdangerous>=2.2.0
|
|
41
|
+
Requires-Dist: jinja2==3.1.6
|
|
42
|
+
Requires-Dist: more-itertools~=10.7.0
|
|
43
|
+
Requires-Dist: nwa-stdlib~=1.9.0
|
|
44
|
+
Requires-Dist: oauth2-lib~=2.4.0
|
|
45
|
+
Requires-Dist: orjson==3.10.18
|
|
46
|
+
Requires-Dist: prometheus-client==0.22.1
|
|
47
|
+
Requires-Dist: psycopg2-binary==2.9.10
|
|
48
|
+
Requires-Dist: pydantic-forms>=1.4.0,<=2.1.0
|
|
49
|
+
Requires-Dist: pydantic-settings~=2.9.1
|
|
50
|
+
Requires-Dist: pydantic[email]~=2.8.2
|
|
51
|
+
Requires-Dist: python-dateutil==2.8.2
|
|
52
|
+
Requires-Dist: python-rapidjson>=1.18,<1.21
|
|
53
|
+
Requires-Dist: pytz==2025.2
|
|
54
|
+
Requires-Dist: redis==5.1.1
|
|
55
|
+
Requires-Dist: schedule==1.1.0
|
|
56
|
+
Requires-Dist: semver==3.0.4
|
|
57
|
+
Requires-Dist: sentry-sdk[fastapi]~=2.29.1
|
|
58
|
+
Requires-Dist: sqlalchemy==2.0.41
|
|
59
|
+
Requires-Dist: sqlalchemy-utils==0.41.2
|
|
60
|
+
Requires-Dist: strawberry-graphql>=0.246.2
|
|
61
|
+
Requires-Dist: structlog>=25.4.0
|
|
62
|
+
Requires-Dist: tabulate==0.9.0
|
|
63
|
+
Requires-Dist: typer==0.15.4
|
|
64
|
+
Requires-Dist: uvicorn[standard]~=0.34.0
|
|
65
|
+
Requires-Dist: celery~=5.5.1 ; extra == "celery"
|
|
66
|
+
Project-URL: Documentation, https://workfloworchestrator.org/orchestrator-core
|
|
67
|
+
Project-URL: Homepage, https://workfloworchestrator.org/orchestrator-core
|
|
68
|
+
Project-URL: Source, https://github.com/workfloworchestrator/orchestrator-core
|
|
69
|
+
Provides-Extra: celery
|
|
70
|
+
|
|
71
|
+
# Orchestrator-Core
|
|
72
|
+
|
|
73
|
+
[](https://pepy.tech/project/orchestrator-core)
|
|
74
|
+
[](https://codecov.io/gh/workfloworchestrator/orchestrator-core)
|
|
75
|
+
[](https://pypi.org/project/orchestrator-core)
|
|
76
|
+
[](https://pypi.org/project/orchestrator-core)
|
|
77
|
+

|
|
78
|
+
|
|
79
|
+
<p style="text-align: center"><em>Production ready Orchestration Framework to manage product lifecycle and workflows. Easy to use, built on top of FastAPI and Pydantic</em></p>
|
|
80
|
+
|
|
81
|
+
## Documentation
|
|
82
|
+
|
|
83
|
+
The documentation can be found at [workfloworchestrator.org](https://workfloworchestrator.org/orchestrator-core/).
|
|
84
|
+
|
|
85
|
+
## Installation (quick start)
|
|
86
|
+
|
|
87
|
+
Simplified steps to install and use the orchestrator-core.
|
|
88
|
+
For more details, read the [Getting started](https://workfloworchestrator.org/orchestrator-core/getting-started/base/) documentation.
|
|
89
|
+
|
|
90
|
+
### Step 1 - Install the package
|
|
91
|
+
|
|
92
|
+
Create a virtualenv and install the orchestrator-core.
|
|
93
|
+
|
|
94
|
+
```shell
|
|
95
|
+
python -m venv .venv
|
|
96
|
+
source .venv/bin/activate
|
|
97
|
+
pip install orchestrator-core
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Step 2 - Setup the database
|
|
101
|
+
|
|
102
|
+
Create a postgres database:
|
|
103
|
+
|
|
104
|
+
```shell
|
|
105
|
+
createuser -sP nwa
|
|
106
|
+
createdb orchestrator-core -O nwa # set password to 'nwa'
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Configure the database URI in your local environment:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
export DATABASE_URI=postgresql://nwa:nwa@localhost:5432/orchestrator-core
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Step 3 - Create main.py
|
|
116
|
+
|
|
117
|
+
Create a `main.py` file.
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from orchestrator import OrchestratorCore
|
|
121
|
+
from orchestrator.cli.main import app as core_cli
|
|
122
|
+
from orchestrator.settings import AppSettings
|
|
123
|
+
|
|
124
|
+
app = OrchestratorCore(base_settings=AppSettings())
|
|
125
|
+
|
|
126
|
+
if __name__ == "__main__":
|
|
127
|
+
core_cli()
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Step 4 - Run the database migrations
|
|
131
|
+
|
|
132
|
+
Initialize the migration environment and database tables.
|
|
133
|
+
|
|
134
|
+
```shell
|
|
135
|
+
python main.py db init
|
|
136
|
+
python main.py db upgrade heads
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Step 5 - Run the app
|
|
140
|
+
|
|
141
|
+
```shell
|
|
142
|
+
export OAUTH2_ACTIVE=False
|
|
143
|
+
uvicorn --reload --host 127.0.0.1 --port 8080 main:app
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Visit the [ReDoc](http://127.0.0.1:8080/api/redoc) or [OpenAPI](http://127.0.0.1:8080/api/docs) page to view and interact with the API.
|
|
147
|
+
|
|
148
|
+
## Contributing
|
|
149
|
+
|
|
150
|
+
We use [uv](https://docs.astral.sh/uv/getting-started/installation/) to manage dependencies.
|
|
151
|
+
|
|
152
|
+
To get started, follow these steps:
|
|
153
|
+
|
|
154
|
+
```shell
|
|
155
|
+
# in your postgres database
|
|
156
|
+
createdb orchestrator-core-test -O nwa # set password to 'nwa'
|
|
157
|
+
|
|
158
|
+
# on your local machine
|
|
159
|
+
git clone https://github.com/workfloworchestrator/orchestrator-core
|
|
160
|
+
cd orchestrator-core
|
|
161
|
+
export DATABASE_URI=postgresql://nwa:nwa@localhost:5432/orchestrator-core-test
|
|
162
|
+
uv sync --all-extras --all-groups
|
|
163
|
+
uv run pytest
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
For more details please read the [development docs](https://workfloworchestrator.org/orchestrator-core/contributing/development/).
|
|
167
|
+
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
orchestrator/__init__.py,sha256=
|
|
1
|
+
orchestrator/__init__.py,sha256=KuNtfAwhqS1RMy4hovcLLlT1kTH_aNMFLNu1SnkB0Qo,1066
|
|
2
2
|
orchestrator/app.py,sha256=7UrXKjBKNSEaSSXAd5ww_RdMFhFqE4yvfj8faS2MzAA,12089
|
|
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=TFIv09JIKY-lXqd04lH_XEcijEEyheaz3zTcgeG8DEI,4339
|
|
|
8
8
|
orchestrator/targets.py,sha256=WizBgnp8hWX9YLFUIju7ewSubiwQqinCvyiYNcXHbHI,802
|
|
9
9
|
orchestrator/types.py,sha256=qzs7xx5AYRmKbpYRyJJP3wuDb0W0bcAzefCN0RWLAco,15459
|
|
10
10
|
orchestrator/version.py,sha256=b58e08lxs47wUNXv0jXFO_ykpksmytuzEXD4La4W-NQ,1366
|
|
11
|
-
orchestrator/workflow.py,sha256=
|
|
11
|
+
orchestrator/workflow.py,sha256=PVHe6vnnkswzqw2UoY-j6NMSEhL6rLHXRnO7yLOyDC8,45551
|
|
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,13 +17,13 @@ orchestrator/api/api_v1/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n
|
|
|
17
17
|
orchestrator/api/api_v1/api.py,sha256=m4iDktsSpzxUDaudkdgXeZ83a6B4wfc3pczQsa-Pb-8,2866
|
|
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=3ggFkLLTqX7zwJmEmr77RbN2n-iIuNNCIpsPMeMIYFA,16149
|
|
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
|
|
24
24
|
orchestrator/api/api_v1/endpoints/settings.py,sha256=5s-k169podZjgGHUbVDmSQwpY_3Cs_Bbf2PPtZIkBcw,6184
|
|
25
25
|
orchestrator/api/api_v1/endpoints/subscription_customer_descriptions.py,sha256=1_6LtgQleoq3M6z_W-Qz__Bj3OFUweoPrUqHMwSH6AM,3288
|
|
26
|
-
orchestrator/api/api_v1/endpoints/subscriptions.py,sha256=
|
|
26
|
+
orchestrator/api/api_v1/endpoints/subscriptions.py,sha256=zn_LeVfmp2uw7CszK4BvQ5n37hZccy3K2htkoDgF1sI,9809
|
|
27
27
|
orchestrator/api/api_v1/endpoints/translations.py,sha256=dIWh_fCnZZUxJoGiNeJ49DK_xpf75IpR_0EIMSvzIvY,963
|
|
28
28
|
orchestrator/api/api_v1/endpoints/user.py,sha256=RyI32EXVu6I-IxWjz0XB5zQWzzLL60zKXLgLqLH02xU,1827
|
|
29
29
|
orchestrator/api/api_v1/endpoints/workflows.py,sha256=_0vhGiQeu3-z16Zi0WmuDWBs8gmed6BzRNwYH_sF6AY,1977
|
|
@@ -77,7 +77,7 @@ orchestrator/cli/generator/templates/additional_modify_steps.j2,sha256=jwle7hIvd
|
|
|
77
77
|
orchestrator/cli/generator/templates/additional_terminate_steps.j2,sha256=jwle7hIvd-EYbnecVFmG0n-6Jpr4DearM0era8AvGYM,25
|
|
78
78
|
orchestrator/cli/generator/templates/constrained_int_definitions.j2,sha256=59FKIWOeXrO0nblLmbhaFXKb4UQesQ8zFUZ1jDCp9Vk,282
|
|
79
79
|
orchestrator/cli/generator/templates/create_data_head.j2,sha256=ArP9TUsbobXF4CIpckcaIYos-dgGmPeL-n7SQATvSiE,361
|
|
80
|
-
orchestrator/cli/generator/templates/create_product.j2,sha256=
|
|
80
|
+
orchestrator/cli/generator/templates/create_product.j2,sha256=P5XUD-s8ouAfoT14xv7f5VrgpWytvClrWVnBV6Bm1YI,4785
|
|
81
81
|
orchestrator/cli/generator/templates/enums.j2,sha256=pmx7_DeoE4X9u83_In18C97XqZP_YwETiw54_E33p1A,298
|
|
82
82
|
orchestrator/cli/generator/templates/lazy_workflow_instance.j2,sha256=BYB6LwE19OarY7_7Ovej5rqppZWtjiDkG7TDK5dYU7Y,523
|
|
83
83
|
orchestrator/cli/generator/templates/list_definitions.j2,sha256=XS-F5XXy4HOdsZ-xahprwxfhU0UaiF4VeopkIxfoado,277
|
|
@@ -106,7 +106,7 @@ orchestrator/db/database.py,sha256=MU_w_e95ho2dVb2JDnt_KFYholx___XDkiQXbc8wCkI,1
|
|
|
106
106
|
orchestrator/db/helpers.py,sha256=L8kEdnSSNGnUpZhdeGx2arCodakWN8vSpKdfjoLuHdY,831
|
|
107
107
|
orchestrator/db/listeners.py,sha256=UBPYcH0FE3a7aZQu_D0O_JMXpXIRYXC0gjSAvlv5GZo,1142
|
|
108
108
|
orchestrator/db/loaders.py,sha256=ez6JzQ3IKVkC_oLAkVlIIiI8Do7hXbdcPKCvUSLxRog,7962
|
|
109
|
-
orchestrator/db/models.py,sha256=
|
|
109
|
+
orchestrator/db/models.py,sha256=9XOppPkXlbILM3M87wgaItsE8BKLNdnyyfeiSfYuYQ8,27502
|
|
110
110
|
orchestrator/db/filters/__init__.py,sha256=RUj6P0XxEBhYj0SN5wH5-Vf_Wt_ilZR_n9DSar5m9oM,371
|
|
111
111
|
orchestrator/db/filters/filters.py,sha256=55RtpQwM2rhrk4A6CCSeSXoo-BT9GnQoNTryA8CtLEg,5020
|
|
112
112
|
orchestrator/db/filters/process.py,sha256=xvGhyfo_MZ1xhLvFC6yULjcT4mJk0fKc1glJIYgsWLE,4018
|
|
@@ -159,7 +159,7 @@ orchestrator/graphql/__init__.py,sha256=avq8Yg3Jr_9pJqh7ClyIAOX7YSg1eM_AWmt5C3FR
|
|
|
159
159
|
orchestrator/graphql/autoregistration.py,sha256=pF2jbMKG26MvYoMSa6ZpqpHjVks7_NvSRFymHTgmfjs,6342
|
|
160
160
|
orchestrator/graphql/pagination.py,sha256=iqVDn3GPZpiQhEydfwkBJLURY-X8wwUphS8Lkeg0BOc,2413
|
|
161
161
|
orchestrator/graphql/schema.py,sha256=gwZ3nAgKL0zlpc-aK58hSUAGPVD11Tb3aRSSK9hC39I,9204
|
|
162
|
-
orchestrator/graphql/types.py,sha256=
|
|
162
|
+
orchestrator/graphql/types.py,sha256=CpWrDqVTQwxYkJQqidPzHEAURGirJ-6i-dlBcBwBaTI,5196
|
|
163
163
|
orchestrator/graphql/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
164
164
|
orchestrator/graphql/extensions/model_cache.py,sha256=1uhMRjBs9eK7zJ1Y6P6BopX06822w2Yh9jliwYvG6yQ,1085
|
|
165
165
|
orchestrator/graphql/extensions/stats.py,sha256=pGhEBQg45XvqZhRobcrCSGwt5AGmR3gflsm1dYiIg5g,2018
|
|
@@ -184,15 +184,15 @@ orchestrator/graphql/schemas/customer_description.py,sha256=fize71IMpkvk_rTzcqCY
|
|
|
184
184
|
orchestrator/graphql/schemas/errors.py,sha256=VRl-Zd1FHMnscyozhfxzqeEUZ0ERAWum_Y8YwjGxwmA,203
|
|
185
185
|
orchestrator/graphql/schemas/fixed_input.py,sha256=1yqYHADQRgHz8OIP7ObYsPFS-gmzfkCvEO0a-KKf7zI,513
|
|
186
186
|
orchestrator/graphql/schemas/helpers.py,sha256=Kpj4kIbmoKKN35bdgUSwQvGUIbeg7VJAVMEq65YS_ik,346
|
|
187
|
-
orchestrator/graphql/schemas/process.py,sha256=
|
|
188
|
-
orchestrator/graphql/schemas/product.py,sha256=
|
|
187
|
+
orchestrator/graphql/schemas/process.py,sha256=nvD6Rvr0hnrMINdXF_rQuLF8szKJ7E-SywCFMuZsnlg,4940
|
|
188
|
+
orchestrator/graphql/schemas/product.py,sha256=vUCqcjrKBJj-VKSrMYPKzjmmxLMXL7alKTJ8UdUkhTg,4342
|
|
189
189
|
orchestrator/graphql/schemas/product_block.py,sha256=Qk9cbA6vm7ZPrhdgPHatKRuy6TytBmxSr97McEOxAu8,2860
|
|
190
190
|
orchestrator/graphql/schemas/resource_type.py,sha256=s5d_FwQXL2-Sc-IDUxTJun5qFQ4zOP4-XcHF9ql-t1g,898
|
|
191
191
|
orchestrator/graphql/schemas/settings.py,sha256=drhm5VcLmUbiYAk6WUSJcyJqjNM96E6GvpxVdPAobnA,999
|
|
192
192
|
orchestrator/graphql/schemas/strawberry_pydantic_patch.py,sha256=CjNUhTKdYmLiaem-WY_mzw4HASIeaZitxGF8pPocqVw,1602
|
|
193
193
|
orchestrator/graphql/schemas/subscription.py,sha256=RnnxPgha_7D4Ii87cp3eyBV93_RZIryzWyVHZwyn3eA,9603
|
|
194
194
|
orchestrator/graphql/schemas/version.py,sha256=HSzVg_y4Sjd5_H5rRUtu3FJKOG_8ifhvBNt_qjOtC-E,92
|
|
195
|
-
orchestrator/graphql/schemas/workflow.py,sha256=
|
|
195
|
+
orchestrator/graphql/schemas/workflow.py,sha256=WLbegRNxOfvXg4kPYrO5KPBwtHmUofAr2pvZT2JsW1c,1761
|
|
196
196
|
orchestrator/graphql/utils/__init__.py,sha256=1JvenzEVW1CBa1sGVI9I8IWnnoXIkb1hneDqph9EEZY,524
|
|
197
197
|
orchestrator/graphql/utils/create_resolver_error_handler.py,sha256=PpQMVwGrE9t0nZ12TwoxPxksXxEwQM7lSNPeh7qW3vk,1233
|
|
198
198
|
orchestrator/graphql/utils/get_query_loaders.py,sha256=abS_HJ7K9een78gMiGq3IhwGwxQXHvZygExe0h_t9ns,815
|
|
@@ -241,6 +241,8 @@ orchestrator/migrations/versions/schema/2025-03-06_42b3d076a85b_subscription_ins
|
|
|
241
241
|
orchestrator/migrations/versions/schema/2025-03-06_42b3d076a85b_subscription_instance_as_json_function.sql,sha256=hPldk0DAesUbHv3Qd_N7U-cAk-t1wIgxt4FOA120gQ8,1776
|
|
242
242
|
orchestrator/migrations/versions/schema/2025-04-09_fc5c993a4b4a_add_cascade_constraint_on_processes_.py,sha256=6kHRNSZxUze2jy7b8uRvkt5mzsax10Z-Z3lsACtPLRM,1067
|
|
243
243
|
orchestrator/migrations/versions/schema/2025-05-08_161918133bec_add_is_task_to_workflow.py,sha256=VLFDHFYRWn5ktUba0KuSPWyvjYJdfN1WypWmOPqIW18,721
|
|
244
|
+
orchestrator/migrations/versions/schema/2025-07-01_93fc5834c7e5_changed_timestamping_fields_in_process_steps.py,sha256=Oezd8b2qaI1Kyq-sZFVFmdzd4d9NjXrf6HtJGk11fy0,1914
|
|
245
|
+
orchestrator/migrations/versions/schema/2025-07-04_4b58e336d1bf_deprecating_workflow_target_in_.py,sha256=xnD6w-97R4ClS7rbmXQEXc36K3fdcXKhCy7ZZNy_FX4,742
|
|
244
246
|
orchestrator/schedules/__init__.py,sha256=JnnaglfK1qYUBKI6Dd9taV-tCZIPlAdAkHtnkJDMXxY,1066
|
|
245
247
|
orchestrator/schedules/resume_workflows.py,sha256=kSotzTAXjX7p9fpSYiGOpuxuTQfv54eRFAe0YSG0DHc,832
|
|
246
248
|
orchestrator/schedules/scheduling.py,sha256=ehtwgpbvMOk1jhn-hHgVzg_9wLJkI6l3mRY3DcO9ZVY,1526
|
|
@@ -252,7 +254,7 @@ orchestrator/schemas/base.py,sha256=Vc444LetsINLRhG2SxW9Bq01hOzChPOhQWCImQTr-As,
|
|
|
252
254
|
orchestrator/schemas/engine_settings.py,sha256=LF8al7tJssiilb5A4emPtUYo0tVDSaT1Lvo_DN_ttrY,1296
|
|
253
255
|
orchestrator/schemas/fixed_input.py,sha256=Rth3hT5K7zYuQr1bUY_NJRzb03xEZuT1p6EvYXVNE54,1214
|
|
254
256
|
orchestrator/schemas/problem_detail.py,sha256=DxiUhWv6EVXLZgdKFv0EYVnCgtkDj7xteDCR0q2f5yw,802
|
|
255
|
-
orchestrator/schemas/process.py,sha256=
|
|
257
|
+
orchestrator/schemas/process.py,sha256=UACBNt-4g4v9Y528u-gZ-Wk7YxwJHhnI4cEu5CtQm2w,2541
|
|
256
258
|
orchestrator/schemas/product.py,sha256=MhMCh058ZuS2RJq-wSmxIPUNlhQexxXIx3DSz2OmOh4,1570
|
|
257
259
|
orchestrator/schemas/product_block.py,sha256=kCqvm6qadHpegMr9aWI_fYX-T7mS-5S-ldPxnGQZg7M,1519
|
|
258
260
|
orchestrator/schemas/resource_type.py,sha256=VDju4XywcDDLxdpbWU62RTvR9QF8x_GRrpTlN_NE8uI,1064
|
|
@@ -264,7 +266,7 @@ orchestrator/services/celery.py,sha256=PsIgRBJsmA3vKwAUaqPq9ynLwDsXHY2ggDWc-nQAw
|
|
|
264
266
|
orchestrator/services/fixed_inputs.py,sha256=kyz7s2HLzyDulvcq-ZqefTw1om86COvyvTjz0_5CmgI,876
|
|
265
267
|
orchestrator/services/input_state.py,sha256=HF7wl9fWdaAW8pdCCqbuYoKyNj8dY0g8Ff8vXis8z5A,2211
|
|
266
268
|
orchestrator/services/process_broadcast_thread.py,sha256=D44YbjF8mRqGuznkRUV4SoRn1J0lfy_x1H508GnSVlU,4649
|
|
267
|
-
orchestrator/services/processes.py,sha256=
|
|
269
|
+
orchestrator/services/processes.py,sha256=W-MCuGxRXLNIx3zn_jQQWXXFIBUrjJgXyBMsx2E0FbQ,30490
|
|
268
270
|
orchestrator/services/products.py,sha256=BP4KyE8zO-8z7Trrs5T6zKBOw53S9BfBJnHWI3p6u5Y,1943
|
|
269
271
|
orchestrator/services/resource_types.py,sha256=_QBy_JOW_X3aSTqH0CuLrq4zBJL0p7Q-UDJUcuK2_qc,884
|
|
270
272
|
orchestrator/services/settings.py,sha256=HEWfFulgoEDwgfxGEO__QTr5fDiwNBEj1UhAeTAdbLQ,3159
|
|
@@ -280,7 +282,7 @@ orchestrator/utils/crypt.py,sha256=18eNamYWMllPkxyRtWIde3FDr3rSF74R5SAL6WsCj9Y,5
|
|
|
280
282
|
orchestrator/utils/datetime.py,sha256=a1WQ_yvu7MA0TiaRpC5avwbOSFdrj4eMrV4a7I2sD5Q,1477
|
|
281
283
|
orchestrator/utils/deprecation_logger.py,sha256=oqju7ecJcB_r7cMnldaOAA79QUZYS_h69IkDrFV9nAg,875
|
|
282
284
|
orchestrator/utils/docs.py,sha256=GbyD61oKn1yVYaphUKHCBvrWEWJDTQfRc_VEbVb-zgU,6172
|
|
283
|
-
orchestrator/utils/enrich_process.py,sha256=
|
|
285
|
+
orchestrator/utils/enrich_process.py,sha256=sIb9jVM6MzttK1uJsRbUNMN8Aevo3erSAX0Agjbo5EA,4732
|
|
284
286
|
orchestrator/utils/errors.py,sha256=6FxvXrITmRjP5bYnJJ3CxjAwA5meNjRAVYouz4TWKkU,4653
|
|
285
287
|
orchestrator/utils/expose_settings.py,sha256=0NOjLBifQy4k2zUYJ31QjGQCaXEQ1zB4UtCle7XglAM,1640
|
|
286
288
|
orchestrator/utils/fixed_inputs.py,sha256=pnL6I_19VMp_Bny8SYjSzVFNvTFDyeCxFFOWGhTnDiQ,2665
|
|
@@ -300,17 +302,17 @@ orchestrator/websocket/websocket_manager.py,sha256=hwlG9FDXcNU42jDNNsPMQLIyrvEpG
|
|
|
300
302
|
orchestrator/websocket/managers/broadcast_websocket_manager.py,sha256=fwoSgTjkHJ2GmsLTU9dqQpAA9i8b1McPu7gLNzxtfG4,5401
|
|
301
303
|
orchestrator/websocket/managers/memory_websocket_manager.py,sha256=lF5EEx1iFMCGEkTbItTDr88NENMSaSeG1QrJ7teoPkY,3324
|
|
302
304
|
orchestrator/workflows/__init__.py,sha256=NzIGGI-8SNAwCk2YqH6sHhEWbgAY457ntDwjO15N8v4,4131
|
|
303
|
-
orchestrator/workflows/modify_note.py,sha256=
|
|
305
|
+
orchestrator/workflows/modify_note.py,sha256=eXt5KQvrkOXf-3YEXCn2XbBLP9N-n1pUYRW2t8Odupo,2150
|
|
304
306
|
orchestrator/workflows/removed_workflow.py,sha256=V0Da5TEdfLdZZKD38ig-MTp3_IuE7VGqzHHzvPYQmLI,909
|
|
305
|
-
orchestrator/workflows/steps.py,sha256=
|
|
306
|
-
orchestrator/workflows/utils.py,sha256=
|
|
307
|
+
orchestrator/workflows/steps.py,sha256=CZxfzkG5ANJYwuYTkQ4da2RpQqIjXCtey_Uy1ezRAZ4,6479
|
|
308
|
+
orchestrator/workflows/utils.py,sha256=bhX9vm3oc9k6RSaESl34v4Nrh40G4Ys91INoTjZ0XVM,13966
|
|
307
309
|
orchestrator/workflows/tasks/__init__.py,sha256=GyHNfEFCGKQwRiN6rQmvSRH2iYX7npjMZn97n8XzmLU,571
|
|
308
310
|
orchestrator/workflows/tasks/cleanup_tasks_log.py,sha256=BfWYbPXhnLAHUJ0mlODDnjZnQQAvKCZJDVTwbwOWI04,1624
|
|
309
311
|
orchestrator/workflows/tasks/resume_workflows.py,sha256=MzJqlSXUvKStkT7NGzxZyRlfAer_ezYm-kjUqaZi0yc,2359
|
|
310
312
|
orchestrator/workflows/tasks/validate_product_type.py,sha256=paG-NAY1bdde3Adt8zItkcBKf5Pxw6f5ngGW6an6dYU,3192
|
|
311
313
|
orchestrator/workflows/tasks/validate_products.py,sha256=GZJBoFF-WMphS7ghMs2-gqvV2iL1F0POhk0uSNt93n0,8510
|
|
312
314
|
orchestrator/workflows/translations/en-GB.json,sha256=ST53HxkphFLTMjFHonykDBOZ7-P_KxksktZU3GbxLt0,846
|
|
313
|
-
orchestrator_core-4.
|
|
314
|
-
orchestrator_core-4.
|
|
315
|
-
orchestrator_core-4.
|
|
316
|
-
orchestrator_core-4.
|
|
315
|
+
orchestrator_core-4.2.0rc1.dist-info/licenses/LICENSE,sha256=b-aA5OZQuuBATmLKo_mln8CQrDPPhg3ghLzjPjLn4Tg,11409
|
|
316
|
+
orchestrator_core-4.2.0rc1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
317
|
+
orchestrator_core-4.2.0rc1.dist-info/METADATA,sha256=Kkb7hvUNxHfux_npyFWEVr7FVci_N84-9PRvo-ogOqk,5963
|
|
318
|
+
orchestrator_core-4.2.0rc1.dist-info/RECORD,,
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: orchestrator-core
|
|
3
|
-
Version: 4.1.0rc2
|
|
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.16.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.7.0
|
|
39
|
-
Requires-Dist: itsdangerous
|
|
40
|
-
Requires-Dist: Jinja2==3.1.6
|
|
41
|
-
Requires-Dist: orjson==3.10.18
|
|
42
|
-
Requires-Dist: prometheus-client==0.22.0
|
|
43
|
-
Requires-Dist: psycopg2-binary==2.9.10
|
|
44
|
-
Requires-Dist: pydantic[email]~=2.8.2
|
|
45
|
-
Requires-Dist: pydantic-settings~=2.9.1
|
|
46
|
-
Requires-Dist: python-dateutil==2.8.2
|
|
47
|
-
Requires-Dist: python-rapidjson>=1.18,<1.21
|
|
48
|
-
Requires-Dist: pytz==2025.2
|
|
49
|
-
Requires-Dist: redis==5.1.1
|
|
50
|
-
Requires-Dist: schedule==1.1.0
|
|
51
|
-
Requires-Dist: semver==3.0.4
|
|
52
|
-
Requires-Dist: sentry-sdk[fastapi]~=2.29.1
|
|
53
|
-
Requires-Dist: SQLAlchemy==2.0.41
|
|
54
|
-
Requires-Dist: SQLAlchemy-Utils==0.41.2
|
|
55
|
-
Requires-Dist: structlog
|
|
56
|
-
Requires-Dist: typer==0.15.4
|
|
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, <=2.1.0
|
|
63
|
-
Requires-Dist: celery~=5.5.1 ; 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: Source, https://github.com/workfloworchestrator/orchestrator-core
|
|
115
|
-
Provides-Extra: celery
|
|
116
|
-
Provides-Extra: dev
|
|
117
|
-
Provides-Extra: doc
|
|
118
|
-
Provides-Extra: test
|
|
File without changes
|
{orchestrator_core-4.1.0rc2.dist-info → orchestrator_core-4.2.0rc1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|