
    ph                        S r SSKrSSKrSSKrSSKJr  SrSrSrS r	S r
S	 rS
 rS rS r " S S\R                  5      rS rS rS rS rS r " S S\R,                  5      r " S S\R0                  5      rS rS rg)a  
PyPhi- and NumPy-aware JSON serialization.

To be properly serialized and deserialized, PyPhi objects must implement a
``to_json`` method which returns a dictionary of attribute names and attribute
values. These attributes should be the names of arguments passed to the object
constructor. If the constructor takes additional, fewer, or different
arguments, the object needs to implement a custom ``classmethod`` called
``from_json`` that takes a Python dictionary as an argument and returns a PyPhi
object. For example::

    class Phi:
        def __init__(self, phi):
            self.phi = phi

        def to_json(self):
            return {'phi': self.phi, 'twice_phi': 2 * self.phi}

        @classmethod
        def from_json(cls, json):
            return Phi(json['phi'])

The object must also be added to ``jsonify._loadable_models``.

The JSON encoder adds the name of the object and the current PyPhi version to
the JSON stream. The JSON decoder uses this metadata to recursively deserialize
the stream to a nested PyPhi object structure. The decoder will raise an
exception if current PyPhi version doesn't match the version in the JSON data.
    N)cache	__class____version____id__c                     [         R                  [         R                  [         R                  [         R                  [         R
                  R                  [         R                  R                  [         R                  R                  [         R                  R                  [         R                  R                  [         R                  R                  [         R                  R                  [         R                  R                  [         R                  R                  [         R                  R                   [         R                  R"                  [         R                  R$                  [         R                  R&                  [         R                  R(                  [         R                  R*                  [         R                  R,                  [         R                  R.                  [         R                  R0                  [         R                  R2                  [         R                  R4                  /n U  Vs0 s H  oR6                  U_M     sn$ s  snf )zA dictionary of loadable PyPhi models.

These are stored in this function (instead of module scope) to resolve
circular import issues.
)pyphi	DirectionNetwork	Subsystem
Transitionlabels
NodeLabelsmodelsCutKCutNullCutPartBipartition
KPartitionTripartition RepertoireIrreducibilityAnalysis!MaximallyIrreducibleCauseOrEffectMaximallyIrreducibleCauseMaximallyIrreducibleEffectConceptCauseEffectStructureSystemIrreducibilityAnalysis	ActualCut"AcRepertoireIrreducibilityAnalysis
CausalLinkAccountAcSystemIrreducibilityAnalysis__name__)classesclss     G/home/james-whalen/.local/lib/python3.13/site-packages/pyphi/jsonify.py_loadable_modelsr'   3   sN    	  !!5566..//))1177331G4 *11#LL#111s   7Ic                 l    U R                  5        VVs0 s H  u  pU[        U5      _M     snn$ s  snnf N)itemsjsonify)dctkeyvalues      r&   _jsonify_dictr/   V   s+    25))+>+JCC+>>>s   0c           
          U R                  [        UR                  R                  [        [
        R                  [        [        U5      05        U $ r)   )	update	CLASS_KEYr   r#   VERSION_KEYr   r   ID_KEYhash)r,   objs     r&   _push_metadatar7   Z   s=    JJ3==))U&&S	 
 J    c                 6    U [            U [           U [           4$ r)   )r2   r3   r4   r,   s    r&   _get_metadatar;   c   s    y>3{+S[88r8   c                 ~    U R                  [        5      U R                  [        5      U R                  [        5      4$ r)   )popr2   r3   r4   r:   s    r&   _pop_metadatar>   g   s)    779sww{3SWWV_DDr8   c                    [        U S5      (       a&  U R                  5       n[        X5        [        U5      $ [	        U [
        R                  5      (       a  U R                  5       $ [	        U [
        R                  [
        R                  45      (       a  [        U 5      $ [	        U [
        R                  5      (       a  [        U 5      $ [	        U [        5      (       a  [        U 5      $ [        U S5      (       a  [        U R                  5      $ [	        U [         ["        45      (       a  U  Vs/ s H  n[        U5      PM     sn$ U $ s  snf )zReturn a JSON-encodable representation of an object, recursively using
any available ``to_json`` methods, converting NumPy arrays and datatypes to
native lists and types along the way.
to_json__dict__)hasattrr@   r7   r+   
isinstancenpndarraytolistint32int64intfloat64floatdictr/   rA   listtuple)r6   ditems      r&   r+   r+   k   s     sIKKMqqz #rzz""zz| #"((+,,3x#rzz""Sz #tS!! sJS\\** #e}%%*-.#$#.. J /s   0E
c                   8   ^  \ rS rSrSrU 4S jrU 4S jrSrU =r$ )PyPhiJSONEncoder   zCJSONEncoder that allows serializing PyPhi objects with ``jsonify``.c                 4   > [         TU ]  [        U5      5      $ )z:Encode the output of ``jsonify`` with the default encoder.)superencoder+   )selfr6   r   s     r&   rV   PyPhiJSONEncoder.encode   s    w~gcl++r8   c                 8   > [         TU ]  " [        U5      40 UD6$ )z%Analog to `encode` used by json.dump.)rU   
iterencoder+   )rW   r6   kwargsr   s      r&   rZ   PyPhiJSONEncoder.iterencode   s    w!'#,9&99r8    )	r#   
__module____qualname____firstlineno____doc__rV   rZ   __static_attributes____classcell__r   s   @r&   rR   rR      s    M,: :r8   rR   c                 :    S[         S.nUR                  U 5        U$ )z>Update kwargs for `dump` and `dumps` to use the PyPhi encoder.),:)
separatorsr%   )rR   r1   )user_kwargsr[   s     r&   _encoder_kwargsrj      s    &/?@F
MM+Mr8   c                 B    [         R                  " U 40 [        U5      D6$ )z+Serialize ``obj`` as JSON-formatted stream.)jsondumpsrj   )r6   ri   s     r&   rm   rm      s    ::c:_[9::r8   c                 B    [         R                  " X40 [        U5      D6$ )znSerialize ``obj`` as a JSON-formatted stream and write to ``fp`` (a
``.write()``-supporting file-like object.
)rl   dumprj   )r6   fpri   s      r&   ro   ro      s     99S= <==r8   c                     U [         R                  :w  a=  [         R                  R                  SR	                  U [         R                  5      5      eg)z9Check whether the JSON version matches the PyPhi version.z^Cannot load JSON from a different version of PyPhi. JSON version = {0}, current version = {1}.N)r   r   
exceptionsJSONVersionErrorformat)versions    r&   _check_versionrv      sH    %###//99?**:,- 	- $r8   c                     [         U ;   $ )z0Check if ``dct`` is a PyPhi model serialization.)r2   r:   s    r&   	_is_modelrx      s    r8   c                       \ rS rSrSrS rSrg)_ObjectCache   zCCache mapping ids to loaded objects, keyed by the id of the object.c                     [        U5      $ r)   )r;   )rW   r,   r[   s      r&   r-   _ObjectCache.key   s    S!!r8   r]   N)r#   r^   r_   r`   ra   r-   rb   r]   r8   r&   rz   rz      s
    M"r8   rz   c                   b   ^  \ rS rSrSrU 4S jrS r\R                  " S5      S 5       r	Sr
U =r$ )PyPhiJSONDecoder   zoExtension of the default encoder which automatically deserializes
PyPhi JSON to the appropriate model classes.
c                    > U R                   US'   [        TU ]  " U0 UD6  [        5       U l        [        5       U l        g )Nobject_hook)_load_objectrU   __init__r'   _modelsrz   _object_cache)rW   argsr[   r   s      r&   r   PyPhiJSONDecoder.__init__   s=     $ 1 1}$)&) () *^r8   c                 B  ^  [        U[        5      (       aX  UR                  5        VVs0 s H  u  p#UT R                  U5      _M     nnn[	        U5      (       a  T R                  U5      $  U$ [        U[        5      (       a  [        U 4S jU 5       5      $ U$ s  snnf )ai  Recursively load a PyPhi object.

PyPhi models are recursively loaded, using the model metadata to
recreate the original object relations. Lists are cast to tuples
because most objects in PyPhi which are serialized to lists (eg.
mechanisms and purviews) are ultimately tuples. Other lists (tpms,
repertoires) should be cast to the correct type in init methods.
c              3   F   >#    U  H  nTR                  U5      v   M     g 7fr)   )r   ).0rP   rW   s     r&   	<genexpr>0PyPhiJSONDecoder._load_object.<locals>.<genexpr>   s     AST**400Ss   !)rC   rL   r*   r   rx   _load_modelrM   rN   )rW   r6   kvs   `   r&   r   PyPhiJSONDecoder._load_object   s     c4  7:yy{C{tq1d''**{CC~~'',,  
 T""ASAAA
 Ds   Br   c                     [        U5      u  p#n[        U5        U R                  U   n[        US5      (       a  UR	                  U5      $ U" S0 UD6$ )z`Load a serialized PyPhi model.

The object is memoized for reuse elsewhere in the object graph.
	from_jsonr]   )r>   rv   r   rB   r   )rW   r,   	classnameru   _r%   s         r&   r   PyPhiJSONDecoder._load_model   sU     !.c 2	Awll9% 3$$==%% zSzr8   )r   r   )r#   r^   r_   r`   ra   r   r   r   methodr   rb   rc   rd   s   @r&   r   r      s/    ,( \\/" #r8   r   c                 4    [         R                  " U [        S9$ )z-Deserialize a JSON string to a Python object.r%   )rl   loadsr   )strings    r&   r   r      s    ::f"233r8   c                 4    [         R                  " U [        S9$ )z-Deserialize a JSON stream to a Python object.r   )rl   loadr   )rp   s    r&   r   r      s    99R-..r8   )ra   rl   numpyrD   r   r   r2   r3   r4   r'   r/   r7   r;   r>   r+   JSONEncoderrR   rj   rm   ro   rv   rx   	DictCacherz   JSONDecoderr   r   r   r]   r8   r&   <module>r      s   <    		 2F?9E"J	:t'' 	:;
>-
"5?? "3t'' 3l4
/r8   