
    hS                        S r SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKrSSK	r	SSK
JrJrJr  SSKrSSKrSSKrSSKJr  SSKJrJr  S\S\S\4S	 jrS\S\S
\SS4S jrS\S\4S jrS\\\4   S\4S jrS%S\S\\\\4      S\\\4   4S jjr\R@                   S&S\\\RB                  \RD                  4   S\S\#S\\   S\\RH                  \RJ                  \RL                  \RN                  4   4
S jj5       r(\(RS                  \5      S&S\S\S\#S\\   S\RD                  4
S jj5       r*\(RS                  \RB                  5      S&S\RB                  S\S\#S\\   S\RD                  4
S jj5       r+    S'S\\\RB                  \RD                  4   S\\\\4      S\\\\4      S\\\\4      S\#SS4S jjr,S(S\\\RB                  \RD                  4   S\S\#SS4S jjr-S(S\\\RB                  \RD                  4   S\#S\4S jjr.     S)S \\\RB                  \RD                  4   S!\S\\\\4      S"\\R^                  \4   S\#S#\S\0\\\\4      \\\   4   4S$ jjr1g)*zb
Save util taken from stable_baselines
used to serialize data (class parameters) of model classes
    N)AnyOptionalUnion)
TensorDict)
get_deviceget_system_infoobjattrreturnc                    ^ S[         S[        S[         4U4S jjn[        R                  " X0/UR	                  S5      Q5      $ )a  
Recursive version of getattr
taken from https://stackoverflow.com/questions/31174295

Ex:
> MyObject.sub_object = SubObject(name='test')
> recursive_getattr(MyObject, 'sub_object.name')  # return test
:param obj:
:param attr: Attribute to retrieve
:return: The attribute
r	   r
   r   c                    > [        X/TQ76 $ N)getattr)r	   r
   argss     \/home/james-whalen/.local/lib/python3.13/site-packages/stable_baselines3/common/save_util.py_getattr#recursive_getattr.<locals>._getattr&   s    s(4((    .)r   str	functoolsreducesplit)r	   r
   r   r   s     ` r   recursive_getattrr      s@    )c ) ) ) H&=TZZ_&=>>r   valc                 p    UR                  S5      u  p4n[        U(       a  [        X5      XR5      $ U XR5      $ )a  
Recursive version of setattr
taken from https://stackoverflow.com/questions/31174295

Ex:
> MyObject.sub_object = SubObject(name='test')
> recursive_setattr(MyObject, 'sub_object.name', 'hello')
:param obj:
:param attr: Attribute to set
:param val: New value of the attribute
r   )
rpartitionsetattrr   )r	   r
   r   pre_posts         r   recursive_setattrr"   ,   s5     ??3'LCD#$S.JJ3JJr   itemc                 ^    Sn [         R                  " U 5      nU$ ! [         a    Sn U$ f = f)z
Test if an object is serializable into JSON

:param item: The object to be tested for JSON serialization.
:return: True if object is JSON serializable, false otherwise.
TF)jsondumps	TypeError)r#   json_serializabler    s      r   is_json_serializabler)   <   sB     "JJt   "!"s    ,,datac                 Z   0 nU R                  5        H  u  p#[        U5      (       a  X1U'   M  [        R                  " [        R
                  " U5      5      R                  5       n[        [        U5      5      US.n[        US5      (       d  [        U[        5      (       aj  [        U[        5      (       a  UR                   OUR                  R                   nU" 5        H(  u  px[        U5      (       a  XU'   M  [        U5      XW'   M*     XQU'   GM     [        R
                  " USS9n	U	$ )a   
Turn data (class parameters) into a JSON string for storing

:param data: Dictionary of class parameters to be
    stored. Items that are not JSON serializable will be
    pickled with Cloudpickle and stored as bytearray in
    the JSON file
:return: JSON string of the data serialized.
)z:type::serialized:__dict__   )indent)itemsr)   base64	b64encodecloudpickler&   decoder   typehasattr
isinstancedictr-   r%   )
r*   serializable_datadata_key	data_itembase64_encodedcloudpickle_serializationitem_generatorvariable_namevariable_itemjson_strings
             r   data_to_jsonrB   L   s    #zz|	***3h' $--k.?.?	.JKRRTN d9o. .)% y*--It1L1L4>y$4O4OU^UgUgUmUm4B4D0M ,M::CP-@CF}CU1@ 5E +Dh'K  ,L **.q9Kr   rA   custom_objectsc                 N   Ub   [        U[        5      (       d  [        S5      e[        R                  " U 5      n0 nUR                  5        H  u  pEUb  XAR                  5       ;   a  X   X4'   M#  [        U[        5      (       aZ  SUR                  5       ;   aF  US   n [        R                  " UR                  5       5      n[        R                  " U5      nXU'   M  XSU'   M     U$ ! [        [        [        4 a'  n	[        R                  " SU SU	 35         Sn	A	M  Sn	A	ff = f)a  
Turn JSON serialization of class-parameters back into dictionary.

:param json_string: JSON serialization of the class-parameters
    that should be loaded.
:param custom_objects: Dictionary of objects to replace
    upon loading. If a variable is present in this dictionary as a
    key, it will not be deserialized and the corresponding item
    will be used instead. Similar to custom_objects in
    ``keras.models.load_model``. Useful when you have an object in
    file that can not be deserialized.
:return: Loaded class parameters.
Nz.custom_objects argument must be a dict or Noner,   zCould not deserialize object zN. Consider using `custom_objects` argument to replace this object.
Exception: )r7   r8   
ValueErrorr%   loadsr0   keysr1   	b64decodeencoder3   RuntimeErrorr'   AttributeErrorwarningswarn)
rA   rC   	json_dictreturn_datar:   r;   serializationbase64_objectdeserialized_objectes
             r   json_to_datarT      s    !*^T*J*JIJJ

;'IK(0%(6I6I6K*K %3$<K!	4((^y~~?O-O &n5M< & 0 01E1E1G H&1&7&7&F# )<H% %.!5  16  !)^< 3H: >" #$& s   :C((D$=DD$pathmodeverbosesuffixc                    [         R                  [         R                  [         R                  [         R                  4n[        X5      (       d  [        SU  SU S35      eU R                  (       a  [        SU  S35      eUR                  5       n SSSSS.U   nSU:X  a  U R                  5       (       a  SU:X  a.  U R                  5       (       d  SU:X  a  SOSn[        SU S35      eU $ ! [         a  n[        S	5      UeS
nAff = f)as  
Opens a path for reading or writing with a preferred suffix and raises debug information.
If the provided path is a derivative of io.BufferedIOBase it ensures that the file
matches the provided mode, i.e. If the mode is read ("r", "read") it checks that the path is readable.
If the mode is write ("w", "write") it checks that the file is writable.

If the provided path is a string or a pathlib.Path, it ensures that it exists. If the mode is "read"
it checks that it exists, if it doesn't exist it attempts to read path.suffix if a suffix is provided.
If the mode is "write" and the path does not exist, it creates all the parent folders. If the path
points to a folder, it changes the path to path_2. If the path already exists and verbose >= 2,
it raises a warning.

:param path: the path to open.
    if save_path is a str or pathlib.Path and mode is "w", single dispatch ensures that the
    path actually exists. If path is a io.BufferedIOBase the path exists.
:param mode: how to open the file. "w"|"write" for writing, "r"|"read" for reading.
:param verbose: Verbosity level: 0 for no output, 1 for info messages, 2 for debug messages
:param suffix: The preferred suffix. If mode is "w" then the opened file has the suffix.
    If mode is "r" then we attempt to open the path. If an error is raised and the suffix
    is not None, we attempt to open the path with the suffix.
:return:
zPath z- parameter has invalid type: expected one of r   zFile stream z is closed.wr)writereadrZ   r[   &Expected mode to be either 'w' or 'r'.NwritablereadablezExpected a z file.)ioBufferedWriterBufferedReaderBytesIOBufferedRandomr7   r'   closedrE   lowerKeyErrorr_   r`   )rU   rV   rW   rX   allowed_typesrS   	error_msgs          r   	open_pathrk      s    8 &&(9(92::rGXGXYMd**%v%RS`Raabcdd{{<v[9::::<DJc#>tD 
dmmooC4K"%+J:	;yk899K  JABIJs   
C- -
D7DDc                 D    [        [        R                  " U 5      XU5      $ )a  
Open a path given by a string. If writing to the path, the function ensures
that the path exists.

:param path: the path to open. If mode is "w" then it ensures that the path exists
    by creating the necessary folders and renaming path if it points to a folder.
:param mode: how to open the file. "w" for writing, "r" for reading.
:param verbose: Verbosity level: 0 for no output, 1 for info messages, 2 for debug messages
:param suffix: The preferred suffix. If mode is "w" then the opened file has the suffix.
    If mode is "r" then we attempt to open the path. If an error is raised and the suffix
    is not None, we attempt to open the path with the suffix.
:return:
)open_path_pathlibpathlibPath)rU   rV   rW   rX   s       r   open_path_strrp      s     W\\$/GGr   c                    US;  a  [        S5      eUS:X  a   [        U R                  S5      XU5      $  U R                  S:X  a$  Ub!  US:w  a  [        R
                  " U  SU 35      n U R                  5       (       a5  U R                  5       (       a   US:  a  [        R                  " S	U  S35        [        U R                  S5      XU5      $ ! [         aV  nUbL  US:w  aF  [        R
                  " U  SU 35      nUS:  a  [        R                  " S	U  S
U S35        USp0 SnAOUeSnAff = f! [         a9    [        R                  " S	U  SU  S35        [        R
                  " U  S35      n  OM[         aA    [        R                  " S	U R                   S35        U R                  R                  SSS9   Of = f[        XX#5      $ )a  
Open a path given by a string. If writing to the path, the function ensures
that the path exists.

:param path: the path to check. If mode is "w" then it
    ensures that the path exists by creating the necessary folders and
    renaming path if it points to a folder.
:param mode: how to open the file. "w" for writing, "r" for reading.
:param verbose: Verbosity level: 0 for no output, 2 for indicating if path without suffix is not found when mode is "r"
:param suffix: The preferred suffix. If mode is "w" then the opened file has the suffix.
    If mode is "r" then we attempt to open the path. If an error is raised and the suffix
    is not None, we attempt to open the path with the suffix.
:return:
)rZ   r[   r^   r[   rbN r      zPath 'z' not found. Attempting z' exists, will overwrite it.wbz$' is a folder. Will save instead to _2z!' does not exist. Will create it.T)exist_okparents)rE   rk   openFileNotFoundErrorrn   ro   rL   rM   rX   existsis_fileIsADirectoryErrorparentmkdirrm   )rU   rV   rW   rX   errornewpaths         r   rm   rm      s     :ABBs{		TYYt_dVDD	;{{b V%7FbL||tfAfX$67{{}}GqLtf,HIJTYYt_dVDD ! 	!fl!,,$q'9:a<MMF4&0H	QR"ST&f	 ! 	-MMF4&(LTFRTUV<<4&,D  	;MMF4;;-/PQRKKtT:	; T99s8   C BD3 
D0A
D+)D++D03A F?5AF?>F?	save_pathparamspytorch_variablesc                    [        U SSSS9nUb  [        U5      n[        R                  " USS9 nUb  UR	                  SW5        Ub0  UR                  SSS	S
9 n[        R                  " X85        SSS5        UbL  UR                  5        H8  u  pUR                  U	S-   SS	S
9 n[        R                  " X5        SSS5        M:     UR	                  S[        R                  5        UR	                  S[        SS9S   5        SSS5        [        U [        [        R                  45      (       a  UR!                  5         gg! , (       d  f       N= f! , (       d  f       M  = f! , (       d  f       Nh= f)a6  
Save model data to a zip archive.

:param save_path: Where to store the model.
    if save_path is a str or pathlib.Path ensures that the path actually exists.
:param data: Class parameters being stored (non-PyTorch variables)
:param params: Model parameters being stored expected to contain an entry for every
               state_dict with its name and the state_dict.
:param pytorch_variables: Other PyTorch variables expected to contain name and value of the variable.
:param verbose: Verbosity level: 0 for no output, 1 for info messages, 2 for debug messages
rZ   r   ziprW   rX   NrV   r*   pytorch_variables.pthT)rV   force_zip64.pth_stable_baselines3_versionsystem_info.txtF)
print_info   )rk   rB   zipfileZipFilewritestrry   thsaver0   sb3__version__r   r7   r   rn   ro   close)r   r*   r   r   rW   fileserialized_dataarchivepytorch_variables_file	file_namedict_
param_files               r   save_to_zip_filer   &  s?   $ YQu=D &t, 
C	(GV_5(5CTRVl)B S$*LLN 	\\)f"43D\QU_GGE. RQ %3 	5sG*Ou,Ma,PQ 
)  )c7<<011

 2 SR RQ 
)	(s<   *E&E14E&%E<AE&
E	E&
E#E&&
E4c                     [        U SUSS9n[        R                  " X[        R                  S9  [	        U [
        [        R                  45      (       a  UR                  5         gg)a9  
Save an object to path creating the necessary folders along the way.
If the path exists and is a directory, it will raise a warning and rename the path.
If a suffix is provided in the path, it will use that suffix, otherwise, it will use '.pkl'.

:param path: the path to open.
    if save_path is a str or pathlib.Path and mode is "w", single dispatch ensures that the
    path actually exists. If path is a io.BufferedIOBase the path exists.
:param obj: The object to save.
:param verbose: Verbosity level: 0 for no output, 1 for info messages, 2 for debug messages
rZ   pklr   )protocolN)	rk   pickledumpHIGHEST_PROTOCOLr7   r   rn   ro   r   )rU   r	   rW   r   s       r   save_to_pklr   S  sN     T3>D KKF$;$;<$gll+,,

 -r   c                     [        U SUSS9n[        R                  " U5      n[        U [        [
        R                  45      (       a  UR                  5         U$ )a  
Load an object from the path. If a suffix is provided in the path, it will use that suffix.
If the path does not exist, it will attempt to load using the .pkl suffix.

:param path: the path to open.
    if save_path is a str or pathlib.Path and mode is "w", single dispatch ensures that the
    path actually exists. If path is a io.BufferedIOBase the path exists.
:param verbose: Verbosity level: 0 for no output, 1 for info messages, 2 for debug messages
r[   r   r   )rk   r   loadr7   r   rn   ro   r   )rU   rW   r   r	   s       r   load_from_pklr   g  sF     T3>D
++d
C$gll+,,

Jr   	load_path	load_datadeviceprint_system_infoc           	      $   [        U SUSS9n[        US9n [        R                  " U5       nUR	                  5       nSn	Sn
0 nU(       aU  SU;   a4  [        S5        [        UR                  S5      R                  5       5        O[        R                  " S[        5        S	U;   a/  U(       a(  UR                  S	5      R                  5       n[        XS
9n	U Vs/ s H-  n[        R                  R                  U5      S   S:X  d  M+  UPM/     nnU H  nUR                  USS9 n[         R"                  " 5       nUR%                  UR                  5       5        UR'                  S5        [(        R*                  " UUSS9nUS:X  d  US:X  a  Un
O%UU[        R                  R                  U5      S   '   SSS5        M     SSS5        [1        U [2        [4        R6                  45      (       a  UR9                  5         W	WW
4$ s  snf ! , (       d  f       GM  = f! , (       d  f       N`= f! [        R,                   a  n[/        SU  S35      UeSnAff = f! [1        U [2        [4        R6                  45      (       a  UR9                  5         f f = f)a  
Load model data from a .zip archive

:param load_path: Where to load the model from
:param load_data: Whether we should load and return data
    (class parameters). Mainly used by 'load_parameters' to only load model parameters (weights)
:param custom_objects: Dictionary of objects to replace
    upon loading. If a variable is present in this dictionary as a
    key, it will not be deserialized and the corresponding item
    will be used instead. Similar to custom_objects in
    ``keras.models.load_model``. Useful when you have an object in
    file that can not be deserialized.
:param device: Device on which the code should run.
:param verbose: Verbosity level: 0 for no output, 1 for info messages, 2 for debug messages
:param print_system_info: Whether to print or not the system info
    about the saved model.
:return: Class parameters, model state_dicts (aka "params", dict of state_dict)
    and dict of pytorch variables
r[   r   r   )r   Nr   z== SAVED MODEL SYSTEM INFO ==zOThe model was saved with SB3 <= 1.2.0 and thus cannot print system information.r*   )rC   r   r   r   r   F)map_locationweights_onlyr   ztensors.pthzError: the file z wasn't a zip-file)rk   r   r   r   namelistprintr]   r4   rL   rM   UserWarningrT   osrU   splitextry   ra   rd   r\   seekr   r   
BadZipFilerE   r7   r   rn   ro   r   )r   r   rC   r   rW   r   r   r   r   r*   r   r   	json_datar   	pth_files	file_pathr   file_content	th_objectrS   s                       r   load_from_zip_filer   x  s?   6 YWUCD v&F8__T"g'')H D $F !$09:',,'89@@BCMMi#
 !i $LL0779	#IM
 5=iHy@P@PQZ@[\]@^bh@hHIi&	\\)#\6* $&::<L &&z'89 %%a( !#6X] ^I $;;yM?Y,5) BKrww//	:1=>% 76 '= #l i#w||!455JJL***7 j66? #"d  R+I;6HIJPQQR i#w||!455JJL 6sx   H+ B,H*HHH$BH4H H+ H
H	H
H($H+ 'I (H+ +I?III 8Jr   )r   N)NNNr   )r   )TNautor   F)2__doc__r1   r   ra   r%   r   rn   r   rL   r   typingr   r   r   r3   torchr   stable_baselines3r   %stable_baselines3.common.type_aliasesr   stable_baselines3.common.utilsr   r   r   r   r"   boolr)   r8   rB   rT   singledispatchro   BufferedIOBaseintrb   rc   rd   re   rk   registerrp   rm   r   r   r   r   tupler    r   r   <module>r      s  
   	  	     ' '    < F?3 ?c ?S ?&K3 Kc K K K s t  4tCH~ 4# 4n/c /8DcN3K /W[\_ad\dWe /d lp(
W\\2#4#44
5(=@(KN(\deh\i(
2b//R=N=NNO( (V CH H3 H H(3- H[][l[l H H" GLL!/:GLL /: /:c /:xX[} /:hjhyhy /: "/:h &*'+26*S',,(9(99:*
4S>
"* T#s(^$*  S#X/	*
 * 
*ZeCr/@/@@A  VY bf (c7<<1B1BBC c Z] & /3$*#Z+S',,(9(99:Z+Z+ T#s(^,Z+ "))S.!	Z+
 Z+ Z+ 8DcN#Z*1EEFZ+r   