o
    ϯiP                     @   s   d Z ddlZddlZddlZddlZddlZddlmZ ddlZej	j
dkZh dZdhZer5eejfZnejfZeeeeeeedhZerLeehZerSddlZnddlZeeZ G dd de!Z"e"j#Z#dd
dZ$dd Z%dd Z&dd Z'dd Z(dS )zYACS -- Yet Another Configuration System is designed to be a simple
configuration management system for academic and industrial research
projects.

See README.md for usage and examples.
    N)literal_eval   >   .yml.yaml z.pyc                       s   e Zd ZdZdZdZdZdZd> fdd		Ze	d
d Z
dd Zdd Zdd Z fddZdd Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd?d(d)Zd*d+ Zd,d- Zd.d/ Zd0d1 Zd2d3 Ze	d4d5 Ze	d6d7 Z e	d8d9 Z!e	d:d; Z"e	d<d= Z#  Z$S )@CfgNodez
    CfgNode represents an internal node in the configuration tree. It's a simple
    dict-like container that allows for attribute-based access to keys.
    __immutable____deprecated_keys____renamed_keys____new_allowed__NFc                    sr   |du ri n|}|du rg n|}|  ||}tt| | d| jtj< t | jtj< i | jtj< || jtj	< dS )av  
        Args:
            init_dict (dict): the possibly-nested dictionary to initailize the CfgNode.
            key_list (list[str]): a list of names which index this CfgNode from the root.
                Currently only used for logging purposes.
            new_allowed (bool): whether adding new key is allowed when merging with
                other configs.
        NF)
_create_config_tree_from_dictsuperr   __init____dict__	IMMUTABLEsetDEPRECATED_KEYSRENAMED_KEYSNEW_ALLOWED)self	init_dictkey_listnew_allowed	__class__ ?/home/ubuntu/.local/lib/python3.10/site-packages/yacs/config.pyr   J   s   

zCfgNode.__init__c              
   C   sr   t |}| D ]-\}}t|tr| |||g d||< q	tt|dddd|t	|g t
|t q	|S )aJ  
        Create a configuration tree using the given dict.
        Any dict-like objects inside dict will be treated as a new CfgNode.

        Args:
            dic (dict):
            key_list (list[str]): a list of names which index this CfgNode from the root.
                Currently only used for logging purposes.
        )r   Fallow_cfg_node9Key {} with value {} is not a valid type; valid types: {}.)copydeepcopyitems
isinstancedict_assert_with_logging_valid_typeformatjoinstrtype_VALID_TYPES)clsdicr   kvr   r   r   r   o   s   


z%CfgNode._create_config_tree_from_dictc                 C   s   || v r| | S t |N)AttributeError)r   namer   r   r   __getattr__   s   zCfgNode.__getattr__c                 C   sZ   |   rtd||t|| jvd| tt|dddt||t || |< d S )Nz3Attempted to set {} to {}, but CfgNode is immutablez4Invalid attempt to modify internal CfgNode state: {}Tr   z,Invalid type {} for key {}; valid types = {})	is_frozenr2   r(   r&   r   r'   r+   r,   )r   r3   valuer   r   r   __setattr__   s"   

zCfgNode.__setattr__c                 C   st   dd }d}g }t |  D ]"\}}t|trdnd}dt||t|}||d}|| q|d|7 }|S )Nc                    sP   |  d}t|dkr| S |d} fdd|D }d|}|d | }|S )N
   r   c                    s   g | ]} d  | qS ) r   ).0line
num_spacesr   r   
<listcomp>   s    z4CfgNode.__str__.<locals>._indent.<locals>.<listcomp>)splitlenpopr)   )s_r>   sfirstr   r=   r   _indent   s   


z CfgNode.__str__.<locals>._indentr   r8   r:   z{}:{}{}r   )sortedr#   r$   r   r(   r*   appendr)   )r   rF   rrD   r/   r0   	seperatorattr_strr   r   r   __str__   s   

