Plugins/CheckerPlugins/Pep8/pep8.py

changeset 2863
62171fa4a6a4
parent 2862
a1448560d7dc
child 2864
d973dab8b715
equal deleted inserted replaced
2862:a1448560d7dc 2863:62171fa4a6a4
710 break 710 break
711 assert len(indent) == depth + 1 711 assert len(indent) == depth + 1
712 if start[1] not in indent_chances: 712 if start[1] not in indent_chances:
713 # allow to line up tokens 713 # allow to line up tokens
714 indent_chances[start[1]] = text 714 indent_chances[start[1]] = text
715 ##
716 ## last_token_multiline = (start[0] != end[0])
717 715
718 if indent_next and expand_indent(line) == indent_level + 4: 716 if indent_next and expand_indent(line) == indent_level + 4:
719 yield last_indent, "E125" 717 yield last_indent, "E125"
720 718
721 719
1887 if any(not (code and self.ignore_code(code)) for code in codes): 1885 if any(not (code and self.ignore_code(code)) for code in codes):
1888 checks.append((check.__name__, check, args)) 1886 checks.append((check.__name__, check, args))
1889 return sorted(checks) 1887 return sorted(checks)
1890 1888
1891 1889
1892 ##class Checker(object):
1893 ## """
1894 ## Load a Python source file, tokenize it, check coding style.
1895 ## """
1896 ##
1897 ## def __init__(self, filename, lines=None):
1898 ## self.filename = filename
1899 ## if filename is None:
1900 ## self.filename = 'stdin'
1901 ## self.lines = lines or []
1902 ## elif lines is None:
1903 ## self.lines = readlines(filename)
1904 ## else:
1905 ## self.lines = lines
1906 ## options.counters['physical lines'] += len(self.lines)
1907 ##
1908 ## def readline(self):
1909 ## """
1910 ## Get the next line from the input buffer.
1911 ## """
1912 ## self.line_number += 1
1913 ## if self.line_number > len(self.lines):
1914 ## return ''
1915 ## return self.lines[self.line_number - 1]
1916 ##
1917 ## def readline_check_physical(self):
1918 ## """
1919 ## Check and return the next physical line. This method can be
1920 ## used to feed tokenize.generate_tokens.
1921 ## """
1922 ## line = self.readline()
1923 ## if line:
1924 ## self.check_physical(line)
1925 ## return line
1926 ##
1927 ## def run_check(self, check, argument_names):
1928 ## """
1929 ## Run a check plugin.
1930 ## """
1931 ## arguments = []
1932 ## for name in argument_names:
1933 ## arguments.append(getattr(self, name))
1934 ## return check(*arguments)
1935 ##
1936 ## def check_physical(self, line):
1937 ## """
1938 ## Run all physical checks on a raw input line.
1939 ## """
1940 ## self.physical_line = line
1941 ## if self.indent_char is None and len(line) and line[0] in ' \t':
1942 ## self.indent_char = line[0]
1943 ## for name, check, argument_names in options.physical_checks:
1944 ## result = self.run_check(check, argument_names)
1945 ## if result is not None:
1946 ## offset, code, *args = result
1947 ## self.report_error_args(self.line_number, offset, code, check,
1948 ## *args)
1949 ##
1950 ## def build_tokens_line(self):
1951 ## """
1952 ## Build a logical line from tokens.
1953 ## """
1954 ## self.mapping = []
1955 ## logical = []
1956 ## length = 0
1957 ## previous = None
1958 ## for token in self.tokens:
1959 ## token_type, text = token[0:2]
1960 ## if token_type in SKIP_TOKENS:
1961 ## continue
1962 ## if token_type == tokenize.STRING:
1963 ## text = mute_string(text)
1964 ## if previous:
1965 ## end_line, end = previous[3]
1966 ## start_line, start = token[2]
1967 ## if end_line != start_line: # different row
1968 ## prev_text = self.lines[end_line - 1][end - 1]
1969 ## if prev_text == ',' or (prev_text not in '{[('
1970 ## and text not in '}])'):
1971 ## logical.append(' ')
1972 ## length += 1
1973 ## elif end != start: # different column
1974 ## fill = self.lines[end_line - 1][end:start]
1975 ## logical.append(fill)
1976 ## length += len(fill)
1977 ## self.mapping.append((length, token))
1978 ## logical.append(text)
1979 ## length += len(text)
1980 ## previous = token
1981 ## self.logical_line = ''.join(logical)
1982 ## assert self.logical_line.lstrip() == self.logical_line
1983 ## assert self.logical_line.rstrip() == self.logical_line
1984 ##
1985 ## def check_logical(self):
1986 ## """
1987 ## Build a line from tokens and run all logical checks on it.
1988 ## """
1989 ## options.counters['logical lines'] += 1
1990 ## self.build_tokens_line()
1991 ## first_line = self.lines[self.mapping[0][1][2][0] - 1]
1992 ## indent = first_line[:self.mapping[0][1][2][1]]
1993 ## self.previous_indent_level = self.indent_level
1994 ## self.indent_level = expand_indent(indent)
1995 ## if options.verbose >= 2:
1996 ## print(self.logical_line[:80].rstrip())
1997 ## for name, check, argument_names in options.logical_checks:
1998 ## if options.verbose >= 4:
1999 ## print(' ' + name)
2000 ## result = self.run_check(check, argument_names)
2001 ## if result is not None:
2002 ## offset, code, *args = result
2003 ## if isinstance(offset, tuple):
2004 ## original_number, original_offset = offset
2005 ## else:
2006 ## for token_offset, token in self.mapping:
2007 ## if offset >= token_offset:
2008 ## original_number = token[2][0]
2009 ## original_offset = (token[2][1]
2010 ## + offset - token_offset)
2011 ## self.report_error_args(original_number, original_offset,
2012 ## code, check, *args)
2013 ## self.previous_logical = self.logical_line
2014 ##
2015 ## def check_all(self, expected=None, line_offset=0):
2016 ## """
2017 ## Run all checks on the input file.
2018 ## """
2019 ## self.expected = expected or ()
2020 ## self.line_offset = line_offset
2021 ## self.line_number = 0
2022 ## self.file_errors = 0
2023 ## self.indent_char = None
2024 ## self.indent_level = 0
2025 ## self.previous_logical = ''
2026 ## self.blank_lines = 0
2027 ## self.blank_lines_before_comment = 0
2028 ## self.tokens = []
2029 ## parens = 0
2030 ## try:
2031 ## for token in tokenize.generate_tokens(self.readline_check_physical):
2032 ## if options.verbose >= 3:
2033 ## if token[2][0] == token[3][0]:
2034 ## pos = '[%s:%s]' % (token[2][1] or '', token[3][1])
2035 ## else:
2036 ## pos = 'l.%s' % token[3][0]
2037 ## print('l.%s\t%s\t%s\t%r' %
2038 ## (token[2][0], pos, tokenize.tok_name[token[0]], token[1]))
2039 ## self.tokens.append(token)
2040 ## token_type, text = token[0:2]
2041 ## if token_type == tokenize.OP and text in '([{':
2042 ## parens += 1
2043 ## if token_type == tokenize.OP and text in '}])':
2044 ## parens -= 1
2045 ## if token_type == tokenize.NEWLINE and not parens:
2046 ## self.check_logical()
2047 ## self.blank_lines = 0
2048 ## self.blank_lines_before_comment = 0
2049 ## self.tokens = []
2050 ## if token_type == tokenize.NL and not parens:
2051 ## if len(self.tokens) <= 1:
2052 ## # The physical line contains only this token.
2053 ## self.blank_lines += 1
2054 ## self.tokens = []
2055 ## if token_type == tokenize.COMMENT:
2056 ## source_line = token[4]
2057 ## token_start = token[2][1]
2058 ## if source_line[:token_start].strip() == '':
2059 ## self.blank_lines_before_comment = max(self.blank_lines,
2060 ## self.blank_lines_before_comment)
2061 ## self.blank_lines = 0
2062 ## if text.endswith('\n') and not parens:
2063 ## # The comment also ends a physical line. This works around
2064 ## # Python < 2.6 behaviour, which does not generate NL after
2065 ## # a comment which is on a line by itself.
2066 ## self.tokens = []
2067 ## except tokenize.TokenError as err:
2068 ## msg, (lnum, pos) = err.args
2069 ## self.report_error_args(lnum, pos, "E901", "TokenError", msg)
2070 ## return self.file_errors
2071 ##
2072 ## def report_error(self, line_number, offset, text, check):
2073 ## """
2074 ## Report an error, according to options.
2075 ## """
2076 ## code = text[:4]
2077 ## if ignore_code(code):
2078 ## return
2079 ## if options.quiet == 1 and not self.file_errors:
2080 ## message(self.filename)
2081 ## if code in options.counters:
2082 ## options.counters[code] += 1
2083 ## else:
2084 ## options.counters[code] = 1
2085 ## options.messages[code] = text[5:]
2086 ## if options.quiet or code in self.expected:
2087 ## # Don't care about expected errors or warnings
2088 ## return
2089 ## self.file_errors += 1
2090 ## if options.counters[code] == 1 or options.repeat:
2091 ## message("%s:%s:%d: %s" %
2092 ## (self.filename, self.line_offset + line_number,
2093 ## offset + 1, text))
2094 ## if options.show_source:
2095 ## line = self.lines[line_number - 1]
2096 ## message(line.rstrip())
2097 ## message(' ' * offset + '^')
2098 ## if options.show_pep8:
2099 ## message(check.__doc__.lstrip('\n').rstrip())
2100 ##
2101 ##
2102 ##def input_file(filename):
2103 ## """
2104 ## Run all checks on a Python source file.
2105 ## """
2106 ## if options.verbose:
2107 ## message('checking ' + filename)
2108 ## Checker(filename).check_all()
2109 ##
2110 ##
2111 ##def input_dir(dirname, runner=None):
2112 ## """
2113 ## Check all Python source files in this directory and all subdirectories.
2114 ## """
2115 ## dirname = dirname.rstrip('/')
2116 ## if excluded(dirname):
2117 ## return
2118 ## if runner is None:
2119 ## runner = input_file
2120 ## for root, dirs, files in os.walk(dirname):
2121 ## if options.verbose:
2122 ## message('directory ' + root)
2123 ## options.counters['directories'] += 1
2124 ## dirs.sort()
2125 ## for subdir in dirs:
2126 ## if excluded(subdir):
2127 ## dirs.remove(subdir)
2128 ## files.sort()
2129 ## for filename in files:
2130 ## if filename_match(filename) and not excluded(filename):
2131 ## options.counters['files'] += 1
2132 ## runner(os.path.join(root, filename))
2133 ##
2134 ##
2135 ##def excluded(filename):
2136 ## """
2137 ## Check if options.exclude contains a pattern that matches filename.
2138 ## """
2139 ## basename = os.path.basename(filename)
2140 ## for pattern in options.exclude:
2141 ## if fnmatch(basename, pattern):
2142 ## # print basename, 'excluded because it matches', pattern
2143 ## return True
2144 ##
2145 ##
2146 ##def filename_match(filename):
2147 ## """
2148 ## Check if options.filename contains a pattern that matches filename.
2149 ## If options.filename is unspecified, this always returns True.
2150 ## """
2151 ## if not options.filename:
2152 ## return True
2153 ## for pattern in options.filename:
2154 ## if fnmatch(filename, pattern):
2155 ## return True
2156 ##
2157 ##
2158 ##def ignore_code(code):
2159 ## """
2160 ## Check if options.ignore contains a prefix of the error code.
2161 ## If options.select contains a prefix of the error code, do not ignore it.
2162 ## """
2163 ## for select in options.select:
2164 ## if code.startswith(select):
2165 ## return False
2166 ## for ignore in options.ignore:
2167 ## if code.startswith(ignore):
2168 ## return True
2169 ##
2170 ##
2171 ##def reset_counters():
2172 ## for key in list(options.counters.keys()):
2173 ## if key not in BENCHMARK_KEYS:
2174 ## del options.counters[key]
2175 ## options.messages = {}
2176 ##
2177 ##
2178 ##def get_error_statistics():
2179 ## """Get error statistics."""
2180 ## return get_statistics("E")
2181 ##
2182 ##
2183 ##def get_warning_statistics():
2184 ## """Get warning statistics."""
2185 ## return get_statistics("W")
2186 ##
2187 ##
2188 ##def get_statistics(prefix=''):
2189 ## """
2190 ## Get statistics for message codes that start with the prefix.
2191 ##
2192 ## prefix='' matches all errors and warnings
2193 ## prefix='E' matches all errors
2194 ## prefix='W' matches all warnings
2195 ## prefix='E4' matches all errors that have to do with imports
2196 ## """
2197 ## stats = []
2198 ## keys = list(options.messages.keys())
2199 ## keys.sort()
2200 ## for key in keys:
2201 ## if key.startswith(prefix):
2202 ## stats.append('%-7s %s %s' %
2203 ## (options.counters[key], key, options.messages[key]))
2204 ## return stats
2205 ##
2206 ##
2207 ##def get_count(prefix=''):
2208 ## """Return the total count of errors and warnings."""
2209 ## keys = list(options.messages.keys())
2210 ## count = 0
2211 ## for key in keys:
2212 ## if key.startswith(prefix):
2213 ## count += options.counters[key]
2214 ## return count
2215 ##
2216 ##
2217 ##def print_statistics(prefix=''):
2218 ## """Print overall statistics (number of errors and warnings)."""
2219 ## for line in get_statistics(prefix):
2220 ## print(line)
2221 ##
2222 ##
2223 ##def print_benchmark(elapsed):
2224 ## """
2225 ## Print benchmark numbers.
2226 ## """
2227 ## print('%-7.2f %s' % (elapsed, 'seconds elapsed'))
2228 ## for key in BENCHMARK_KEYS:
2229 ## print('%-7d %s per second (%d total)' % (
2230 ## options.counters[key] / elapsed, key,
2231 ## options.counters[key]))
2232 ##
2233 ##
2234 ##def run_tests(filename):
2235 ## """
2236 ## Run all the tests from a file.
2237 ##
2238 ## A test file can provide many tests. Each test starts with a declaration.
2239 ## This declaration is a single line starting with '#:'.
2240 ## It declares codes of expected failures, separated by spaces or 'Okay'
2241 ## if no failure is expected.
2242 ## If the file does not contain such declaration, it should pass all tests.
2243 ## If the declaration is empty, following lines are not checked, until next
2244 ## declaration.
2245 ##
2246 ## Examples:
2247 ##
2248 ## * Only E224 and W701 are expected: #: E224 W701
2249 ## * Following example is conform: #: Okay
2250 ## * Don't check these lines: #:
2251 ## """
2252 ## lines = readlines(filename) + ['#:\n']
2253 ## line_offset = 0
2254 ## codes = ['Okay']
2255 ## testcase = []
2256 ## for index, line in enumerate(lines):
2257 ## if not line.startswith('#:'):
2258 ## if codes:
2259 ## # Collect the lines of the test case
2260 ## testcase.append(line)
2261 ## continue
2262 ## if codes and index > 0:
2263 ## label = '%s:%s:1' % (filename, line_offset + 1)
2264 ## codes = [c for c in codes if c != 'Okay']
2265 ## # Run the checker
2266 ## errors = Checker(filename, testcase).check_all(codes, line_offset)
2267 ## # Check if the expected errors were found
2268 ## for code in codes:
2269 ## if not options.counters.get(code):
2270 ## errors += 1
2271 ## message('%s: error %s not found' % (label, code))
2272 ## if options.verbose and not errors:
2273 ## message('%s: passed (%s)' % (label, ' '.join(codes)))
2274 ## # Keep showing errors for multiple tests
2275 ## reset_counters()
2276 ## # output the real line numbers
2277 ## line_offset = index
2278 ## # configure the expected errors
2279 ## codes = line.split()[1:]
2280 ## # empty the test case buffer
2281 ## del testcase[:]
2282 ##
2283 ##
2284 ##def selftest():
2285 ## """
2286 ## Test all check functions with test cases in docstrings.
2287 ## """
2288 ## count_passed = 0
2289 ## count_failed = 0
2290 ## checks = options.physical_checks + options.logical_checks
2291 ## for name, check, argument_names in checks:
2292 ## for line in check.__doc__.splitlines():
2293 ## line = line.lstrip()
2294 ## match = SELFTEST_REGEX.match(line)
2295 ## if match is None:
2296 ## continue
2297 ## code, source = match.groups()
2298 ## checker = Checker(None)
2299 ## for part in source.split(r'\n'):
2300 ## part = part.replace(r'\t', '\t')
2301 ## part = part.replace(r'\s', ' ')
2302 ## checker.lines.append(part + '\n')
2303 ## options.quiet = 2
2304 ## checker.check_all()
2305 ## error = None
2306 ## if code == 'Okay':
2307 ## if len(options.counters) > len(BENCHMARK_KEYS):
2308 ## codes = [key for key in options.counters.keys()
2309 ## if key not in BENCHMARK_KEYS]
2310 ## error = "incorrectly found %s" % ', '.join(codes)
2311 ## elif not options.counters.get(code):
2312 ## error = "failed to find %s" % code
2313 ## # Reset the counters
2314 ## reset_counters()
2315 ## if not error:
2316 ## count_passed += 1
2317 ## else:
2318 ## count_failed += 1
2319 ## if len(checker.lines) == 1:
2320 ## print("pep8.py: %s: %s" %
2321 ## (error, checker.lines[0].rstrip()))
2322 ## else:
2323 ## print("pep8.py: %s:" % error)
2324 ## for line in checker.lines:
2325 ## print(line.rstrip())
2326 ## if options.verbose:
2327 ## print("%d passed and %d failed." % (count_passed, count_failed))
2328 ## if count_failed:
2329 ## print("Test failed.")
2330 ## else:
2331 ## print("Test passed.")
2332 ##
2333 ##
2334 def get_parser(prog='pep8', version=__version__): 1890 def get_parser(prog='pep8', version=__version__):
2335 parser = OptionParser(prog=prog, version=version, 1891 parser = OptionParser(prog=prog, version=version,
2336 usage="%prog [options] input ...") 1892 usage="%prog [options] input ...")
2337 parser.config_options = [ 1893 parser.config_options = [
2338 'exclude', 'filename', 'select', 'ignore', 'max-line-length', 1894 'exclude', 'filename', 'select', 'ignore', 'max-line-length',

eric ide

mercurial