o
    ,wi+-                     @   sH  d 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	 ddl
mZ ddl
mZ ddlmZ ddlmZ ejZe	dZd	ed
eej defddZd"d	ededefddZd	ededeej fddZe Zd	edefddZ	d#ddd	edeee  deeeee f  defddZG dd dZ	d$d	ededefd d!ZdS )%a<  Helper functions for visualization of Fiddle configurations.

By default, you should be able to call APIs in `graphviz` and `printing` with no
special handling. But some real-world configurations become gigantic, and so
having a few helper functions for trimming them for interactive demos and such
can be valuable.
    N)AnyDictListOptionalTypeVar)daglish)diffing)config)graphviz_custom_object_Tr	   trimreturnc                 C   s   t | dd |D S )a  Returns a deep copy of a Buildable, with certain nodes replaced.

  This copy should have the same DAG structure as the original configuration.

  Example usage:

  graphviz.render(visualize.trimmed(config, [config.my_large_model_sub_config]))

  Args:
    config: Root buildable object, or collection of buildables.
    trim: List of sub-buildables that will be replaced by Trimmed() instances.

  Returns:
    Copy of the Buildable with nodes replaced.
  c                 S   s   i | ]}t |t qS  )idTrimmed).0
sub_configr   r   _/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/fiddle/_src/experimental/visualize.py
<dictcomp>:   s    ztrimmed.<locals>.<dictcomp>)copydeepcopy)r	   r   r   r   r   trimmed(   s   r   Fremove_deep_defaultsc                    s`   i dt jdt jffdd dtdtdtjdtfdd	d
tjf fdd}tj|| S )a  Trims arguments that match their default values.

  Args:
    config: Root buildable object, or nested structure of Buildables.
    remove_deep_defaults: Whether to remove defaults that are equal to
      dataclass.field(default_factory=auto_config_fn) defaults. If any of these
      default values have external references, i.e. they are shared, then they
      will not be removed.

  Returns:
    Copy of the Buildable with args matching defaults removed.
  	buildabler   c                    sB   t | }t| t|f}| v r | S t| |}| |< |S N)
config_libget_callabletyper   )r   	fn_or_clskeyresult)cached_deep_defaultsr   r   _get_defaultP   s   
z+with_defaults_trimmed.<locals>._get_defaultnode	attr_nameparent_statec                    s   fdd|j ddD fdd dtjdtf fd	d
}tj||jj|jj|jjd}t|g |j	t
R | |}|| |S )au  Returns whether we can safely delete a deep default.

    (This function presumes we've already checked equality with the default, and
    helps to check that sharing isn't altered.)

    Args:
      node: Default node to delete.
      attr_name: Attribute referring to `node`.
      parent_state: State from the traversal, which should correspond to
        `parent`.
    c                    s    g | ]}g |t  R qS r   )r   Attr)r   parent_path)r$   r   r   
<listcomp>i   s    zJwith_defaults_trimmed.<locals>.can_remove_deep_default.<locals>.<listcomp>Tallow_cachingc                    s   t  fddD S )Nc                 3   s$    | ]} d t | |kV  qd S r   )len)r   	node_pathpathr   r   	<genexpr>o   s
    
zewith_defaults_trimmed.<locals>.can_remove_deep_default.<locals>._goes_through_node.<locals>.<genexpr>)anyr-   )valid_paths_to_noder-   r   _goes_through_noden   s   zRwith_defaults_trimmed.<locals>.can_remove_deep_default.<locals>._goes_through_nodesubstater   c                    sB   | | r
t| rdS | D ]	} |s dS qt|| S NTF)is_traversabler   is_immutableget_all_pathsallyield_map_child_values)valuer3   sub_path)r2   r   r   _helpert   s   zGwith_defaults_trimmed.<locals>.can_remove_deep_default.<locals>._helper)traversal_fnroot_objregistrypaths_cache)r7   r   StateboolMemoizedTraversal	traversalr>   r?   r@   current_pathr&   )r#   r$   r%   r<   sub_traversalstater   )r2   r$   r1   r   can_remove_deep_defaultY   s$   


z6with_defaults_trimmed.<locals>.can_remove_deep_defaultrG   c                    s   t | tjrTi }r | j}d}t| j D ];\}}| jj|d }|d u r)q||v r1|| n|j	}|j
tjjkrS||krS|||rS|rNt| } d}t| | q|| S r4   )
isinstancer   	Buildable__arguments__listitems__signature_info__
parametersgetdefaultkindinspect	ParameterVAR_KEYWORDr   delattrmap_children)r:   rG   deep_defaultsshould_copyname
attr_valueparamparam_default)r"   rH   r   r   r   traverse_fn   s*   




z*with_defaults_trimmed.<locals>.traverse_fn)	r   rJ   r   strr   rA   rB   rC   run)r	   r   r^   r   )r"   r!   rH   r   r   with_defaults_trimmed>   s   	
4ra   depthc                    s^   i i dt jdtfdd dt jddf fdd}t j||  fd	d
 D S )a  Returns a list of sub-Buildable objects over a given depth from the root.

  If a sub-Buildable has multiple paths from the root to it, its depth is the
  *minimum* distance of those paths.

  Furthermore, only Buildable nodes count towards the depth; if a
  sub-configuration is nested in containers like lists, tuples, or dicts, those
  do not count. This is because this function is primarily geared towards
  visualization, and those containers are usually displayed inline.

  Args:
    config: Root buildable object, or collection of buildable objects.
    depth: Depth value.

  Returns:
    List of all sub-Buildables with depth strictly greater than `depth`.
  r.   r   c                 S   s   t dd | D S )Nc                 s   s$    | ]}t |tjrd ndV  qdS )   r   N)rI   r   r&   )r   eltr   r   r   r/      s   " z0depth_over.<locals>._path_len.<locals>.<genexpr>)sumr-   r   r   r   	_path_len   s   zdepth_over.<locals>._path_lenrG   Nc                    sZ   t | tjr!|jdd}t fdd|D t| < | t| < |j| ddD ]}q(d S )NTr)   c                 3   s    | ]} |V  qd S r   r   )r   r.   )rf   r   r   r/          z/depth_over.<locals>.traverse.<locals>.<genexpr>)ignore_leaves)rI   r   rJ   r7   minr   r9   )r#   rG   	all_paths_)rf   
id_to_nodenode_to_depthr   r   traverse   s   zdepth_over.<locals>.traversec                    s    g | ]\}}| kr| qS r   r   )r   r   
node_depth)rb   rl   r   r   r(      s
    zdepth_over.<locals>.<listcomp>)r   PathintrA   rC   r`   rM   )r	   rb   rn   r   )rf   rb   rl   rm   r   
