
    "                         d Z ddlmZ ddlmZ ddlmZ ddlmZ ddlZ G d de      Z	d	 Z
d
 Zd ZdZddZdZddZd ZddZy)zLCode to transform the (cleaned-up) description of a dataflow into Graphviz.
    )absolute_import)division)unicode_literals)
exceptionsNc                   H    e Zd ZdZd Zd Zd Zd Zd Zd Z	dd	Z
d
 Zd Zy)_Clustera  Encapsulation of a single cluster in the final Step-Graph.

  The cluster hierarchy represents pieces of the user_name. A given cluster is
  either a leaf (it contains a single step and no sub-clusters) or a transform
  (it contains no step and one or more sub-clusters).
  c                 <    i | _         || _        || _        d | _        y N)_Cluster__children_Cluster__parent_Cluster__name_in_parent_Cluster__step)selfparentname_in_parents      1lib/googlecloudsdk/api_lib/dataflow/step_graph.py__init__z_Cluster.__init__"   s    DODM*DDK    c                     | j                    S )zbA leaf cluster contains no sub-clusters.

    Returns:
      True iff this is a leaf cluster.
    )r   r   s    r   IsLeafz_Cluster.IsLeaf(   s     r   c                 2    t        | j                        dk(  S )zwA singleton is any cluster that contains a single child.

    Returns:
      True iff this is a singleton cluster.
       )lenr   r   s    r   IsSingletonz_Cluster.IsSingleton0   s     t1$$r   c                     | j                    S )zbDetermine if this cluster is the root.

    Returns:
      True iff this is the root cluster.
    )r   r   s    r   IsRootz_Cluster.IsRoot8   s     }}r   c                     | j                   S )zxReturn the step for this cluster.

    Returns:
      The step for this cluster. May be None if this is not a leaf.
    )r   r   s    r   GetStepz_Cluster.GetStep@   s     ;;r   c                 J    | j                   rJ | j                  rJ || _        y)zSet the step for this cluster.

    Can only be called on leaf nodes that have not yet had their step set.

    Args:
      step: The step that this cluster represents.
    N)r   r   )r   steps     r   SetStepz_Cluster.SetStepH   s$     {{?DKr   Nc                     | j                   r| j                   |k(  r| j                  S | j                   j                  |      }|r|dz   | j                  z   S | j                  S )zReturn the name of this sub-cluster relative to the given ancestor.

    Args:
      relative_to: The ancestor to output the name relative to.

    Returns:
      The string representing the user_name component for this cluster.
    /)r   r   Name)r   relative_toparent_names      r   r%   z_Cluster.NameT   s[     MMt}};"""--$$[1K3!6!666"""r   c                     | j                   rJ || j                  vrt        | |      | j                  |<   | j                  |   S )zReturn the cluster representing the given piece_name within this cluster.

    Args:
      piece_name: String representing the piece name of the desired child.
    Returns:
      Cluster representing the child.
    )r   r   r   )r   
piece_names     r   GetOrAddChildz_Cluster.GetOrAddChildf   s@     {{?($,T:$>dooj!??:&&r   c                 R    t        t        j                  | j                              S )zhReturn the sub-clusters.

    Returns:
      Sorted list of pairs for the children in this cluster.
    )sortedsix	iteritemsr   r   s    r   Childrenz_Cluster.Childrens   s     #--011r   r
   )__name__
__module____qualname____doc__r   r   r   r   r   r"   r%   r*   r/    r   r   r   r      s4    %
#$'2r   r   c                 J   d}g }g }| j                  d      D ]u  }||j                  d      |j                  d      z
  z  }|j                  |       |dk(  r&|j                  dj                  |             |dd= e|j                  d       w |r|j                  |       |S )aQ  Given a user name for a step, split it into the individual pieces.

  Examples:
     _SplitStep('Transform/Step') = ['Transform', 'Step']
     _SplitStep('Read(gs://Foo)/Bar') = ['Read(gs://Foo)', 'Bar']

  Args:
    user_name: The full user_name of the step.
  Returns:
    A list representing the individual pieces of the step name.
  r   r$   () N)splitcountappendjoin)	user_nameparensaccum
step_partspieces        r   
_SplitSteprB   |   s     &
%*s#e
ekk#S!111F	LL{'
(ll3 $ e	r   c                     t        dd      }| D ]N  }t        |d   j                  d|d               }|}|D ]  }|j                  |      } |j	                  |       P |S )a  Extract a hierarchy from the steps provided.

  The `step graph' is constructed as follows:

    1. Every node has a `name'. This is flat, something like "s1", "s100".
    2. Each node can depend on others. These edges are specified by "name".
    3. Each node can also have a user_name, like "Foo/Bar". This name creates
       a hierarchy of subgraphs (eg., Foo/Bar and Foo/Baz are in the same
       cluster).

  Args:
    steps: A list of steps from the Job message.
  Returns:
    A Cluster representing the root of the step hierarchy.
  Nr8   