zCfgNode.__str__c                    s   d | jjtt|  S )Nz{}({}))r(   r   __name__r   r   __repr__r   r   r   r   rN      s   zCfgNode.__repr__c                    s(    fdd  | g }t j|fi |S )zDump to a string.c                    sb   t | tstt| dd|t| t | S t| }|	 D ]\}} |||g ||< q |S )Nr   r    )
r$   r   r&   r'   r(   r)   r+   r,   r%   r#   )cfg_noder   cfg_dictr/   r0   convert_to_dictr   r   rS      s   
z%CfgNode.dump.<locals>.convert_to_dict)yaml	safe_dump)r   kwargsself_as_dictr   rR   r   dump   s   
zCfgNode.dumpc                 C   sB   t |d}| |}W d   n1 sw   Y  | | dS )z2Load a yaml config file and merge it this CfgNode.rI   N)openload_cfgmerge_from_other_cfg)r   cfg_filenamefcfgr   r   r   merge_from_file   s   zCfgNode.merge_from_filec                 C   s   t || | g  dS )z$Merge `cfg_other` into this CfgNode.N)_merge_a_into_b)r   	cfg_otherr   r   r   r[      s   zCfgNode.merge_from_other_cfgc           	      C   s   t t|d dkd| | }t|ddd |ddd D ]R\}}||r)q||r3|| |d}| }|dd D ]}t ||v d| || }q@|d }t ||v d| | |}t	||| ||}|||< qdS )	zMerge config (keys, values) in a list (e.g., from command line) into
        this CfgNode. For example, `cfg_list = ['FOO.BAR', 0.5]`.
        r   r   z<Override list has odd length: {}; it must be a list of pairsNr9   r    zNon-existent key: {})
r&   rA   r(   zipkey_is_deprecatedkey_is_renamedraise_key_rename_errorr@   _decode_cfg_value _check_and_coerce_cfg_value_type)	r   cfg_listrootfull_keyr0   r   dsubkeyr6   r   r   r   merge_from_list   s2   &






zCfgNode.merge_from_listc                 C      |  d dS )z4Make this CfgNode and all of its children immutable.TN
_immutablerO   r   r   r   freeze      zCfgNode.freezec                 C   ro   )z2Make this CfgNode and all of its children mutable.FNrp   rO   r   r   r   defrost   rs   zCfgNode.defrostc                 C      | j tj S )zReturn mutability.)r   r   r   rO   r   r   r   r5      s   zCfgNode.is_frozenc                 C   V   || j tj< | j  D ]}t|tr|| q|  D ]}t|tr(|| qdS )zkSet immutability to is_immutable and recursively apply the setting
        to all nested CfgNodes.
        N)r   r   r   valuesr$   rq   )r   is_immutabler0   r   r   r   rq     s   



zCfgNode._immutablec                 C   s
   t | S )zRecursively copy this CfgNode.)r!   r"   rO   r   r   r   clone  s   
zCfgNode.clonec                 C   s2   t || jtj vd| | jtj | dS )zRegister key (e.g. `FOO.BAR`) a deprecated option. When merging deprecated
        keys a warning is generated and the key is ignored.
        z0key {} is already registered as a deprecated keyN)r&   r   r   r   r(   add)r   keyr   r   r   register_deprecated_key  s
   zCfgNode.register_deprecated_keyc                 C   s@   t || jtj vd| |}|r||f}|| jtj |< dS )zRegister a key as having been renamed from `old_name` to `new_name`.
        When merging a renamed key, an exception is thrown alerting to user to
        the fact that the key has been renamed.
        z1key {} is already registered as a renamed cfg keyN)r&   r   r   r   r(   )r   old_namenew_namemessager6   r   r   r   register_renamed_key  s   zCfgNode.register_renamed_keyc                 C   s(   || j tj v rtd| dS dS )zTest if a key is deprecated.z$Deprecated config key (ignoring): {}TF)r   r   r   loggerwarningr(   r   rk   r   r   r   rd   -  s   zCfgNode.key_is_deprecatedc                 C   s   || j tj v S )zTest if a key is renamed.)r   r   r   r   r   r   r   re   4  s   zCfgNode.key_is_renamedc                 C   sF   | j tj | }t|trd|d  }|d }nd}td|||)Nz Note: r9   r   r   z6Key {} was renamed to {}; please update your config.{})r   r   r   r$   tupleKeyErrorr(   )r   rk   new_keymsgr   r   r   rf   8  s   

zCfgNode.raise_key_rename_errorc                 C   ru   r1   )r   r   r   rO   r   r   r   is_new_allowedE  s   zCfgNode.is_new_allowedc                 C   rv   )zx
        Set this config (and recursively its subconfigs) to allow merging
        new keys from other configs.
        N)r   r   r   rw   r$   set_new_allowed)r   r   r0   r   r   r   r   H  s   



