
    eh                    p   U d Z ddlmZ ddlZddlmZ ddlmZ ddlm	Z	m
Z
 ddlm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mZmZ e	rddlmZ h dZej>                  ej@                  hZ!dddddddddddejD                  ifddddZ#de$d <   d'd"Z% G d# d!      Z& G d$ d%ee      Z'd(d&Z(y))zPython code format's checker.

By default, try to follow Guido's style guide :

https://www.python.org/doc/essays/styleguide/

Some parts of the process_token method is based from The Tab Nanny std module.
    )annotationsN)reduce)Match)TYPE_CHECKINGLiteral)nodes)BaseRawFileCheckerBaseTokenChecker)only_required_for_messages)WarningScope)HIGH)MessageDefinitionTuple)	OPTION_POPragmaParserErrorparse_pragma)PyLinter>   ifindelfornotelifwithraisewhileyieldassertexceptreturn=:=)zLine too long (%s/%s)line-too-longz=Used when a line is longer than a given number of characters.)z Too many lines in module (%s/%s)too-many-linesz@Used when a module has too many lines, reducing its readability.)zTrailing whitespacetrailing-whitespacezHUsed when there is whitespace between the end of a line and the newline.)zFinal newline missingmissing-final-newlinez7Used when the last line in a file is missing a newline.)zTrailing newlinestrailing-newlinesz3Used when there are trailing blank lines in a file.)z)Bad indentation. Found %s %s, expected %sbad-indentationzUUsed when an unexpected number of indentation's tabulations or spaces has been found.)zUnnecessary semicolonunnecessary-semicolonzeUsed when a statement is ended by a semi-colon (";"), which isn't necessary (that's python, not C ;).z(More than one statement on a single linemultiple-statementsz<Used when more than on statement are found on the same line.scope)z#Unnecessary parens after %r keywordsuperfluous-parenszLUsed when a single item in parentheses follows an if, for, or other keyword.)zMixed line endings LF and CRLFmixed-line-endingsz@Used when there are mixed (LF and CRLF) newline signs in a file.)zEUnexpected line ending format. There is '%s' while it should be '%s'.unexpected-line-ending-formatz3Used when there is different newline than expected.)C0301C0302C0303C0304C0305W0311W0301C0321C0325C0327C0328z!dict[str, MessageDefinitionTuple]MSGSTokenWrapperc                    |dkD  xr | j                  |dz
        |k(  xsE |dkD  xr> | j                  |dz
        |k(  xr% | j                  |dz
        t        j                  k(  S )Nr         )tokentypetokenizeCOMMENT)tokensline_endr>   s      8/usr/lib/python3/dist-packages/pylint/checkers/format.py_last_token_on_line_isrE   u   sn    1 	0LLA&%/	:a< :LLA&%/:KK1%)9)99    c                  @    e Zd ZdZd	dZd
