
    i.                         S SK r S SKrS SKJr  S SKJrJrJrJrJ	r	  S SK
JrJr  S SKJr  S SKJr  SSKJr  S	r " S
 S\5      r\R,                  " S\5         " S S\5      r\" S\\S9r " S S\\   5      rg)    N)asynccontextmanager)AnyAsyncGeneratorGenericOptionalType)	BaseModelValidationError)TypeVar)DictLikeModel   )BaseSerializeri  c                       \ rS rSrSrg)UnserializableKeyWarning    N)__name__
__module____qualname____firstlineno____static_attributes__r       W/home/james-whalen/.local/lib/python3.13/site-packages/workflows/context/state_store.pyr   r      s    r   r   oncec                   4   ^  \ rS rSrSrS\4U 4S jjrSrU =r$ )	DictState   a  
Dynamic, dict-like Pydantic model for workflow state.

Used as the default state model when no typed state is provided. Behaves
like a mapping while retaining Pydantic validation and serialization.

Examples:
    ```python
    from workflows.context.state_store import DictState

    state = DictState()
    state["foo"] = 1
    state.bar = 2  # attribute-style access works for nested structures
    ```

See Also:
    - [InMemoryStateStore][workflows.context.state_store.InMemoryStateStore]
paramsc                 &   > [         TU ]  " S0 UD6  g )Nr   )super__init__)selfr   	__class__s     r   r!   DictState.__init__,   s    "6"r   r   )	r   r   r   r   __doc__r   r!   r   __classcell__)r#   s   @r   r   r      s    &# # #r   r   MODEL_T)bounddefaultc                   6   \ rS rSr% SrSr\\   \S'   S\4S jr	S\4S jr
S	\SS
4S jrSSS\\\4   4S jr\S\\\4   SSSS4S j5       r\S\\S
4   4S j5       r\4S\S\\   S\4S jjrS\S\SS
4S jrSS jrS\S\S\4S jrS\S\S\SS
4S jrSrg
)InMemoryStateStore4   a  
Async, in-memory, type-safe state manager for workflows.

This store holds a single Pydantic model instance representing global
workflow state. When the generic parameter is omitted, it defaults to
[DictState][workflows.context.state_store.DictState] for flexible,
dictionary-like usage.

Thread-safety is ensured with an internal `asyncio.Lock`. Consumers can
either perform atomic reads/writes via `get_state` and `set_state`, or make
in-place, transactional edits via the `edit_state` context manager.

Examples:
    Typed state model:

    ```python
    from pydantic import BaseModel
    from workflows.context.state_store import InMemoryStateStore

    class MyState(BaseModel):
        count: int = 0

    store = InMemoryStateStore(MyState())
    async with store.edit_state() as state:
        state.count += 1
    ```

    Dynamic state with `DictState`:

    ```python
    from workflows.context.state_store import InMemoryStateStore, DictState

    store = InMemoryStateStore(DictState())
    await store.set("user.profile.name", "Ada")
    name = await store.get("user.profile.name")
    ```

See Also:
    - [Context.store][workflows.context.context.Context.store]
)memory
state_typeinitial_statec                 d    Xl         [        R                  " 5       U l        [	        U5      U l        g )N)_stateasyncioLock_locktyper.   )r"   r/   s     r   r!   InMemoryStateStore.__init__d   s     #\\^
}-r   returnc                 >   #    U R                   R                  5       $ 7f)z{Return a shallow copy of the current state model.

Returns:
    MODEL_T: A `.model_copy()` of the internal Pydantic model.
)r1   
model_copyr"   s    r   	get_stateInMemoryStateStore.get_statei   s      {{%%''s   stateNc                 (  #    [        U[        U R                  5      5      (       d!  [        S[        U R                  5       35      eU R                   ISh  vN   Xl        SSS5      ISh  vN   g N N! , ISh  vN  (       d  f       g= f7f)zReplace the current state model.

Args:
    state (MODEL_T): New state of the same type as the existing model.

Raises:
    ValueError: If the type differs from the existing state type.
