<s> from __future__ import ( absolute_import , division , generators , nested_scopes , print_function , <EOL> unicode_literals , with_statement ) <EOL> import ast <EOL> import codecs <EOL> import itertools <EOL> import os <EOL> import re <EOL> import textwrap <EOL> import tokenize <EOL> from abc import abstractmethod <EOL> from collections import Sequence <EOL> import six <EOL> from pants . util . meta import AbstractClass <EOL> __all__ = ( <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> ) <EOL> class OffByOneList ( Sequence ) : <EOL> def __init__ ( self , iterator ) : <EOL> self . _list = list ( iterator ) <EOL> def __iter__ ( self ) : <EOL> return iter ( self . _list ) <EOL> def __reversed__ ( self ) : <EOL> return reversed ( self . _list ) <EOL> def __len__ ( self ) : <EOL> return len ( self . _list ) <EOL> def __getitem__ ( self , element_id ) : <EOL> if isinstance ( element_id , six . integer_types ) : <EOL> return self . __get_list_item ( element_id ) <EOL> elif isinstance ( element_id , slice ) : <EOL> return self . __getslice ( element_id ) <EOL> raise TypeError ( '<STR_LIT>' ) <EOL> def __getslice ( self , sl ) : <EOL> if sl . start == <NUM_LIT:0> or sl . stop == <NUM_LIT:0> : <EOL> raise IndexError <EOL> new_slice = slice ( sl . start - <NUM_LIT:1> if sl . start > <NUM_LIT:0> else sl . start , <EOL> sl . stop - <NUM_LIT:1> if sl . stop > <NUM_LIT:0> else sl . stop ) <EOL> return self . _list [ new_slice ] <EOL> def __get_list_item ( self , item ) : <EOL> if item == <NUM_LIT:0> : <EOL> raise IndexError <EOL> if item < <NUM_LIT:0> : <EOL> return self . _list [ item ] <EOL> return self . _list [ item - <NUM_LIT:1> ] <EOL> def index ( self , value ) : <EOL> return self . _list . index ( value ) + <NUM_LIT:1> <EOL> class PythonFile ( object ) : <EOL> """<STR_LIT>""" <EOL> SKIP_TOKENS = frozenset ( ( tokenize . COMMENT , tokenize . NL , tokenize . DEDENT ) ) <EOL> @ classmethod <EOL> def _parse ( cls , blob , filename ) : <EOL> blob_minus_coding_header = cls . _remove_coding_header ( blob ) <EOL> try : <EOL> tree = ast . parse ( blob_minus_coding_header , filename ) <EOL> except SyntaxError as e : <EOL> raise CheckSyntaxError ( e , blob , filename ) <EOL> return tree <EOL> @ classmethod <EOL> def _remove_coding_header ( cls , blob ) : <EOL> """<STR_LIT>""" <EOL> lines = blob . split ( '<STR_LIT:\n>' ) <EOL> if lines and '<STR_LIT>' in lines [ <NUM_LIT:0> ] : <EOL> lines [ <NUM_LIT:0> ] = '<STR_LIT>' <EOL> return '<STR_LIT:\n>' . join ( lines ) . encode ( '<STR_LIT:ascii>' , errors = '<STR_LIT:replace>' ) <EOL> def __init__ ( self , blob , tree , filename ) : <EOL> self . _blob = self . _remove_coding_header ( blob ) <EOL> self . tree = tree <EOL> self . lines = OffByOneList ( self . _blob . split ( '<STR_LIT:\n>' ) ) <EOL> self . filename = filename <EOL> self . logical_lines = dict ( ( start , ( start , stop , indent ) ) <EOL> for start , stop , indent in self . iter_logical_lines ( self . _blob ) ) <EOL> def __iter__ ( self ) : <EOL> return iter ( self . lines ) <EOL> def __getitem__ ( self , line_number ) : <EOL> return self . lines [ self . line_range ( line_number ) ] <EOL> def __str__ ( self ) : <EOL> return '<STR_LIT>' . format ( filename = self . filename ) <EOL> @ classmethod <EOL> def parse ( cls , filename , root = None ) : <EOL> """<STR_LIT>""" <EOL> if root is not None : <EOL> if os . path . isabs ( filename ) : <EOL> raise ValueError ( "<STR_LIT>" ) <EOL> full_filename = os . path . join ( root , filename ) <EOL> else : <EOL> full_filename = filename <EOL> with codecs . open ( full_filename , encoding = '<STR_LIT:utf-8>' ) as fp : <EOL> blob = fp . read ( ) <EOL> tree = cls . _parse ( blob , filename ) <EOL> return cls ( blob , tree , filename ) <EOL> @ classmethod <EOL> def from_statement ( cls , statement , filename = '<STR_LIT>' ) : <EOL> """<STR_LIT>""" <EOL> lines = textwrap . dedent ( statement ) . split ( '<STR_LIT:\n>' ) <EOL> if lines and not lines [ <NUM_LIT:0> ] : <EOL> lines = lines [ <NUM_LIT:1> : ] <EOL> blob = '<STR_LIT:\n>' . join ( lines ) <EOL> tree = cls . _parse ( blob , filename ) <EOL> return cls ( blob , tree , filename ) <EOL> @ classmethod <EOL> def iter_tokens ( cls , blob ) : <EOL> """<STR_LIT>""" <EOL> return tokenize . generate_tokens ( six . StringIO ( blob ) . readline ) <EOL> @ property <EOL> def tokens ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . iter_tokens ( self . _blob ) <EOL> @ staticmethod <EOL> def translate_logical_line ( start , end , contents , indent_stack , endmarker = False ) : <EOL> """<STR_LIT>""" <EOL> while contents [ <NUM_LIT:0> ] == '<STR_LIT:\n>' : <EOL> start += <NUM_LIT:1> <EOL> contents . pop ( <NUM_LIT:0> ) <EOL> while contents [ - <NUM_LIT:1> ] == '<STR_LIT:\n>' : <EOL> end -= <NUM_LIT:1> <EOL> contents . pop ( ) <EOL> indent = len ( indent_stack [ - <NUM_LIT:1> ] ) if indent_stack else <NUM_LIT:0> <EOL> if endmarker : <EOL> indent = len ( contents [ <NUM_LIT:0> ] ) <EOL> return start , end + <NUM_LIT:1> , indent <EOL> def iter_logical_lines ( self , blob ) : <EOL> """<STR_LIT>""" <EOL> indent_stack = [ ] <EOL> contents = [ ] <EOL> line_number_start = None <EOL> for token in self . iter_tokens ( blob ) : <EOL> token_type , token_text , token_start = token [ <NUM_LIT:0> : <NUM_LIT:3> ] <EOL> if token_type == tokenize . INDENT : <EOL> indent_stack . append ( token_text ) <EOL> if token_type == tokenize . DEDENT : <EOL> indent_stack . pop ( ) <EOL> if token_type in self . SKIP_TOKENS : <EOL> continue <EOL> contents . append ( token_text ) <EOL> if line_number_start is None : <EOL> line_number_start = token_start [ <NUM_LIT:0> ] <EOL> elif token_type in ( tokenize . NEWLINE , tokenize . ENDMARKER ) : <EOL> yield self . translate_logical_line ( <EOL> line_number_start , <EOL> token_start [ <NUM_LIT:0> ] + ( <NUM_LIT:1> if token_type is tokenize . NEWLINE else - <NUM_LIT:1> ) , <EOL> list ( filter ( None , contents ) ) , <EOL> indent_stack , <EOL> endmarker = token_type == tokenize . ENDMARKER ) <EOL> contents = [ ] <EOL> line_number_start = None <EOL> def line_range ( self , line_number ) : <EOL> """<STR_LIT>""" <EOL> if line_number <= <NUM_LIT:0> or line_number > len ( self . lines ) : <EOL> raise IndexError ( '<STR_LIT>' ) <EOL> if line_number not in self . logical_lines : <EOL> return slice ( line_number , line_number + <NUM_LIT:1> ) <EOL> else : <EOL> start , stop , _ = self . logical_lines [ line_number ] <EOL> return slice ( start , stop ) <EOL> def enumerate ( self ) : <EOL> """<STR_LIT>""" <EOL> return enumerate ( self , <NUM_LIT:1> ) <EOL> class Nit ( object ) : <EOL> """<STR_LIT>""" <EOL> COMMENT = <NUM_LIT:0> <EOL> WARNING = <NUM_LIT:1> <EOL> ERROR = <NUM_LIT:2> <EOL> SEVERITY = { <EOL> COMMENT : '<STR_LIT>' , <EOL> WARNING : '<STR_LIT>' , <EOL> ERROR : '<STR_LIT>' <EOL> } <EOL> @ staticmethod <EOL> def flatten_lines ( * line_or_line_list ) : <EOL> return itertools . chain ( * line_or_line_list ) <EOL> def __init__ ( self , code , severity , filename , message , line_range = None , lines = None ) : <EOL> if severity not in self . SEVERITY : <EOL> raise ValueError ( '<STR_LIT>' . format ( '<STR_LIT:U+0020>' . join ( self . SEVERITY . values ( ) ) ) ) <EOL> if not re . match ( r'<STR_LIT>' , code ) : <EOL> raise ValueError ( '<STR_LIT>' ) <EOL> self . filename = filename <EOL> self . code = code <EOL> self . severity = severity <EOL> self . _message = message <EOL> self . _line_range = line_range <EOL> self . _lines = lines <EOL> def __str__ ( self ) : <EOL> """<STR_LIT>""" <EOL> flat = list ( self . flatten_lines ( [ self . message ] , self . lines ) ) <EOL> return '<STR_LIT>' . join ( flat ) . encode ( '<STR_LIT:ascii>' , errors = '<STR_LIT:replace>' ) <EOL> @ property <EOL> def line_number ( self ) : <EOL> if self . _line_range : <EOL> line_range = self . _line_range <EOL> if line_range . stop - line_range . start > <NUM_LIT:1> : <EOL> return '<STR_LIT>' % ( line_range . start , line_range . stop - <NUM_LIT:1> ) <EOL> else : <EOL> return '<STR_LIT>' % line_range . start <EOL> @ property <EOL> def message ( self ) : <EOL> return '<STR_LIT>' . format ( <EOL> code = self . code , <EOL> severity = self . SEVERITY [ self . severity ] , <EOL> filename = self . filename , <EOL> linenum = self . line_number or '<STR_LIT:*>' , <EOL> message = self . _message ) <EOL> @ property <EOL> def lines ( self ) : <EOL> return self . _lines or [ ] <EOL> @ property <EOL> def has_lines_to_display ( self ) : <EOL> return len ( self . lines ) > <NUM_LIT:0> <EOL> class CheckSyntaxError ( Exception ) : <EOL> def __init__ ( self , syntax_error , blob , filename ) : <EOL> self . filename = filename <EOL> self . _blob = blob <EOL> self . _syntax_error = syntax_error <EOL> def as_nit ( self ) : <EOL> line_range = slice ( self . _syntax_error . lineno , self . _syntax_error . lineno + <NUM_LIT:1> ) <EOL> lines = OffByOneList ( self . _blob . split ( '<STR_LIT:\n>' ) ) <EOL> return Nit ( '<STR_LIT>' , Nit . ERROR , self . filename , <EOL> '<STR_LIT>' . format ( error = self . _syntax_error . msg ) , <EOL> line_range = line_range , lines = lines ) <EOL> class CheckstylePlugin ( AbstractClass ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , options , python_file ) : <EOL> super ( CheckstylePlugin , self ) . __init__ ( ) <EOL> if not isinstance ( python_file , PythonFile ) : <EOL> raise TypeError ( '<STR_LIT>' ) <EOL> self . options = options <EOL> self . python_file = python_file <EOL> def iter_ast_types ( self , ast_type ) : <EOL> for node in ast . walk ( self . python_file . tree ) : <EOL> if isinstance ( node , ast_type ) : <EOL> yield node <EOL> @ abstractmethod <EOL> def nits ( self ) : <EOL> """<STR_LIT>""" <EOL> def __iter__ ( self ) : <EOL> for nit in self . nits ( ) : <EOL> yield nit <EOL> def errors ( self ) : <EOL> for nit in self : <EOL> if nit . severity is Nit . ERROR : <EOL> yield nit <EOL> def nit ( self , code , severity , message , line_number_or_ast = None ) : <EOL> line_number = None <EOL> if isinstance ( line_number_or_ast , six . integer_types ) : <EOL> line_number = line_number_or_ast <EOL> elif isinstance ( line_number_or_ast , ast . AST ) : <EOL> line_number = getattr ( line_number_or_ast , '<STR_LIT>' , None ) <EOL> if line_number : <EOL> line_range = self . python_file . line_range ( line_number ) <EOL> lines = self . python_file [ line_number ] <EOL> else : <EOL> line_range = None <EOL> lines = None <EOL> return Nit ( code , severity , self . python_file . filename , message , <EOL> line_range = line_range , <EOL> lines = lines ) <EOL> def comment ( self , code , message , line_number_or_ast = None ) : <EOL> return self . nit ( code , Nit . COMMENT , message , line_number_or_ast ) <EOL> def warning ( self , code , message , line_number_or_ast = None ) : <EOL> return self . nit ( code , Nit . WARNING , message , line_number_or_ast ) <EOL> def error ( self , code , message , line_number_or_ast = None ) : <EOL> return self . nit ( code , Nit . ERROR , message , line_number_or_ast ) </s>