dZddZddZddZd
dZ	y)r:   z3A wrapper for readable access to token information.c                    || _         y N_tokens)selfrB   s     rD   __init__zTokenWrapper.__init__   s	    rF   c                &    | j                   |   d   S )Nr<   rJ   rL   idxs     rD   r>   zTokenWrapper.token       ||C ##rF   c                &    | j                   |   d   S )Nr   rJ   rO   s     rD   r?   zTokenWrapper.type   rQ   rF   c                ,    | j                   |   d   d   S )Nr=   r   rJ   rO   s     rD   
start_linezTokenWrapper.start_line       ||C #A&&rF   c                ,    | j                   |   d   d   S )Nr=   r<   rJ   rO   s     rD   	start_colzTokenWrapper.start_col   rU   rF   c                &    | j                   |   d   S )N   rJ   rO   s     rD   linezTokenWrapper.line   rQ   rF   NrB   list[tokenize.TokenInfo]r   None)rP   intr   str)rP   r^   r   r^   )
__name__
__module____qualname____doc__rM   r>   r?   rT   rW   rZ    rF   rD   r:   r:      s#    =$$''$rF   c                  z    e Zd ZdZdZe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$g d%d&d'ffZd8 fd(Zd9d)Z	d:d*Z
	 	 	 	 	 	 d;d+Zd<d,Zd=d-Z ed.      d>d/       Zd?d0Zd@d1ZdAd2ZedBd3       ZedCd4       ZedDd5       Z	 	 	 	 	 	 	 	 	 	 dEd6ZdFd7Z xZS )GFormatCheckerzvFormatting checker.

    Checks for :
    * unauthorized constructions
    * strict indentation
    * line length
    formatzmax-line-lengthd   r^   z<int>z.Maximum number of characters on a single line.)defaultr?   metavarhelpzignore-long-linesregexpz<regexp>z^\s*(# )?<?https?://\S+>?$z>Regexp for a line that is allowed to be longer than the limit.)r?   rj   ri   rk   zsingle-line-if-stmtFynz<y or n>zOAllow the body of an if to be on the same line as the test if there is no else.zsingle-line-class-stmtzfAllow the body of a class to be on the same line as the declaration if body contains single statement.zmax-module-linesi  z$Maximum number of lines in a module.zindent-stringz    non_empty_stringz<string>zSString used as indentation unit. This is usually "    " (4 spaces) or "\t" (1 tab).zindent-after-parenrY   zGNumber of spaces of indent required inside a hanging or continued line.zexpected-line-ending-formatchoicez<empty or LF or CRLF> )rp   LFCRLFzIExpected format of line ending, e.g. empty (any line ending), LF or CRLF.)r?   rj   ri   choicesrk   c                @    t         |   |       i | _        i | _        y rI   )superrM   _lines_visited_lines)rL   linter	__class__s     rD   rM   zFormatChecker.__init__   s     &(8:rF   c                >   t        ||d      r"| j                  d|j                  |             |j                  |      }|j                  |      }|j	                  |      t
        vr!|j                  d      d   | j                  |<   | j                  ||||       y)z9A new line has been encountered, process it if necessary.;r(   rZ   
r   N)	rE   add_messagerT   rZ   r?   _JUNK_TOKENSsplitrv   check_lines)rL   rB   rC   
line_startline_numrZ   s         rD   new_linezFormatChecker.new_line  s    !&(C846;L;LX;VW$$Z0{{:&;;z",6$(JJt$4Q$7DKK!T8<rF   c                     y rI   rd   )rL   nodes     rD   process_modulezFormatChecker.process_module  s    rF   c                   ||dz      j                   dk7  ry||   j                   dk(  r|dkD  r||dz
     j                   dk(  ryd}d}d}d}d}t        ||   j                         }||   j                  d   }	t        |t	        |      dz
        D ]  }
||
   }|j
                  t        j                  k(  r y|j                   dk(  s"|j                   ||
dz      j                   z   dk(  rd	}|}|j                   dk(  r|dz  }||
dz      j                   dk(  sd}|j                   d
k(  r|dz  }|r$|r||
dz      j                   d
k(  r|dv r y|dz  }||
dz      j                   dv sA||
dz      j
                  t        j                  t        j                  t        j                  hv r5|r
|dz
  |k(  r y|
|dz   k(  r y|r y|dk(  r y| j                  d|	|        y|dk(  sW|d   dk(  r y|d   dv rd	}l|d   dk(  r y|d   dk(  r y|d   dk(  sdd ||
d D        v r| j                  ||
d d        y y)aN  Check that there are not unnecessary parentheses after a keyword.

        Parens are unnecessary if there is exactly one balanced outer pair on a
        line and contains no commas (i.e. is not a tuple).

        Args:
        tokens: The entire list of Tokens.
        start: The position of the keyword in the token list.
        r<   (Nr   r   isFr!   T)>   r   r   r   >   r   r   :]}r=   r   r+   rZ   args,>   orandr   r   elsec              3  4   K   | ]  }|j                     y wrI   )string).0is     rD   	<genexpr>z;FormatChecker._check_keyword_parentheses.<locals>.<genexpr>u  s     <Aqxx<s   )r   r_   startrangelenr?   r@   NLNEWLINE	ENDMARKERrA   r~   _check_keyword_parentheses)rL   rB   r   found_and_orcontains_walrus_operatorwalrus_operator_depthcontains_double_parensdepthkeyword_tokenr   r   r>   s               rD   r   z(FormatChecker._check_keyword_parentheses  s    %!)##s*5M  E)	uqy!((D0 #(  !!"F5M001%=&&q)uc&kAo. G	A1IE zzX[[( $<<&Q-"6"66$>+/((-%||s"
