o
    ,wi(                     @   sX  d 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 ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ eed	ef e
e f ZG d
d dejdZd"ddZejddG dd deZejddG dd deZe ZdedefddZ	d"ddejdddejde	e de	ej dede
ej de	e defd d!Z dS )#zLibrary for manipulating selections of a Buildable DAG.

A common need for configuration libraries is to override settings in some kind
of base configuration, and these APIs allow such overrides to take place
imperatively.
    N)AnyCallableIteratorOptionalTypeUnion)config)daglish)mutate_buildable)tag_type)tagging.c                   @   sh   e Zd ZdZdee fddZejdde	ddfdd	Z
ejdd
dZejdedee fddZdS )	SelectionzBBase class for selections of nodes/objects/values in a config DAG.returnc                 C   s   t dt|  )z"Iterates over the selected values.zIteration is not supported for )NotImplementedErrortypeself r   R/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/fiddle/_src/selectors.py__iter__+      zSelection.__iter__TdeepcopyNc                 C      t  )zReplaces all selected nodes/objects/values with a new value.

    Args:
      value: Value to replace selected nodes/objects/values with.
      deepcopy: Whether to deepcopy `value` every time it is set.
    r   )r   valuer   r   r   r   replace/   s   zSelection.replacec                 K   r   )zvSets attributes on nodes matching this selection.

    Args:
      **kwargs: Attributes to set on matching nodes.
    r   r   kwargsr   r   r   set9   s   zSelection.setnamec                 C   r   )Gets all values for a particular attribute.

    Args:
      name: Name of the attribute on matching nodes.

    Yields:
      Values configured for the attribute with name `name` on matching nodes.
    r   r   r   r   r   r   getB   s   
zSelection.getTr   N)__name__
__module____qualname____doc__r   r   r   abcabstractmethodboolr   r   strr"   r   r   r   r   r   (   s    	r   )	metaclassc                 c   sB    |p	t jt| }|| r|| D ]}|E dH  q| V  dS )z6Yields all values (memoized) from a configuration DAG.N)r	   MemoizedTraversalbegin_memoized_walk_leaves_firstis_traversableyield_map_child_values)r   state
sub_resultr   r   r   r0   O   s   

r0   T)frozenc                   @   s   e Zd ZU dZejed< ee ed< e	ed< e
ej ed< dejde	fdd	Zdeej fd
dZdefddZeZddede	ddfddZdddZdedee fddZdS )NodeSelectiona  Represents a selection of nodes.

  This selection is declarative, so if subtrees / subgraphs of `cfg` change and
  later match or don't match, a different set of nodes will be returned.

  Generally this class is intended for modifying attributes of a buildable DAG
  in a way that doesn't alter its structure. We do not pay particular attention
  to structure-altering modifications right now; please do not depend on such
  behavior.
  cfg	fn_or_clsmatch_subclassesbuildable_typenoder   c                 C   sj   t || jsdS | jdur3| jt|kr3| jo.t | jto.t t|to.tt|| j}|s3dS dS )z<Helper for __iter__ function, determining if a node matches.FNT)
isinstancer:   r8   
config_libget_callabler9   r   
issubclass)r   r;   is_subclassr   r   r   _matchesj   s   

zNodeSelection._matchesc                 c   s&    t | jD ]
}| |r|V  qdS )zgYields all selected nodes.

    Nodes that are reachable via multiple paths are yielded only once.
    N)r0   r7   rA   )r   r   r   r   r   r      s   
zNodeSelection.__iter__c                 C   s   d| j  d| j dS )NzNodeSelection(cfg, fn_or_cls=z, match_subclasses=))r8   r9   r   r   r   r   __str__   s   
zNodeSelection.__str__Tr   r   Nc                    sX    jr
tddtjf fdd}|jtj|j}tj|jd d S )NzNodeSelection.replace() is not supported on selections that match the root Buildable, because select() is primarily a mutation-based API that does not return new/replacement configs.r3   c                    sV    | r rtS S || r)|| }t| tjr'tj	|| d | S |} | S )Nsourcedestination)
rA   copyr   r1   map_childrenr<   r=   	Buildabler
   move_buildable_internals)r;   r3   resultr   r   r   r   r   traverse   s   


z'NodeSelection.replace.<locals>.traverserD   )	rA   r7   
ValueErrorr	   Stater.   r/   r
   rJ   )r   r   r   rM   
