Skip to content

Commit 67c3d67

Browse files
authored
Functions api ✨ 🗃️ (#7539)
1 parent c552e46 commit 67c3d67

File tree

30 files changed

+8301
-1494
lines changed

30 files changed

+8301
-1494
lines changed
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
from collections.abc import Mapping
2+
from enum import Enum
3+
from typing import Annotated, Any, Literal, TypeAlias
4+
from uuid import UUID
5+
6+
from common_library.errors_classes import OsparcErrorMixin
7+
from models_library import projects
8+
from models_library.services_types import ServiceKey, ServiceVersion
9+
from pydantic import BaseModel, Field
10+
11+
from ..projects import ProjectID
12+
13+
FunctionID: TypeAlias = UUID
14+
FunctionJobID: TypeAlias = UUID
15+
FileID: TypeAlias = UUID
16+
17+
InputTypes: TypeAlias = FileID | float | int | bool | str | list
18+
19+
20+
class FunctionSchemaClass(str, Enum):
21+
json_schema = "application/schema+json"
22+
23+
24+
class FunctionSchemaBase(BaseModel):
25+
schema_content: Any | None = Field(default=None)
26+
schema_class: FunctionSchemaClass
27+
28+
29+
class JSONFunctionSchema(FunctionSchemaBase):
30+
schema_content: Mapping[str, Any] = Field(
31+
default={}, description="JSON Schema", title="JSON Schema"
32+
) # json-schema library defines a schema as Mapping[str, Any]
33+
schema_class: FunctionSchemaClass = FunctionSchemaClass.json_schema
34+
35+
36+
class JSONFunctionInputSchema(JSONFunctionSchema):
37+
schema_class: Literal[FunctionSchemaClass.json_schema] = (
38+
FunctionSchemaClass.json_schema
39+
)
40+
41+
42+
class JSONFunctionOutputSchema(JSONFunctionSchema):
43+
schema_class: Literal[FunctionSchemaClass.json_schema] = (
44+
FunctionSchemaClass.json_schema
45+
)
46+
47+
48+
FunctionInputSchema: TypeAlias = Annotated[
49+
JSONFunctionInputSchema,
50+
Field(discriminator="schema_class"),
51+
]
52+
53+
FunctionOutputSchema: TypeAlias = Annotated[
54+
JSONFunctionOutputSchema,
55+
Field(discriminator="schema_class"),
56+
]
57+
58+
59+
class FunctionClass(str, Enum):
60+
PROJECT = "PROJECT"
61+
SOLVER = "SOLVER"
62+
PYTHON_CODE = "PYTHON_CODE"
63+
64+
65+
FunctionClassSpecificData: TypeAlias = dict[str, Any]
66+
FunctionJobClassSpecificData: TypeAlias = FunctionClassSpecificData
67+
68+
69+
# NOTE, use InputTypes here, but api is throwing weird errors and asking for dict for elements
70+
# see here https://github.com/ITISFoundation/osparc-simcore/issues/7659
71+
FunctionInputs: TypeAlias = dict[str, Any] | None
72+
73+
FunctionInputsList: TypeAlias = list[FunctionInputs]
74+
75+
FunctionOutputs: TypeAlias = dict[str, Any] | None
76+
77+
FunctionOutputsLogfile: TypeAlias = Any
78+
79+
80+
class FunctionBase(BaseModel):
81+
function_class: FunctionClass
82+
title: str = ""
83+
description: str = ""
84+
input_schema: FunctionInputSchema
85+
output_schema: FunctionOutputSchema
86+
default_inputs: FunctionInputs
87+
88+
89+
class RegisteredFunctionBase(FunctionBase):
90+
uid: FunctionID
91+
92+
93+
class ProjectFunction(FunctionBase):
94+
function_class: Literal[FunctionClass.PROJECT] = FunctionClass.PROJECT
95+
project_id: ProjectID
96+
97+
98+
class RegisteredProjectFunction(ProjectFunction, RegisteredFunctionBase):
99+
pass
100+
101+
102+
SolverJobID: TypeAlias = UUID
103+
104+
105+
class SolverFunction(FunctionBase):
106+
function_class: Literal[FunctionClass.SOLVER] = FunctionClass.SOLVER
107+
solver_key: ServiceKey
108+
solver_version: ServiceVersion
109+
110+
111+
class RegisteredSolverFunction(SolverFunction, RegisteredFunctionBase):
112+
pass
113+
114+
115+
class PythonCodeFunction(FunctionBase):
116+
function_class: Literal[FunctionClass.PYTHON_CODE] = FunctionClass.PYTHON_CODE
117+
code_url: str
118+
119+
120+
class RegisteredPythonCodeFunction(PythonCodeFunction, RegisteredFunctionBase):
121+
pass
122+
123+
124+
Function: TypeAlias = Annotated[
125+
ProjectFunction | PythonCodeFunction | SolverFunction,
126+
Field(discriminator="function_class"),
127+
]
128+
RegisteredFunction: TypeAlias = Annotated[
129+
RegisteredProjectFunction | RegisteredPythonCodeFunction | RegisteredSolverFunction,
130+
Field(discriminator="function_class"),
131+
]
132+
133+
FunctionJobCollectionID: TypeAlias = projects.ProjectID
134+
135+
136+
class FunctionJobBase(BaseModel):
137+
title: str = ""
138+
description: str = ""
139+
function_uid: FunctionID
140+
inputs: FunctionInputs
141+
outputs: FunctionOutputs
142+
function_class: FunctionClass
143+
144+
145+
class RegisteredFunctionJobBase(FunctionJobBase):
146+
uid: FunctionJobID
147+
148+
149+
class ProjectFunctionJob(FunctionJobBase):
150+
function_class: Literal[FunctionClass.PROJECT] = FunctionClass.PROJECT
151+
project_job_id: ProjectID
152+
153+
154+
class RegisteredProjectFunctionJob(ProjectFunctionJob, RegisteredFunctionJobBase):
155+
pass
156+
157+
158+
class SolverFunctionJob(FunctionJobBase):
159+
function_class: Literal[FunctionClass.SOLVER] = FunctionClass.SOLVER
160+
solver_job_id: ProjectID
161+
162+
163+
class RegisteredSolverFunctionJob(SolverFunctionJob, RegisteredFunctionJobBase):
164+
pass
165+
166+
167+
class PythonCodeFunctionJob(FunctionJobBase):
168+
function_class: Literal[FunctionClass.PYTHON_CODE] = FunctionClass.PYTHON_CODE
169+
170+
171+
class RegisteredPythonCodeFunctionJob(PythonCodeFunctionJob, RegisteredFunctionJobBase):
172+
pass
173+
174+
175+
FunctionJob: TypeAlias = Annotated[
176+
ProjectFunctionJob | PythonCodeFunctionJob | SolverFunctionJob,
177+
Field(discriminator="function_class"),
178+
]
179+
180+
RegisteredFunctionJob: TypeAlias = Annotated[
181+
RegisteredProjectFunctionJob
182+
| RegisteredPythonCodeFunctionJob
183+
| RegisteredSolverFunctionJob,
184+
Field(discriminator="function_class"),
185+
]
186+
187+
188+
class FunctionJobStatus(BaseModel):
189+
status: str
190+
191+
192+
class FunctionJobCollection(BaseModel):
193+
"""Model for a collection of function jobs"""
194+
195+
title: str = ""
196+
description: str = ""
197+
job_ids: list[FunctionJobID] = []
198+
199+
200+
class RegisteredFunctionJobCollection(FunctionJobCollection):
201+
uid: FunctionJobCollectionID
202+
203+
204+
class FunctionJobCollectionStatus(BaseModel):
205+
status: list[str]
206+
207+
208+
class FunctionBaseError(OsparcErrorMixin, Exception):
209+
pass
210+
211+
212+
class FunctionIDNotFoundError(FunctionBaseError):
213+
msg_template: str = "Function {function_id} not found"
214+
215+
216+
class FunctionJobIDNotFoundError(FunctionBaseError):
217+
msg_template: str = "Function job {function_job_id} not found"
218+
219+
220+
class FunctionJobCollectionIDNotFoundError(FunctionBaseError):
221+
msg_template: str = "Function job collection {function_job_collection_id} not found"
222+
223+
224+
class UnsupportedFunctionClassError(FunctionBaseError):
225+
msg_template: str = "Function class {function_class} is not supported"
226+
227+
228+
class UnsupportedFunctionJobClassError(FunctionBaseError):
229+
msg_template: str = "Function job class {function_job_class} is not supported"
230+
231+
232+
class UnsupportedFunctionFunctionJobClassCombinationError(FunctionBaseError):
233+
msg_template: str = (
234+
"Function class {function_class} and function job class {function_job_class} combination is not supported"
235+
)
236+
237+
238+
class FunctionInputsValidationError(FunctionBaseError):
239+
msg_template: str = "Function inputs validation failed: {error}"
240+
241+
242+
class FunctionJobDB(BaseModel):
243+
function_uuid: FunctionID
244+
title: str = ""
245+
description: str = ""
246+
inputs: FunctionInputs
247+
outputs: FunctionOutputs
248+
class_specific_data: FunctionJobClassSpecificData
249+
function_class: FunctionClass
250+
251+
252+
class RegisteredFunctionJobDB(FunctionJobDB):
253+
uuid: FunctionJobID
254+
255+
256+
class FunctionDB(BaseModel):
257+
function_class: FunctionClass
258+
title: str = ""
259+
description: str = ""
260+
input_schema: FunctionInputSchema
261+
output_schema: FunctionOutputSchema
262+
default_inputs: FunctionInputs
263+
class_specific_data: FunctionClassSpecificData
264+
265+
266+
class RegisteredFunctionDB(FunctionDB):
267+
uuid: FunctionID
268+
269+
270+
class FunctionJobCollectionDB(BaseModel):
271+
title: str = ""
272+
description: str = ""
273+
274+
275+
class RegisteredFunctionJobCollectionDB(FunctionJobCollectionDB):
276+
uuid: FunctionJobCollectionID

0 commit comments

Comments
 (0)