GraphBuilder->Graph with separate Workflow type#381
Conversation
e8d272b to
7e92fcb
Compare
dc8ba1f to
e8ce026
Compare
…puts_type before outputs_type (#391) Also remove some overloads that seem pointless (??), and tidy some imports Removing generics_in_ptype as a preliminary to #381 because it's hard to handle parametrized FinishedGraph. `TypedGraphRef[Inputs, Outputs]` was constructed via `TypedGraphRef(outputs_type, inputs_type)`, so reorder the latter. (Although the `inputs_type` field is unused it helps `pyright` figure out the `Inputs` type parameter when in strict mode or with `reportUnknownVariableType` so keep it for now.)
e8ce026 to
969cd0f
Compare
…ke & stubs import FinGraph, regen stubs+import FinishedGraph...tests pass but pyright fails
| graph: GraphBuilder[A, B], | ||
| graph: FinishedGraph[A, B], | ||
| ) -> TypedGraphRef[A, B]: | ||
| # TODO @philipp-seitz: Turn this into a public method? |
There was a problem hiding this comment.
I'd +1 this, shall I do it in this PR?
There was a problem hiding this comment.
Go for it if it's a simple change
There was a problem hiding this comment.
Was gonna leave this until we could unify TKR[Workflow...] and TypedGraphRef but now I realise that we can't - the former is a handle to a Workflow that will have outputs_type when it appears, whereas TypedGraphRef gives us that outputs_type right now.
So, yes, done, removing a #noqa
|
Why do we need both |
As per last paragraph in the description (TODOs/future work):
I.e. I think we need GraphData as an internal struct, for (a) serialization, and (b) passing from GraphBuilder into FinishedGraph, but we could hide it from the user with more updates to tests etc. Except this may restrict |
…es from types.py (still defined at bottom)
07f9b93 to
6ccf080
Compare
johnchildren
left a comment
There was a problem hiding this comment.
I have some small comments but I think we can likely proceed with merging with or/without them
| from typing import NamedTuple | ||
|
|
||
| from tierkreis.builder import GraphBuilder | ||
| from tierkreis.builder import Graph |
There was a problem hiding this comment.
Entirely a vanity thing but do we want to change the module where we import this from as well? I don't think it matters too much though. Possibly we should at least re-export Graph from the root module.
| outs_str = "\n ".join(outs) | ||
|
|
||
| bases = ["NamedTuple"] if is_portmapping else ["Struct", "Protocol"] | ||
| def is_tmodel() -> bool: |
There was a problem hiding this comment.
Is it worth moving this out into a top level function? As far as I can tell it only captures model from the outer scope.
There was a problem hiding this comment.
Or a method on tierkreis.idl.models.Model ?
There was a problem hiding this comment.
Yes that could make sense as we know we have a Model at this point, I don't have a preference.
There was a problem hiding this comment.
Moved to a function on Model, admittedly it is a little bit dubious because GenericType.is_ptype itself is a bit dubious (i.e. we only really know if we build the GenericType from a type)
| graph: GraphBuilder[A, B], | ||
| graph: FinishedGraph[A, B], | ||
| ) -> TypedGraphRef[A, B]: | ||
| # TODO @philipp-seitz: Turn this into a public method? |
There was a problem hiding this comment.
Go for it if it's a simple change
| :rtype: TypedGraphRef[Inputs, Outputs] | ||
| """ | ||
| return TypedGraphRef((-1, "body"), self.inputs_type, self.outputs_type) | ||
| return TypedGraphRef(TKR(-1, "body"), self.outputs_type) |
There was a problem hiding this comment.
I think this might be the first time we are constructing TKR directly rather than using ValueRef. I don't really object to this but we might want to clarify what the distinction between the two is meant to be later.
There was a problem hiding this comment.
Not the first time - existing cases in ifelse, eifelse, and _map_fn_single_in in this file. I am not really sure what the difference is - is it just that TKR is parametrized (TKR[T: PModel]) whereas ValueRef is not? (in which case we might want to combine them?? one can always use x: TKR without specifying the type argument)
fwiw, TKR has a method for returning a ValueRef.
There was a problem hiding this comment.
Yeah possibly TKR carries type information while ValueRef doesn't then? Worth reviewing again at a later date.
…references from types.py (still defined at bottom)" This reverts commit 6ccf080.
|
|
||
| if issubclass(origin, Workflow): | ||
| _inputs, outputs = get_args(annotation) | ||
| return annotation(coerce_from_annotation(ser, GraphData), outputs) # type: ignore |
There was a problem hiding this comment.
annotation(output_type=outputs, **ser)Could work if we want to do something minimal that allows type erasure.
This reverts commit c5bb444.
|
Reverted to listing |
Workflowholding a GraphData and outputs_type..outputsrenamed to.finish_with_outputswhich returns a Workflowfinish_with_outputstobuild??loop,eval) to take Workflow's, removing check inembedthat the Output node is present (this is now guaranteed if your python code is well-typed - I was surprised not to find more such checks in map/loop/eval/const/etc.)ModelConvertibleprotocol like DictConvertible/etc. but that works for parametrized types. (This was a bit of a can of worms, there are some slightly suspect bits intypes.py.) Workflow implements this, and serializes as aGraphData. (Type erasure: Workflow is a build-time-only construct).PType's which was a bit hacky (special-case, awkward circular import, etc.) but a lot shorter/easier (andDictConvertiblemakes me worry about robustness and parametrization). Thoughts?Structs (by adding anis_ptypefield to GenericType - this is not super-neat, suggestions of better ways to do this welcome, but my previous attempt was even (much) worse]: 454c18f)@runtime_checkablefrom theRestrictedNamedTuplesubclasses/instantiations, but leaving that for Another PRGraphBuilderandGraphrather thanGraphandWorkflow???The end result is that you need fewer
TypedGraphRefs (but still some), and when you do need one,pyrightshould catch cases of providing the wrongoutputs_type(because this is now just a runtime reification of a type thatpyrightknows statically).Other possible TODOs (maybe too much for one PR??)
_BaseGraph[Inputs]with all methods exceptfinish_with_outputsandgraph_ref, thenclass Graph[Inputs](_BaseGraph[Inputs]): ...fn finish_with_outputs[Outputs](self, outputs_type: type[Outputs], outputs: Outputs)and separatelyclass RecursiveGraph[Inputs,Outputs](_BaseGraph[Inputs]): ...fn finish_with_outputs(self, outputs: Outputs)plusfn graph_ref(self). Not sure whether this is worth it so I think leave for another PR?