new_configr   rL   r   r      s   
zNodeSelection.replacec                 K   s,   | D ]}|  D ]
\}}t||| qqdS )zSets multiple attributes on nodes matching this selection.

    Args:
      **kwargs: Properties to set on matching nodes.
    N)itemssetattr)r   r   matchingr   r   r   r   r   r      s
   zNodeSelection.setr   c                 c   s    | D ]}t ||V  qdS )r    N)getattr)r   r   rS   r   r   r   r"      s   	zNodeSelection.getr#   r$   )r%   r&   r'   r(   r=   rI   __annotations__r   	FnOrClassr+   r   rA   r   r   r,   rC   __repr__r   r   r   r"   r   r   r   r   r6   Y   s   
 




r6   c                   @   sp   e Zd ZU dZejed< ejed< de	e
 fddZdde
d	edd
fddZdede	e
 fddZdddZd
S )TagSelectionz7Represents a selection of fields tagged by a given tag.r7   tagr   c                 #   s\    t  jD ]%}t|tjr+|j D ]\}}t fdd|D r*t||t	j
V  qqdS )z'Yields all values for the selected tag.c                 3       | ]	}t | jV  qd S Nr?   rY   .0rY   r   r   r   	<genexpr>       z(TagSelection.__iter__.<locals>.<genexpr>N)r0   r7   r<   r=   rI   __argument_tags__rQ   anyrT   r   NO_VALUE)r   r   r   tagsr   r   r   r      s   zTagSelection.__iter__Tr   r   Nc                    sh   t  jD ],}t|tjr1|j D ]\}}t fdd|D r0|s%|nt	|}t
||| qqd S )Nc                 3   rZ   r[   r\   r]   r   r   r   r_      r`   z'TagSelection.replace.<locals>.<genexpr>)r0   r7   r<   r=   rI   ra   rQ   rb   rG   r   rR   )r   r   r   
node_valuer   rd   to_setr   r   r   r      s   zTagSelection.replacer   c                 C      t d)NzKTo iterate through values of a TagSelection, use __iter__ instead of get().r   r!   r   r   r   r"         zTagSelection.getc                 K   rg   )NzsYou can't set named attributes on tagged values, you can only replace them. Please call replace() instead of set().r   r   r   r   r   r      rh   zTagSelection.setr#   r$   )r%   r&   r'   r(   r=   rI   rU   r   TagTyper   r   r   r+   r   r,   r"   r   r   r   r   r   rX      s   
 

		rX   	selectionr   c                 C   s   t t| ttu S )z%Returns whether a selection is empty.)nextiter_missing)rj   r   r   r   	_is_empty   r   rn   )rY   r9   r:   check_nonemptyr7   r8   rY   r9   r:   ro   c                C   s   |dur|durt d|st dt| |}n|du r tdt| |||d}|r6t|r6td| d|du rCt|rCtd |S )	a  Selects sub-buildables or fields within a configuration DAG.

  Example configuring attention classes::

    select(my_config, MyDenseAttention).set(num_heads=12, head_dim=512)

  Example configuring all activation dtypes::

    select(my_config, tag=DType).set(value=jnp.float32)

  Args:
    cfg: Configuraiton to traverse.
    fn_or_cls: Select by a given function or class that is being configured.
    tag: If set, selects all attributes tagged by `tag`. This will return a
      TagSelection instead of a Selection, which has a slightly different API.
    match_subclasses: If fn_or_cls is provided and a class, then also match
      subclasses of `fn_or_cls`.
    buildable_type: Restrict the selection to a particular buildable type. Not
      valid for tag selections.
    check_nonempty: Whether to raise an error on empty selections. This will be
      true in the future.

  Returns:
    A Selection, which is a TagSelection if `tag` is set, and a NodeSelection
    otherwise.
  Nz4Selecting by tag and fn_or_cls is not supported yet.z2match_subclasses is ignored when selecting by tag.z)Either tag or fn_or_cls must be provided.)r9   r:   z
Selection zG is empty! If this is OK, please call select(..., check_nonempty=False)ztYour selection was empty. In the future, this will be an error. Please set check_nonempty=False if this is intended.)r   rX   rN   r6   rn   loggingwarning)r7   r8   rY   r9   r:   ro   rj   r   r   r   select   s6   #
rr   r[   )!r(   r)   rG   dataclassesrp   typingr   r   r   r   r   r   fiddle._srcr   r=   r	   r
   r   r   rV   ABCMetar   r0   	dataclassr6   rX   objectrm   r+   rn   rI   ri   rr   r   r   r   r   <module>   sR    
'


k"