!a%=''3.-.*$
-&Q-2F2F#2M(,??$*a/*!a%=''+EEEJ$8++X-?-?AQAQRJS 04IA4MQV4VEAI~#$, $$,8- %  !8s? 8},#'L 1X(
 1X& 1X'<<<77qr
AFOG	rF   c                r    dg}d}d}i  _         i  _        d _        d}t        |      D ]  \  }\  }}}	}
}|	d   |k7  rZ|	d   }|t        j
                  k(  r# j                  t        |      |dz
  |dz          n j                  t        |      |dz
  |       |t        j                  k(  rd} j                  ||       n|t        j
                  k(  r3d} j                  ||d   dz   |       |j                  |d   dz          n|t        j                  k(  rd}t        |      dkD  rg|d= nc|t        j                  k(  r|j                  d      s?|}n<|t        j                   t        j"                  fvr|rd} j                  ||d   |       |t        j$                  k(  r$|j'                  d      r j)                  d	|
       |t*        v s j-                  ||        |dz  }| j.                  j0                  j2                  kD  r j.                  j4                  j7                  d      d   }|j8                  df}t;        t=        d fd|D              d      } j)                  d| j.                  j0                  j2                  f|       ||k(  r|dkD  r j)                  d|
       yyy)zProcess tokens and search for:

        - too long lines (i.e. longer than <max_chars>)
        - optionally bad construct (if given, bad_construct must be a compiled
          regular expression).
        r   FNr<   T
