B
    A!p\D                 @   s   d Z ddlmZ ddlZddlZddlmZ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 d
dddddddddd
ZedZdZdZdZejedddZejedddZejedddZd d! Zd"d# ZG d$d% d%eZd&d' ZdS )(zcheck for signs of poor design    )defaultdictN)IfBoolOp)
decorators)IAstroidChecker)BaseChecker)check_messages)utils)zToo many ancestors (%s/%s)ztoo-many-ancestorsznUsed when class has too many parent classes, try to reduce this to get a simpler (and so easier to use) class.)z$Too many instance attributes (%s/%s)ztoo-many-instance-attributeszsUsed when class has too many instance attributes, try to reduce this to get a simpler (and so easier to use) class.)zToo few public methods (%s/%s)ztoo-few-public-methodszLUsed when class has too few public methods, so be sure it's really worth it.)zToo many public methods (%s/%s)ztoo-many-public-methodsznUsed when class has too many public methods, try to reduce this to get a simpler (and so easier to use) class.)z"Too many return statements (%s/%s)ztoo-many-return-statementszWUsed when a function or method has too many return statement, making it hard to follow.)zToo many branches (%s/%s)ztoo-many-brancheszOUsed when a function or method has too many branches, making it hard to follow.)zToo many arguments (%s/%s)ztoo-many-argumentsz8Used when a function or method takes too many arguments.)z Too many local variables (%s/%s)ztoo-many-localsz<Used when a function or method has too many local variables.)zToo many statements (%s/%s)ztoo-many-statementszpUsed when a function or method has too many statements. You should then split it in smaller functions / methods.)z4Too many boolean expressions in if statement (%s/%s)ztoo-many-boolean-expressionsz@Used when an if statement contains too many boolean expressions.)
ZR0901ZR0902ZR0903ZR0904ZR0911ZR0912ZR0913ZR0914ZR0915ZR0916z^_{2}[a-z]+_{2}$Z	dataclassZdataclassesztyping.NamedTuple)nodereturnc             C   s&   x |   D ]}| tkr
dS q
W dS )z2Check if a class node is a typing.NamedTuple classTF)	ancestorsZqnameTYPING_NAMEDTUPLE)r
   base r   >lib/python3.7/site-packages/pylint/checkers/design_analysis.py_is_typing_namedtupleb   s    r   c          	   C   sr   xl| j D ]b}y| }W n tjk
r0   wY nX x6|D ].}t|tjsJq8|jdkr8| jdkr8dS q8W qW dS )zCheck if a class definition defines an Enum class.

    :param node: The class node to check.
    :type node: astroid.ClassDef

    :returns: True if the given node represents an Enum class. False otherwise.
    :rtype: bool
    EnumenumTF)basesZinferredastroidZInferenceError
isinstanceClassDefnameroot)r
   r   Zinferred_basesZancestorr   r   r   _is_enum_classj   s    	
r   c             C   s~   | j s
dS |  j}xd| j jD ]X}t|tjr4|j}t|tjtj	fsHqt|tjr\|j
}n|j}|tkrt|krdS qW dS )zCheck if a class definition defines a Python 3.7+ dataclass

    :param node: The class node to check.
    :type node: astroid.ClassDef

    :returns: True if the given node represents a dataclass class. False otherwise.
    :rtype: bool
    FT)r   r   localsZnodesr   r   ZCallfuncNameZ	Attributer   ZattrnameDATACLASS_DECORATOR)r
   Zroot_localsZ	decoratorr   r   r   r   _is_dataclass   s    	
r   c             C   s:   d}x0|   D ]$}t|tr*|t|7 }q|d7 }qW |S )zCounts the number of boolean expressions in BoolOp `bool_op` (recursive)

    example: a and (b or c or (d and e)) ==> 5 boolean expressions
    r      )Zget_childrenr   r   _count_boolean_expressions)Zbool_opnb_bool_exprZ	bool_exprr   r   r   r!      s    
r!   c             C   sJ   t dd |  D }x.|  D ]"}t|jr |jdkr |d7 }q W |S )Nc             s   s   | ]}|j d sdV  qdS )_r    N)r   
startswith).0methodr   r   r   	<genexpr>   s    z*_count_methods_in_class.<locals>.<genexpr>__init__r    )summethods	mymethodsSPECIAL_OBJsearchr   )r
   all_methodsr&   r   r   r   _count_methods_in_class   s
    r/   c               @   s  e Zd ZdZefZdZeZdZ	dddddd	fd