zState must be of type N)
isinstancer5   r1   
ValueErrorr4   r"   r=   s     r   	set_stateInMemoryStateStore.set_stateq   sW      %dkk!2335d4;;6G5HIJJ:::K :::::sH   ABA4BA8#B.A6/B6B8B>B?BB
serializerr   c                    [        U R                  [        5      (       a{  0 nU R                  R                  5        H  u  p4 UR	                  U5      X#'   M     SU0[        U R                  5      R                  [        U R                  5      R                  S.$ UR	                  U R                  5      nU[        U R                  5      R                  [        U R                  5      R                  S.$ ! [
         aH  nX0R                  ;   a#  [        R                  " SU S3[        S9   SnAM  [        SU SU 35      eSnAff = f)	a  Serialize the state and model metadata for persistence.

For `DictState`, each individual item is serialized using the provided
serializer since values can be arbitrary Python objects. For other
Pydantic models, defers to the serializer (e.g. JSON) which can leverage
model-aware encoding.

Args:
    serializer (BaseSerializer): Strategy used to encode values.

Returns:
    dict[str, Any]: A payload suitable for
    [from_dict][workflows.context.state_store.InMemoryStateStore.from_dict].
z4Skipping serialization of known unserializable key: zY -- This is expected but will require this item to be set manually after deserialization.)categoryNz(Failed to serialize state value for key : _data)
state_datar.   state_module)r?   r1   r   items	serialize	Exceptionknown_unserializable_keyswarningswarnr   r@   r5   r   r   )r"   rD   serialized_datakeyvalueeserialized_states          r   to_dictInMemoryStateStore.to_dict   s2     dkk9-- O"kk//1
+5+?+?+FO( 2   '8"4;;/88 $T[[ 1 < <   *33DKK@ /"4;;/88 $T[[ 1 < < + ! 
<<< RSVRW Xt t%=
 !$B3%r!M 
s   C66
E ,E2EErU   zInMemoryStateStore[MODEL_T]c                    U(       d  U " [        5       5      $ UR                  S0 5      nUR                  SS5      nUS:X  aK  UR                  S0 5      n0 nUR                  5        H  u  px UR                  U5      Xg'   M     [        US9n
OUR                  U5      n
U " U
5      $ ! [         a  n	[        SU SU	 35      eSn	A	ff = f)	aX  Restore a state store from a serialized payload.

Args:
    serialized_state (dict[str, Any]): The payload produced by
        [to_dict][workflows.context.state_store.InMemoryStateStore.to_dict].
    serializer (BaseSerializer): Strategy to decode stored values.

Returns:
    InMemoryStateStore[MODEL_T]: A store with the reconstructed model.
rI   r.   r   rH   z*Failed to deserialize state value for key rG   N)rH   )r   getrK   deserializerM   r@   )clsrU   rD   rI   r.   _data_serializeddeserialized_datarR   rS   rT   state_instances              r   	from_dictInMemoryStateStore.from_dict   s      y{##%)),;
%)),D
 $)~~gr: ".446
-7-C-CE-J%* 7 '->?N'33J?N>"" ! $DSEA3O s   ,B&&
C0CCc                   #    U R                    ISh  vN   U R                  nU7v   Xl        SSS5      ISh  vN   g N, N! , ISh  vN  (       d  f       g= f7f)zEdit state transactionally under a lock.

Yields the mutable model and writes it back on exit. This pattern avoids
read-modify-write races and keeps updates atomic.

Yields:
    MODEL_T: The current state model for in-place mutation.
