Include the python_gut tool

This commit is contained in:
Andrew Hamilton 2016-01-01 17:55:43 +00:00
parent 5b894d85b0
commit 3e9601033a
3 changed files with 257 additions and 9 deletions

72
gut.py Executable file
View file

@ -0,0 +1,72 @@
#!/usr/bin/env python3
# Copyright (C) 2015-2016 Andrew Hamilton. All rights reserved.
# Licensed under the Artistic License 2.0.
import re
import sys
USAGE = """Usage: gut.py <python file>
# gut.py test.py"""
INDENT_SIZE = 4
TAB_SIZE = 4
def indentation_of_line(line):
indentation = 0
for character in line:
if character == " ":
indentation += 1
elif character == "\t":
indentation += TAB_SIZE
elif character == "\n":
return None
else: # Is a non-whitespace character.
return indentation
def is_start_line_of_signature(line):
return re.match("^\s*def\s", line) is not None
def is_end_line_of_signature(line):
return (re.match(".*\):\s*\n$", line) is not None or
re.match(".*\):\s*#.*\n$", line) is not None)
def gut_module(module_contents):
SIGNATURE, BODY, TOP_LEVEL = 1, 2, 3
state = TOP_LEVEL
body_depth = 0
result = []
for line in module_contents.splitlines(keepends=True):
indent = indentation_of_line(line)
if state == BODY and indent is not None and \
indent < body_depth:
state = TOP_LEVEL
result.append("\n")
if state == TOP_LEVEL and is_start_line_of_signature(line):
state = SIGNATURE
body_depth = indent + INDENT_SIZE
if state == SIGNATURE and is_end_line_of_signature(line):
result.append(line)
state = BODY
elif state != BODY:
result.append(line)
return "".join(result)
def main(module_path):
with open(module_path) as module_file:
print(gut_module(module_file.read()))
if __name__ == "__main__":
if len(sys.argv) != 2:
print(USAGE)
sys.exit(-1)
main(sys.argv[1])

178
gut_test.py Executable file
View file

@ -0,0 +1,178 @@
#!/usr/bin/env python3
# Copyright (C) 2015-2016 Andrew Hamilton. All rights reserved.
# Licensed under the Artistic License 2.0.
import textwrap
import unittest
import gut
class GutTestCase(unittest.TestCase):
def test_import(self):
program = "import hello"
self.assertEqual(gut.gut_module(program), program)
def test_import_and_function(self):
program = textwrap.dedent("""
import hello
def first():
a = 1
""")
expected = textwrap.dedent("""
import hello
def first():
""")
self.assertEqual(gut.gut_module(program), expected)
def test_import_and_function_and_command(self):
program = textwrap.dedent("""
import hello
def first():
a = 1
b = 1
""")
expected = textwrap.dedent("""
import hello
def first():
b = 1
""")
self.assertEqual(gut.gut_module(program), expected)
def test_import_and_class(self):
program = textwrap.dedent("""
import hello
class Foo:
def bar():
a = 1
""")
expected = textwrap.dedent("""
import hello
class Foo:
def bar():
""")
self.assertEqual(gut.gut_module(program), expected)
def test_short_blank_line_in_def(self):
program = textwrap.dedent("""
def bar():
a = 1
b = 2
""")
expected = textwrap.dedent("""
def bar():
""")
self.assertEqual(gut.gut_module(program), expected)
def test_nested_functions(self):
program = textwrap.dedent("""
def bar():
a = 1
def foo():
pass
b = 2
""")
expected = textwrap.dedent("""
def bar():
""")
self.assertEqual(gut.gut_module(program), expected)
def test_multiline_signature(self):
program = textwrap.dedent("""
def bar(a, b
c, d):
a = 1
""")
expected = textwrap.dedent("""
def bar(a, b
c, d):
""")
self.assertEqual(gut.gut_module(program), expected)
def test_tab_in_indentation(self):
program = textwrap.dedent("""
def bar():
a = 1
\tb=2
""")
expected = textwrap.dedent("""
def bar():
""")
self.assertEqual(gut.gut_module(program), expected)
def test_comment_in_signature_line(self):
program = textwrap.dedent("""
def bar(): # comment
pass
""")
expected = textwrap.dedent("""
def bar(): # comment
""")
self.assertEqual(gut.gut_module(program), expected)
def test_indented_comment_in_body(self):
program = textwrap.dedent("""
def bar():
pass
# comment
pass
""")
expected = textwrap.dedent("""
def bar():
""")
self.assertEqual(gut.gut_module(program), expected)
def test_non_indented_comment_in_body(self):
program = textwrap.dedent("""
def bar():
pass
# comment
pass
""")
expected = textwrap.dedent("""
def bar():
# comment
pass
""")
self.assertEqual(gut.gut_module(program), expected)
def test_non_indented_comment_after_body(self):
program = textwrap.dedent("""
def bar():
pass
pass
# comment
pass
""")
expected = textwrap.dedent("""
def bar():
# comment
pass
""")
self.assertEqual(gut.gut_module(program), expected)
def test_commented_out_function(self):
program = textwrap.dedent("""
# def bar():
# pass
""")
self.assertEqual(gut.gut_module(program), program)
if __name__ == "__main__":
unittest.main()

View file

@ -25,6 +25,7 @@ import pygments.styles
import traceback
import fill3
import gut
import termstr
@ -245,15 +246,11 @@ def unittests(path):
unittests.dependencies = {"python3"}
def gut(path):
status, output = Status.info, ""
try:
output = subprocess.check_output(
["/home/ahamilton/code/python-gut/gut.py", path])
except subprocess.CalledProcessError:
status = Status.failure
def python_gut(path):
with open(path) as module_file:
output = gut.gut_module(module_file.read())
source_widget = _syntax_highlight_code(fix_input(output), path)
return status, source_widget
return Status.info, source_widget
def pydoc3(path):
@ -502,7 +499,8 @@ def generic_tools():
def tools_for_extension():
return {
"py": [python_syntax, unittests, pydoc3, python3_coverage, profile,
pep8, pyflakes, pylint3, gut, modulefinder, python3_mccabe],
pep8, pyflakes, pylint3, python_gut, modulefinder,
python3_mccabe],
"pyc": [disassemble_pyc],
"pl": [perl_syntax, perldoc, perltidy],
"pm": [perl_syntax, perldoc, perltidy],