o
    ]i1                     @   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mZm	Z	m
Z
mZmZmZ ddlmZ edZejdd ejdd ejdd ejd	d ejd
d eddd iZdd Zdedee fddZ	d6de	e fddZdededeeef fddZdedefddZdedede
e fddZdede	e fdd Zdedeeeed!f f fd"d#Z dede!fd$d%Z"dede	e fd&d'Z#dedefd(d)Z$	*	d7deded+e	ee  fd,d-Z%dedede!fd.d/Z&d0d1deded2ed3e!fd4d5Z'dS )8z"Module for spliting flag prefixes.    N)AnyMutableSequenceOptionalSequenceTupleUnionType)config_dictc                 C   s   g t | j| jR S N)_split_nodevalueattrn r   [/home/ubuntu/.local/lib/python3.10/site-packages/ml_collections/config_flags/config_path.py<lambda>   s    r   c                 C   s
   t | jS r
   )r   r   ir   r   r   r       s   
 c                 C   s   | j fS r
   )idr   r   r   r   r   !   s    c                 C   s   t tt| j| j| jf S r
   )slicemapr   lowerupperstepr   r   r   r   r   "       c                 C   s   g t | jt | jR S r
   )r   r   r   r   r   r   r   r   #   r   c                 C   s   d S r
   r   r   r   r   r   r   $   s    c                 C   s   t t| tj| S r
   )_AST_SPLIT_CONFIG_PATHgettypeastliteral_eval)noder   r   r   r   (   s   r   config_pathreturnc              
   C   sn   z	t j| dd}W n ty  } ztd| d|dd}~ww t|t jr3t|j}t|tr3|S t| )a  Returns config_path split into a tuple of parts.

  Example usage:
    >>> assert config_path.split('a.b.cc') == ('a', 'b', 'cc')
    >>> assert config_path.split('a.b["cc.d"]') == ('a', 'b', 'cc.d')
    >>> assert config_path.split('a.b[10]') == ('a', 'b', 10)
    >>> assert config_path.split('a[(1, 2)]') == ('a', (1, 2))
    >>> assert config_path.split('a[:]') == ('a', slice(None))

  Args:
    config_path: Input path to be split - see example usage.

  Returns:
    Tuple of config_path split into parts. Parts are attributes or subscripts.
    Attrributes are treated as strings and subscripts are parsed using
    ast.literal_eval. It is up to the caller to ensure all returned types are
    valid.

  Raises:
    ValueError: Failed to parse config_path.
  eval)modezCould not parse z: N)	r   parseSyntaxError
ValueError
isinstance
Expressionr   bodytuple)r"   r!   eresultr   r   r   split,   s   

r/   
field_pathc                 C   st   t |trt| |rt| |S t| dr| | S t |tr+tt|  d| d| tdt|  d| d| )z2Returns attribute of member failing that the item.__getitem__z$ does not support integer indexing [z]]. Attempting to lookup: z
Attribute .zN does not exist and the type does not support indexing. Attempting to lookup: )r)   strhasattrgetattrint
IndexErrorr   KeyError)configfieldr0   r   r   r   _get_item_or_attributeM   s   


r;   r9   c                 C   sD   t | }|s
tdtjt| d}t||dd |}||d fS )a  Returns the last part config_path and config to allow assignment.

  Example usage:
    >>> config = {'a': {'b', {'c', 10}}}
    >>> holder, lastfield = _get_holder_field('a.b.c', config)
    >>> assert lastfield == 'c'
    >>> assert holder is config['a']['b']
    >>> assert holder[lastfield] == 10

  Args:
    config_path: Any string that `split` can process.
    config: A nested datastructure that can be accessed via
      _get_item_or_attribute

  Returns:
    The penultimate object when walking config with config_path. And the final
    part of the config path.

  Raises:
    IndexError: Integer field not found in nested structure.
    KeyError: Non-integer field not found in nested structure.
    ValueError: Empty/invalid config_path after parsing.
  zPath cannot be emptyr0   N)r/   r(   	functoolspartialr;   reduce)r"   r9   fieldsget_itemholderr   r   r   _get_holder_field^   s   rD   c                 C   s    t jt| d}t |t| |S )a  Gets value of a single field.

  Example usage:
    >>> config = {'a': {'b', {'c', 10}}}
    >>> assert config_path.get_value('a.b.c', config) == 10

  Args:
    config_path: Any string that `split` can process.
    config: A nested datastructure

  Returns:
    The last object when walking config with config_path.

  Raises:
    IndexError: Integer field not found in nested structure.
    KeyError: Non-integer field not found in nested structure.
    ValueError: Empty/invalid config_path after parsing.
  r<   )r>   r?   r;   r@   r/   )r"   r9   rB   r   r   r   	get_value~   s   rE   overrideallowed_missingc                    s  t  } fdd|D }| }t|dd dD ]l\}}|}t|| }|dur)qt||}	t|	sFtd  d| d|	 d	t| d
	||vr[td  d| d| d| d	z|	 }W n ty} }
 ztd  d| d|	 d|
 |
d}
~
ww t	||| qdS )a{  Adds some missing nested holder fields for a particular override.

  For example if override is 'config.a.b.c' and config.a is None, it
  will default initialize config.a, and if config.a.b is None will default
  initialize it as well. Only overrides present in allowed_missing will
  be initialized.

  Args:
    config: config object (typically dataclass)
    override: dot joined override name.
    allowed_missing: list of overrides that are allowed
    to be set. For example, if override is 'a.b.c.d',
    allowed_missing could be ['a.b.c', 'a', 'foo.bar'].

  Raises:
    ValueError: if parent field is not of dataclass type.
  c                    s&   h | ]}  |d  rtt|qS )r2   )