N)r4   r1   rA   s     r   
edit_stateInMemoryStateStore.edit_state   s2      :::KKEKK :::::sA   AA AAAAAAA
AAApathr)   c                   #    U(       a  UR                  S5      O/ n[        U5      [        :  a  [        S[         S35      eU R                   ISh  vN    U R
                  nU H  nU R                  XE5      nM     SSS5      ISh  vN   U$  N=! [         a1    U[        La  Us sSSS5      ISh  vN    $ SU S3n[        U5      ef = f NF! , ISh  vN  (       d  f       W$ = f7f)a  Get a nested value using dot-separated paths.

Supports dict keys, list indices, and attribute access transparently at
each segment.

Args:
    path (str): Dot-separated path, e.g. "user.profile.name".
    default (Any): If provided, return this when the path does not
        exist; otherwise, raise `ValueError`.

Returns:
    Any: The resolved value.

Raises:
    ValueError: If the path is invalid and no default is provided or if
        the path depth exceeds limits.
.Path length exceeds 	 segmentsNzPath 'z' not found in state)	splitlen	MAX_DEPTHr@   r4   r1   _traverse_steprM   Ellipsis)r"   rd   r)   segmentsrS   segmentmsgs          r   rY   InMemoryStateStore.get   s     $ '+4::c?x=9$3I;iHII:::	&![['G //?E  ( :  
  &(*"N :: tf$89 o%& :: sx   AC.BC.C&B?C.
CC.C(C)C.5B86C.<CCC.C+CC+&C.rS   c                   #    U(       d  [        S5      eUR                  S5      n[        U5      [        :  a  [        S[         S35      eU R                   ISh  vN   U R
                  nUSS  H  n U R                  XE5      nM     U R                  XCS   U5        SSS5      ISh  vN   g NT! [        [        [        [        4 a    0 nU R                  XEU5        Un Mt  f = f N>! , ISh  vN  (       d  f       g= f7f)aK  Set a nested value using dot-separated paths.

Intermediate containers are created as needed. Dicts, lists, tuples, and
Pydantic models are supported where appropriate.

Args:
    path (str): Dot-separated path to write.
    value (Any): Value to assign.

Raises:
    ValueError: If the path is empty or exceeds the maximum depth.
zPath cannot be emptyrf   rg   rh   N)r@   ri   rj   rk   r4   r1   rl   KeyErrorAttributeError
IndexError	TypeError_assign_step)r"   rd   rS   rn   currentro   intermediates          r   setInMemoryStateStore.set  s      344::c?x=9$3I;iHII:::kkG $CR=+"11'CG ) g|U; :: !.*iH +(*L%%gE*G	+ :::sl   ADB1D C,6B3C, D+C*,D30C'#C,&C''C,*D,D2C53D?Dc                    #     U R                  U R                  R                  5       5      I Sh  vN   g N! [         a    [	        S5      ef = f7f)zReset the state to its type defaults.

Raises:
    ValueError: If the model type cannot be instantiated from defaults
        (i.e., fields missing default values).
Nz'State must have defaults for all fields)rB   r1   r#   r
   r@   r:   s    r   clearInMemoryStateStore.clear1  sF     	H..!6!6!8999 	HFGG	Hs%   A,8 68 A8 AAobjro   c                     [        U[        5      (       a  X   $  [        U5      nX   $ ! [        [        [
        4 a     Of = f[        X5      $ )zCFollow one segment into *obj* (dict key, list index, or attribute).)r?   dictintr@   rw   rv   getattr)r"   r   ro   idxs       r   rl   !InMemoryStateStore._traverse_step=  sR    c4  <	g,C8OIz2 		 s$$s   * AAc                     [        U[        5      (       a  X1U'   g [        U5      nX1U'   g! [        [        [
        4 a     Of = f[        XU5        g)zJAssign *value* to *segment* of *obj* (dict key, list index, or attribute).N)r?   r   r   r@   rw   rv   setattr)r"   r   ro   rS   r   s        r   rx   InMemoryStateStore._assign_stepL  sV    c4   L	g,CHIz2 		 	e$s   , AA)r4   r1   r.   )r7   N)r   r   r   r   r%   rN   r   r'   __annotations__r!   r;   rB   r   strr   rV   classmethodr_   r   r   rb   rm   r   rY   r{   r~   rl   rx   r   r   r   r   r+   r+   4   s<   'V !,W.g .
( ( W    ."2 .tCH~ .` %##CH~%#;K%#	&%# %#N  .$"?      =E "c "HSM " "H"<c "<# "<$ "<H
H%# % % %% %c %# %$ %r   r+   )r2   rO   
contextlibr   typingr   r   r   r   r   pydanticr	   r
   typing_extensionsr   workflows.eventsr   serializersr   rk   Warningr   simplefilterr   r'   r+   r   r   r   <module>r      ss      * ? ? / % * '		w 	 	  f6 7# #2 )9i
@g%) g%r   