U
    Vcl                     @   s$  d Z ddlZddlZddl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 ddlmZ G d	d
 d
e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ed#d$ZG d%d& d&eZd'd( Zed)d*d+gZd,d- Z d.d/ Z!d0d1 Z"dS )2zBClasses and functions for handling the ListSessionGroups API call.    N)
struct_pb2)provider)api_pb2)error)metadata)metricsc                   @   sh   e Z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S )Handlerz$Handles a ListSessionGroups request.c                 C   sX   || _ || _|| _|| _t|j| _t|j| j| _|	||| _
|||| j
| _dS )a$  Constructor.

        Args:
          request_context: A tensorboard.context.RequestContext.
          backend_context: A backend_context.Context instance.
          experiment_id: A string, as from `plugin_util.experiment_id`.
          request: A ListSessionGroupsRequest protobuf.
        N)_request_context_backend_context_experiment_id_request_create_extractors
col_params_extractors_create_filters_filtersZhparams_metadata_hparams_run_to_tag_to_contentZexperiment_from_metadata_experiment)selfrequest_contextZbackend_contextZexperiment_idrequest r   S/tmp/pip-unpacked-wheel-g8kmtpbc/tensorboard/plugins/hparams/list_session_groups.py__init__"   s       zHandler.__init__c                 C   s&   |   }| |}| | | |S )zwHandles the request specified on construction.

        Returns:
          A ListSessionGroupsResponse object.
        )_build_session_groups_filter_sort_create_responser   session_groupsr   r   r   run>   s    

zHandler.runc                 C   s6  i }dd | j  D }t }t }|D ]<}| jjD ].}|j}t||\}}	|| ||	 q4q(| j	j
| j| jtj||dd}
| j  D ]n\}}tj|krqt|tj }d}tj|krt|tj }| ||||
}|j| jjkr| ||| q| }|D ]$}|jjtdd | | q|S )zKReturns a list of SessionGroups protobuffers from the summary
        data.c                 S   s   g | ]\}}t j|kr|qS r   )r   SESSION_START_INFO_TAG).0r    tagsr   r   r   
<listcomp>W   s   
z1Handler._build_session_groups.<locals>.<listcomp>)runsr#   )Zrun_tag_filterNnamekey)r   itemssetr   metric_infosr&   r   run_tag_from_session_and_metricaddr
   Zread_last_scalarsr	   r   r   ZRunTagFilterr   r!   Z$parse_session_start_info_plugin_dataZSESSION_END_INFO_TAGZ"parse_session_end_info_plugin_data_build_sessionstatusr   Zallowed_statuses_add_sessionvaluessessionssortoperator
attrgetter_aggregate_metrics)r   groups_by_nameZsession_namesZmetric_runsZmetric_tagssession_namemetricmetric_namer    tagall_metric_evalsZtag_to_content
start_infoend_infosessiongroupsgroupr   r   r   r   I   sd    
 
 


   zHandler._build_session_groupsc                 C   sl   |j p
|j}||kr(|| j|g n@tj||g|jd}|j D ]\}}|j| 	| qF|||< dS )av  Adds a new Session protobuffer to the 'groups_by_name' dictionary.

        Called by _build_session_groups when we encounter a new session. Creates
        the Session protobuffer and adds it to the relevant group in the
        'groups_by_name' dict. Creates the session group if this is the first time
        we encounter it.

        Args:
          session: api_pb2.Session. The session to add.
          start_info: The SessionStartInfo protobuffer associated with the session.
          groups_by_name: A str to SessionGroup protobuffer dict. Representing the
            session groups and sessions found so far.
        )r&   r2   monitor_urlN)

group_namer&   r2   extendr   ZSessionGrouprB   hparamsr)   ZCopyFrom)r   r?   r=   r7   rC   rA   r(   valuer   r   r   r0      s    	zHandler._add_sessionc                 C   sJ   |dk	st tj||j|j| |||jd}|dk	rF|j|_|j|_|S )zBuilds a session object.N)r&   start_time_secs	model_urimetric_valuesrB   )	AssertionErrorr   SessionrG   rH   _build_session_metric_valuesrB   r/   Zend_time_secs)r   r&   r=   r>   r<   resultr   r   r   r.      s     	zHandler._build_sessionc           
   	   C   sf   g }| j j}|D ]P}|j}t||\}}||i |}	|	sBq|tj||	j	|	j
