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', |