
    c,                        d Z dZeZddlm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 Zd Z G d d      Zd	 Z G d
 d      Z G d de      Z ed      Zeeee   f   Zdedeedf   fdZddedee   dee   fdZdedededee   deddfdZ	 ddee ee    f   de de deee       deee       f
dZ!y)z^Graph manipulation utilities.

(dot generation adapted from pypy/translator/tool/make_dot.py)
zrestructuredtext en    N)DictListTupleOptionalSetTypeVarIterablec                     | j                  d      D cg c]  }|j                  dd       }}dj                  |      }d|z   S c c}w )z"Make <value> usable in a dot file.
"z\"z\lz\n)splitreplacejoin)valuelinelinesdatas       6/usr/lib/python3/dist-packages/logilab/common/graph.pyescaper   $   sG    27++d2CD$T\\#u%DED::eD4< Es   Ac                     t        j                  |       }t        j                  t        j                  |             }| j	                  d      d   }|||fS )zDTransforms /some/path/foo.png into ('/some/path', 'foo.png', 'png')..)ospbasenamedirnameabspathr   )filenamer   storedirtargets       r   target_info_from_filenamer    +   sG    ||H%H{{3;;x01H^^C $FXv%%    c                   T    e Zd ZdZdddddi fdZd Z ee      ZddZd Z	d	 Z
d
 Zy)
DotBackendzDot File backend.Nutf-8dotc                    || _         || _        g | _        d | _        | j	                  dt        |      z         |r| j	                  d|z         |r| j	                  d|z         |r| j	                  d|z         |r0|j                         dv s
J d|z         | j	                  d|z         t        |j                               D ]"  }| j	                  dj                  |             $ y )	Nzdigraph %s {z
rankdir=%szratio=%sz	size="%s")r$   z
iso-8859-1latin1zunsupported charset %szcharset="%s"=)
	graphnamerendererr   _sourceemitnormalize_node_idlowersorteditemsr   )	selfr)   rankdirsizeratiocharsetr*   additionnal_paramparams	            r   __init__zDotBackend.__init__6   s     # 
		.#4Y#??@IIlW,-IIj5()IIkD()==?&GG (72G IInw./-3356 	'EIIchhuo&	'r!   c                     | j                   3| j                  d       dj                  | j                        | _         | `| j                   S )zreturns self._sourcez}
r   )r+   r,   r   r   )r1   s    r   
get_sourcezDotBackend.get_sourceS   s;    <<IIe99TZZ0DL
||r!   c                     ddl }| j                  }|s|r|j                  d      r|}nd|z  }|Zt        |      \  }}}|dk7  r/t	        j
                  d|      \  }	}
t        j                  |	       nut        j                  ||      }
n^d}t	        j
                  d|      \  }	}
t	        j
                  d|      \  }}t        j                  |	       t        j                  |       t        j                  |
dd	
      }	|	j                  | j                         |	j                          |dk7  rzt        j                  dk(  rd}nd}	 |r'|j!                  | j"                  dd|d||
d|g	|       n#|j!                  | j"                  d||
d|g|       t        j.                  |
       |S # t$        $ rH}|j&                  t&        j(                  k(  r!dj+                  | j"                        |_         Y d}~cd}~ww xY w)zGenerates a graph file.

        :param outputfile: filename and path [defaults to graphname.png]
        :param dotfile: filename and path [defaults to graphname.dot]

        :rtype: str
        :return: a path to the generated file
        r   Nz.dotz%s.dotr%   pngz.pngwutf8)encodingwin32TFz-Tcmapxz-oz-T)shellzFile not found: {})
subprocessr)   endswithr    tempfilemkstemposcloser   r   codecsopenwritesourcesysplatformcallr*   OSErrorerrnoENOENTformatstrerrorunlink)r1   
outputfiledotfilemapfilerB   namer   r   r   pdotdot_sourcepathppng	use_shelles                 r   generatezDotBackend.generate]   s    	~~j11&9$"T/!)B:)N&Hh'/'7'7'E$n!$(G!<F#+#3#3FD#A D.'//=D*HHTNHHTN{{>3@

4;;