zCfgNode.set_new_allowedc                 C   sT   t t|ttf dttt| t|tr| |S t|tr&| |S td)a  
        Load a cfg.
        Args:
            cfg_file_obj_or_str (str or file):
                Supports loading from:
                - A file object backed by a YAML file
                - A file object backed by a Python source file that exports an attribute
                  "cfg" that is either a dict or a CfgNode
                - A string that can be parsed as valid YAML
        z=Expected first argument to be of type {} or {}, but it was {}z/Impossible to reach here (unless there's a bug))	r&   r$   _FILE_TYPESr*   r(   r+   _load_cfg_from_yaml_str_load_cfg_from_fileNotImplementedError)r-   cfg_file_obj_or_strr   r   r   rZ   V  s   




zCfgNode.load_cfgc                 C   sR   t j|j\}}|tv r| | S |tv r| |jS t	d
|tt)z7Load a config from a YAML file or a Python source file.zGAttempt to load from an unsupported file type {}; only {} are supported)ospathsplitextr3   
_YAML_EXTSr   read_PY_EXTS_load_cfg_py_source	Exceptionr(   union)r-   file_obj_file_extensionr   r   r   r   o  s   zCfgNode._load_cfg_from_filec                 C   s   t |}| |S )z*Load a config from a YAML string encoding.)rT   	safe_load)r-   str_objcfg_as_dictr   r   r   r   }  s   
zCfgNode._load_cfg_from_yaml_strc                 C   sT   t d|}tt|dd| tth}tt|j|v d|t|j | |jS )z(Load a config from a Python source file.zyacs.config.overrider^   z/Python module from file {} must have 'cfg' attrz:Imported module 'cfg' attr must be in {} but is {} instead)_load_module_from_filer&   hasattrr(   r%   r   r+   r^   )r-   filenamemoduleVALID_ATTR_TYPESr   r   r   r     s   


zCfgNode._load_cfg_py_sourcec                 C   sV   t |tr	| |S t |ts|S zt|}W |S  ty!   Y |S  ty*   Y |S w )a7  
        Decodes a raw config value (e.g., from a yaml config files or command
        line argument) into a Python object.

        If the value is a dict, it will be interpreted as a new CfgNode.
        If the value is a str, it will be evaluated as literals.
        Otherwise it is returned as-is.
        )r$   r%   r*   r   
ValueErrorSyntaxError)r-   r6   r   r   r   rg     s   


zCfgNode._decode_cfg_value)NNFr1   )%rM   
__module____qualname____doc__r   r   r   r   r   classmethodr   r4   r7   rL   rN   rX   r_   r[   rn   rr   rt   r5   rq   ry   r|   r   rd   re   rf   r   r   rZ   r   r   r   rg   __classcell__r   r   r   r   r   ?   sN    %






r   Fc                 C   s   t | tv p|ot| tS r1   )r+   r,   r$   r   )r6   r   r   r   r   r'     s   r'   c              	   C   s  t t| tdt| t t t|tdt|t |  D ]d\}}d||g }t|}|	|}||v rdt
||| ||}t|tr_zt||| |||g  W q  ty^    w |||< q | rm|||< q ||rsq ||r~|| q td|dS )zMerge config dictionary a into config dictionary b, clobbering the
    options in b whenever they are also specified in a.
    z+`a` (cur type {}) must be an instance of {}z+`b` (cur type {}) must be an instance of {}r    zNon-existent config key: {}N)r&   r$   r   r(   r+   r#   r)   r!   r"   rg   rh   r`   BaseExceptionr   rd   re   rf   r   )abrj   r   r/   v_rk   r0   r   r   r   r`     s:   






r`   c           
         s   t | t  krS t dkr tv s" t dkr$tv r$S  fdd}ttfttfg}z	|ttf W n	 tyF   Y nw |D ]\}}|||\}}	|rZ|	  S qItd	 ||)zChecks that `replacement`, which is intended to replace `original` is of
    the right type. The type is correct if it matches exactly or is one of a few
    cases in which the type can be easily coerced.
    Nc                    s    | kr |krd|fS dS )NT)FNr   )	from_typeto_typeoriginal_typereplacementreplacement_typer   r   conditional_cast  s   z:_check_and_coerce_cfg_value_type.<locals>.conditional_castzDType mismatch ({} vs. {}) with values ({} vs. {}) for config key: {})
r+   r,   r   listrH   r*   unicoder   r   r(   )
r   originalr{   rk   r   castsr   r   	convertedconverted_valuer   r   r   rh     s2   
rh   c                 C   s   | st | | sJ |d S r1   )r   debug)condr   r   r   r   r&     s   
r&   c                 C   s>   t r
t| |}|S tj| |}tj|}|j| |S r1   )	_PY2impload_source	importlibutilspec_from_file_locationmodule_from_specloaderexec_module)r3   r   r   specr   r   r   r   $  s   r   )F))r   r!   iologgingr   sysastr   rT   version_infomajorr   r   r   fileIOBaser   r   r   r*   intfloatboolr+   r,   r   r   r   importlib.utilr   	getLoggerrM   r   r%   r   rZ   r'   r`   rh   r&   r   r   r   r   r   <module>   s>   

  
(0