B
    A!p\8                 @   s   d 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d	d
ddddZ
ddddddddhZd"ddZG dd dejZdd Zdd Zd d! ZdS )#z"checker for use of Python logging
    N)checkers)
interfaces)utils)check_messages)z>Specify string format arguments as logging function parameterszlogging-not-lazya  Used when a logging statement has a call form of "logging.<logging method>(format_string % (format_args...))". Such calls should leave string interpolation to the logging method itself and be written "logging.<logging method>(format_string, format_args...)" so that the program may avoid incurring the cost of the interpolation in those cases in which no message will be logged. For more, see http://www.python.org/dev/peps/pep-0282/.)zLUse % formatting in logging functions and pass the % parameters as argumentszlogging-format-interpolationzUsed when a logging statement has a call form of "logging.<logging method>(format_string.format(format_args...))". Such calls should use % formatting instead, but leave interpolation to the logging function by passing the parameters as arguments.)zLUse % formatting in logging functions and pass the % parameters as argumentszlogging-fstring-interpolationzUsed when a logging statement has a call form of "logging.method(f"..."))". Such calls should use % formatting instead, but leave interpolation to the logging function by passing the parameters as arguments.)z;Unsupported logging format character %r (%#02x) at index %dzlogging-unsupported-formatzWUsed when an unsupported format character is used in a logging statement format string.)z<Logging format string ends in middle of conversion specifierzlogging-format-truncatedz`Used when a logging statement format string terminates before the end of a conversion specifier.)z,Too many arguments for logging format stringzlogging-too-many-argsz>Used when a logging format string is given too many arguments.)z.Not enough arguments for logging format stringzlogging-too-few-argsz=Used when a logging format string is given too few arguments.)ZW1201ZW1202ZW1203ZE1200ZE1201ZE1205ZE1206ZcriticaldebugerrorZ	exceptionZfatalinfowarnZwarning c             C   s@   t | tjo>t | jtjo>|r*| jj|kndo>|r<| j|kS dS )a  Determines if a BoundMethod node represents a method call.

    Args:
      func (astroid.BoundMethod): The BoundMethod AST node to check.
      types (Optional[String]): Optional sequence of caller type names to restrict check.
      methods (Optional[String]): Optional sequence of method names to restrict check.

    Returns:
      bool: true if the node represents a method call for the given type and
      method names, False otherwise.
    T)
isinstanceastroidBoundMethodboundZInstancename)functypesmethodsr
   r
   6lib/python3.7/site-packages/pylint/checkers/logging.pyis_method_calle   s    r   c               @   s   e Zd ZdZejZdZeZ	ddddddfd	d
ddd
dgddffZ
dd Zdd Zdd Zee dd Zdd Zedd Zdd Zdd Zd S )!LoggingCheckerz!Checks use of the logging module.loggingzlogging-modules)r   Zcsvz<comma separated list>zcLogging modules to check that the string format arguments are in logging function parameter format.)defaulttypemetavarhelpzlogging-format-styleoldZchoicez<old (%) or new ({)>newzuFormat style used to check logging format string. `old` means using % formatting, while `new` is for `{}` formatting.)r   r   r   choicesr   c             C   sf   t  | _| jj}| jj| _t || _i | _x6|D ].}|dd}t	|dkr0|d | j|d < q0W dS )z?Clears any state left in this checker from last module checked..   r   N)
set_logging_namesZconfigZlogging_modulesZlogging_format_style_format_style_logging_modules_from_importsrsplitlen)selfnodeZlogging_modsZlogging_modpartsr
   r
   r   visit_module   s    


zLoggingChecker.visit_modulec             C   sV   y<| j |j }x*|jD ] \}}||kr| j|p2| qW W n tk
rP   Y nX dS )z;Checks to see if a module uses a non-Python logging module.N)r$   modnamenamesr!   addKeyError)r'   r(   Zlogging_namemoduleas_namer
   r
   r   visit_importfrom   s    zLoggingChecker.visit_importfromc             C   s2   x,|j D ]"\}}|| jkr| j|p&| qW dS )z<Checks to see if this module uses Python's built-in logging.N)r,   r#   r!   r-   )r'   r(   r/   r0   r
   r
   r   visit_import   s    
