@@ -255,23 +255,27 @@ def DynamicNestedDictGenerator(n: int):
255255from aiida_workgraph .socket_spec import Leaf
256256
257257
258+ class InputsModel (BaseModel ):
259+ x : int
260+ y : int
261+
262+
258263class OutputsModel (BaseModel ):
259264 sum : int
260265 product : int
261266
262267
263268@task
264- def add_multiply_pydantic_in_out (x , y ) -> OutputsModel :
265- return {'sum' : x + y , 'product' : x * y }
269+ def add_multiply_pydantic_in_out (data : InputsModel ) -> OutputsModel :
270+ return {'sum' : data . x + data . y , 'product' : data . x * data . y }
266271
267272
268273@task .graph
269- def AddMultiplyPydantic ():
270- # IMPORTANT: pass a plain dict, not OutputsModel(x=3, y=4)
271- add_multiply_pydantic_in_out (x = 3 , y = 4 )
274+ def AddMultiplyPydantic (data : InputsModel ) -> OutputsModel :
275+ return add_multiply_pydantic_in_out (data = data )
272276
273277
274- wg = AddMultiplyPydantic .build ()
278+ wg = AddMultiplyPydantic .build (data = InputsModel ( x = 3 , y = 4 ) )
275279wg .run ()
276280wg .generate_provenance_graph ()
277281
@@ -309,6 +313,12 @@ def GraphDynamicOut(n: int):
309313# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
310314#
311315# Sometimes you want to **validate** with a Pydantic model but store it as a **single node** instead of expanding fields.
316+ # For leaf models, WorkGraph treats the value as a blob. If a serializer is registered for the class, it is used;
317+ # otherwise ``JsonableData`` stores the model as a JSON-friendly dict.
318+ #
319+ # Note: Pydantic annotations define the *schema* for WorkGraph sockets. Outputs are stored as typed
320+ # AiiDA nodes per field, so runtime results are dicts of nodes (not Pydantic instances). Use those
321+ # nodes for linking/provenance; rebuild a Pydantic model only for convenience.
312322# There are two ways:
313323#
314324# 1) Mark the model: ``model_config = {"leaf": True}``
@@ -325,7 +335,7 @@ class BlobModel(BaseModel):
325335@task
326336def consume_blob (m : BlobModel ) -> dict :
327337 # 'm' is validated by Pydantic but stored/treated as one leaf node
328- return {'sum' : m [ 'a' ] + m [ 'b' ] }
338+ return {'sum' : m . a + m . b }
329339
330340
331341# Per-use override without modifying the model:
@@ -336,13 +346,13 @@ class AnotherModel(BaseModel):
336346
337347@task
338348def consume_blob_per_use (m : Leaf [AnotherModel ]) -> dict :
339- return {'sum' : m [ 'a' ] + m [ 'b' ] }
349+ return {'sum' : m . a + m . b }
340350
341351
342352@task .graph
343353def BlobExamples ():
344- consume_blob (m = { 'a' : 1 , 'b' : 2 } )
345- consume_blob_per_use (m = { 'a' : 3 , 'b' : 4 } )
354+ consume_blob (m = BlobModel ( a = 1 , b = 2 ) )
355+ consume_blob_per_use (m = AnotherModel ( a = 3 , b = 4 ) )
346356
347357
348358wg = BlobExamples .build ()
@@ -402,12 +412,14 @@ def AddMultiplyDataclass():
402412# %%
403413# .. important::
404414#
405- # Models/ dataclasses are annotation-only
406- # Even when you annotate with BaseModel or @dataclass, do not pass instances of these types to tasks/graphs. Always pass plain dictionaries :
415+ # Structured models (Pydantic or dataclasses) are supported as *runtime* values.
416+ # You may pass instances to tasks/graphs and return them from tasks :
407417#
408- # - This lets WorkGraph expand inputs/outputs into individual sockets, so it can wire provenance edges precisely (e.g., data.x --> task.data.x).
409- # - It allows graph inputs to be collected from task outputs as a dict of AiiDA ORM nodes, preserving AiiDA links between nodes.
410- # - Validation still happens via the WorkGraph spec (derived from your annotations)--you’re just not constructing runtime model/dataclass objects.
418+ # - Instances are expanded to plain dicts when assigned to namespace sockets, so WorkGraph can
419+ # wire provenance edges precisely (e.g., data.x --> task.data.x).
420+ # - Graph inputs can still be collected from task outputs as a dict of AiiDA ORM nodes,
421+ # preserving AiiDA links between nodes.
422+ # - Validation still happens via the WorkGraph spec (derived from your annotations).
411423#
412424# Data linkage
413425# ------------
0 commit comments