Skip to content

Commit 30e109a

Browse files
timkpaineNeejWeej
andauthored
Add @Flow.model functional API (#232)
* Add Flow.model generated callable models Signed-off-by: Nijat K <nijat.khanbabayev@gmail.com> * Handle FlowContext and existing context case and clean up code Signed-off-by: Nijat K <nijat.khanbabayev@gmail.com> * Further simplify Flow.model internals Signed-off-by: Nijat K <nijat.khanbabayev@gmail.com> * Trim public export Signed-off-by: Nijat K <nijat.khanbabayev@gmail.com> * Bug fixes Signed-off-by: Nijat K <nijat.khanbabayev@gmail.com> * Simplify tests, harden detecting nested/local @Flow.model Signed-off-by: Nijat K <nijat.khanbabayev@gmail.com> * Move examples inside ccflow, not top level Signed-off-by: Nijat K <nijat.khanbabayev@gmail.com> * Add 'inspect' to consolidate introspection for @Flow.model Signed-off-by: Nijat K <nijat.khanbabayev@gmail.com> * Remove uneeded ray tests, add comment pointing to issue 221 for helpers defining local classes Signed-off-by: Nijat K <nijat.khanbabayev@gmail.com> * Split _build_compute_context into focused per-path helpers (#233) `_build_compute_context` mixed argument validation, the explicit-context path, plain-CallableModel defaults, and generated-model handling across one long function with several exit branches. Extract the three paths into `_compute_context_from_explicit`, `_compute_context_for_plain_model`, and `_compute_context_for_generated_model`, leaving `_build_compute_context` as a thin dispatcher. Behavior-preserving refactor; no functional change. Verified against the full flow_model, flow_context, hydra, and evaluator suites. Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com> * Add parity tests for model_alias vs bare-string registry aliases (#234) In ccflow a bare string field value already resolves from the model registry, so `ccflow.compose.model_alias`, a bare-string alias, and a root-relative `/name` alias should all dereference to the same registered model instance. `model_alias` is a Hydra convenience for the existing bare-string convention, not a separate mechanism. Adds a small Hydra config wiring one registered source three equivalent ways and tests asserting all three resolve to the same instance (not a literal string) and compute identically. Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com> * Fix Optional[FromContext[T]] classification and define its semantics (#235) `_parse_annotation` only peeled the top-level `Annotated`, so `Optional[FromContext[int]]` (a Union on the outside) was silently misclassified as a regular parameter and every call failed with a misleading "cannot satisfy unbound regular parameter" error. Detect `FromContext`/`Lazy` markers nested inside a top-level Optional and define the two spellings precisely: - `FromContext[Optional[int]]`: contextual, required-in-context, value may be None. - `Optional[FromContext[int]]`: contextual, optional; absent -> bound to None (an implicit None default synthesized in `_analyze_flow_function`). `FromContext[Optional[int]] = None` is therefore equivalent to `Optional[FromContext[int]]`, and an explicit default still wins. Distinct required-ness yields distinct config/cache identities via the existing has_function_default/function_default identity terms. Reject nested `Lazy` (`Optional[Lazy[int]]`) and non-Optional unions carrying `FromContext` (e.g. `Union[FromContext[int], str]`) with clear messages. Adds focused regression tests covering all call shapes, the consistency equivalences, and the rejection cases. Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com> * Accept positional/string context shorthand for Flow.model(context_type=) (#237) Class-based CallableModel execution already accepts positional/string context shorthand via ContextBase's ordered `zip(model_fields, v)` mapping (as used by Hydra `+context=[...]`). Generated @Flow.model instances expose the open FlowContext bag as their runtime context type, which has no declared fields to zip against, so positional shorthand was silently dropped. When a generated model declares a `context_type`, `compute()` now validates non-mapping shorthand (list/tuple/str) through that declared type first, then forwards the named values into the FlowContext bag. Mapping and named-kwarg inputs keep their existing paths. Scope: this covers the `compute()` entry point only. The direct-call form (`model([...])`) is intentionally not supported, since `Flow.call` validates against FlowContext before the generated body runs; supporting it would require reverting the bag-of-types design. Adds `_declared_context_type_for_model` and focused tests for list/tuple/string shorthand, parity with named inputs, and that bag-only models are unaffected. Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com> * Add characterization tests for effective-key equivalence (#238) The dependency-graph builder and cache-key path route every node through `_effective_evaluation_key()`. For models that do not opt into effective identity (everything except generated @Flow.model / BoundModel), the result must stay byte-for-byte identical to the structural `cache_key()`. Pin that equivalence so future changes to the effective path cannot silently shift cache or graph identity for ordinary CallableModel graphs: - effective cache_key == structural cache_key for simple, chain, and diamond graphs; - the dependency graph (root_id, node keys, edges) built via the effective path equals an independently-computed structural graph; - shared diamond leaves still dedupe to one node; - `_build_dependency_graph` returns the structural root key. Test-only; no library changes. Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com> * Add Flow.model(context_type=, strict=False) subset/omnibus context (#236) By default a declared `context_type` may now be an "omnibus" superset: every `FromContext[...]` parameter must exist on the context with a compatible type, but the context may carry extra fields the model does not consume. This matches the otherwise-permissive bag-of-types design and lets multiple models share one broad context. - `_validate_declared_context_type(..., strict=False)` keeps the missing-field and type-compatibility checks but only enforces the "every required context field is a FromContext param" bijection when `strict=True`. - Runtime: `_validate_declared_context_values` validates the consumed fields individually when the declared context has unconsumed required fields (subset mode); otherwise it constructs the whole declared context so its cross-field validators still run. No config/serialization change needed. - Thread `strict` through `flow_model` and document it on `Flow.model`. Updates the existing extra-required-field test to reflect the new default (allowed by default, rejected under strict=True) and adds focused tests for subset execution, strict rejection/acceptance, and the shared missing/type checks that apply in both modes. Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com> * Allow `flow` as a @Flow.model parameter name `model.flow` was a property (data descriptor), so a same-named pydantic field was silently unreadable; `@Flow.model` therefore rejected params named `flow`. Replace the property with a non-data descriptor so a `flow` field shadows it through the instance __dict__, and add `Flow.of(model)` (backed by `_flow_api`) as the escape hatch to reach the API in that case. `meta`, `context_type`, `result_type`, and `type_` stay reserved: the runtime reads them directly, so shadowing them would silently break execution rather than raise. Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com> --------- Signed-off-by: Nijat K <nijat.khanbabayev@gmail.com> Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com> Co-authored-by: Nijat K <nijat.khanbabayev@gmail.com>
1 parent 6deda80 commit 30e109a

29 files changed

Lines changed: 10843 additions & 30 deletions

ccflow/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from .callable import *
1212
from .context import *
1313
from .enums import Enum
14+
from .flow_model import *
1415
from .global_state import *
1516
from .local_persistence import *
1617
from .models import *

0 commit comments

Comments
 (0)