lzlowercase-l-suffixr|   r#   c              3  h   K   | ])  }j                   j                  j                  |       + y wrI   )rx   _pragma_linenoget)r   namerL   s     rD   r   z/FormatChecker.process_tokens.<locals>.<genexpr>  s&     Utdkk88<<TBUs   /2r   rZ   r&   )rv   rw   _last_line_ending	enumerater@   INDENTr   r:   r   _check_line_endingcheck_indent_levelappendDEDENTr   r   striprA   ENCODINGNUMBERendswithr~   _KEYWORD_TOKENSr   rx   configmax_module_lines
msgs_storeget_message_definitionsmsgidnextfilter)rL   rB   indentscheck_equalr   last_blank_line_numrP   tok_typer   r   _rZ   message_definitionnameslinenos   `              rD   process_tokenszFormatChecker.process_tokensy  s    # -17@7H 1	=3C3(FE1dQx8# 8 x.MM,v"6aqIMM,v"6aE8+++ #''9X__,#''aJwr{Q/X__,
 #w<!#X[[(zz&)*2'("2"2H4E4E!FF "'K++D'"+xH8??*vs/C  !5H E(//<c1	=f 	Adkk((999 "&!7!7!O!O "" (--/?@EtUuUVF   2 2 C CD   **x!|0x@ 0<*rF   c                   | j                   $|r"|| j                   k7  r| j                  d|       || _         | j                  j                  j                  }|r4t        d |d      }|dk(  rdnd}||k7  r| j                  d||f|	       y y y )
Nr,   r|   c                    | |k7  r| |z   S | S rI   rd   )xys     rD   <lambda>z2FormatChecker._check_line_ending.<locals>.<lambda>  s    qAva!e 1 rF   rp   r}   rq   rr   r-   r   )r   r~   rx   r   expected_line_ending_formatr   )rL   line_endingr   expecteds       rD   r   z FormatChecker._check_line_ending  s    !!- {d.D.DD  !5H E!, ;;%%AA !DkSUVK"-"5$6Kh&  3%x0! !  '	 rF   r)   c                "   |j                   sy|j                         j                  sy|j                         }||j                  }nKt        |j                  t        j                        rd}n$|j                  j                         j                  }|j                  }|sJ |       ||k(  r1| j                  j                  |      dk7  r| j                  ||       y|| j                  v ry	 |j                  }|sJ |       g }t!        ||dz         D ]>  }d| j                  |<   	 |j#                  | j$                  |   j'                                @ y# t        $ r |j                  }Y sw xY w# t(        $ r |j#                  d       Y yw xY w)z8Check the node line number and check it if not yet done.Nr   r=   r<   rp   )is_statementrootpure_pythonprevious_sibling
fromlineno
isinstanceparentr   Module	statementrw   r   _check_multi_statement_lineblockstart_tolinenoAttributeErrortolinenor   r   rv   rstripKeyError)rL   r   	prev_sibl	prev_linerZ   r   liness          rD   visit_defaultzFormatChecker.visit_default  sq      yy{&&))+	 !,,IU\\2I--/::ITt!4!4!8!8!>!!C,,T484&&&	%//H x$1- 	!D()D%!T[[.5578	!	  	%}}H	%  !R !s$   .E ',E1E.-E.1FFc                    t        |t        j                        ryt        |j                  t        j                        r7|j                  j
                  s!| j                  j                  j                  ryt        |j                  t        j                        rCt        |j                  j                        dk(  r!| j                  j                  j                  ryt        |j                  t        j                        r[t        |t        j                        rAt        |j                  t        j                         r|j                  j                  t"        u ry| j%                  d|       d| j&                  |<   y)z/Check for lines containing multiple statements.Nr<   r)   )r   r=   )r   r   Withr   Iforelserx   r   single_line_if_stmtClassDefr   bodysingle_line_class_stmtFunctionDefExprvalueConstEllipsisr~   rw   )rL   r   rZ   s      rD   r   z)FormatChecker._check_multi_statement_line  s     dEJJ't{{EHH-KK&&""66t{{ENN3DKK$$%*""99 t{{E$5$564,4::u{{3

  H,.T:$%D!rF   c                    |j                  d      }|t        |      d dvr#| j                  d|t        |      t               yy)z,Check that there is no trailing white-space.z	
 N)r}   r   r$   )rZ   
col_offset
confidence)r   r   r~   r   )rL   rZ   r   stripped_lines       rD    check_trailing_whitespace_endingz.FormatChecker.check_trailing_whitespace_ending*  sP     K0M"$%^;%}-	   <rF   c                b   | j                   j                  j                  }| j                   j                  j                  }|j	                         }t        |      |kD  rQ|j                  |      s?|r| j                   j                  d|       y| j                  d|t        |      |f       yyy)z=Check that the line length is less than the authorized value.r"   r   N)	rx   r   max_line_lengthignore_long_linesr   r   searchadd_ignored_messager~   )rL   rZ   r   checker_off	max_charsignore_long_lines         rD   check_line_lengthzFormatChecker.check_line_length6  s    KK&&66	;;--??{{}t9y )9)@)@)F//C  qD	9?U V	 *G rF   c                    | j                   }|d| j                  d       j                         || j                  d      d z   }|S )z-Remove the `# pylint ...` pattern from lines.Nr<   )r   r   r   end)options_pattern_objr   purged_liness      rD   remove_pylint_option_from_linesz-FormatChecker.remove_pylint_option_from_linesA  sX     $**0'--a0188:'++A.012 	 rF   c                    	 t        | j                  d            D ]"  }|j                  dk(  sd|j                  v s" y 	 y# t        $ r Y yw xY w)z2Return True if the line length check is activated.r=   disabler"   FT)r   groupactionmessagesr   )pylint_pattern_match_objectpragmas     rD   is_line_length_check_activatedz,FormatChecker.is_line_length_check_activatedK  s]    	&'B'H'H'KL !==I-/V__2T !  ! 		s!   ,A A A  A 	AAc                    h d}g }d}| j                  d      D ]%  }|d   |vr|j                  ||z          d}!||z  }' |S )z]Split lines according to universal newlines except those in a specific
        sets.
        >              rp   Tr   )
