B
    sX)                 @   s  d Z ddlmZ ddlZddlZddlZddlmZ yddlZddlm	Z	 W n$ e
k
rp   ddlmZm	Z	 Y nX dZG dd	 d	eZG d
d deZG dd deZG dd deZG dd deZdddZdddZdd Zd ddZedkreejdd  dS )!z Meager code path measurement tool.
    Ned Batchelder
    http://nedbatchelder.com/blog/200803/python_code_complexity_microtool.html
    MIT License.
    )with_statementN)defaultdict)iter_child_nodes)astr   z0.6.1c               @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )
ASTVisitorz'Performs a depth-first walk of the AST.c             C   s   d | _ i | _d S )N)node_cache)self r
   %lib/python3.7/site-packages/mccabe.py__init__   s    zASTVisitor.__init__c             G   s&   x t |D ]}| j|f|  q
W d S )N)r   dispatch)r	   r   argsZchildr
   r
   r   default   s    zASTVisitor.defaultc             G   sR   || _ |j}| j|}|d krD|j}t| jd| | j}|| j|< ||f| S )Nvisit)r   	__class__r   get__name__getattrvisitorr   )r	   r   r   klassmethZ	classNamer
   r
   r   r   !   s    
zASTVisitor.dispatchc             G   s"   || _ | j|_| j|f|  dS )z&Do preorder walk of tree using visitorN)r   r   r   )r	   treer   r   r
   r
   r   preorder+   s    zASTVisitor.preorderN)r   
__module____qualname____doc__r   r   r   r   r
   r
   r
   r   r      s
   
r   c               @   s&   e Zd Zd	ddZdd Zdd ZdS )
PathNodecirclec             C   s   || _ || _d S )N)namelook)r	   r   r    r
   r
   r   r   3   s    zPathNode.__init__c             C   s   t d| j| j|  f  d S )Nznode [shape=%s,label="%s"] %d;)printr    r   dot_id)r	   r
   r
   r   to_dot7   s    zPathNode.to_dotc             C   s   t | S )N)id)r	   r
   r
   r   r"   ;   s    zPathNode.dot_idN)r   )r   r   r   r   r#   r"   r
   r
   r
   r   r   2   s   
r   c               @   s.   e Zd ZdddZdd Zdd Zdd	 Zd
S )	PathGraphr   c             C   s&   || _ || _|| _|| _tt| _d S )N)r   entitylinenocolumnr   listnodes)r	   r   r&   r'   r(   r
   r
   r   r   @   s
    zPathGraph.__init__c             C   s   | j | | g | j |< d S )N)r*   append)r	   Zn1Zn2r
   r
   r   connectG   s    zPathGraph.connectc             C   sj   t d x| jD ]}|  qW x<| j D ].\}}x$|D ]}t d| | f  q:W q,W t d d S )Nz
subgraph {z	%s -- %s;})r!   r*   r#   itemsr"   )r	   r   Znextsnextr
   r
   r   r#   L   s    
 zPathGraph.to_dotc             C   s.   t dd | j D }t| j}|| d S )zG Return the McCabe complexity for the graph.
            V-E+2
        c             S   s   g | ]}t |qS r
   )len).0nr
   r
   r   
<listcomp>Y   s    z(PathGraph.complexity.<locals>.<listcomp>   )sumr*   valuesr0   )r	   Z	num_edgesZ	num_nodesr
   r
   r   
complexityU   s    
zPathGraph.complexityN)r   )r   r   r   r   r,   r#   r7   r
   r
   r
   r   r%   ?   s   
	r%   c                   s   e Zd ZdZ fddZdd Zdd Zdd	 ZeZd