depth_over   s   rr   c                 C   s   dt jfdd}t j|| S )aC  Returns a skeleton of a configuration.

  Args:
    config: Buildable item, or collection of Buildable items.

  Returns:
    Copy of `config` that has all of the original Buildable's, plus any fields
    and containers necessary to make all of those original Buildable's linked.
    Any leaf arguments (primitives, containers of primitives) are removed. In
    cases where there is a list with primitives and buildables, then the
    primitive will be replaced with AnyValue and the buildable will be
    maintained, like [1, fdl.Config(Foo)] --> [AnyValue, fdl.Config(Foo)].
  rG   c                 S   s|   | | stS t| tjr)|| }t| D ]\}}|tu r&t|| q|S |	| }t
dd |jD r<| S tS )Nc                 s   s    | ]}|t uV  qd S r   )
_any_value)r   itemr   r   r   r/      rg   z.structure.<locals>.traverse.<locals>.<genexpr>)r5   rs   rI   r   rJ   rW   ordered_argumentsrM   rV   flattened_map_childrenr0   values	unflatten)r:   rG   r    rZ   	sub_valuer   r   r   rn      s   



zstructure.<locals>.traverse)r   rA   rC   r`   )r	   rn   r   r   r   	structure   s   rz   )fields_by_config_idtop_level_fieldsr{   c                   s   |rt  |ni    D ]\}}t|tstd| t|ttfs(tdq|dur>t|ttfs8td| t| <  sEt | S dt	j
f fdd}t	j|| S )a1  Trims fields to a list of desired fields.

  Args:
    config: Configuration object.
    top_level_fields: Fields on the top-level configuration object to keep.
    fields_by_config_id: Fields to keep, indexed by id(sub_config).

  Returns:
    Deep copy of configuration object, with defaults trimmed.
  z4fields_by_config_id should have integer keys, found z:Expected fields_by_config_id values to be lists or tuples.Nz0Expected top_level_fields to be a list or tuple.rG   c                    sb   t | tjr,t|  v r, t|  }t| } tt| t| D ]	}t| |t  q"|	| S r   )
rI   r   rJ   r   r   setru   setattrr   rW   )r:   rG   to_keepargumentfields_by_idr   r   rn     s   

z trim_fields_to.<locals>.traverse)r   rM   rI   rq   	TypeErrorrL   tupler   r   r   rA   rC   r`   )r	   r|   r{   r   r:   rn   r   r   r   trim_fields_to   s&   

r   c                   @   s&   e Zd ZdZdefddZdd ZdS )_TruncatedReprz>Represent the truncated fields for visualization purpose only.prefixc                 C   s
   || _ d S r   _prefix)selfr   r   r   r   __init__,  s   
z_TruncatedRepr.__init__c                 C   s   | j S r   r   )r   r   r   r   __repr__/  s   z_TruncatedRepr.__repr__N)__name__
__module____qualname____doc__r_   r   r   r   r   r   r   r   )  s    r   <   	thresholdc                    sD   t  tr	 dkrtd  ddtjf fdd}tj|| S )zTrims fields to a bounded length.

  Args:
    config: Configuration object.
    threshold: Long fields will be trimmed to the threshold length.

  Returns:
    Deep copy of configuration object, with long fileds trimmed.
  r   z&threshold must be a positive int, got .rG   c                    s   t | tjr=tt| D ]/}t| |}t |tjtttfs<t	|}t
| kr<tjt	| dd}t|}t| || q|| S )Nz...)widthplaceholder)rI   r   rJ   r}   ru   getattrrL   r   dictreprr+   textwrapshortenr   r~   rW   )r:   rG   r   field
field_reprsr   r   r   r   rn   D  s   


z"trim_long_fields.<locals>.traverse)rI   rq   
ValueErrorr   rA   rC   r`   )r	   r   rn   r   r   r   trim_long_fields3  s   r   )Fr   )r   ) r   r   rS   r   typingr   r   r   r   r   fiddler   r   fiddle._srcr	   r   r
   r   r   rJ   r   rB   ra   rq   rr   AnyValuers   rz   r_   r   r   r   r   r   r   r   <module>   sJ   n*$

.