splitlinesr   )r   unsplit_endsresbufferatomic_lines        rD   specific_splitlinesz!FormatChecker.specific_splitlinesW  sb    
	
  ++D1 	&K2l2

6K/0+%	& 
rF   c                f   | j                   j                  j                  | j                  |      }t	        |      D ]e  \  }}|j                  d      s| j                  d||z          .|j                  |      t        j                  k7  sQ| j                  |||z          g t        fd|D              }|syt        j                  |      }	d}
|	r$| j                  |	      sd}
| j                  |	      }t	        | j                  |            D ]  \  }}| j!                  |||z   |
        y)zCheck given lines for potential messages.

        Check if lines have:
        - a final newline
        - no trailing white-space
        - less than a maximum number of characters
        r}   r%   r|   c              3  :   K   | ]  }t        |      kD    y wrI   )r   )r   rZ   r   s     rD   r   z,FormatChecker.check_lines.<locals>.<genexpr>  s      ,
&*CI	!,
s   NFT)rx   r   r   r  r   r   r~   r?   r@   STRINGr   anyr   r   r  r  r  )rL   rB   r   r   r   split_linesoffsetrZ   potential_line_length_warningmobjr   r   s              @rD   r   zFormatChecker.check_linesp  s2   $ KK&&66	..u5%k2 	MLFD==&  !8v O {{:&(//955dFVOL	M ), ,
.9,
 )
% - &66t<"88>E &d&>&>u&EF 	GLFD""4&+F	GrF   c                `   | j                   j                  j                  }|dk(  rd}d}t        |      }|d| |k(  r||d }|dz  }|d| |k(  rd}|r|d   dv r||d   z  }|dd }|r|d   dv r||k7  s|r6d}|d   dk(  rd	}| j	                  d
|||z  t        |      z   |||z  f       yy)z&Return the indent level of the string.z\t	r   Nr<   rp   z 	spacestabsr'   r   )rx   r   indent_stringr   r~   )	rL   r   r   r   indentlevel	unit_sizesuppli_types	            rD   r   z FormatChecker.check_indent_level  s   ##11U?FK	Zi F*IJ'FQJE Zi F* e+VAYEABZF e+ HFayD !i'#e*4fh>RS  	 !&rF   rx   r   r   r]   )rB   r:   rC   r^   r   r^   r   r]   )r   znodes.Moduler   r]   )rB   r\   r   r^   r   r]   r[   )r   r_   r   r^   r   r]   )r   nodes.NodeNGr   r]   )r   r2  rZ   r^   r   r]   )rZ   r_   r   r^   r   r]   )rZ   r_   r   r^   r   boolr   r]   )r  
Match[str]r   r_   )r  r4  r   r3  )r   r_   r   z	list[str])
rB   r:   r   r^   r   r_   r   r^   r   r]   )r   r_   r   r^   r   r^   r   r]   )r`   ra   rb   rc   r   r9   msgsoptionsrM   r   r   r   r   r   r   r   r   r   r  staticmethodr  r  r  r   r   __classcell__)ry   s   @rD   rf   rf      s    DD
 "H		
   %8T
	
 " %<	
 % %(		
 ">		
 !*%6			
 !"%			
 * 2-@		
WXGt;
	=e.e7:e	eNVAp0   56! 7!B&>
	W   	 	  06G"6G036G<?6GIL6G	6GprF   rf   c                8    | j                  t        |              y rI   )register_checkerrf   )rx   s    rD   registerr;    s    
M&12rF   )rB   r:   rC   r^   r>   r_   r   r3  r1  ))rc   
__future__r   r@   	functoolsr   rer   typingr   r   astroidr   pylint.checkersr	   r
   pylint.checkers.utilsr   pylint.constantsr   pylint.interfacesr   pylint.typingr   pylint.utils.pragma_parserr   r   r   pylint.lintr   r   rA   r   r   NODEr9   __annotations__rE   r:   rf   r;  rd   rF   rD   <module>rJ     s   
 #    )  @ < ) " 0 Q Q$"   (++.




 	3F	,##$	
o<+' <~$ $,i$&8 iX3rF   