d Z	dd Z
dd Z fddZdd Ze Z ZZdd ZdddZdd Zdd ZeZdd ZeZ  ZS ) PathGraphingAstVisitorz\ A visitor for a parsed Abstract Syntax Tree which finds executable
        statements.
    c                s&   t t|   d| _i | _|   d S )N )superr8   r   	classnamegraphsreset)r	   )r   r
   r   r   c   s    zPathGraphingAstVisitor.__init__c             C   s   d | _ d | _d S )N)graphtail)r	   r
   r
   r   r=   i   s    zPathGraphingAstVisitor.resetc             C   s   x|D ]}|  | qW d S )N)r   )r	   Z	node_listr   r
   r
   r   dispatch_listm   s    
z$PathGraphingAstVisitor.dispatch_listc             C   s   | j rd| j |jf }n|j}d|j|j|f }| jd k	r| |}|| _| |j t	ddd}| j
| j| | j
|| || _nNt|||j|j| _t	|}|| _| |j | j| jd| j |jf < |   d S )Nz%s%sz	%d:%d: %rr9   point)r    )r;   r   r'   
col_offsetr>   appendPathNoder?   r@   bodyr   r,   r%   r<   r=   )r	   r   r&   r   pathnodebottomr
   r
   r   visitFunctionDefq   s$    

z'PathGraphingAstVisitor.visitFunctionDefc             C   s0   | j }|  j |jd 7  _ | |j || _ d S )N.)r;   r   r@   rD   )r	   r   Zold_classnamer
   r
   r   visitClassDef   s    z$PathGraphingAstVisitor.visitClassDefc             C   s,   | j s
d S t|}| j| j | || _ |S )N)r?   r   r>   r,   )r	   r   rE   r
   r
   r   rC      s    z%PathGraphingAstVisitor.appendPathNodec             C   s,   |j d krd}n|j }d| }| | d S )Nr   zStmt %d)r'   rC   )r	   r   r'   r   r
   r
   r   visitSimpleStatement   s
    
z+PathGraphingAstVisitor.visitSimpleStatementc                s2   t |tjr| | ntt| j|f|  d S )N)
isinstancer   ZstmtrJ   r:   r8   r   )r	   r   r   )r   r
   r   r      s    zPathGraphingAstVisitor.defaultc             C   s   d|j  }| || d S )NzLoop %d)r'   	_subgraph)r	   r   r   r
   r
   r   	visitLoop   s    
z PathGraphingAstVisitor.visitLoopc             C   s   d|j  }| || d S )NzIf %d)r'   rL   )r	   r   r   r
   r
   r   visitIf   s    
zPathGraphingAstVisitor.visitIfr
   c             C   sp   | j dkrTt|||j|j| _ t|}| ||| | j | jd| j|f < |   n| 	|}| ||| dS )z?create the subgraphs representing any `if` and `for` statementsNz%s%s)
r>   r%   r'   rB   r   _subgraph_parser<   r;   r=   rC   )r	   r   r   extra_blocksrE   r
   r
   r   rL      s    


z PathGraphingAstVisitor._subgraphc             C   s   g }|| _ | |j || j  x*|D ]"}|| _ | |j || j  q(W |jrt|| _ | |j || j  n
|| |rtddd}x|D ]}| j|| qW || _ dS )z@parse the body and any `else` block of `if` and `for` statementsr9   rA   )r    N)r?   r@   rD   r+   Zorelser   r>   r,   )r	   r   rE   rP   Z
loose_endsZextrarF   ler
   r
   r   rO      s$    


z&PathGraphingAstVisitor._subgraph_parsec             C   s    d|j  }| j|||jd d S )NzTryExcept %d)rP   )r'   rL   Zhandlers)r	   r   r   r
   r
   r   visitTryExcept   s    
z%PathGraphingAstVisitor.visitTryExceptc             C   s$   d|j  }| | | |j d S )NzWith %d)r'   rC   r@   rD   )r	   r   r   r
   r
   r   	visitWith   s    

z PathGraphingAstVisitor.visitWith)r
   )r   r   r   r   r   r=   r@   rG   ZvisitAsyncFunctionDefrI   rC   rJ   r   rM   ZvisitAsyncForZvisitForZ