U?||w& 	!	OO MM% # "* &
 ( $  OOfndJW' $  IIn%  77ell*!5!<!<T]]!KAJ +s   	AF, ,	G=5>G88G=c                 :    | j                   j                  |       y)zAdds <line> to final output.N)r   append)r1   r   s     r   r,   zDotBackend.emit   s    

$r!   c                     |j                         D cg c]  \  }}|d|d }}}t        |      t        |      }}| j                  |d|ddj                  t	        |            d       yc c}}w )zwemit an edge from <name1> to <name2>.
        edge properties: see http://www.graphviz.org/doc/info/attrs.html
        ="r    ->  [, ];N)r0   r-   r,   r   r/   )	r1   name1name2propspropr   attrsn_fromn_tos	            r   	emit_edgezDotBackend.emit_edge   sa     ?DkkmL{tUdE*LL(/1B51I		fdDIIfUm4LMN Ms   A2c           	          |j                         D cg c]  \  }}|d|d }}}| j                  t        |      ddj                  t	        |            d       yc c}}w )ztemit a node with given properties.
        node properties: see http://www.graphviz.org/doc/info/attrs.html
        rb   r   rd   re   rf   N)r0   r,   r-   r   r/   )r1   rX   ri   rj   r   rk   s         r   	emit_nodezDotBackend.emit_node   sQ     ?DkkmL{tUdE*LL		 1$ 76%=9QRS Ms   A")NNN)__name__
__module____qualname____doc__r8   r:   propertyrK   r^   r,   rn   rp    r!   r   r#   r#   3   sG    
 ': j!FAF OTr!   r#   c                     d| z  S )z)Returns a suitable DOT node id for `nid`.z"%s"rv   )nids    r   r-   r-      s    C<r!   c                       e Zd Zd ZddZy)GraphGeneratorc                     || _         y N)backend)r1   r}   s     r   r8   zGraphGenerator.__init__   s	    r!   Nc                 j   || _         |j                         D ]3  \  }}|j                  |      } | j                  j                  |fi | 5 |j                         D ]7  \  }}	}
|j                  |
||	      } | j                  j                  ||	fi | 9 | j                  j                  ||      S )N)rU   rW   )		propshdlrnodesnode_propertiesr}   rp   edgesedge_propertiesrn   r^   )r1   visitorr   rU   rW   nodeidnoderi   subjnodeobjnodeedges              r   r^   zGraphGenerator.generate   s     ##MMO 	4LFD--d3E"DLL""63U3	4 (/}} 	?#Hgt--dHgFE"DLL""8W>>	? ||$$
G$LLr!   )NN)rq   rr   rs   r8   r^   rv   r!   r   rz   rz      s    
Mr!   rz   c                       e Zd Zy)UnorderableGraphN)rq   rr   rs   rv   r!   r   r   r      s    r!   r   Vgraphreturn.c                    t        |       }|rJdj                  |D cg c]!  }dj                  t        t        |            # c}      }t	        d|z        t        |       }t               }| j                         D ]  }|t        |      z  } ||z
  }|rt	        ddj                  |      z        g }t               }	d}
| r|
t        |       k(  rt	        d| z        t        |       }
g }| j                         D ]#  \  }}|D ]  }||	vs  |j                  |       % |j                  |       |	t        |      z  }	|D ]  }| |=  | rg }t        |      D ]  }|j                  t        |              t        |      S c c}w )a!  takes a dependency graph dict as arguments and return an ordered tuple of
    nodes starting with nodes without dependencies and up to the outermost node.

    If there is some cycle in the graph, :exc:`UnorderableGraph` will be raised.

    Also the given graph dict will be emptied.
    r   rc   zcycles in graph: %szmissing vertices: %sre   Nzunknown problem with %s)
get_cyclesr   mapstrr   setvalueslenr0   r`   reversedextendr/   tuple)r   cyclescycle
bad_cyclesverticesto_verticesr   missing_verticesorder	order_setold_lendeps_okr   	node_depsdepresultgrps                    r   ordered_nodesr      s    'u-FYY&QCUO <QR
4zABB5zH%K "s5z!" #X-5		BR8SSTT EIG
c%j "#<u#DEEe*${{} 	%OD)  %i'% t$	% 	WS\!	 	Dd	# ( F #fSk"# =W  Rs   &F
graph_dictr   c                 r    | sg S g }|| j                         }|D ]  }t        | g t               ||        |S )zgiven a dictionary representing an ordered graph (i.e. key are vertices
    and values is a list of destination vertices representing edges), return a
    list of detected cycles
    )keys_get_cyclesr   )r   r   r   vertices       r   r   r     sK    
 	F??$ <JCE67;< Mr!   pathvisitedr   r   c                    ||v rf|g}|ddd   D ]  }||k(  r n|j                  d|        t        |      }|j                  |      }||d |d| z   }||vr|j                  |       y|j                  |       	 | |   D ]'  }||vst	        | ||||       |j                  |       ) 	 |j                          y# t        $ r Y w xY w)z5recursive function doing the real work for get_cyclesNr   r   )insertminindexr`   r   addKeyErrorpop)	r   r   r   r   r   r   r   
start_fromr   s	            r   r   r   !  s     $	2J 	"DwLLD!		" Z
J'efa. MM% KKw' 	"D7"JgvtDD!		" 	HHJ  s   =B> 
"B> >	C
	C
fromnodetonodec                     |g }n||v ry|j                  |       | |   D ]   }||k(  st        | |||      s|dd |gz   c S  |j                          y)a.  generic function taking a simple graph definition as a dictionary, with
    node has key associated to a list of nodes directly reachable from it.

    Return None if no path exists to go from `fromnode` to `tonode`, else the
    first path found (as a list including the destination node at last)
    N   )r`   has_pathr   )r   r   r   r   destnodes        r   r   r   J  so     |	T	KKx( 'v*h!M8vh&&' 	HHJr!   r|   )"rt   __docformat__type__metaclass__os.pathr   r   rF   rL   rD   rH   rP   typingr   r   r   r   r   r   r	   r   r    r#   r-   rz   	Exceptionr   r   _Graphr   r   r   r   r   rv   r!   r   <module>r      sT  $
 &  	 
    F F F&~T ~TB
M M(	y 	 CL	aaj	7 7E!S&M 7t6 Xh-? 4PT: $&&"&-0&:>t*&OP&	&T _cS$s)^$03=@HPQUVYQZH[d3ir!   