ddddd	fdddddd	fdddddd	fdddddd	fdddddd	fdddddd	fdddddd	fdd ddd!d	fd"dddd#d	ff
Z
dQd%d&Zd'd( Zd)d* Zejd+d, Zed-d.d/d0d1d2 Zed/d0d3d4 Zed5d6d7d8d9d:d;d< ZeZed5d6d7d8d9d=d> ZeZd?d@ ZdAdB ZdCdD ZdEdF ZedGdHdI ZdJdK ZdLdM ZeZdRdOdPZ d$S )SMisdesignCheckerzchecks for sign of poor/misdesign:
    * number of methods, attributes, local variables...
    * size, complexity of functions, methods
    Zdesignzmax-args   intz<int>z2Maximum number of arguments for function / method.)defaulttypemetavarhelpz
max-locals   z4Maximum number of locals for function / method body.zmax-returns   z<Maximum number of return / yield for function / method body.zmax-branches   z4Maximum number of branch for function / method body.zmax-statements2   z7Maximum number of statements in function / method body.zmax-parents   z<num>z2Maximum number of parents for a class (see R0901).zmax-attributesz5Maximum number of attributes for a class (see R0902).zmin-public-methods   z9Minimum number of public methods for a class (see R0903).zmax-public-methods   z9Maximum number of public methods for a class (see R0904).zmax-bool-exprz9Maximum number of boolean expressions in an if statement.Nc             C   s(   t | | d | _d | _d | _d | _d S )N)r   r(   stats_returns	_branches_stmts)selflinterr   r   r   r(   %  s
    zMisdesignChecker.__init__c             C   s&   | j  | _g | _tt| _g | _dS )zinitialize visit variablesN)rD   Z	add_statsr?   r@   r   r3   rA   rB   )rC   r   r   r   open,  s    
zMisdesignChecker.openc             C   s.   x(t t| jD ]}| j|  |7  < qW d S )N)rangelenrB   )rC   Zamountir   r   r   _inc_all_stmts3  s    zMisdesignChecker._inc_all_stmtsc             C   s   t j| dd dS )Nzignored-argument-names)r4   )r	   Zget_global_option)rC   r   r   r   _ignored_argument_names7  s    z(MisdesignChecker._ignored_argument_namesztoo-many-ancestorsztoo-many-instance-attributesztoo-few-public-methodsztoo-many-public-methodsc             C   sh   t t| }|| jjkr4| jd||| jjfd t |j| jjkrd| jd|t |j| jjfd dS )zNcheck size of inheritance hierarchy and number of instance attributes
        ztoo-many-ancestors)r
   argsztoo-many-instance-attributesN)rG   listr   configZmax_parentsadd_messageZinstance_attrsZmax_attributes)rC   r
   Z