propertiesr=   name)r   rB   getr*   r"   )stepsrootr!   	step_pathnoderA   s         r   _UnflattenStepsToClustersrK      sl      
$	$d4-11+tF|LMID&d LL  
+r   c                     | j                  d      r$t        j                  dj                  |             dj                  | j	                  dd            S )a  Escape a string for use as in Graphviz.

  Args:
    name: The string to escape.

  Returns:
    The `name', with double-quotes escaped, and quotes around it.

  Raises:
    exceptions.UnsupportedNameException: If the name is incompatible with
      Graphviz ID escaping.
  \z0Unsupported name for Graphviz ID escaping: {0!r}z"{0}""z\")endswithr   UnsupportedNameExceptionformatreplace)rE   s    r   _EscapeGraphvizIdrS      sM     
]]4

-
-:AA$GI I	S%0	11r   zO{name} [label={user_name}, tooltip={full_name}, style=filled, fillcolor=white];c           	   #      K   | j                         rg| j                         }t        j                  t	        |d         t	        | j                               t	        | j                  |                   y | j                         s| j                         r/| j                         D ]  \  }}t        ||      D ]  }|   y | j                         }dj                  t	        d|z                d d d	 d
j                  t	        |             dj                  t	        | j                  |                   | j                         D ]  \  }}t        ||       D ]  }|   d y w)NrE   )r&   )rE   	full_namer=   )r   zsubgraph {0} {{zcluster zstyle=filled;zbgcolor=white;zlabeljust=left;ztooltip={0};z
label={0};})
r   r   _NODE_FORMATrQ   rS   r%   r   r   r/   _YieldGraphvizClusters)clusterr   r!   
unused_key
subclusterlinerU   subgroups           r   rX   rX      sQ    ^^??D


tF|,#GLLN3#GLLVL$DE  G G  0")"2"2"4
J(FC$
 D #5 I

"
"#4Z)5K#L
MM





 1) <
==


/V0DE
FF ' 0 0 2
H('B$
 C !3 Is   E<E>zF{edge_source} -> {edge_dest} [taillabel={edge_output}, style={style}];c                 v    t         j                  t        |d         t        |       t        |d         |      S )a;  Returns an edge from the output referred to by output_ref to step_name.

  Args:
    step_name: String identifying the step with the dependency.
    output_ref: Output-reference dictionary to start the edge at.
    style: The style for the edge.

  Returns:
    A string representing the edge in Graphviz format.
  	step_nameoutput_name)edge_source	edge_destedge_outputstyle)_EDGE_FORMATrQ   rS   )r_   
output_refrd   s      r   _GraphvizEdgerg      sA     
		#J{$;<!),#J}$=>	 
 
 r   c              #      K   | d   }| d   j                  dd      }|rt        ||       | d   j                  dg       D ]  }t        ||        | d   j                  di       j                         D ]  }t        ||d        yw)	zOutput Graphviz edges for the given step.

  Args:
    step: Step to write edges for.

  Yields:
    The Graphviz edge lines for the given step.
  rE   rD   parallel_inputNinputsnon_parallel_inputsdashed)rd   )rF   rg   values)r!   r_   	par_inputother_input
side_inputs        r   _YieldGraphvizEdgesrq      s      6l)< $$%5t<)
	9
--,'++Hb9k
	;
// : &**+@"ELLNj
	:X
>> Os   BBc              #      K   dj                  t        |xs d             t        |       }t        |      D ]  }|  d | D ]  }t	        |      D ]  }|   d yw)a  Given a root cluster produce the Graphviz DOT format.

  No attempt is made to produce `pretty' output.

  Args:
    steps: A list of steps from the Job message.
    graph_name: The name of the graph to output.

  Yields:
    The lines representing the step-graph in Graphviz format.
  zstrict digraph {graph_name} {{G)
graph_namer8   rV   N)rQ   rS   rK   rX   rq   )rG   rt   rH   r\   r!   s        r   YieldGraphvizru     sy      	)//":#45 	0 	7 7 
#5	)$$T*d
J + 	(d#D)j * 
 	)s   A%A'r
   )solid)r3   
__future__r   r   r   googlecloudsdk.api_lib.dataflowr   r-   objectr   rB   rK   rS   rW   rX   re   rg   rq   ru   r4   r   r   <module>rz      s^    '  ' 6 
_2v _2D>42(( 
2<$?,r   