startswithlenr/   ).0xrF   r   r   	<setcomp>   s    z3initialize_missing_parent_fields.<locals>.<setcomp>Nr=      z	Override z# can not be applied because field "z" is None, and its type "z," is not a dataclass in the parent of type "z".zFlag zv" is None by default and it is not explicitly provided in flags (it can be default intialized by providing --<path-to-z>.z=build flagz
" of type z! can not be default instantiated:)
r/   	enumerater;   get_typedcis_dataclassr(   r   	Exception	set_value)r9   rF   rG   rA   allowed_levelschildlevelfparent
field_typer-   r   rL   r    initialize_missing_parent_fields   s^   


r[   	type_specc                 C   s    t tdr
t| S t| ddS )zACall typing.get_origin, with a fallback for Python 3.7 and below.
get_origin
__origin__N)r4   typingr]   r5   r\   r   r   r   r]         

r]   .c                 C   s    t tdr
t| S t| dtS )z=Call typing.get_args, with fallback for Python 3.7 and below.get_args__args__)r4   r_   rb   r5   NoneTyper`   r   r   r   rb      ra   rb   c                 C   s   t | tttdtfv S )z-Cheeck if a type_spec is a Union type or not.	UnionType)r]   r   r5   typesr`   r   r   r   _is_union_type   s   rg   c                 C   s6   t | sdS dd t| D }t|dkrdS |d S )zEIf type_spec is of type Optional[T], returns T object, otherwise NoneNc                 S   s   g | ]}|t ur|qS r   )rd   )rJ   tr   r   r   
<listcomp>   s    z.extract_type_from_optional.<locals>.<listcomp>rN   r   )rg   rb   rI   )r\   non_noner   r   r   extract_type_from_optional   s   rk   c                 C   s.   t | rt| }|du rtd|  |S | S )a  Normalizes a type object.

  Strips all None types from the type specification and returns the remaining
  single type. This is primarily useful for Optional type annotations in which
  case it will strip out the NoneType and return the inner type.

  Args:
    type_spec: The type to normalize.

  Raises:
    TypeError: If there is not exactly 1 non-None type in the union.
  Returns:
    The normalized type.
  Nz$Unable to normalize ambiguous type: )rg   rk   	TypeError)r\   subtyper   r   r   normalize_type   s   rn   Tdefault_typec                    s   t | |\} t|tjtjfr|dur |vr|S | S t|rJ fddt|D }|s>t	d  dt
| |rFt|d S |d S t
t| | S )aF  Gets type of field in config described by a config_path.

  Example usage:
    >>> config = {'a': {'b', {'c', 10}}}
    >>> assert config_path.get_type('a.b.c', config) is int

  Args:
    config_path: Any string that `split` can process.
    config: A nested datastructure
    normalize: whether to normalize the type (in particular strip Optional
      annotations on dataclass fields)
    default_type: If the `config_path` is not found and `default_type` is set,
      the `default_type` is returned.

  Returns:
    The type of last object when walking config with config_path.

  Raises:
    IndexError: Integer field not found in nested structure.
    KeyError: Non-integer field not found in nested structure.
    ValueError: Empty/invalid config_path after parsing.
    TypeError: Ambiguous type annotation on dataclass field.
  Nc                    s   g | ]
}|j  kr|jqS r   )namer   )rJ   rX   r:   r   r   ri   -  s    zget_type.<locals>.<listcomp>zField z not found on dataclass r   )rD   r)   r	   
ConfigDictFieldReferencerP   rQ   rR   rA   r8   r   rn   r;   )r"   r9   	normalizero   rC   matchesr   rq   r   rP     s   


rP   c                 C   s   t | |dd}t|d uS )NF)rt   )rP   rk   )r"   r9   raw_typer   r   r   is_optional5  s   rw   F)accept_new_attributesr   rx   c                C   s   t | |\}}t|trt|tr|||< dS t|dr(||v s"|r(|||< dS t|t|r9t|t|| dS t|trMt| dt| d|  dt	| dt| d|  d)ae  Sets value of field described by config_path.

  Example usage:
    >>> config = {'a': {'b', {'c', 10}}}
    >>> config_path.set_value('a.b.c', config, 20)
    >>> assert config['a']['b']['c'] == 20

  Args:
    config_path: Any string that `split` can process.
    config: A nested datastructure
    value: A value to assign to final field.
    accept_new_attributes: If `True`, the new config attributes can be added

  Raises:
    IndexError: Integer field not found in nested structure.
    KeyError: Non-integer field not found in nested structure.
    ValueError: Empty/invalid config_path after parsing.
  __setitem__z is not a valid index for z (in: )z$ is not a valid key or attribute of N)
rD   r)   r6   r   r4   r3   setattrr7   r   r8   )r"   r9   r   rx   rC   r:   r   r   r   rT   :  s"   


rT   r
   )TN)(__doc__r   dataclassesrQ   r>   rf   r_   r   r   r   r   r   r   r   ml_collectionsr	   r   rd   	AttributeIndexNameSlice	Subscriptr   r   r3   r/   r;   rD   rE   r[   r]   rb   boolrg   rk   rn   rP   rw   rT   r   r   r   r   <module>   sp   $





"
 
;"


.