|	jd q|S )z!Builds the session metric values.)r&   wall_time_secstraining_steprF   )r   r+   r&   r   r,   getappendr   ZMetricValueZ	wall_timesteprF   )
r   r8   r<   rM   r+   Zmetric_infor:   r    r;   Zdatumr   r   r   rL      s(     z$Handler._build_session_metric_valuesc                 C   s   | j jtjks| j jtjkr&t| np| j jtjkrDt|| j j nR| j jtj	krdt
|| j jt n2| j jtjkrt
|| j jt ntd| j j dS )z8Sets the metrics of the group based on aggregation_type.z'Unknown aggregation_type in request: %sN)r   Zaggregation_typer   ZAGGREGATION_AVGZAGGREGATION_UNSET_set_avg_session_metricsZAGGREGATION_MEDIAN_set_median_session_metricsaggregation_metricZAGGREGATION_MIN_set_extremum_session_metricsminZAGGREGATION_MAXmaxr   HParamsErrorr   session_groupr   r   r   r6      s6    
     zHandler._aggregate_metricsc                    s    fdd|D S )Nc                    s   g | ]}  |r|qS r   )_passes_all_filters)r"   Zsgr   r   r   r$      s     
 z#Handler._filter.<locals>.<listcomp>r   r   r   r]   r   r      s    zHandler._filterc                    s   t  fdd| jD S )Nc                 3   s   | ]}| V  qd S Nr   )r"   	filter_fnr[   r   r   	<genexpr>   s     z.Handler._passes_all_filters.<locals>.<genexpr>)allr   rZ   r   r`   r   r\      s    zHandler._passes_all_filtersc                 C   s   |j tdd ttt| jj| jD ]p\}}|j	t
jkr@q*|j	t
jkrf|j t||j dd q*|j	t
jkr|j t||jddd q*td| q*dS )zASorts 'session_groups' in place according to _request.col_params.r&   r'   )none_is_largestT)r(   reversez!Unknown col_param.order given: %sN)r3   r4   r5   reversedlistzipr   r   r   orderr   ZORDER_UNSPECIFIEDZ	ORDER_ASC_create_key_funcZmissing_values_firstZ
ORDER_DESCr   rY   )r   r   	col_param	extractorr   r   r   r      s0    zHandler._sortc                 C   s*   t j|| jj| jj| jj  t|dS )N)r   Z
total_size)r   ZListSessionGroupsResponser   start_indexZ
slice_sizelenr   r   r   r   r     s     zHandler._create_responseN)__name__
__module____qualname____doc__r   r    r   r0   r.   rL   r6   r   r\   r   r   r   r   r   r   r      s   @##r   c                    s$   |r fdd}|S  fdd}|S )a  Returns a key_func to be used in list.sort().

    Returns a key_func to be used in list.sort() that sorts session groups
    by the value extracted by extractor. 'None' extracted values will either
    be considered largest or smallest as specified by the "none_is_largest"
    boolean parameter.

    Args:
      extractor: An extractor function that extract the key from the session
        group.
      none_is_largest: bool. If true treats 'None's as largest; otherwise
        smallest.
    c                    s    | }|d k|fS r^   r   r[   rF   rk   r   r   key_func_none_is_largest5  s    z2_create_key_func.<locals>.key_func_none_is_largestc                    s    | }|d k	|fS r^   r   rr   rs   r   r   key_func_none_is_smallest;  s    z3_create_key_func.<locals>.key_func_none_is_smallestr   )rk   rc   rt   ru   r   rs   r   ri   %  s
    ri   c                 C   s    g }| D ]}| t| q|S )aM  Creates extractors to extract properties corresponding to 'col_params'.

    Args:
      col_params: List of ListSessionGroupsRequest.ColParam protobufs.
    Returns:
      A list of extractor functions. The ith element in the
      returned list extracts the column corresponding to the ith element of
      _request.col_params
    )rQ   _create_extractor)r   rM   rj   r   r   r   r   D  s    
r   c                 C   s:   |  drt| jS |  dr(t| jS td|  d S )Nr9   hparamz=Got ColParam with both "metric" and "hparam" fields unset: %s)HasField_create_metric_extractorr9   _create_hparam_extractorrw   r   rY   )rj   r   r   r   rv   T  s    



rv   c                    s    fdd}|S )a  Returns function that extracts a metric from a session group or a
    session.

    Args:
      metric_name: tensorboard.hparams.MetricName protobuffer. Identifies the
      metric to extract from the session group.
    Returns:
      A function that takes a tensorboard.hparams.SessionGroup or
      tensorborad.hparams.Session protobuffer and returns the value of the metric
      identified by 'metric_name' or None if the value doesn't exist.
    c                    s   t |  }|r|jS d S r^   )_find_metric_valuerF   )session_or_groupmetric_valuer:   r   r   extractor_fnm  s    
