11"""
2- Models Node as a central element in a project's pipeline
2+ Models Node as a central element in a project's pipeline
33"""
44
55from typing import Annotated , Any , TypeAlias , Union
1717 StringConstraints ,
1818 field_validator ,
1919)
20+ from pydantic .config import JsonDict
2021
2122from .basic_types import EnvVarKey , KeyIDStr
2223from .projects_access import AccessEnum
7172
7273
7374class NodeState (BaseModel ):
74- modified : bool = Field (
75- default = True , description = "true if the node's outputs need to be re-computed"
76- )
77- dependencies : set [NodeID ] = Field (
78- default_factory = set ,
79- description = "contains the node inputs dependencies if they need to be computed first" ,
80- )
81- current_status : RunningState = Field (
82- default = RunningState .NOT_STARTED ,
83- description = "the node's current state" ,
84- alias = "currentStatus" ,
85- )
86- progress : float | None = Field (
87- default = 0 ,
88- ge = 0.0 ,
89- le = 1.0 ,
90- description = "current progress of the task if available (None if not started or not a computational task)" ,
91- )
75+ modified : Annotated [
76+ bool ,
77+ Field (
78+ description = "true if the node's outputs need to be re-computed" ,
79+ ),
80+ ] = True
81+
82+ dependencies : Annotated [
83+ set [NodeID ],
84+ Field (
85+ default_factory = set ,
86+ description = "contains the node inputs dependencies if they need to be computed first" ,
87+ ),
88+ ] = DEFAULT_FACTORY
89+
90+ current_status : Annotated [
91+ RunningState ,
92+ Field (
93+ description = "the node's current state" ,
94+ alias = "currentStatus" ,
95+ ),
96+ ] = RunningState .NOT_STARTED
97+
98+ progress : Annotated [
99+ float | None ,
100+ Field (
101+ ge = 0.0 ,
102+ le = 1.0 ,
103+ description = "current progress of the task if available (None if not started or not a computational task)" ,
104+ ),
105+ ] = 0
106+
92107 model_config = ConfigDict (
93108 extra = "forbid" ,
109+ populate_by_name = True ,
94110 json_schema_extra = {
95111 "examples" : [
96112 {
@@ -113,24 +129,35 @@ class NodeState(BaseModel):
113129 )
114130
115131
132+ def _convert_old_enum_name (v ) -> RunningState :
133+ if v == "FAILURE" :
134+ return RunningState .FAILED
135+ return RunningState (v )
136+
137+
116138class Node (BaseModel ):
117- key : ServiceKey = Field (
118- ...,
119- description = "distinctive name for the node based on the docker registry path" ,
120- examples = [
121- "simcore/services/comp/itis/sleeper" ,
122- "simcore/services/dynamic/3dviewer" ,
123- "simcore/services/frontend/file-picker" ,
124- ],
125- )
126- version : ServiceVersion = Field (
127- ...,
128- description = "semantic version number of the node" ,
129- examples = ["1.0.0" , "0.0.1" ],
130- )
131- label : str = Field (
132- ..., description = "The short name of the node" , examples = ["JupyterLab" ]
133- )
139+ key : Annotated [
140+ ServiceKey ,
141+ Field (
142+ description = "distinctive name for the node based on the docker registry path" ,
143+ examples = [
144+ "simcore/services/comp/itis/sleeper" ,
145+ "simcore/services/dynamic/3dviewer" ,
146+ "simcore/services/frontend/file-picker" ,
147+ ],
148+ ),
149+ ]
150+ version : Annotated [
151+ ServiceVersion ,
152+ Field (
153+ description = "semantic version number of the node" ,
154+ examples = ["1.0.0" , "0.0.1" ],
155+ ),
156+ ]
157+ label : Annotated [
158+ str ,
159+ Field (description = "The short name of the node" , examples = ["JupyterLab" ]),
160+ ]
134161 progress : Annotated [
135162 float | None ,
136163 Field (
@@ -204,9 +231,9 @@ class Node(BaseModel):
204231 Field (default_factory = dict , description = "values of output properties" ),
205232 ] = DEFAULT_FACTORY
206233
207- output_node : Annotated [
208- bool | None , Field ( deprecated = True , alias = "outputNode" )
209- ] = None
234+ output_node : Annotated [bool | None , Field ( deprecated = True , alias = "outputNode" )] = (
235+ None
236+ )
210237
211238 output_nodes : Annotated [
212239 list [NodeID ] | None ,
@@ -255,24 +282,109 @@ def _convert_empty_str_to_none(cls, v):
255282 return None
256283 return v
257284
258- @classmethod
259- def _convert_old_enum_name (cls , v ) -> RunningState :
260- if v == "FAILURE" :
261- return RunningState .FAILED
262- return RunningState (v )
263-
264285 @field_validator ("state" , mode = "before" )
265286 @classmethod
266287 def _convert_from_enum (cls , v ):
267288 if isinstance (v , str ):
289+
268290 # the old version of state was a enum of RunningState
269- running_state_value = cls . _convert_old_enum_name (v )
270- return NodeState (currentStatus = running_state_value )
291+ running_state_value = _convert_old_enum_name (v )
292+ return NodeState (current_status = running_state_value )
271293 return v
272294
295+ @staticmethod
296+ def _update_json_schema_extra (schema : JsonDict ) -> None :
297+ schema .update (
298+ {
299+ "examples" : [
300+ # Minimal example with only required fields
301+ {
302+ "key" : "simcore/services/comp/no_ports" ,
303+ "version" : "1.0.0" ,
304+ "label" : "Sleep" ,
305+ },
306+ # Complete example with optional fields
307+ {
308+ "key" : "simcore/services/comp/only_inputs" ,
309+ "version" : "1.0.0" ,
310+ "label" : "Only INputs" ,
311+ "inputs" : {
312+ "input_1" : 1 ,
313+ "input_2" : 2 ,
314+ "input_3" : 3 ,
315+ },
316+ },
317+ # Complete example with optional fields
318+ {
319+ "key" : "simcore/services/comp/only_outputs" ,
320+ "version" : "1.0.0" ,
321+ "label" : "Only Outputs" ,
322+ "outputs" : {
323+ "output_1" : 1 ,
324+ "output_2" : 2 ,
325+ "output_3" : 3 ,
326+ },
327+ },
328+ # Example with all possible input and output types
329+ {
330+ "key" : "simcore/services/comp/itis/all-types" ,
331+ "version" : "1.0.0" ,
332+ "label" : "All Types Demo" ,
333+ "inputs" : {
334+ "boolean_input" : True ,
335+ "integer_input" : 42 ,
336+ "float_input" : 3.14159 ,
337+ "string_input" : "text value" ,
338+ "json_input" : {"key" : "value" , "nested" : {"data" : 123 }},
339+ "port_link_input" : {
340+ "nodeUuid" : "f2700a54-adcf-45d4-9881-01ec30fd75a2" ,
341+ "output" : "out_1" ,
342+ },
343+ "simcore_file_link" : {
344+ "store" : "simcore.s3" ,
345+ "path" : "123e4567-e89b-12d3-a456-426614174000/test.csv" ,
346+ },
347+ "datcore_file_link" : {
348+ "store" : "datcore" ,
349+ "dataset" : "N:dataset:123" ,
350+ "path" : "path/to/file.txt" ,
351+ },
352+ "download_link" : {
353+ "downloadLink" : "https://example.com/downloadable/file.txt"
354+ },
355+ "array_input" : [1 , 2 , 3 , 4 , 5 ],
356+ "object_input" : {"name" : "test" , "value" : 42 },
357+ },
358+ "outputs" : {
359+ "boolean_output" : False ,
360+ "integer_output" : 100 ,
361+ "float_output" : 2.71828 ,
362+ "string_output" : "result text" ,
363+ "json_output" : {"status" : "success" , "data" : [1 , 2 , 3 ]},
364+ "simcore_file_output" : {
365+ "store" : "simcore.s3" ,
366+ "path" : "987e6543-e21b-12d3-a456-426614174000/result.csv" ,
367+ },
368+ "datcore_file_output" : {
369+ "store" : "datcore" ,
370+ "dataset" : "N:dataset:456" ,
371+ "path" : "results/output.txt" ,
372+ },
373+ "download_link_output" : {
374+ "downloadLink" : "https://example.com/results/download.txt"
375+ },
376+ "array_output" : ["a" , "b" , "c" , "d" ],
377+ "object_output" : {"status" : "complete" , "count" : 42 },
378+ },
379+ },
380+ ],
381+ }
382+ )
383+
273384 model_config = ConfigDict (
274385 extra = "forbid" ,
275386 populate_by_name = True ,
387+ json_schema_extra = _update_json_schema_extra ,
276388 )
277389
278390
0 commit comments