Pārlūkot izejas kodu

feat/fix: allow for anonymous output structs to be emitted from e.g. cipy.Script objects

Sam Jaffe 1 mēnesi atpakaļ
vecāks
revīzija
0cbf275c7e
2 mainītis faili ar 18 papildinājumiem un 6 dzēšanām
  1. 12 0
      src/cipy/__init__.py
  2. 6 6
      src/cipy/runner.py

+ 12 - 0
src/cipy/__init__.py

@@ -5,6 +5,7 @@ Entry point for cipy library, re-exporting all of the default items
 import logging
 import types
 import typing
+import sys
 
 import pydantic
 
@@ -44,6 +45,7 @@ __all__ = [
     "Workflow",
     "compute",
     "context",
+    "outputs",
     "required",
 ]
 
@@ -69,3 +71,13 @@ def compute(arg: typing.Callable[[Context], typing.Any], /) -> typing.Any:
     based on the runtime CI context.
     """
     return pydantic.Field(default=Factory(arg))
+
+
+def outputs(**fields: types.UnionType | type[typing.Any]) -> Outputs:
+    frame = sys._getframe(1)
+    return pydantic.create_model(  # type: ignore[call-overload]
+        f"__{frame.f_lineno}_AnonymousOutputs",
+        __base__=Outputs,
+        __module__=frame.f_globals["__name__"],
+        **{k: typing.Annotated[t, pydantic.Field(default=None)] for k, t in fields.items()}
+    )()

+ 6 - 6
src/cipy/runner.py

@@ -63,13 +63,13 @@ def ipc(func: Run[Action]) -> Run[Action]:
         ):
             rval = func(self, context)
 
-            if self.outputs is None:
-                self.outputs = self.__pydantic_fields__["outputs"].annotation()
-
             outdata = dotenv_values(output.name)
-            for k in self.outputs.__pydantic_fields__:
-                if k in outdata:
-                    setattr(self.outputs, k, outdata[k])
+            if self.outputs is not None:
+                outdata = vars(self.outputs) | outdata
+
+            annotation = self.__pydantic_fields__["outputs"].annotation
+            assert annotation is not None
+            self.outputs = annotation(**outdata)
 
             _validate(self.outputs)
         return rval