z._create_metric_extractor.<locals>.extractor_fnr   )r:   r   r   r~   r   ry   `  s    ry   c                 C   s4   | j D ](}|jj|jkr|jj|jkr|  S qdS )a  Returns the metric_value for a given metric in a session or session
    group.

    Args:
      session_or_group: A Session protobuffer or SessionGroup protobuffer.
      metric_name: A MetricName protobuffer. The metric to search for.
    Returns:
      A MetricValue protobuffer representing the value of the given metric or
      None if no such metric was found in session_or_group.
    N)rI   r&   r;   rA   )r|   r:   r}   r   r   r   r{   t  s    
r{   c                    s    fdd}|S )ao  Returns an extractor function that extracts an hparam from a session
    group.

    Args:
      hparam_name: str. Identies the hparam to extract from the session group.
    Returns:
      A function that takes a tensorboard.hparams.SessionGroup protobuffer and
      returns the value, as a native Python object, of the hparam identified by
      'hparam_name'.
    c                    s    | j krt| j   S d S r^   )rE   _value_to_pythonr`   hparam_namer   r   r     s    
z._create_hparam_extractor.<locals>.extractor_fnr   )r   r   r   r   r   rz     s    rz   c                 C   s4   g }t | |D ] \}}t||}|r|| q|S )a  Creates filters for the given col_params.

    Args:
      col_params: List of ListSessionGroupsRequest.ColParam protobufs.
      extractors: list of extractor functions of the same length as col_params.
        Each element should extract the column described by the corresponding
        element of col_params.
    Returns:
      A list of filter functions. Each corresponding to a single
      col_params.filter oneof field of _request
    )rg   _create_filterrQ   )r   Z
extractorsrM   rj   rk   Za_filterr   r   r   r     s    
r   c                    sn   | j  | drt| jn<| dr4t| jn&| drJt| jnrRdS dd  fdd}|S )	af  Creates a filter for the given col_param and extractor.

    Args:
      col_param: A tensorboard.hparams.ColParams object identifying the column
        and describing the filter to apply.
      extractor: A function that extract the column value identified by
        'col_param' from a tensorboard.hparams.SessionGroup protobuffer.
    Returns:
      A boolean function taking a tensorboard.hparams.SessionGroup protobuffer
      returning True if the session group passes the filter described by
      'col_param'. If col_param does not specify a filter (i.e. any session
      group passes) returns None.
    filter_regexpfilter_intervalfilter_discreteNc                 S   s   dS )NTr   )_r   r   r   <lambda>      z _create_filter.<locals>.<lambda>c                    s    | }|d krS |S r^   r   rr   rk   Zinclude_missing_valuesZvalue_filter_fnr   r   r_     s    z!_create_filter.<locals>.filter_fn)Zexclude_missing_valuesrx   _create_regexp_filterr   _create_interval_filterr   _create_discrete_set_filterr   )rj   rk   r_   r   r   r   r     s    


r   c                    s   t |   fdd}|S )zReturns a boolean function that filters strings based on a regular exp.

    Args:
      regex: A string describing the regexp to use.
    Returns:
      A function taking a string and returns True if any of its substrings
      matches regex.
    c                    s0   t | ts tdt| | f t | d k	S )Nz<Cannot use a regexp filter for a value of type %s. Value: %s)
isinstancestrr   rY   typeresearchrF   Zcompiled_regexr   r   r_     s    

z(_create_regexp_filter.<locals>.filter_fn)r   compile)regexr_   r   r   r   r     s    
r   c                    s    fdd}|S )a0  Returns a function that checkes whether a number belongs to an interval.

    Args:
      interval: A tensorboard.hparams.Interval protobuf describing the interval.
    Returns:
      A function taking a number (float or int) that returns True if the number
      belongs to (the closed) 'interval'.
    c                    s8   t | ttfs$tdt| | f  j| ko6|  jkS )Nz@Cannot use an interval filter for a value of type: %s, Value: %s)r   intfloatr   rY   r   Z	min_valueZ	max_valuer   intervalr   r   r_     s    
z*_create_interval_filter.<locals>.filter_fnr   )r   r_   r   r   r   r     s    
r   c                    s    fdd}|S )ai  Returns a function that checks whether a value belongs to a set.

    Args:
      discrete_set: A list of objects representing the set.
    Returns:
      A function taking an object and returns True if its in the set. Membership
      is tested using the Python 'in' operator (thus, equality of distinct
      objects is computed using the '==' operator).
    c                    s   |  kS r^   r   r   discrete_setr   r   r_     s    z._create_discrete_set_filter.<locals>.filter_fnr   )r   r_   r   r   r   r     s    r   c                 C   sT   t | tjst| d}|dkr(| jS |dkr6| jS |dkrD| jS td| dS )z;Converts a google.protobuf.Value to a native Python object.kindnumber_valuestring_value
bool_valuez,Unknown struct_pb2.Value oneof field set: %sN)	r   r   ValuerJ   Z
WhichOneofr   r   r   
ValueError)rF   fieldr   r   r   r     s    
r   _MetricIdentifierz	group tagc                   @   s$   e Zd ZdZddddgZdd ZdS )	_MetricStatsa	  A simple class to hold metric stats used in calculating metric averages.

    Used in _set_avg_session_metrics(). See the comments in that function
    for more details.

    Attributes:
      total: int. The sum of the metric measurements seen so far.
      count: int. The number of largest-step measuremens seen so far.
      total_step: int. The sum of the steps at which the measurements were taken
      total_wall_time_secs: float. The sum of the wall_time_secs at
          which the measurements were taken.
    totalcount
total_steptotal_wall_time_secsc                 C   s   d| _ d| _d| _d| _d S )Nr   g        )r   r   r   r   r]   r   r   r   r   L  s    z_MetricStats.__init__N)rn   ro   rp   rq   	__slots__r   r   r   r   r   r   5  s   r   c                 C   s   | j stdtt}| j D ]j}|jD ]^}t|jj|jj	d}|| }| j
|j7  _
| jd7  _| j|j7  _| j|j7  _q(q| jdd= | D ]J\}}| jjtj|j|j	dt|j
t|j |j|j |j|j d qdS )a  Sets the metrics for the group to be the average of its sessions.

    The resulting session group metrics consist of the union of metrics across
    the group's sessions. The value of each session group metric is the average
    of that metric values across the sessions in the group. The 'step' and
    'wall_time_secs' fields of the resulting MetricValue field in the session
    group are populated with the corresponding averages (truncated for 'step')
    as well.

    Args:
      session_group: A SessionGroup protobuffer.
    zSessionGroup cannot be empty.)rA   r;      N)r&   rF   rO   rN   )r2   rJ   collectionsdefaultdictr   rI   r   r&   rA   r;   r   rF   r   r   rO   r   rN   r)   r-   r   Z
MetricNamer   )r[   Zmetric_statsr?   r}   r:   statsr   r   r   rS   S  s0    


  

rS   _Measurementr}   session_indexc                 C   sR   t t| |tdd}|t|d d  j}| jdd= | j| j| j dS )a  Sets the metrics for session_group to those of its "median session".

    The median session is the session in session_group with the median value
    of the metric given by 'aggregation_metric'. The median is taken over the
    subset of sessions in the group whose 'aggregation_metric' was measured
    at the largest training step among the sessions in the group.

    Args:
      session_group: A SessionGroup protobuffer.
      aggregation_metric: A MetricName protobuffer.
    metric_value.valuer'   r      N)	sorted_measurementsr4   r5   rm   r   rI   	MergeFromr2   )r[   rU   measurementsZmedian_sessionr   r   r   rT     s    
rT   c                 C   sB   t | |}||tddj}| jdd= | j| j| j dS )a[  Sets the metrics for session_group to those of its "extremum session".

    The extremum session is the session in session_group with the extremum value
    of the metric given by 'aggregation_metric'. The extremum is taken over the
    subset of sessions in the group whose 'aggregation_metric' was measured
    at the largest training step among the sessions in the group.

    Args:
      session_group: A SessionGroup protobuffer.
      aggregation_metric: A MetricName protobuffer.
      extremum_fn: callable. Must be either 'min' or 'max'. Determines the type of
        extremum to compute.
    r   r'   N)r   r4   r5   r   rI   r   r2   )r[   rU   Zextremum_fnr   Zext_sessionr   r   r   rV     s    
 
rV   c                 c   s4   t | jD ]$\}}t||}|s"q
t||V  q
dS )a  A generator for the values of the metric across the sessions in the
    group.

    Args:
      session_group: A SessionGroup protobuffer.
      metric_name: A MetricName protobuffer.
    Yields:
      The next metric value wrapped in a _Measurement instance.
    N)	enumerater2   r{   r   )r[   r:   r   r?   r}   r   r   r   r     s
    

r   )#rq   r   r4   r   Zgoogle.protobufr   Ztensorboard.datar   Ztensorboard.plugins.hparamsr   r   r   r   objectr   ri   r   rv   ry   r{   rz   r   r   r   r   r   r   
namedtupler   r   rS   r   rT   rV   r   r   r   r   r   <module>   sD     &+ 