Last active
June 16, 2019 22:20
-
-
Save xni/f6ce6d5a832b8c5543d46150c83b1c92 to your computer and use it in GitHub Desktop.
Try counter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
This module counts amount of try and try/else statements | |
in the files. | |
Usage: | |
find ../cpython/Lib/ -type f -name '*.py' | xargs python3.7 main.py output.md FILE1 FILE2 ... | |
""" | |
import ast | |
import logging | |
import multiprocessing | |
import pathlib | |
import os | |
import sys | |
class TryVisitor(ast.NodeVisitor): | |
""" | |
TryVisitor collects all of the finally statements from the code, | |
caprturing the enclosing function definitions. | |
""" | |
def __init__(self): | |
self.total_trys = 0 | |
self.trys_elses = 0 | |
super(TryVisitor, self).__init__() | |
def visit_Try(self, node): | |
self.total_trys += 1 | |
if node.orelse: | |
self.trys_elses += 1 | |
def get_try_cnts(path): | |
logger = logging.getLogger(__name__) | |
try: | |
tree = ast.parse(path.read_text('utf-8')) | |
except: | |
logger.info("Unable to parse the file %s", path) | |
return 0, 0 | |
v = TryVisitor() | |
v.visit(tree) | |
logger.debug("%s Try's with else: %d, total try's: %d", path, v.trys_elses, v.total_trys) | |
return v.trys_elses, v.total_trys | |
def main(paths): | |
logging.basicConfig(level=logging.INFO, stream=sys.stdout) | |
logger = logging.getLogger(__name__) | |
pool = multiprocessing.Pool(processes=4) | |
else_trys = 0 | |
total_trys = 0 | |
paths = filter(lambda p: not p.name.startswith('test_'), paths) | |
analyzed_files = 0 | |
for else_trys_in_file, total_trys_in_file in pool.imap_unordered(get_try_cnts, paths): | |
analyzed_files += 1 | |
else_trys += else_trys_in_file | |
total_trys += total_trys_in_file | |
logger.info("Try's with else: %d, total try's: %d in %d files", else_trys, total_trys, analyzed_files) | |
if __name__ == "__main__": | |
import argparse | |
import sys | |
parser = argparse.ArgumentParser() | |
parser.add_argument('paths', nargs='+') | |
ns = parser.parse_args() | |
sys.exit( | |
main([pathlib.Path(p) for p in ns.paths]) | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
This module provides a tool to search for | |
try: | |
STMT | |
else: | |
STMT | |
finally: | |
STMT | |
patterns in the files. | |
Usage: | |
find ../cpython/Lib/ -type f -name '*.py' | xargs -n 1 -I{} python3.7 main.py {} output.md | |
""" | |
import ast | |
import logging | |
import pathlib | |
import os | |
import sys | |
class TryVisitor(ast.NodeVisitor): | |
""" | |
TryVisitor collects all of the finally statements from the code, | |
caprturing the enclosing function definitions. | |
""" | |
def __init__(self): | |
self.enclosing_fn = None | |
self._found_fns = {} | |
super(TryVisitor, self).__init__() | |
def visit_Try(self, node): | |
if node.finalbody and node.orelse: | |
self.on_found() | |
def visit_FunctionDef(self, node): | |
self.enclosing_fn = node | |
self.generic_visit(node) | |
def on_found(self): | |
fn_hash = self.enclosing_fn.lineno | |
self._found_fns[fn_hash] = self.enclosing_fn | |
@property | |
def found_fns(self): | |
return self._found_fns.values() | |
def get_nodes_line_range(arg_node): | |
""" | |
get_nodes_line_range finds the range of lines where the function's | |
source code is located. | |
""" | |
max_child_line = arg_node.lineno | |
for subnode in ast.walk(arg_node): | |
try: | |
max_child_line = max(max_child_line, subnode.lineno) | |
except: | |
pass | |
return arg_node.lineno, max_child_line | |
def get_next_line(tree, lineno): | |
result = None | |
for node in ast.walk(tree): | |
try: | |
if node.lineno > lineno and (not result or result > node.lineno): | |
result = node.lineno | |
except: | |
pass | |
return result | |
def main(path, output): | |
logger = logging.getLogger(__name__) | |
logging.basicConfig(level=logging.INFO, stream=sys.stdout) | |
logger.info('Analyzing %s', path) | |
if (path.name.startswith('test_')): | |
logger.info('Skipping because it is a test') | |
return | |
filecontents = path.read_text('utf-8') | |
try: | |
tree = ast.parse(filecontents) | |
except: | |
logger.info("Unable to parse the file") | |
return | |
visitor = TryVisitor() | |
visitor.visit(tree) | |
lines = filecontents.splitlines() | |
if not visitor.found_fns: | |
logger.info("No patterns found") | |
return | |
data = [f"== {path}"] | |
for fn_node in visitor.found_fns: | |
rg = get_nodes_line_range(fn_node) | |
line_after_rg = get_next_line(tree, rg[1]) | |
if line_after_rg: | |
line_after_rg -= 1 | |
else: | |
line_after_rg = len(lines) | |
data.append(f"=== {fn_node.name} ({rg[0]} - {line_after_rg})") | |
offset = fn_node.col_offset | |
data.append('```') | |
data.extend( | |
lines[line][offset:] for line in range(rg[0]-1, line_after_rg) | |
) | |
data.append('```') | |
with open(output, 'a', encoding='utf-8') as output_file: | |
for line in data: | |
output_file.write(line) | |
output_file.write('\n') | |
if __name__ == "__main__": | |
import argparse | |
import sys | |
parser = argparse.ArgumentParser() | |
parser.add_argument('path') | |
parser.add_argument('output') | |
ns = parser.parse_args() | |
sys.exit(main(pathlib.Path(ns.path), pathlib.Path(ns.output))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
try: | |
st = _stat(fn) | |
except OSError: | |
# File most likely does not exist | |
pass | |
else: | |
# XXX What about other special files? (sockets, devices...) | |
if stat.S_ISFIFO(st.st_mode): | |
fn = fn.path if isinstance(fn, os.DirEntry) else fn | |
raise SpecialFileError("`%s` is a named pipe" % fn) | |
if _WINDOWS and i == 0: | |
file_size = st.st_size |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
try: | |
method = getattr(router, action) | |
except AttributeError: | |
# If the router doesn't have a method, skip to the next one. | |
pass | |
else: | |
chosen_db = method(model, **hints) | |
if chosen_db: | |
return chosen_db |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment