o
    ]i                    @   s  d Z ddlZddlZddlmZ ddlZddlZddl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mZmZmZ ddlmZ ddlZddlmZ ejjejejjd G dd	 d	eZG d
d deZG dd deZedZdd Zdd Z d=ddZ!dd Z"de#dee#ee$ f fddZ%G dd de&dddgZ'ej(G dd  d Z)d>d!d"Z*G d#d$ d$Z+de,fd%d&Z-d>d'd(Z.d)d* Z/d+d, Z0d>d-d.Z1G d/d0 d0e+Z2G d1d2 d2e	j3Z4G d3d4 d4e4Z5d5d6 Z6d=d7d8Z7d9d: Z8d;d< Z9dS )?aI  Classes for defining configurations of experiments and models.

This file defines the classes `ConfigDict` and `FrozenConfigDict`, which are
"dict-like" data structures with Lua-like access and some other nice features.
Together, they are supposed to be used as a main way of expressing
configurations of experiments and models.
    N)abc)AnyMappingOptionalTuple)logging)representer)	data_typer   c                   @      e Zd ZdS )RequiredValueErrorN__name__
__module____qualname__ r   r   Z/home/ubuntu/.local/lib/python3.10/site-packages/ml_collections/config_dict/config_dict.pyr   3       r   c                   @   r
   )MutabilityErrorNr   r   r   r   r   r   7   r   r   c                   @   r
   )JSONDecodeErrorNr   r   r   r   r   r   ;   r   r   c                 C   s   t dd | jD S )zATries to ensure: `_is_callable_type(type(obj)) == callable(obj)`.c                 s   s    | ]}d |j v V  qdS )__call__N)__dict__).0cr   r   r   	<genexpr>C   s    z$_is_callable_type.<locals>.<genexpr>)any__mro__
field_typer   r   r   _is_callable_typeA   s   r   c                 C   s4   | du s|t kr
dS t| |rdS t| ot| S )a]  Helper function for type safety exceptions.

  This function determines whether or not assigning a value to a field violates
  type safety.

  Args:
    value: The value to be assigned.
    field_type: Type of the field that we would like to assign value to.

  Returns:
    True if assigning value to field violates type safety, False otherwise.
  NF)	_NoneType
isinstancecallabler   )valuer   r   r   r   _is_type_safety_violationF   s
   
r#   Fc                 C   s   t | }t| tr|tu rt| S t| tr|tu r|| S t| tr+|tu r+t| S t| tr8|tu r8t| S t| trC|tu rC| S |rWt| |rWtd	| t|t|| S )a1  Helper function to handle the exceptional type conversions.

  This function implements the following exceptions for type-checking rules:

  * An `int` will be converted to a `float` if overriding a `float` field.
  * Any string value can override a `str` or `unicode` field. The value is
  converted to `field_type`.
  * A `tuple` will be converted to a `list` if overriding a `list` field.
  * A `list` will be converted to a `tuple` if overriding `tuple` field.
  * Short and long integers are indistinguishable. The final value will always
  be a `long` if both types are present.

  Args:
    value: The value to be assigned.
    field_type: The type for the field that we would like to assign value to.
    type_safe: If True, the method will throw an error if the `value` is not of
        type `field_type` after safe type conversions.

  Returns:
    The converted type-safe version of the value if it is one of the cases
    described. Otherwise, return the value without conversion.

  Raises:
    TypeError: if types don't match  after safe type conversions.
  z9{} is of original type {} and cannot be casted to type {})
typer    intfloatstrtuplelistr#   	TypeErrorformat)r"   r   	type_safeoriginal_value_typer   r   r   
_safe_cast]   s"   r.   c                 C   s   t | tr	|  S | S Nr    FieldReferenceget)value_or_fieldreferencer   r   r   _get_computed_value   s   
r4   keyreturnc                 C   sJ   |  dd } td| }|r|d} t|d}| |fS d}| |fS )zDParse a ConfigDict key into to it's initial part and index (if any)..r   z(.*)\[([0-9]+)\]      N)splitrematchgroupr%   )r5   index_matchindexr   r   r   
_parse_key   s   
r@   c                   @   s   e Zd ZdZdS )_OpzA named tuple representing a lazily computed op.

  The _Op named tuple has two fields:
    fn: The function to be applied.
    args: a tuple/list of arguments that are used with the op.
  N)r   r   r   __doc__r   r   r   r   rA      s    rA   fnargsc                   @   sB  e Zd ZdZdOddZdPddZdQd	d
Zdd Zdd Zdd Z	dd Z
dd Z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* Zd+d, Zd-d. Zd/d0 Zd1d2 Zd3d4 Zd5d6 Zd7d8 Zd9d: Zd;d< Z d=d> Z!d?d@ Z"dAdB Z#dCdD Z$dEdF Z%dGdH Z&dIdJ Z'dKdL Z(dMdN Z)dS )Rr1   a  Reference to a configuration element.

  Typed configuration element that can take a None default value. Example::

    from ml_collections import config_dict

    cfg_field = config_dict.FieldReference(0)
    cfg = config_dict.ConfigDict({
        'optional': configdict.FieldReference(None, field_type=str)
        'field': cfg_field,
        'nested': {'field': cfg_field}
    })

    with self.assertRaises(TypeError):
      cfg.optional = 10  # Raises an error because it's defined as an
                          # intfield.

    cfg.field = 1  # Changes the value of both cfg.field and cfg.nested.field.
    print(cfg)

  This class also supports lazy computation. Example::

    ref = config_dict.FieldReference(0)

    # Using ref in a standard operation returns another FieldReference. The new
    # reference ref_plus_ten will evaluate ref's value only when we call
    # ref_plus_ten.get()
    ref_plus_ten = ref + 10

    ref.set(3)  # change ref's value
    print(ref_plus_ten.get())  # Prints 13 because ref's value is 3

    ref.set(-2)  # change ref's value again
    print(ref_plus_ten.get())  # Prints 8 because ref's value is -2
  NFc                 C   s   |du r|du rt dt|tr| }nt|}nztd| W n ty2   tdt|w || _| | |rE|durEt d|| _	|du rQg | _
dS |g| _
dS )a  Creates an instance of FieldReference.

    Args:
      default: Default value.
      field_type: Type for the values contained by the configuration element. If
          None the type will be inferred from the default value. This value is
          used as the second argument in calls to isinstance, so it has to
          follow that function's requirements (class, type or a tuple containing
          classes, types or tuples).
      op: An optional operation that is applied to the underlying value when
          `get()` is called.
      required: If True, the `get()` method will raise an error if the reference
           does not contain a value. This argument has no effect when a default
           value is provided. Setting this to True will raise an error if `op`
           is not None.

    Raises:
      TypeError: If field_type is not None and is different from the type of the
          default value.
      ValueError: If both the default value and field_type is None.
    Nz2Default value cannot be None if field_type is Nonez#field_type should be a type, not {}z-Cannot set required to True if op is not None)
ValueErrorr    r1   get_typer$   r*   r+   _field_typeset	_required_ops)selfdefaultr   oprequiredr   r   r   __init__   s&   




zFieldReference.__init__c                 C   s   |pt  }t| |v rdS |t|  | j}t|tr%|| r%dS | jD ]}|j	D ]}t|tr?|| r?  dS q-q(dS )zFinds cycles in the reference graph.

    Args:
      visited: Set containing the ids of all visited nodes in the graph. The
          default value is the empty set.

    Returns:
      True if there is a cycle in the reference graph.
    TF)
rH   idadd_valuer    r1   	has_cyclecopyrJ   rD   )rK   visitedr"   rM   argr   r   r   rS     s   



zFieldReference.has_cycleTc                 C   s   g | _ |du rd| _dS t|tr>|r(t| |  s(td| |  t| dd}|| _| 	 r<|| _t
ddS t|| j|| _dS )aO  Overwrites the value pointed by a FieldReference.

    Args:
      value: New value.
      type_safe: Check that old and new values are of the same type.

    Raises:
      TypeError: If type_safe is true and old and new values are not of the same
          type.
      MutabilityError: If a cycle is found in the reference graph.
    Nz0Reference is of type {} but should be of type {}rR   zFound cycle in reference graph.)rJ   rR   r    r1   
issubclassrF   r*   r+   getattrrS   r   r.   rG   )rK   r"   r,   	old_valuer   r   r   rH   #  s   

zFieldReference.setc                 C   s
   | j du S )z5Returns True if the reference points to a None value.N)rR   rK   r   r   r   emptyA     
zFieldReference.emptyc                 C   s~   | j r| jdu rtdt| j}| jD ](}dd |jD }|du s&d|v r/d}td| n	|j|g|R  }t|}q|S )aE  Gets the value of the `FieldReference` object.

    This will dereference `_pointer` and apply all ops to its value.

    Returns:
      The result of applying all ops to the dereferenced pointer.

    Raises:
      RequiredValueError: if `required` is True and the underlying value for the
          reference is False.
    Nz&None value found in required referencec                 S   s   g | ]}t |qS r   )r4   r   rV   r   r   r   
<listcomp>W      z&FieldReference.get.<locals>.<listcomp>z&Cannot apply `%s` to `None`; skipping.)	rI   rR   r   r4   rJ   rD   r   debugrC   )rK   r"   rM   rD   r   r   r   r2   E  s   


zFieldReference.getc                 C      | j S r/   )rG   rZ   r   r   r   rF   `     zFieldReference.get_typec                 C   s&   t |tr|  | kS |  |kS r/   r0   rK   otherr   r   r   __eq__c     
zFieldReference.__eq__c                 C   s&   t |tr|  | kS |  |kS r/   r0   rc   r   r   r   __le__i  rf   zFieldReference.__le__c                    s(    fdd|D }t   jt||dS )Nc                    s   g | ]}t | jqS r   )r.   rG   r]   rZ   r   r   r^   s      z,FieldReference._apply_op.<locals>.<listcomp>r   rM   )r1   rG   rA   )rK   rC   rD   r   rZ   r   	_apply_opr  s   zFieldReference._apply_opc                    s    t    t fdd| gdS )a  Apply a cast op that changes the field_type of this FieldReference.

    `_apply_op` assumes that the `field_type` does not change after the op is
    applied whereas `_apply_cast_op` generates a FieldReference with casted
    field_type.

    Since the signature is `fn(value, *args)` we need to ignore `value`
      which now contains a unused default value of field_type.

    Args:
      field_type: data type to cast to.

    Returns:
      A new FieldReference with of `field_type`.
    c                    s    |S r/   r   )_valr   r   r   <lambda>  s    z/FieldReference._apply_cast_op.<locals>.<lambda>ri   )r1   rA   )rK   r   r   r   r   _apply_cast_opy  s   zFieldReference._apply_cast_opc                 C   s   |  dd S )Nc                 S   s   | S r/   r   )xr   r   r   rm     s    z)FieldReference.identity.<locals>.<lambda>)rj   rZ   r   r   r   identity     zFieldReference.identityc                 C   s   |  t|S r/   )rj   operator
attrgetter)rK   	attr_namer   r   r   attr     zFieldReference.attrc                 C      |  tj|S r/   )rj   rr   rQ   rc   r   r   r   __add__  rq   zFieldReference.__add__c                 C      t tj|}| |S r/   )	functoolspartialrr   rQ   rj   )rK   rd   raddr   r   r   __radd__     
zFieldReference.__radd__c                 C   rw   r/   )rj   rr   subrc   r   r   r   __sub__  rq   zFieldReference.__sub__c                 C   ry   r/   )rz   r{   rr   r   rj   )rK   rd   rsubr   r   r   __rsub__  r~   zFieldReference.__rsub__c                 C   rw   r/   )rj   rr   mulrc   r   r   r   __mul__  rq   zFieldReference.__mul__c                 C   ry   r/   )rz   r{   rr   r   rj   )rK   rd   rmulr   r   r   __rmul__  r~   zFieldReference.__rmul__c                 C   rw   r/   rj   rr   truedivrc   r   r   r   __div__  rq   zFieldReference.__div__c                 C   ry   r/   rz   r{   rr   r   rj   )rK   rd   rdivr   r   r   __rdiv__  r~   zFieldReference.__rdiv__c                 C   rw   r/   r   rc   r   r   r   __truediv__  rq   zFieldReference.__truediv__c                 C   ry   r/   r   )rK   rd   rtruedivr   r   r   __rtruediv__  r~   zFieldReference.__rtruediv__c                 C   rw   r/   )rj   rr   floordivrc   r   r   r   __floordiv__  rq   zFieldReference.__floordiv__c                 C   ry   r/   )rz   r{   rr   r   rj   )rK   rd   	rfloordivr   r   r   __rfloordiv__  r~   zFieldReference.__rfloordiv__c                 C   rw   r/   )rj   rr   powrc   r   r   r   __pow__  rq   zFieldReference.__pow__c                 C   rw   r/   )rj   rr   modrc   r   r   r   __mod__  rq   zFieldReference.__mod__c                 C   rw   r/   )rj   rr   and_rc   r   r   r   __and__  rq   zFieldReference.__and__c                 C   rw   r/   )rj   rr   or_rc   r   r   r   __or__  rq   zFieldReference.__or__c                 C   rw   r/   )rj   rr   xorrc   r   r   r   __xor__  rq   zFieldReference.__xor__c                 C      |  tjS r/   )rj   rr   negrZ   r   r   r   __neg__     zFieldReference.__neg__c                 C   r   r/   )rj   rr   absrZ   r   r   r   __abs__  r   zFieldReference.__abs__c                 C   
   |  tS r/   )rn   r%   rZ   r   r   r   to_int     
zFieldReference.to_intc                 C   r   r/   )rn   r&   rZ   r   r   r   to_float  r   zFieldReference.to_floatc                 C   r   r/   )rn   r'   rZ   r   r   r   to_str  r   zFieldReference.to_strc                 C   s0   |d | _ |d | _|d | _|dd| _d S )NrR   rG   rJ   rI   F)rR   rG   rJ   r2   rI   rK   stater   r   r   __setstate__  s   


zFieldReference.__setstate__c                 C      t dNzuFieldReference cannot be used for control flow. For boolean operations use "&" (logical "and") or "|" (logical "or").NotImplementedErrorrZ   r   r   r   __nonzero__     zFieldReference.__nonzero__c                 C   r   r   r   rZ   r   r   r   __bool__  r   zFieldReference.__bool__)NNFr/   )T)*r   r   r   rB   rO   rS   rH   r[   r2   rF   re   rg   __hash__rj   rn   rp   ru   rx   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   r1      sP    
$
0
r1   c                 C   sJ  t | tsJ | rJ |pi }| |t|< t |tr!|jdd}n| }|D ]{\}}t||v r8|t| }ndt |trw| tu rw| jrw|	 rKnQt|
 |v r`||t|
  d n<t| j| jd}t||
 | ||d n%t |tr| jrt| j| jd}t||| |}nt |trt|| jd}| || q'dS )a  Fills an empty ConfigDict without copying previously visited nodes.

  Turns seed (an empty ConfigDict) into a ConfigDict version of
  initial_dictionary. Avoids infinite looping on a self-referencing
  initial_dictionary because if a value of initial_dictionary has been
  previously visited, that value is not re-converted to a ConfigDict. If a
  FieldReference is encountered which contains a dict or FrozenConfigDict, its
  contents will be converted to ConfigDict.

  Note: As described in the __init__() documentation, this will not
  replicate the structure of initial_dictionary if it contains
  self-references within lists, tuples, or other types. There is no warning
  or error in this case.

  Args:
    seed: Empty ConfigDict, to be filled in.
    initial_dictionary: The template on which seed is built. May be of type
        dict, ConfigDict or FrozenConfigDict.
    visit_map: Dictionary from memory addresses to values, storing the
        ConfigDict versions of dictionary values. visit_map need not contain
        (id(initial_dictionary), seed) as a key/value pair.

  Raises:
    TypeError: If seed is not a ConfigDict.
    ValueError: If seed is not an empty ConfigDict.
  Tpreserve_field_referencesF)r,   allow_dotted_keys)r   N)r    
ConfigDictrP   	iteritemsitemsr1   rF   dictconvert_dictr[   r2   rH   is_type_safer   _configdict_fill_seedFrozenConfigDict__setattr__)seedinitial_dictionary	visit_mapr   r5   r"   value_cdr   r   r   r     sD   

r   c                       sb  e Zd ZU dZdZeed< eed< 			dnddddeee	e
f  d	ed
ededef
 fddZedefddZedefddZedd Zdo fddZedefddZdo fddZdpde	fddZdd  Zd!d" Zdqd#d$Zed%d& Zdqd'd(Z fd)d*Zd+d, Zd-d. Zd/d0 Zd1d2 Zdrd4d5Zde	fd6d7Zde	fd8d9Z de	fd:d;Z!de	fd<d=Z"de	fd>d?Z#d@dA Z$dBdC Z%dqdDdEZ&dqdFdGZ'dHdI Z(dJdK Z)dLdM Z*dNdO Z+dPdQ Z,dRdS Z-dZ.dTdU Z/dVdW Z0dpdXdYZ1dZd[ Z2dsd\d]Z3dp fd^d_	Z4 fd`daZ5e6j7dbdc Z8e6j7 fdddeZ9dfdg Z:dhdi Z;djdk Z<drdldmZ=  Z>S )tr   a  Base class for configuration objects used in DeepMind.

  This is a container for configurations. It behaves similarly to Lua tables.
  Specifically:

  - it has dot-based access as well as dict-style key access,
  - it is type safe (once a value is set one cannot change its type).

  Typical usage example::

    from ml_collections import config_dict

    cfg = config_dict.ConfigDict()
    cfg.float_field = 12.6
    cfg.integer_field = 123
    cfg.another_integer_field = 234
    cfg.nested = config_dict.ConfigDict()
    cfg.nested.string_field = 'tom'

    print(cfg)

  Config dictionaries can also be used to pass named arguments to functions::

    from ml_collections import config_dict

    def print_point(x, y):
      print "({},{})".format(x, y)

    point = config_dict.ConfigDict()
    point.x = 1
    point.y = 2
    print_point(**point)

  Note that, depending on your use case, it may be easier to use the `create`
  function in this package to construct a `ConfigDict`:

    from ml_collections import config_dict
    point = config_dict.create(x=1, y=2)

  Differently from standard `dicts`, `ConfigDicts` also have the nice property
  that iterating over them is deterministic, in a fashion similar to
  `collections.OrderedDicts`.
  T_allow_dotted_keys
_sort_keysNF)r   	sort_keysr   r,   r   r   r   c                   s   t |tr	| }tt| di  tt| dd tt| d| tt| d| tt| d| tt| d| |durHt| | t |trctt| d|j tt| d|j dS dS )	a  Creates an instance of ConfigDict.

    Warning: In most cases, this faithfully reproduces the reference structure
    of initial_dictionary, even if initial_dictionary is self-referencing.
    However, unexpected behavior occurs if self-references are contained within
    list, tuple, or custom types. For example::

      d = {}
      d['a'] = d
      d['b'] = [d]
      cd = ConfigDict(d)
      cd.a    # refers to cd, type ConfigDict. Expected behavior.
      cd.b    # refers to d, type dict. Unexpected behavior.

    Warning: FieldReference values may be changed. If initial_dictionary
    contains a FieldReference with a value of type dict or FrozenConfigDict,
    that value is converted to ConfigDict.

    Args:
      initial_dictionary: May be one of the following:  1) dict. In this case,
        all values of initial_dictionary that are dictionaries are also be
        converted to ConfigDict. However, dictionaries within values of non-dict
        type are untouched.  2) ConfigDict. In this case, all attributes are
        uncopied, and only the top-level object (self) is re-addressed. This is
        the same behavior as Python dict, list, and tuple.  3) FrozenConfigDict.
        In this case, initial_dictionary is converted to a ConfigDict version of
        the initial dictionary for the FrozenConfigDict (reversing any
        mutability changes FrozenConfigDict made).
      type_safe: If set to True, once an attribute value is assigned, its type
        cannot be overridden without .ignore_type() context manager (default:
        True).
      convert_dict: If set to True, all dict used as value in the ConfigDict
        will automatically be converted to ConfigDict (default: True).
      allow_dotted_keys: If set to True, keys can contain `.`. Integer and float
        keys are always allowed to have dots.
      sort_keys: If `True` (default), keys are sorted in alphabetical order.
    _fields_lockedF
_type_safe_convert_dictr   r   N)	r    r   as_configdictsuperr   r   r   	is_lockedr   )rK   r   r,   r   r   r   	__class__r   r   rO   s  s$   
/

zConfigDict.__init__r6   c                 C   ra   )z)Returns True if config dict is type safe.)r   rZ   r   r   r   r        zConfigDict.is_type_safec                 C   ra   )z%Returns True if keys can contain `.`.)r   rZ   r   r   r   r     r   zConfigDict.allow_dotted_keysc                 C   ra   )zCReturns True if it is converting dicts to ConfigDict automatically.)r   rZ   r   r   r   r     r   zConfigDict.convert_dictc                    sP   | j r| S tt| dd | jD ]}| j| }t|}t|tr%|  q| S )zSLocks object, preventing user from adding new fields.

    Returns:
      self
    r   T)r   r   r   r   r   r4   r    lock)rK   fieldelementr   r   r   r     s   


zConfigDict.lockc                 C   ra   )z!Returns True if object is locked.)r   rZ   r   r   r   r     r   zConfigDict.is_lockedc                    sF   t t| dd | j D ]}t|}t|tr |jr |  q| S )zGrants user the ability to add new fields to ConfigDict.

    In most cases, the unlocked() context manager should be preferred to the
    direct use of the unlock method.

    Returns:
      self
    r   F)	r   r   r   r   valuesr4   r    r   unlock)rK   r   r   r   r   r     s   	zConfigDict.unlockr5   c                 C   s"   z| | W S  t y   | Y S w )zCReturns value if key is present, or a user defined value otherwise.)KeyError)rK   r5   rL   r   r   r   r2     s
   
zConfigDict.getc                 C   sb   | j | }|du rtdt|ts/t|}|   || |< W d   |S 1 s*w   Y  |S )z4Returns a FieldReference initialized on key's value.Nz6Cannot create reference to a field whose value is None)r   rE   r    r1   ignore_typerK   r5   r   r   r   r   get_ref  s   




zConfigDict.get_refc                 C   s   |  | S )aU  Returns a one-way FieldReference.

    Example::

      cfg = config_dict.ConfigDict(dict(a=1))
      cfg.b = cfg.get_oneway_ref('a')

      cfg.a = 2
      print(cfg.b)  # 2

      cfg.b = 3
      print(cfg.a)  # 2 (would have been 3 if using get_ref())
      print(cfg.b)  # 3

    Args:
      key: Key for field we want to reference.
    )r   rp   rK   r5   r   r   r   get_oneway_ref  s   zConfigDict.get_oneway_refc                    s"   |r j  S  fdd j D S )aQ  Returns list of dictionary key, value pairs, sorted by key.

    Args:
      preserve_field_references: (bool) Whether to preserve FieldReferences if
        the ConfigDict has them. By default, False: any FieldReferences will be
        resolved in the result.

    Returns:
      The key, value pairs in the config, sorted by key.
    c                    s   g | ]}| | fqS r   r   r   krZ   r   r   r^   '  rh   z$ConfigDict.items.<locals>.<listcomp>)_ordered_fieldsr   rK   r   r   rZ   r   r     s   
zConfigDict.itemsc                 C   s    | j rtt| j S | jS )z4Returns ordered dict shallow cast of _fields member.)r   collectionsOrderedDictsortedr   r   rZ   r   r   r   r   )  s   zConfigDict._ordered_fieldsc                 c   s6    | j D ]}|r|| j| fV  q|| | fV  qdS )aP  Deterministically iterates over dictionary key, value pairs.

    Args:
      preserve_field_references: (bool) Whether to preserve FieldReferences if
        the ConfigDict has them. By default, False: any FieldReferences will be
        resolved in the result.
    Yields:
      The key, value pairs in the config, sorted by key.
    Nr   r   rK   r   r   r   r   r   r   1  s   

zConfigDict.iteritemsc                    s$   |t tt| v rtd|d S )Nz{} cannot be overridden.)dirr   r   r   r+   rK   	attributer   r   r   _ensure_mutabilityA  s   zConfigDict._ensure_mutabilityc              
   C   s:   z|  | || |< W d S  ty } zt|d }~ww r/   r   r   AttributeError)rK   r   r"   er   r   r   r   E  s   
zConfigDict.__setattr__c              
   C   s8   z|  | | |= W d S  ty } zt|d }~ww r/   r   rK   r   r   r   r   r   __delattr__L  s   
zConfigDict.__delattr__c              
   C   s,   z| | W S  t y } zt|d }~ww r/   )r   r   r   r   r   r   __getattr__S  s   
zConfigDict.__getattr__c              
   C   sx  | j st|ttfsd|v rtd| d| jr-|| jvr-d}t| ||	|| j|| jv r| j| }z0t|t
rG||| j W d S t||sft|tr]| jr]t| || jd}t|t|| j}W n ty~ } ztd| d| d d }~ww | jrt|trt|| j}n't|t
r| rtnt| }|tu s|tu rt| | j}||d || j|< d S )	Nr7   z]ConfigDict does not accept dots in field names (when `allow_dotted_keys=False`), but the key z contains one.zbKey "{}" does not exist and cannot be added since the config is locked. Other fields present: "{}"r,   zCould not override field 'z' (reference). F)r   r    r%   r&   rE   r   r   r   _generate_did_you_mean_messager+   r1   rH   r   _should_skip_type_checkr   r   r$   r.   r*   r   r[   r   r2   r   )rK   r5   r"   	error_msgr   r   ref_typer   r   r   r   __setitem__Y  sZ   





zConfigDict.__setitem__ c                 C   s`   t |ttfr	|S tdd |  D }t||dd}|r.|r$|d7 }|d|d |7 }|S )Nc                 s   s    | ]}t |V  qd S r/   )r'   r   r   r   r   r     s    z<ConfigDict._generate_did_you_mean_message.<locals>.<genexpr>r8   g      ?
z"Did you mean "{}" instead of "{}"?r   )r    r%   r&   r(   keysdifflibget_close_matchesr+   )rK   requestmessager   matchesr   r   r   r     s   z)ConfigDict._generate_did_you_mean_messagec              
   C   s   | j rtd| js$t|ttfs$d|v r$|dd\}}| | |= d S z| j|= W d S  tyA } z
t| |t	|d }~ww )NzQThis ConfigDict is locked, you have to unlock it before trying to delete a field.r7   r8   )
r   r   r   r    r%   r&   r:   r   r   r'   )rK   r5   restr   r   r   r   __delitem__  s    
zConfigDict.__delitem__c              
   C   s   | j st|ttfsd|v r|dd\}}| | | S z| j| }t|tr,| W S |W S  tyD } z
t| 	|t
|d }~ww )Nr7   r8   )r   r    r%   r&   r:   r   r1   r2   r   r   r'   )rK   r5   r   r   r   r   r   r   __getitem__  s    


zConfigDict.__getitem__c                 C   s
   || j v S r/   )r   r   r   r   r   __contains__  r   zConfigDict.__contains__c                 C   s8   zt j| jddddW S  ty   t|   Y S w )NTr   F)default_flow_style)yamldumpto_dict	ExceptionreprrZ   r   r   r   __repr__  s   zConfigDict.__repr__c                 C   s0   zt |  W S  ty   t|   Y S w r/   )r  r  r  r  r'   rZ   r   r   r   __str__  s
   zConfigDict.__str__c                 C   s   t | j S )z<Returns the sorted list of all the keys defined in a config.)r)   r   r   rZ   r   r   r   r     s   zConfigDict.keysc                 C   
   | j  S )zADeterministically iterates over dictionary keys, in sorted order.)r   r   rZ   r   r   r   iterkeys  r\   zConfigDict.iterkeysc                    s&   |r	t  j S  fdd jD S )aa  Returns the list of all values in a config, sorted by their keys.

    Args:
      preserve_field_references: (bool) Whether to preserve FieldReferences if
        the ConfigDict has them. By default, False: any FieldReferences will be
        resolved in the result.
    Returns:
      The values in the config, sorted by their corresponding keys.
    c                    s   g | ]} | qS r   r   r   rZ   r   r   r^     r_   z%ConfigDict.values.<locals>.<listcomp>)r)   r   r   r   r   rZ   r   r     s   
zConfigDict.valuesc                 c   s.    | j D ]}|r| j| V  q| | V  qdS )ah  Deterministically iterates over values in a config, sorted by their keys.

    Args:
      preserve_field_references: (bool) Whether to preserve FieldReferences if
        the ConfigDict has them. By default, False: any FieldReferences will be
        resolved in the result.
    Yields:
      The values in the config, sorted by their corresponding keys.
    Nr   r   r   r   r   
itervalues  s   

zConfigDict.itervaluesc                 C   s   |   tt S r/   )r   r   r   rZ   r   r   r   __dir__  rv   zConfigDict.__dir__c                 C   r	  r/   )r   __len__rZ   r   r   r   r    r   zConfigDict.__len__c                 C   r	  r/   )r   __iter__rZ   r   r   r   r    r   zConfigDict.__iter__c                 C   s@   t || jr| j|jk}|| j|jkM }|| j|jkM }|S dS )z%Override the default Equals behavior.F)r    r   r   r   r   r   r   )rK   rd   samer   r   r   re     s   zConfigDict.__eq__c                 C   s   |  | S )zDefine a non-equality test.)re   rc   r   r   r   __ne__  s   zConfigDict.__ne__c                 C   s   t |trt| t|kS dS )a~  Type-invariant equals.

    This is like `__eq__`, except it does not distinguish `FrozenConfigDict`
    from `ConfigDict`. For example::

      cd = ConfigDict()
      fcd = FrozenConfigDict()
      fcd.eq_as_configdict(cd)  # Returns True

    Args:
      other: Object to compare self to.

    Returns:
      same: `True` if `self == other` after conversion to `ConfigDict`.
    F)r    r   rc   r   r   r   eq_as_configdict  s   
zConfigDict.eq_as_configdictc                 K   s   t j| fi |S )aa  Returns a YAML representation of the object.

    ConfigDict serializes types of fields as well as the values of fields
    themselves. Deserializing the YAML representation hence requires using
    YAML's UnsafeLoader:

    ```
    yaml.load(cfg.to_yaml(), Loader=yaml.UnsafeLoader)
    ```

    or equivalently:

    ```
    yaml.unsafe_load(cfg.to_yaml())
    ```

    Please see the PyYAML documentation and https://msg.pyyaml.org/load for more
    details on the consequences of this.

    Args:
      **kwargs: Keyword arguments for yaml.dump.

    Returns:
      YAML representation of the object.
    )r  r  rK   kwargsr   r   r   to_yaml)  s   zConfigDict.to_yamlc              
   K   s@   z
t j| fi |W S  ty } z	d|}t|d}~ww )a^  Wrapper for json.dumps() method.

    Produces a more informative error message when there is a problem with
    string encodings in the ConfigDict.

    Args:
      **kwargs: Keyword arguments for json.dumps.

    Returns:
      JSON representation of the object.

    Raises:
      JSONDecodeError: If there is a problem with string encodings.
    zDecoding error. Make sure all strings in your ConfigDict use ASCII-compatible encodings. See https://docs.python.org/2.7/howto/unicode.html#the-unicode-type for details. Original error message: {}N)jsondumpsUnicodeDecodeErrorr+   r   )rK   r  errornew_messager   r   r   _json_dumps_wrapperE  s   zConfigDict._json_dumps_wrapperc                 K   s   |pt }| jdd|i|S )a  Returns a JSON representation of the object, fails if there is a cycle.

    Args:
      json_encoder_cls: An optional JSON encoder class to customize JSON
        serialization.
      **kwargs: Keyword arguments for json.dumps. They cannot contain "cls"
          as this method specifies it on its own.

    Returns:
      JSON representation of the object.

    Raises:
      TypeError: If self contains set, frozenset, custom type fields or any
          other objects that are not JSON serializable.
    clsNr   )CustomJSONEncoderr  )rK   json_encoder_clsr  r   r   r   to_json_  s   zConfigDict.to_jsonc                 K   s   | j ddti|S )a  Returns a best effort JSON representation of the object.

    Tries to serialize objects not inherently supported by JSON encoder. This
    may result in the configdict being partially serialized, skipping the
    unserializable bits. Ensures that no errors are thrown. Fails if there is a
    cycle.

    Args:
      **kwargs: Keyword arguments for json.dumps. They cannot contain "cls"
          as this method specifies it on its own.

    Returns:
      JSON representation of the object.
    r  Nr   )r  _BestEffortCustomJSONEncoderr  r   r   r   to_json_best_effortr  s   zConfigDict.to_json_best_effortc                 C   s  |pi }i }||t | < | D ]x}t| j| tr$|r$| j| }| }n| | }|}t ||v r9|t | ||< qt|tret|trZ|}ti t}||t |< |||| n|||}|||< qt|tr|}td|	 }|j| dd ||t |< |||< q|S )a  Converts ConfigDict to regular dict recursively with valid references.

    By default, the output dict will not contain FieldReferences, any present
    in the ConfigDict will be resolved. However, if `preserve_field_references`
    is True, the output dict will contain FieldReferences where the original
    ConfigDict has them. They will not be the same as the ConfigDict's, and
    their ops will be applied and dropped.

    Note: As with __eq__() and __init__(), this may not behave as expected on a
    ConfigDict with self-references contained in lists, tuples, or custom types.

    Args:
      visit_map: A mapping from object ids to their dict representation. Method
          is recursive in nature, and it will call ".to_dict(visit_map)" on each
          encountered object, unless it is already in visit_map.
      preserve_field_references: (bool) Whether the output dict should have
        FieldReferences if the ConfigDict has them. By default, False: any
        FieldReferences will be resolved and the result will go to the dict.
    Returns:
      Dictionary with the same values and references structure as a calling
          ConfigDict.
    NFr   )
rP   r    r   r1   r2   r   r   rH   r  rF   )rK   r   r   	dict_selfr5   	referencer"   old_referencer   r   r   r    s8   







zConfigDict.to_dictc                    s   |pi }|   }tt|d| j tt|d| j ||t| < | j D ]4\}}t	|t
r4| }t||v rA|t| }n
t	|trK||}t	| trW||| q'|||< q'tt|d| j tt|d| j |S )a7  Returns a ConfigDict copy with FieldReferences replaced by values.

    If the object is a FrozenConfigDict, the copy returned is also a
    FrozenConfigDict. However, note that FrozenConfigDict should already have
    FieldReferences resolved to values, so this method effectively produces
    a deep copy.

    Note: As with __eq__() and __init__(), this may not behave as expected on a
    ConfigDict with self-references contained in lists, tuples, or custom types.

    Args:
      visit_map: A mapping from ConfigDict object ids to their copy. Method
          is recursive in nature, and it will call
          ".copy_and_resolve_references(visit_map)" on each encountered object,
          unless it is already in visit_map.

    Returns:
      ConfigDict copy with previous FieldReferences replaced by values.
    r   r   r   r   )r   r   r   r   r   r   rP   r   r   r    r1   r2   copy_and_resolve_referencesr   _frozen_setattrr   r   )rK   r   config_dict_copyr5   r"   r   r   r   r$    s8   






z&ConfigDict.copy_and_resolve_referencesc                    sx   |    tt| d|d  tt| d|dd |d D ]
}|d | | |< q |d r:tt| dd dS dS )z2Recreates ConfigDict from its dict representation.r   r   Tr   r   N)rO   r   r   r   r2   )rK   r   r   r   r   r   r     s   
zConfigDict.__setstate__c                 c   sB    | j }|r
|   z| V  W |r|   dS dS |r |   w w )z7Context manager which temporarily unlocks a ConfigDict.N)r   r   r   )rK   
was_lockedr   r   r   unlocked  s   $zConfigDict.unlockedc              
   #   s8   | j }g }t }t| j }|rN| }t||v rq|t| t|t	r0|
|j nt|tjr>||  nt|tjtjfrL|| |stt	| dd z:t }|D ]}||  q_| V  W d   n1 suw   Y  W tt	| d| dS W tt	| d| dS tt	| d| w )zDContext manager which temporarily turns off type safety recursively.r   FN)r   rH   r)   r   r   poprP   rQ   r    r   appendr   collections_abcr   extendSequenceSetr   r   
contextlib	ExitStackenter_context)rK   original_type_safetymanagersrU   fieldsr   stackmanagerr   r   r   r     s6   


*zConfigDict.ignore_typec                 C   s0   |  |}t| j| tr| j|  S t|S )z0Returns type of the field associated with a key.)r   r    r   r1   rF   r$   r   r   r   r   rF   -  s   
zConfigDict.get_typec                 O   s   t |dkrtdt |||f D ]M}i }t|tr!d|d< |jdi |D ]7\}}|| vr6|| |< q)t| j| trH| | ||  q)t| j| tr\t|tr\td||| |< q)qdS )a&  Update values based on matching keys in another dict-like object.

    Mimics the built-in dict's update method: iterates over a given
    mapping object and adds/overwrites keys with the given mapping's
    values for those keys.

    Differs from dict.update in that it operates recursively on existing keys
    that are already a ConfigDict (i.e. calls their update() on the
    corresponding value from other), and respects the ConfigDict's
    type safety status.

    If keyword arguments are specified, the ConfigDict is updated with those
    key/value pairs.

    Args:
      *other: A (single) dict-like container, e.g. a dict or ConfigDict.
      **kwargs: Additional keyword arguments to update the ConfigDict.

    Raises:
      TypeError: if more than one value for `other` is specified.
    r8   z+update expected at most 1 arguments, got {}Tr   z<Cannot update a FieldReference from another FieldReference: Nr   )	lenr*   r+   r    r   r   r   updater1   )rK   rd   r  iteritems_kwargsr5   r"   r   r   r   r8  9  s0   


zConfigDict.updatec                 C   sh   |d u r
|| |< d S t | | tr|| | |< d S t | | tr2t| | }|||< t|| |< d S d S r/   )r    r)   r(   )rK   r5   r?   r"   tuple_as_listr   r   r   _update_valuex  s   zConfigDict._update_valuec                    s\   r fdd|  D }n|}i }|  D ]\}} r$|t d n|}|dd }t|\}	}
d|vr@|
du r@|| |	< q|	| vrNtd| |	 |
duret| |	 ttfsetd| |	 d|v r|
du rq| |	 n| |	 |
 }t|t	std| | t
||||< q| |	|
| q|  D ]\}}  | d}||| qdS )	a  In-place updates values taken from a flattened dict.

    This allows a potentially nested source `ConfigDict` of the following form::

      cfg = ConfigDict({
          'a': 1,
          'b': {
              'c': {
                  'd': 2
              }
          }
      })

    to be updated from a dict containing paths navigating to child items, of the
    following form::

      updates = {
          'a': 2,
          'b.c.d': 3,
          'b.c.e': 4,
      }

    Note that update_from_flattened_dict will allow you add (not just update)
    leaf nodes - for example, 'b.c.e' above

    This filters `paths_dict` to only contain paths starting with
    `strip_prefix` and strips the prefix when applying the update.

    For example, consider we have the following values returned as flags::

      flags = {
          'flag1': x,
          'flag2': y,
          'config': 'some_file.py',
          'config.a.b': 1,
          'config.a.c': 2
      }

      config = ConfigDict({
          'a': {
              'b': 0,
              'c': 0
          }
      })

      config.update_from_flattened_dict(flags, 'config.')

    Then we will now have::

      config = ConfigDict({
          'a': {
              'b': 1,
              'c': 2
          }
      })

    Args:
      flattened_dict: A mapping (key path) -> value.
      strip_prefix: A prefix to be stripped from `path`. If specified, only
        paths matching `strip_prefix` will be processed.

    Raises:
      KeyError: if any of the key paths can't be found.
    c                    s    i | ]\}}|  r||qS r   )
startswith)r   r5   r"   strip_prefixr   r   
<dictcomp>  s    z9ConfigDict.update_from_flattened_dict.<locals>.<dictcomp>Nr7   r   z-Key "{}" cannot be set as "{}" was not found.z3Key "{}" cannot be set as "{}" is not a tuple/list.z<Key "{}" cannot be updated as "{}" is not a ConfigDict ({}).)r   r7  r:   r@   r   r+   r    r)   r(   r   r$   r;  update_from_flattened_dict)rK   flattened_dictr>  interesting_itemschildren_to_updatefull_keyr"   r5   
full_childchildr?   child_valuechild_strip_prefixr   r=  r   r@    sH   A
	

z%ConfigDict.update_from_flattened_dict)NTT)r6   r   r/   F)r   )NF)?r   r   r   rB   _HAS_DYNAMIC_ATTRIBUTESbool__annotations__r   r   r'   r   rO   propertyr   r   r   r   r   r   r2   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r   r
  r   r  r  r  r  re   r  r  r   r  r  r  r   r  r$  r   r/  contextmanagerr(  r   rF   r8  r;  r@  __classcell__r   r   r   r   r   =  s   
 .B





1	

	

A2
	?r   c                 C   s*   t |tsdS | t| tfv rdS dS )z1Returns True if the type check should be skipped.FT)r    r1   rF   r$   object)rY   	new_valuer   r   r   r     s
   
r   c                 C   s   |pg }t | trJ t| |v rtd|t|  t | tr.|  D ]}t|| q%n*t | tr;t| 	 | nt | t
tfrX| D ]}t |tttfrRtdt|| qD|  dS )ao  Raises error if obj is NOT a valid input for FrozenConfigDict.

  Args:
    obj: Object to check. In the first call (with ancestor_list = None), obj
        should be of type ConfigDict. During recursion, it may be any type
        except dict.
    ancestor_list: List of ancestors of obj in the attribute/element
        structure, used to detect reference cycles in obj.

  Raises:
    ValueError: If obj is an invalid input for FrozenConfigDict, i.e. if it
        contains a dict within a list/tuple or contains a reference cycle. Also
        if obj is a dict, which means it wasn't already converted to ConfigDict.
  zWBad FrozenConfigDict initialization: Cannot contain a cycle in its reference structure.zqBad FrozenConfigDict initialization: Cannot contain a dict, ConfigDict, or FieldReference within a list or tuple.N)r    r   rP   rE   r*  r   r   _frozenconfigdict_valid_inputr1   r2   r)   r(   r)  )objancestor_listr"   r   r   r   r   rR    s"   

rR  c                 C   s   t | |vsJ g }d}| D ]+}t|tttfrJ t|tttfr4t||\}}}||M }|	| q|	| q|rA| d|fS t|d|fS )a  Convert tuple to fully immutable tuple.

  Args:
    value: Tuple to be made fully immutable (including its elements).
    visit_map: As used elsewhere. See _frozenconfigdict_fill_seed()
        documentation. Must not contain id(value) as a key (if it does, an
        immutable version of value already exists).

  Returns:
    immutable_value: Immutable version of value, created with minimal
        copying (for example, if a value contains no mutable elements, it is
        returned untouched).
    same_value: Whether the same value was returned untouched, i.e. with the
        same memory address. Boolean.
    visit_map: Updated visit_map

  Raises:
    TypeError: If one of the following:
        1) value is not a tuple.
        2) value contains a dict, ConfigDict, or FieldReference. If it does,
           value is an invalid attribute of FrozenConfigDict, and this
           should have been caught in valid_input at initialization.
    ValueError: id(value) is in visit_map.
  TF)
rP   r    r   r   r1   r)   r(   rH   _convert_to_immutabler*  )r"   r   
value_copy
same_valuer   new_elementuncopied_elementr   r   r   _tuple_to_immutable6  s   

rZ  c                 C   s   t | }||v r|| d|fS d}t| trt| }n t| tr)t| |\}}}nt| tr9tt| |\}}}nJ |||< |||fS )a]  Convert Python built-in type to immutable, copying if necessary.

  Args:
    value: To be made immutable type (including its elements). Must have
        type list, tuple, or set.
    visit_map: As used elsewhere. See _frozenconfigdict_fill_seed()
        documentation.

  Returns:
    immutable_value: Immutable version of value, created with minimal
        copying.
    same_value: Whether the same value was returned untouched, i.e. with the
        same memory address. Boolean.
    visit_map: Updated visit_map.

  Raises:
    TypeError: If value is an invalid type (not a list, tuple, or set).
  TF)rP   r    rH   	frozensetr(   rZ  r)   )r"   r   value_idrW  immutable_valuerk   r   r   r   rU  e  s"   




rU  c                 C   s   t | tsJ | rJ t| d| |pi }| |t|< | D ]9\}}t |tr-tdt||v r:|t| }nt |trRt |tsRt|j	d}t
||| |}| ||| q dS )a  Fills an empty FrozenConfigDict without copying previously visited nodes.

  Turns seed (an empty FrozenConfigDict) into a FrozenConfigDict version of
  initial_configdict. Avoids duplicating nodes of initial_configdict because if
  a value of initial_configdict has been previously visited, that value is not
  re-converted to a FrozenConfigDict. If a FieldReference is encountered which
  contains a dict, its contents will be converted to FrozenConfigDict.

  Note: As described in the __init__() documentation, this will not
  replicate the structure of initial_configdict if it contains
  self-references within lists, tuples, or other types. There is no warning
  or error in this case.

  Args:
    seed: Empty FrozenConfigDict, to be filled in.
    initial_configdict: The template on which seed is built. Must be of type
        ConfigDict.
    visit_map: Dictionary from memory addresses to values, storing the
        FrozenConfigDict versions of dictionary values. Lists which have
        been converted to tuples and sets to frozensets are also stored in
        visit_map to preserve the reference structure of initial_configdict.
        visit_map need not contain (id(initial_configdict), seed) as a key/value
        pair.

  Raises:
    ValueError: If one of the following, both of which can never happen in
        practice:
            1) seed is not an empty FrozenConfigDict.
            2) initial_configdict contains a FieldReference.
  _configdictzqTrying to initialize a FrozenConfigDict value with a FieldReference. This should never happen, please file a bug.r   N)r    r   rP  r   rP   r   r1   rE   r   r   _frozenconfigdict_fill_seedr%  )r   initial_configdictr   r5   r"   value_frozenconfigdictr   r   r   r_    s(   !

r_  c                       s|   e Zd ZdZd fdd	Zd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  ZS )r   a  Immutable and hashable type of ConfigDict.

  See ConfigDict() documentation above for details and usage.

  FrozenConfigDict is fully immutable. It contains no lists or sets (at
  initialization, lists and sets are converted to tuples and frozensets). The
  only potential sources of mutability are attributes with custom types, which
  are not touched.

  It is recommended to convert a ConfigDict to FrozenConfigDict after
  construction if possible.
  NTc                    sP   t t|   t||d}t| t| | t| d|j t| d|j	 dS )a  Creates an instance of FrozenConfigDict.

    Lists and sets are copied into tuples and frozensets. However, copying is
    kept to a minimum so tuples, frozensets, and other immutable types are not
    copied unless they contain mutable types.

    Prohibited initial_dictionary structures: initial_dictionary may not contain
    any lists or tuples with dictionary, ConfigDict, or FieldReference elements,
    or else an error is raised at initialization. It also may not contain loops
    in the reference structure, i.e. the reference structure must be a Directed
    Acyclic Graph. This includes loops in list-element and tuple-element
    references. initial_dictionary's reference structure need not be a tree.

    Warning: Unexpected behavior may occur with types other than Python's
    built-in types. See ConfigDict() documentation for details.

    Warning: As with ConfigDict, FieldReference values may be changed. If
    initial_dictionary contains a FieldReference with a value of type dict or
    ConfigDict, that value will be converted to FrozenConfigDict.

    Args:
      initial_dictionary: May be one of the following:

        1) dict. In this case all values of initial_dictionary that are
        dictionaries are also converted to FrozenConfigDict. If there are
        dictionaries contained in lists or tuples, an error is raised.

        2) ConfigDict. In this case all ConfigDict attributes are also
        converted to FrozenConfigDict.

        3) FrozenConfigDict. In this case all attributes are uncopied, and
        only the top-level object (self) is re-addressed.

      type_safe: See ConfigDict documentation. Note that this only matters
          if the FrozenConfigDict is converted to ConfigDict at some point.
    )r   r,   r   r   N)
r   r   rO   r   rR  r_  rP  r   r   r   )rK   r   r,   r`  r   r   r   rO     s   &
zFrozenConfigDict.__init__c                 C   sl   |pi }|  | d|vsJ || jv rtdt|tttfr/t||\}}}|| j|< |S || j|< |S )a  Sets attribute, analogous to __setattr__().

    Args:
      key: Name of the attribute to set.
      value: Value of the attribute to set.
      visit_map: Dictionary from memory addresses to values, storing the
          FrozenConfigDict versions of value's elements. Lists which have been
          converted to tuples and sets to frozensets are also stored in
          visit_map.

    Returns:
      visit_map: Updated visit_map.

    Raises:
      ValueError: If there is a dot in key, or value contains dicts inside lists
          or tuples. Also if key is already an attribute, since redefining an
          attribute is prohibited for FrozenConfigDict.
      AttributeError: If key is protected (such as '_type_safe' and '_locked').
    r7   z.Cannot redefine attribute of FrozenConfigDict.)r   r   rE   r    r)   r(   rH   rU  )rK   r5   r"   r   r]  rk   r   r   r   r%    s   



z FrozenConfigDict._frozen_setattrc                 C   s   |  |d  dS )z8Recreates FrozenConfigDict from its dict representation.r^  N)rO   r   r   r   r   r   3  s   zFrozenConfigDict.__setstate__c                 C   r   )Nz9FrozenConfigDict is immutable. Cannot call __setattr__().r   rK   r   r"   r   r   r   r   7     zFrozenConfigDict.__setattr__c                 C   r   )Nz9FrozenConfigDict is immutable. Cannot call __delattr__().rb  r   r   r   r   r   ;  rd  zFrozenConfigDict.__delattr__c                 C   r   )Nz9FrozenConfigDict is immutable. Cannot call __setitem__().rb  rc  r   r   r   r   ?  rd  zFrozenConfigDict.__setitem__c                 C   r   )Nz9FrozenConfigDict is immutable. Cannot call __delitem__().rb  r   r   r   r   r   C  rd  zFrozenConfigDict.__delitem__c                 C   r   )Nz2FrozenConfigDict is immutable. Cannot call lock().rb  rZ   r   r   r   r   G  rd  zFrozenConfigDict.lockc                 C   r   )Nz4FrozenConfigDict is immutable. Cannot call unlock().rb  rZ   r   r   r   r   J  rd  zFrozenConfigDict.unlockc                    s~    fdd d}| j  D ]&\}}t|tr#|tt|t|f7 }q|tt| | jj | f7 }qt|| j| jf}|S )a  Computes hash.

    The hash depends not only on the immutable aspects of the FrozenConfigDict,
    but on the types of the initial_dictionary at initialization (i.e. on the
    _configdict attribute). For example, in the following, hash(frozen_1) will
    not equal hash(frozen_2):
        d_1 = {'a': (1, )}
        d_2 = {'a': [1]}
        frozen_1 = FrozenConfigDict(d_1)
        frozen_2 = FrozenConfigDict(d_2)

    Note: This implementation relies on the particulars of the FrozenConfigDict
    structure. For example, the fact that lists and tuples cannot contain dicts
    or ConfigDicts is crucial, as is the fact that any loop in the reference
    structure is prohibited.

    Note: Due to hash randomization, this hash will likely differ in different
    Python sessions. For comparisons across sessions, please directly use
    equality of the serialization. For more, see
    https://bugs.python.org/issue13703

    Returns:
      frozenconfigdict_hash: The hash value.

    Raises:
      TypeError: self contains an unhashable type.
    c                    s   t | trttt| dfS t | ttfr0t | tg}| D ]} |}|| qtt|S t | tr; |  S zt| W S  t	yP   t	d
t| w )zHashes a single value.r8   z,FrozenConfigDict contains unhashable type {})r    rH   hashr[  r)   r(   r*  r1   r2   r*   r+   r$   )r"   value_hash_listr   element_hash
value_hashr   r   ri  j  s"   



z-FrozenConfigDict.__hash__.<locals>.value_hashr   )r   r   r    r   re  r^  r   r   )rK   fields_hashr5   r"   frozenconfigdict_hashr   rh  r   r   M  s   


zFrozenConfigDict.__hash__c                 C   s   t |trt| t|kS dS )a  Override default Equals behavior.

    Like __hash__(), this pays attention to the type of initial_dictionary. See
    __hash__() documentation for details.

    Warning: This distinguishes FrozenConfigDict from ConfigDict. For example:
        cd = ConfigDict()
        fcd = FrozenConfigDict()
        fcd.__eq__(cd)  # Returns False

    Args:
      other: Object to compare self to.

    Returns:
      same: Boolean self == other.
    F)r    r   r   rc   r   r   r   re     s   
zFrozenConfigDict.__eq__c                 C   ra   r/   )r^  rZ   r   r   r   r     rb   zFrozenConfigDict.as_configdict)NTr/   )r   r   r   rB   rO   r%  r   r   r   r   r   r   r   r   re   r   rO  r   r   r   r   r     s    
2&=r   c                   @   s   e Zd ZdZdd ZdS )r  znJSON encoder for ConfigDict and FieldReference.

  The encoder throws an exception for non-supported types.
  c                 C   sF   t |tr	| S t |tr|jS t |trt|S tdt|)NzI{} is not JSON serializable. Instead use ConfigDict.to_json_best_effort())	r    r1   r2   r   r   r$   r'   r*   r+   rK   rS  r   r   r   rL     s   



zCustomJSONEncoder.defaultN)r   r   r   rB   rL   r   r   r   r   r    s    r  c                       s    e Zd ZdZ fddZ  ZS )r  z}Best effort JSON encoder for ConfigDict.

  The encoder tries to serialize non-supported types (doesn't throw exceptions).
  c                    s   z	t t| |W S  ty_   t|trtt| Y S t	|r*d
|j Y S t|r6t| Y S t|drJ|jrJt|sJt|j Y S t|drVd
| Y S d
t| Y S w )Nzfunction {}r   r  zunserializable object: {}z!unserializable object of type: {})r   r  rL   r*   r    rH   r   r)   inspect
isfunctionr+   r   dataclassesis_dataclassasdicthasattrr   isclassr   r$   rl  r   r   r   rL     s&   




z$_BestEffortCustomJSONEncoder.default)r   r   r   rB   rL   rO  r   r   r   r   r    s    r  c                  K   s
   t | dS )a  Creates a `ConfigDict` with the given named arguments as key-value pairs.

  This allows for simple dictionaries whose elements can be accessed directly
  using field access::

    from ml_collections import config_dict
    point = config_dict.create(x=1, y=2)
    print(point.x, point.y)

  This is particularly useful for compactly writing nested configurations::

    config = config_dict.create(
      data=config_dict.create(
        game='freeway',
        frame_size=100),
      model=config_dict.create(num_hidden=1000))

  The reason for the existence of this function is that it simplifies the
  code required for the majority of the use cases of `ConfigDict`, compared
  to using either `ConfigDict` or `namedtuple's`. Examples of such use cases
  include training script configuration, and returning multiple named values.

  Args:
    **kwargs: key-value pairs to be stored in the `ConfigDict`.

  Returns:
    A `ConfigDict` containing the key-value pairs in `kwargs`.
  )r   )r   )r  r   r   r   create  s   
rt  c                 C   s   t d| |dS )a  Defines an entry in a ConfigDict that has no value yet.

  Example::

    config = configdict.create(
        batch_size = configdict.placeholder(int),
        frame_shape = configdict.placeholder(tf.TensorShape))

  Args:
    field_type: type of value.
    required: If True, the placeholder will raise an error on access if the
         underlying value hasn't been set.

  Returns:
    A `FieldReference` with value None and the given type.
  Nr   rN   )r1   ru  r   r   r   placeholder  s   rv  c                 C   s   t | ddS )a  Defines an entry in a ConfigDict with unknown but required value.

  Example::

    config = configdict.create(
        batch_size = configdict.required_placeholder(int))

    try:
      print(config.batch_size)
    except RequiredValueError:
      pass

    config.batch_size = 10
    print(config.batch_size)  # 10

  Args:
    field_type: type of value.

  Returns:
    A `FieldReference` with value None and the given type.
  T)rN   )rv  r   r   r   r   required_placeholder  s   rw  c                 C   sZ   t  }|  D ]#\}}t|t rt|||}n|}||kr$t||| qt||| q|S )a  Returns copy of conf with old_name recursively replaced by new_name.

  This is not done in place, no changes are made to conf but a new ConfigDict is
  returned with the changes made. This is useful if the name of a parameter has
  been changed in code but you need to load an old config.

  Example usage:
    updated_conf = configdict.recursive_rename(conf, "config", "kwargs")

  Args:
    conf: a ConfigDict which needs updating
    old_name: the name used in the ConfigDict which is out of sync with the code
    new_name: the name used in the code

  Returns:
    A ConfigDict which is a copy of conf but with all instances of old_name
    replaced with new_name.
  )r   r   r    recursive_renamesetattr)confold_namenew_namenew_confnamer   new_cr   r   r   rx    s   
rx  rI  r/   ):rB   r   r   r+  r/  ro  r   rz   rm  r  rr   r;   typingr   r   r   r   abslr   r  r   Representeradd_representerABCMetarepresent_namer  r   r   r   r$   r   r   r#   r.   r4   r'   r%   r@   
namedtuplerA   total_orderingr1   r   r   rK  r   rR  rZ  rU  r_  r   JSONEncoderr  r  rt  rv  rw  rx  r   r   r   r   <module>   sp   
6	  
DL       K
(/
'A X
!