Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
de87bb2
Add ability to define dynamic context from kwargs
NeejWeej Dec 31, 2025
c16613f
Merge branch 'nk/local_model_context_registration' into nk/add_dynami…
NeejWeej Dec 31, 2025
f89ff9f
Merge branch 'nk/local_model_context_registration' into nk/add_dynami…
NeejWeej Dec 31, 2025
66b0e4e
Merge branch 'nk/local_model_context_registration' into nk/add_dynami…
NeejWeej Dec 31, 2025
6f71e38
Merge branch 'nk/local_model_context_registration' into nk/add_dynami…
NeejWeej Dec 31, 2025
95119e3
Remove dynamic context, add option to Flow.call
NeejWeej Jan 1, 2026
989e278
Add @Flow.model decorator, new annotation that pulls from deps
NeejWeej Jan 5, 2026
970b4ab
Inside CallableModel, force calling resolve on DepOf to not do hacky …
NeejWeej Jan 5, 2026
2696fce
High level design doc
NeejWeej Jan 5, 2026
d180f35
Add extra stuff, need clean-up
NeejWeej Jan 13, 2026
504dd96
Merge branch 'main' into nk/auto_deps_auto_callable_model
NeejWeej Mar 16, 2026
9495915
Lint fixes
NeejWeej Mar 16, 2026
765299d
Flow.model cleanup
NeejWeej Mar 17, 2026
097ae62
Update docs for @Flow.model
NeejWeej Mar 17, 2026
3d26896
Clean up, ty check @Flow.model, add test
NeejWeej Mar 17, 2026
0c274a1
Clean up more, make repr nicer for BoundModel
NeejWeej Mar 17, 2026
9c7bc7d
Small bug fixes for @Flow.model
NeejWeej Mar 17, 2026
5569ed0
Temp progress for cleaning up
NeejWeej Mar 18, 2026
20612e2
Further clean-up
NeejWeej Mar 19, 2026
587b26f
Update docs and small flow_model changes
NeejWeej Mar 19, 2026
517f45e
Add more examples
NeejWeej Mar 19, 2026
324fc4e
More test coverage
NeejWeej Mar 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ccflow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from .callable import *
from .context import *
from .enums import Enum
from .flow_model import *
from .global_state import *
from .local_persistence import *
from .models import *
Expand Down
334 changes: 295 additions & 39 deletions ccflow/callable.py

Large diffs are not rendered by default.

49 changes: 47 additions & 2 deletions ccflow/context.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
"""This module defines re-usable contexts for the "Callable Model" framework defined in flow.callable.py."""

from collections.abc import Mapping
from datetime import date, datetime
from typing import Generic, Hashable, Optional, Sequence, Set, TypeVar
from typing import Any, Generic, Hashable, Optional, Sequence, Set, TypeVar

from deprecated import deprecated
from pydantic import field_validator, model_validator
from pydantic import ConfigDict, field_validator, model_validator

from .base import ContextBase
from .exttypes import Frequency
from .validators import normalize_date, normalize_datetime

__all__ = (
"FlowContext",
"NullContext",
"GenericContext",
"DateContext",
Expand Down Expand Up @@ -89,6 +91,49 @@
# Starting 0.8.0 Nullcontext is an alias to ContextBase
NullContext = ContextBase


class FlowContext(ContextBase):
"""Universal context for @Flow.model functions.

Instead of generating a new ContextBase subclass for each @Flow.model,
this single class with extra="allow" serves as the universal carrier.
Validation happens via TypedDict + TypeAdapter at compute() time.

This design avoids:
- Proliferation of dynamic _funcname_Context classes
- Class registration overhead for serialization
- Pickling issues with Ray/distributed computing
"""

model_config = ConfigDict(extra="allow", frozen=True)

def __eq__(self, other: Any) -> bool:
if not isinstance(other, FlowContext):
return False
return self.model_dump(mode="python") == other.model_dump(mode="python")

def __hash__(self) -> int:
return hash(_freeze_for_hash(self.model_dump(mode="python")))


def _freeze_for_hash(value: Any) -> Hashable:
if isinstance(value, Mapping):
return tuple(sorted((key, _freeze_for_hash(item)) for key, item in value.items()))
if isinstance(value, (list, tuple)):
return tuple(_freeze_for_hash(item) for item in value)
if isinstance(value, (set, frozenset)):
return frozenset(_freeze_for_hash(item) for item in value)
if hasattr(value, "model_dump"):
return (type(value), _freeze_for_hash(value.model_dump(mode="python")))
try:
hash(value)
except TypeError as exc:
if hasattr(value, "__dict__"):
return (type(value), _freeze_for_hash(vars(value)))
raise TypeError(f"FlowContext contains an unhashable value of type {type(value).__name__}") from exc
return value


C = TypeVar("C", bound=Hashable)


Expand Down
Loading
Loading