zLoggingChecker.visit_importc                sL    fdd} fdd}| r* j j}n| \}}|s<dS  | dS )z Checks calls to logging methods.c                  s.   t  jtjo,t  jjtjo, jjjjkS )N)r   r   r   Z	AttributeexprNamer   r!   r
   )r(   r'   r
   r   is_logging_name   s    z2LoggingChecker.visit_call.<locals>.is_logging_namec                 s   yfx` j  D ]R} t| tjr| jj}t|tjr| dksTt	dd |
 D rd| jjfS qW W n tjjk
r~   Y nX dS )Nzlogging.Loggerc             s   s   | ]}|  d kV  qdS )zlogging.LoggerN)qname).0Zancestorr
   r
   r   	<genexpr>   s   zELoggingChecker.visit_call.<locals>.is_logger_class.<locals>.<genexpr>T)FN)r   Zinferr   r   r   Z_proxiedparentZClassDefr6   anyZ	ancestorsr   
exceptionsZInferenceError)inferredr9   )r(   r
   r   is_logger_class   s    z2LoggingChecker.visit_call.<locals>.is_logger_classN)r   Zattrname_check_log_method)r'   r(   r5   r=   r   resultr
   )r(   r'   r   
visit_call   s    

zLoggingChecker.visit_callc                s0  |dkr,|j s"|js"t|jdk r&dS d}n(|tkrP|j sF|jsF|jsJdS d}ndS t|j| tjr|j| }|jdk}|jdkrt	 fdd	|j
|jfD }|dk}|r jd
|d nnt|j| tjr |j|  nJt|j| tjr || n(t|j| tjtjfr, jd|d dS )z9Checks calls to logging.log(level, format, *format_args).log   Nr   r   %+c             3   s"   | ]}  t|rd V  qdS )r   N)_is_operand_literal_strr   
safe_infer)r7   operand)r'   r
   r   r8      s   z3LoggingChecker._check_log_method.<locals>.<genexpr>zlogging-not-lazy)r(   zlogging-fstring-interpolation)Zstarargskwargsr&   argsCHECKED_CONVENIENCE_FUNCTIONSr   r   ZBinOpopsumleftrightadd_messageZCall_check_call_funcConst_check_format_stringZFormattedValueZ	JoinedStr)r'   r(   r   Z
format_posZbinopemitZtotal_number_of_stringsr
   )r'   r   r>      s4    



z LoggingChecker._check_log_methodc             C   s   t | tjo| jdkS )zL
        Return True if the operand in argument is a literal string
        str)r   r   rQ   r   )rG   r
   r
   r   rE     s    z&LoggingChecker._is_operand_literal_strc             C   s<   t |j}d}d}t|||r8t|js8| jd|d dS )zChecks that function call is not format_string.format().

        Args:
          node (astroid.node_classes.Call):
            Call AST node to be checked.
        )rT   Zunicode)formatzlogging-format-interpolation)r(   N)r   rF   r   r   is_complex_format_strr   rO   )r'   r(   r   r   r   r
   r
   r   rP   	  s    zLoggingChecker._check_call_funcc          
   C   sF  t |j|d d }|sdS |j| j}t|ts:d}nyf| jdkrbt|\}}}}|rdS n<| jdkrt|\}}	}
t	t
dd |D }||	 |
 }W nn tjk
r } z*||j }| jd||t||jfd	 dS d}~X Y n& tjk
r   | jd
|d dS X ||kr*| jd|d n||k rB| jd|d dS )zChecks that format string tokens match the supplied arguments.

        Args:
          node (astroid.node_classes.NodeNG): AST node to be checked.
          format_arg (int): Index of the format string in the node arguments.
        r   Nr   r   r   c             s   s    | ]\}}t |ts|V  qd S )N)r   int)r7   klr
   r
   r   r8   9  s    z6LoggingChecker._check_format_string.<locals>.<genexpr>zlogging-unsupported-format)r(   rI   zlogging-format-truncated)r(   zlogging-too-many-argszlogging-too-few-args)_count_supplied_tokensrI   valuer   rT   r"   r   Zparse_format_stringZparse_format_method_stringr&   r    ZUnsupportedFormatCharacterindexrO   ordZIncompleteFormatString)r'   r(   Z
format_argZnum_argsformat_stringZrequired_num_argsZkeyword_args_Zkeyword_argumentsZimplicit_pos_argsZexplicit_pos_argsZkeyword_args_cntexcharr
   r
   r   rR     s@    





z#LoggingChecker._check_format_stringN)__name__
__module____qualname____doc__r   ZIAstroidCheckerZ__implements__r   MSGSZmsgsZoptionsr*   r1   r2   r   r@   r>   staticmethodrE   rP   rR   r
   r
   r
   r   r   y   s.   
$&r   c             C   sr   t | }|dkst|jts"dS ytt |j}W n t	k
rN   dS X x|D ]\}}}}|rVdS qVW dS )zChecks if node represents a string with complex formatting specs.

    Args:
        node (astroid.node_classes.NodeNG): AST node to check
    Returns:
        bool: True if inferred string uses complex formatting, False otherwise
    NTF)
r   rF   r   r[   rT   liststringZ	Formatterparse
ValueError)r(   r<   Zparsedr_   format_specr
   r
   r   rV   O  s    
rV   c             C   s   t dd | D S )a|  Counts the number of tokens in an args list.

    The Python log functions allow for special keyword arguments: func,
    exc_info and extra. To handle these cases correctly, we only count
    arguments that aren't keywords.

    Args:
      args (list): AST nodes that are arguments for a log format string.

    Returns:
      int: Number of AST nodes that aren't keywords.
    c             s   s   | ]}t |tjsd V  qdS )r   N)r   r   ZKeyword)r7   argr
   r
   r   r8   r  s    z)_count_supplied_tokens.<locals>.<genexpr>)rL   )rI   r
   r
   r   rZ   e  s    rZ   c             C   s   |  t|  dS )z.Required method to auto-register this checker.N)Zregister_checkerr   )Zlinterr
   r
   r   registeru  s    rn   )r
   r
   )re   ri   r   Zpylintr   r   Zpylint.checkersr   Zpylint.checkers.utilsr   rf   rJ   r   ZBaseCheckerr   rV   rZ   rn   r
   r
   r
   r   <module>   s6   


 W