nb_parentsr   r   r   visit_classdef;  s    	zMisdesignChecker.visit_classdefc             C   s   t dd | D }|| jjkr:| jd||| jjfd |jdks\t|s\t|s\t|r`dS t	|}|| jj
k r| jd||| jj
fd dS )zcheck number of public methodsc             s   s   | ]}|j d sdV  qdS )r#   r    N)r   r$   )r%   r&   r   r   r   r'   W  s    z2MisdesignChecker.leave_classdef.<locals>.<genexpr>ztoo-many-public-methods)r
   rK   classNztoo-few-public-methods)r)   r+   rM   Zmax_public_methodsrN   r5   r   r   r   r/   Zmin_public_methods)rC   r
   Z
my_methodsr.   r   r   r   leave_classdefS  s$    

zMisdesignChecker.leave_classdefztoo-many-return-statementsztoo-many-branchesztoo-many-argumentsztoo-many-localsztoo-many-statementszkeyword-arg-before-varargc                s   | j d |jj}| j |dk	rvd} r@t fdd|D }t|| }|| jjkrz| jd|t|| jjfd nd}t|j	| }|| jj
kr| jd||| jj
fd | jd dS )	zdcheck function name, docstring, arguments, redefinition,
        variable names, max locals
        r   Nc             3   s   | ]}  |jrd V  qdS )r    N)matchr   )r%   arg)ignored_argument_namesr   r   r'     s    z5MisdesignChecker.visit_functiondef.<locals>.<genexpr>ztoo-many-arguments)r
   rK   ztoo-many-localsr    )r@   appendrK   rJ   r)   rG   rM   Zmax_argsrN   r   Z
max_localsrB   )rC   r
   rK   Zignored_args_numZargnumZlocnumr   )rT   r   visit_functiondef}  s(    z"MisdesignChecker.visit_functiondefc             C   s   | j  }|| jjkr.| jd||| jjfd | j| }|| jjkr\| jd||| jjfd | j }|| jjkr| jd||| jjfd dS )zkmost of the work is done here on close:
        checks for max returns, branch, return in __init__
        ztoo-many-return-statements)r
   rK   ztoo-many-branchesztoo-many-statementsN)	r@   poprM   Zmax_returnsrN   rA   Zmax_branchesrB   Zmax_statements)rC   r
   ZreturnsbranchesZstmtsr   r   r   leave_functiondef  s$    


z"MisdesignChecker.leave_functiondefc             C   s    | j s
dS | j d  d7  < dS )zcount number of returnsNr    )r@   )rC   r#   r   r   r   visit_return  s    zMisdesignChecker.visit_returnc             C   s   |j r| d dS )zWdefault visit method -> increments the statements counter if
        necessary
        r    N)Zis_statementrI   )rC   r
   r   r   r   visit_default  s    zMisdesignChecker.visit_defaultc             C   s2   t |j}|jr|d7 }| || | | dS )zincrements the branches counterr    N)rG   Zhandlersorelse_inc_branchrI   )rC   r
   rX   r   r   r   visit_tryexcept  s
    
z MisdesignChecker.visit_tryexceptc             C   s   |  |d | d dS )zincrements the branches counterr=   N)r^   rI   )rC   r
   r   r   r   visit_tryfinally  s    z!MisdesignChecker.visit_tryfinallyztoo-many-boolean-expressionsc             C   sT   |  | d}|jr:t|jdks2t|jd ts:|d7 }| || | | dS )z>increments the branches counter and checks boolean expressionsr    r   N)_check_boolean_expressionsr]   rG   r   r   r^   rI   )rC   r
   rX   r   r   r   visit_if  s    
$zMisdesignChecker.visit_ifc             C   sD   |j }t|tsdS t|}|| jjkr@| jd||| jjfd dS )zwGo through "if" node `node` and counts its boolean expressions

        if the "if" node test is a BoolOp node
        Nztoo-many-boolean-expressions)r
   rK   )Ztestr   r   r!   rM   Zmax_bool_exprrN   )rC   r
   Z	conditionr"   r   r   r   ra     s    
z+MisdesignChecker._check_boolean_expressionsc             C   s"   d}|j r|d7 }| || dS )zincrements the branches counterr    N)r]   r^   )rC   r
   rX   r   r   r   visit_while  s    zMisdesignChecker.visit_whiler    c             C   s   | j |   |7  < dS )zincrements the branches counterN)rA   Zscope)rC   r
   Zbranchesnumr   r   r   r^     s    zMisdesignChecker._inc_branch)N)r    )!__name__
__module____qualname____doc__r   Z__implements__r   MSGSZmsgsZpriorityZoptionsr(   rE   rI   r   ZcachedpropertyrJ   r   rO   rQ   rV   Zvisit_asyncfunctiondefrY   Zleave_asyncfunctiondefr[   r\   r_   r`   rb   ra   rc   Z	visit_forr^   r   r   r   r   r0      s   
*$r0   c             C   s   |  t|  dS )z.required method to auto register this checker N)Zregister_checkerr0   )rD   r   r   r   register  s    ri   )rg   collectionsr   rer   r   r   r   Zpylint.interfacesr   Zpylint.checkersr   Zpylint.checkers.utilsr   Zpylintr	   rh   compiler,   r   ZDATACLASS_IMPORTr   r   boolr   r   r   r!   r/   r0   ri   r   r   r   r   <module>   s@   

  \