visitWhilerN   rL   rO   rR   ZvisitTryrS   ZvisitAsyncWith__classcell__r
   r
   )r   r   r8   ^   s&   
r8   c               @   sL   e Zd ZdZdZeZdZdZdZ	dd Z
edd	 Zed
d Zdd ZdS )McCabeCheckerz%McCabe cyclomatic complexity checker.ZmccabeZC901zC901 %r is too complex (%d)c             C   s
   || _ d S )N)r   )r	   r   filenamer
   r
   r   r      s    zMcCabeChecker.__init__c             C   sb   d}dddddd}t |dd }t|trP|d	 |j|f| |jd
 n|j|f| d S )Nz--max-complexityrV   ZstoreintzMcCabe complexity thresholdTrue)r   actiontypehelpparse_from_configconfig_optionsr]   zmax-complexity)r   rK   r)   pop
add_optionr^   r+   )clsparserflagkwargsZconfig_optsr
   r
   r   add_options   s    

zMcCabeChecker.add_optionsc             C   s   t |j| _d S )N)rX   max_complexity)ra   optionsr
   r
   r   parse_options  s    zMcCabeChecker.parse_optionsc             c   sr   | j dk rd S t }|| j| xJ|j D ]<}| | j kr.| j|j| f }|j	|j
|t| fV  q.W d S )Nr   )rf   r8   r   r   r<   r6   r7   _error_tmplr&   r'   r(   r[   )r	   r   r>   textr
   r
   r   run  s    
zMcCabeChecker.runN)r   r   r   r   r   __version__version_coderi   rf   r   classmethodre   rh   rk   r
   r
   r
   r   rU      s   rU      stdinc       
      C   s   yt | |dtj}W n4 tk
rH   t d }tjd||f  dS X g }|t_	x2t||
 D ] \}}}}	|d|||f  qdW t|dkrdS td| t|S )Nexec   zUnable to parse %s: %s
r   z%s:%d:1: %s
)compiler   PyCF_ONLY_ASTSyntaxErrorsysexc_infostderrwriterU   rf   rk   r+   r0   r!   join)
code	thresholdrW   r   eZcomplxr'   offsetrj   Zcheckr
   r
   r   get_code_complexity  s    r   c          	   C   s,   t | d}| }W dQ R X t||| dS )z"Returns the complexity of a modulerUN)rW   )openreadr   )Zmodule_pathr~   modr}   r
   r
   r   get_module_complexity$  s    r   c             C   s   dt j  k rdk r6n nt| d
}| S Q R X ndt j  krLdk rn ny*t| d}t|j\}}W d Q R X W n6 ttt	fk
r   t| dd
}| S Q R X Y nX t| d|d
}| S Q R X d S )	N)r4      )   r   r   )   r   rbzlatin-1)encodingr)
rx   version_infor   r   tokenizedetect_encodingreadlineLookupErrorrw   UnicodeError)rW   fr   _r
   r
   r   _read+  s    r   c             C   s  | d krt jdd  } t }|jdddddd |jdd	d
dddd || \}}t|d }t||d dtj	}t
 }||| |jrtd x.|j D ] }|jr| |jkr|  qW td n2x0|j D ]"}| |jkrt|j|  qW d S )Nrs   z-dz--dotdotzoutput a graphviz dot file
store_true)destr\   rZ   z-mz--minr~   zminimum complexity for outputrX   )r   r\   r[   r   r   rr   zgraph {r-   )rx   argvoptparseZOptionParserr`   
parse_argsr   ru   r   rv   r8   r   r   r!   r<   r6   r~   r7   r#   r   )r   Zoparrg   r   r}   r   r   r>   r
   r
   r   main<  s.    



r   __main__rs   )rp   rq   )rp   )N)r   Z
__future__r   r   rx   r   collectionsr   r   r   ImportErrorZflake8.utilrl   objectr   r   r%   r8   rU   r   r   r   r   r   r   r
   r
   r
   r   <module>   s.    -



