- Save RJ722/0e8578d0920d508fc52461402d304c8d to your computer and use it in GitHub Desktop.
| import sys | |
| import tokenize | |
| class DoubleQuotesChecker: | |
| msg = "single quotes detected, use double quotes instead" | |
| def __init__(self): | |
| self.violations = [] | |
| def find_violations(self, filename, tokens): | |
| for token_type, token, (line, col), _, _ in tokens: | |
| if ( | |
| token_type == tokenize.STRING | |
| and not token.startswith("'''") and | |
| token.startswith("'") | |
| ): | |
| self.violations.append((filename, line, col)) | |
| def check(self, files): | |
| for filename in files: | |
| with tokenize.open(filename) as fd: | |
| tokens = tokenize.generate_tokens(fd.readline) | |
| self.find_violations(filename, tokens) | |
| def report(self): | |
| for violation in self.violations: | |
| filename, line, col = violation | |
| print(f"{filename}:{line}:{col}: {self.msg}") | |
| if __name__ == '__main__': | |
| files = sys.argv[1:] | |
| checker = DoubleQuotesChecker() | |
| checker.check(files) | |
| checker.report() |
| def simulate_quote_warnin(): | |
| ''' | |
| The docstring intentionally uses single quotes. | |
| ''' | |
| if isinstance(shawn, 'sheep'): | |
| print('Shawn the sheep!') |
| import ast | |
| from collections import defaultdict | |
| import sys | |
| import tokenize | |
| def read_file(filename): | |
| with tokenize.open(filename) as fd: | |
| return fd.read() | |
| class BaseChecker(ast.NodeVisitor): | |
| def __init__(self): | |
| self.violations = [] | |
| def check(self, paths): | |
| for filepath in paths: | |
| self.filename = filepath | |
| tree = ast.parse(read_file(filepath)) | |
| self.visit(tree) | |
| def report(self): | |
| for violation in self.violations: | |
| filename, lineno, msg = violation | |
| print(f"{filename}:{lineno}: {msg}") | |
| class UnusedImportChecker(BaseChecker): | |
| def __init__(self): | |
| self.import_map = defaultdict(set) | |
| self.name_map = defaultdict(set) | |
| def _add_imports(self, node): | |
| for import_name in node.names: | |
| # Store only top-level module name ("os.path" -> "os"). | |
| # We can't easily detect when "os.path" is used. | |
| name = import_name.name.partition(".")[0] | |
| self.import_map[self.filename].add((name, node.lineno)) | |
| def visit_Import(self, node): | |
| self._add_imports(node) | |
| def visit_ImportFrom(self, node): | |
| self._add_imports(node) | |
| def visit_Name(self, node): | |
| # We only add those nodes for which a value is being read from. | |
| if isinstance(node.ctx, ast.Load): | |
| self.name_map[self.filename].add(node.id) | |
| def report(self): | |
| for path, imports in self.import_map.items(): | |
| for name, line in imports: | |
| if name not in self.name_map[path]: | |
| print(f"{path}:{line}: unused import '{name}'") | |
| if __name__ == '__main__': | |
| files = sys.argv[1:] | |
| checker = UnusedImportChecker() | |
| checker.check(files) | |
| checker.report() |
| import antigravity | |
| import os.path.join | |
| import sys | |
| import this | |
| tmpdir = os.path.join(sys.path[0], 'tmp') |
| import ast | |
| from collections import defaultdict | |
| import sys | |
| import tokenize | |
| def read_file(filename): | |
| with tokenize.open(filename) as fd: | |
| return fd.read() | |
| class BaseChecker(ast.NodeVisitor): | |
| def __init__(self): | |
| self.violations = [] | |
| def check(self, paths): | |
| for filepath in paths: | |
| self.filename = filepath | |
| tree = ast.parse(read_file(filepath)) | |
| self.visit(tree) | |
| def report(self): | |
| for violation in self.violations: | |
| filename, lineno, msg = violation | |
| print(f"{filename}:{lineno}: {msg}") | |
| class ListDefinitionChecker(BaseChecker): | |
| msg = "usage of 'list()' detected, use '[]' instead" | |
| def visit_Call(self, node): | |
| name = getattr(node.func, "id", None) | |
| if name and name == list.__name__ and not node.args: | |
| self.violations.append((self.filename, node.lineno, self.msg)) | |
| if __name__ == '__main__': | |
| files = sys.argv[1:] | |
| checker = ListDefinitionChecker() | |
| checker.check(files) | |
| checker.report() |
| def build_herd(): | |
| herd = list() | |
| for a_sheep in sheep: | |
| herd.append(a_sheep) | |
| return Herd(herd) |
| import ast | |
| from collections import defaultdict | |
| import sys | |
| import tokenize | |
| def read_file(filename): | |
| with tokenize.open(filename) as fd: | |
| return fd.read() | |
| class BaseChecker(ast.NodeVisitor): | |
| def __init__(self): | |
| self.violations = [] | |
| def check(self, paths): | |
| for filepath in paths: | |
| self.filename = filepath | |
| tree = ast.parse(read_file(filepath)) | |
| self.visit(tree) | |
| def report(self): | |
| for violation in self.violations: | |
| filename, lineno, msg = violation | |
| print(f"{filename}:{lineno}: {msg}") | |
| class TooManyForLoopChecker(BaseChecker): | |
| msg = "too many nested for loops" | |
| def visit_For(self, node, parent=True): | |
| if parent: | |
| self.current_loop_depth = 1 | |
| else: | |
| self.current_loop_depth += 1 | |
| for child in node.body: | |
| if type(child) == ast.For: | |
| self.visit_For(child, parent=False) | |
| if parent and self.current_loop_depth > 3: | |
| self.violations.append((self.filename, node.lineno, self.msg)) | |
| self.current_loop_depth = 0 | |
| if __name__ == '__main__': | |
| files = sys.argv[1:] | |
| checker = TooManyForLoopChecker() | |
| checker.check(files) | |
| checker.report() |
| for _ in range(10): | |
| for _ in range(5): | |
| for _ in range(3): | |
| for _ in range(1): | |
| print("Baa, Baa, black sheep") | |
| for _ in range(4): | |
| for _ in range(3): | |
| print("Have you any wool?") | |
| for _ in range(10): | |
| for _ in range(5): | |
| for _ in range(3): | |
| if True: | |
| for _ in range(3): | |
| print("Yes, sir, yes, sir!") |