Browse Source

Removed outdated files

pull/150/head
chriskiehl 9 years ago
parent
commit
fea11ec404
4 changed files with 0 additions and 865 deletions
  1. 61
      gooey/python_bindings/code_prep.py
  2. 578
      gooey/python_bindings/codegen.py
  3. 171
      gooey/python_bindings/source_parser.py
  4. 55
      gooey/tests/code_prep_unittest.py

61
gooey/python_bindings/code_prep.py

@ -1,61 +0,0 @@
__author__ = 'Chris'
"""
Preps the extracted Python code so that it can be evaled by the
monkey_parser
"""
from itertools import *
source = '''
import sys
import os
import doctest
import cProfile
import pstats
from argparse import ArgumentParser
from argparse import RawDescriptionHelpFormatter
from gooey import Gooey
parser = ArgumentParser(description='Example Argparse Program', formatter_class=RawDescriptionHelpFormatter)
parser.add_argument('filename', help='filename')
parser.add_argument('-r', '--recursive', dest='recurse', action='store_true', help='recurse into subfolders [default: %(default)s]')
parser.add_argument('-v', '--verbose', dest='verbose', action='count', help='set verbosity level [default: %(default)s]')
parser.add_argument('-i', '--include', action='append', help='only include paths matching this regex pattern. Note: exclude is given preference over include. [default: %(default)s]', metavar='RE')
parser.add_argument('-m', '--mycoolargument', help='mycoolargument')
parser.add_argument('-e', '--exclude', dest='exclude', help='exclude paths matching this regex pattern. [default: %(default)s]', metavar='RE')
parser.add_argument('-V', '--version', action='version')
parser.add_argument('-T', '--tester', choices=['yes', 'no'])
parser.add_argument(dest='paths', help='paths to folder(s) with source file(s) [default: %(default)s]', metavar='path', nargs='+')
'''
def take_imports(code):
return takewhile(lambda line: 'import' in line, code)
def drop_imports(code):
return dropwhile(lambda line: 'import' in line, code)
def split_line(line):
# splits an assignment statement into varname and command strings
# in: "parser = ArgumentParser(description='Example Argparse Program')"
# out: "parser", "ArgumentParser(description='Example Argparse Program"
variable, instruction = line.split('=', 1)
return variable.strip(), instruction.strip()
def update_parser_varname(new_varname, code):
# lines = source.split('\n')[1:]
lines = filter(lambda x: x != '', code)
argparse_code = dropwhile(lambda line: 'import' in line, lines)
old_argparser_varname, _ = split_line(argparse_code.next())
updated_code = [line.replace(old_argparser_varname, new_varname)
for line in lines]
return updated_code
if __name__ == '__main__':
pass

578
gooey/python_bindings/codegen.py

@ -1,578 +0,0 @@
# -*- coding: utf-8 -*-
"""
codegen
~~~~~~~
Extension to ast that allow ast -> python code generation.
:copyright: Copyright 2008 by Armin Ronacher.
:license: BSD.
"""
from ast import *
BOOLOP_SYMBOLS = {
And: 'and',
Or: 'or'
}
BINOP_SYMBOLS = {
Add: '+',
Sub: '-',
Mult: '*',
Div: '/',
FloorDiv: '//',
Mod: '%',
LShift: '<<',
RShift: '>>',
BitOr: '|',
BitAnd: '&',
BitXor: '^'
}
CMPOP_SYMBOLS = {
Eq: '==',
Gt: '>',
GtE: '>=',
In: 'in',
Is: 'is',
IsNot: 'is not',
Lt: '<',
LtE: '<=',
NotEq: '!=',
NotIn: 'not in'
}
UNARYOP_SYMBOLS = {
Invert: '~',
Not: 'not',
UAdd: '+',
USub: '-'
}
ALL_SYMBOLS = {}
ALL_SYMBOLS.update(BOOLOP_SYMBOLS)
ALL_SYMBOLS.update(BINOP_SYMBOLS)
ALL_SYMBOLS.update(CMPOP_SYMBOLS)
ALL_SYMBOLS.update(UNARYOP_SYMBOLS)
def to_source(node, indent_with=' ' * 4, add_line_information=False):
"""This function can convert a node tree back into python sourcecode.
This is useful for debugging purposes, especially if you're dealing with
custom asts not generated by python itself.
It could be that the sourcecode is evaluable when the AST itself is not
compilable / evaluable. The reason for this is that the AST contains some
more data than regular sourcecode does, which is dropped during
conversion.
Each level of indentation is replaced with `indent_with`. Per default this
parameter is equal to four spaces as suggested by PEP 8, but it might be
adjusted to match the application's styleguide.
If `add_line_information` is set to `True` comments for the line numbers
of the nodes are added to the output. This can be used to spot wrong line
number information of statement nodes.
"""
generator = SourceGenerator(indent_with, add_line_information)
generator.visit(node)
return ''.join(str(s) for s in generator.result)
class SourceGenerator(NodeVisitor):
"""This visitor is able to transform a well formed syntax tree into python
sourcecode. For more details have a look at the docstring of the
`node_to_source` function.
"""
def __init__(self, indent_with, add_line_information=False):
self.result = []
self.indent_with = indent_with
self.add_line_information = add_line_information
self.indentation = 0
self.new_lines = 0
def write(self, x):
if self.new_lines:
if self.result:
self.result.append('\n' * self.new_lines)
self.result.append(self.indent_with * self.indentation)
self.new_lines = 0
self.result.append(x)
def newline(self, node=None, extra=0):
self.new_lines = max(self.new_lines, 1 + extra)
if node is not None and self.add_line_information:
self.write('# line: %s' % node.lineno)
self.new_lines = 1
def body(self, statements):
self.new_line = True
self.indentation += 1
for stmt in statements:
self.visit(stmt)
self.indentation -= 1
def body_or_else(self, node):
self.body(node.body)
if node.orelse:
self.newline()
self.write('else:')
self.body(node.orelse)
def signature(self, node):
want_comma = []
def write_comma():
if want_comma:
self.write(', ')
else:
want_comma.append(True)
padding = [None] * (len(node.args) - len(node.defaults))
for arg, default in zip(node.args, padding + node.defaults):
write_comma()
self.visit(arg)
if default is not None:
self.write('=')
self.visit(default)
if node.vararg is not None:
write_comma()
self.write('*' + node.vararg)
if node.kwarg is not None:
write_comma()
self.write('**' + node.kwarg)
def decorators(self, node):
for decorator in node.decorator_list:
self.newline(decorator)
self.write('@')
self.visit(decorator)
# Statements
def visit_Assign(self, node):
self.newline(node)
for idx, target in enumerate(node.targets):
if idx:
self.write(', ')
self.visit(target)
self.write(' = ')
self.visit(node.value)
def visit_AugAssign(self, node):
self.newline(node)
self.visit(node.target)
self.write(BINOP_SYMBOLS[type(node.op)] + '=')
self.visit(node.value)
def visit_ImportFrom(self, node):
self.newline(node)
self.write('from %s%s import ' % ('.' * node.level, node.module))
for idx, item in enumerate(node.names):
if idx:
self.write(', ')
self.write(item.name)
def visit_Import(self, node):
self.newline(node)
for item in node.names:
self.write('import ')
self.visit(item)
def visit_Expr(self, node):
self.newline(node)
self.generic_visit(node)
def visit_FunctionDef(self, node):
self.newline(extra=1)
self.decorators(node)
self.newline(node)
self.write('def %s(' % node.name)
self.signature(node.args)
self.write('):')
self.body(node.body)
def visit_ClassDef(self, node):
have_args = []
def paren_or_comma():
if have_args:
self.write(', ')
else:
have_args.append(True)
self.write('(')
self.newline(extra=2)
self.decorators(node)
self.newline(node)
self.write('class %s' % node.name)
for base in node.bases:
paren_or_comma()
self.visit(base)
# XXX: the if here is used to keep this module compatible
# with python 2.6.
if hasattr(node, 'keywords'):
for keyword in node.keywords:
paren_or_comma()
self.write(keyword.arg + '=')
self.visit(keyword.value)
if node.starargs is not None:
paren_or_comma()
self.write('*')
self.visit(node.starargs)
if node.kwargs is not None:
paren_or_comma()
self.write('**')
self.visit(node.kwargs)
self.write(have_args and '):' or ':')
self.body(node.body)
def visit_If(self, node):
self.newline(node)
self.write('if ')
self.visit(node.test)
self.write(':')
self.body(node.body)
while True:
else_ = node.orelse
if len(else_) == 1 and isinstance(else_[0], If):
node = else_[0]
self.newline()
self.write('elif ')
self.visit(node.test)
self.write(':')
self.body(node.body)
else:
self.newline()
self.write('else:')
self.body(else_)
break
def visit_For(self, node):
self.newline(node)
self.write('for ')
self.visit(node.target)
self.write(' in ')
self.visit(node.iter)
self.write(':')
self.body_or_else(node)
def visit_While(self, node):
self.newline(node)
self.write('while ')
self.visit(node.test)
self.write(':')
self.body_or_else(node)
def visit_With(self, node):
self.newline(node)
self.write('with ')
self.visit(node.context_expr)
if node.optional_vars is not None:
self.write(' as ')
self.visit(node.optional_vars)
self.write(':')
self.body(node.body)
def visit_Pass(self, node):
self.newline(node)
self.write('pass')
def visit_Print(self, node):
# XXX: python 2.6 only
self.newline(node)
self.write('print ')
want_comma = False
if node.dest is not None:
self.write(' >> ')
self.visit(node.dest)
want_comma = True
for value in node.values:
if want_comma:
self.write(', ')
self.visit(value)
want_comma = True
if not node.nl:
self.write(',')
def visit_Delete(self, node):
self.newline(node)
self.write('del ')
for idx, target in enumerate(node):
if idx:
self.write(', ')
self.visit(target)
def visit_TryExcept(self, node):
self.newline(node)
self.write('try:')
self.body(node.body)
for handler in node.handlers:
self.visit(handler)
def visit_TryFinally(self, node):
self.newline(node)
self.write('try:')
self.body(node.body)
self.newline(node)
self.write('finally:')
self.body(node.finalbody)
def visit_Global(self, node):
self.newline(node)
self.write('global ' + ', '.join(node.names))
def visit_Nonlocal(self, node):
self.newline(node)
self.write('nonlocal ' + ', '.join(node.names))
def visit_Return(self, node):
self.newline(node)
if node.value:
self.write('return ')
self.visit(node.value)
else:
self.write('return')
def visit_Break(self, node):
self.newline(node)
self.write('break')
def visit_Continue(self, node):
self.newline(node)
self.write('continue')
def visit_Raise(self, node):
# XXX: Python 2.6 / 3.0 compatibility
self.newline(node)
self.write('raise')
if hasattr(node, 'exc') and node.exc is not None:
self.write(' ')
self.visit(node.exc)
if node.cause is not None:
self.write(' from ')
self.visit(node.cause)
elif hasattr(node, 'type') and node.type is not None:
self.visit(node.type)
if node.inst is not None:
self.write(', ')
self.visit(node.inst)
if node.tback is not None:
self.write(', ')
self.visit(node.tback)
# Expressions
def visit_Attribute(self, node):
self.visit(node.value)
self.write('.' + node.attr)
def visit_Call(self, node):
want_comma = []
def write_comma():
if want_comma:
self.write(', ')
else:
want_comma.append(True)
self.visit(node.func)
self.write('(')
for arg in node.args:
write_comma()
self.visit(arg)
for keyword in node.keywords:
write_comma()
self.write(keyword.arg + '=')
self.visit(keyword.value)
if node.starargs is not None:
write_comma()
self.write('*')
self.visit(node.starargs)
if node.kwargs is not None:
write_comma()
self.write('**')
self.visit(node.kwargs)
self.write(')')
def visit_Name(self, node):
self.write(node.id)
def visit_Str(self, node):
self.write(repr(node.s))
def visit_Bytes(self, node):
self.write(repr(node.s))
def visit_Num(self, node):
self.write(repr(node.n))
def visit_Tuple(self, node):
self.write('(')
idx = -1
for idx, item in enumerate(node.elts):
if idx:
self.write(', ')
self.visit(item)
self.write(idx and ')' or ',)')
def sequence_visit(left, right):
def visit(self, node):
self.write(left)
for idx, item in enumerate(node.elts):
if idx:
self.write(', ')
self.visit(item)
self.write(right)
return visit
visit_List = sequence_visit('[', ']')
visit_Set = sequence_visit('{', '}')
del sequence_visit
def visit_Dict(self, node):
self.write('{')
for idx, (key, value) in enumerate(zip(node.keys, node.values)):
if idx:
self.write(', ')
self.visit(key)
self.write(': ')
self.visit(value)
self.write('}')
def visit_BinOp(self, node):
self.visit(node.left)
self.write(' %s ' % BINOP_SYMBOLS[type(node.op)])
self.visit(node.right)
def visit_BoolOp(self, node):
self.write('(')
for idx, value in enumerate(node.values):
if idx:
self.write(' %s ' % BOOLOP_SYMBOLS[type(node.op)])
self.visit(value)
self.write(')')
def visit_Compare(self, node):
self.write('(')
self.write(node.left)
for op, right in zip(node.ops, node.comparators):
self.write(' %s %%' % CMPOP_SYMBOLS[type(op)])
self.visit(right)
self.write(')')
def visit_UnaryOp(self, node):
self.write('(')
op = UNARYOP_SYMBOLS[type(node.op)]
self.write(op)
if op == 'not':
self.write(' ')
self.visit(node.operand)
self.write(')')
def visit_Subscript(self, node):
self.visit(node.value)
self.write('[')
self.visit(node.slice)
self.write(']')
def visit_Slice(self, node):
if node.lower is not None:
self.visit(node.lower)
self.write(':')
if node.upper is not None:
self.visit(node.upper)
if node.step is not None:
self.write(':')
if not (isinstance(node.step, Name) and node.step.id == 'None'):
self.visit(node.step)
def visit_ExtSlice(self, node):
for idx, item in node.dims:
if idx:
self.write(', ')
self.visit(item)
def visit_Yield(self, node):
self.write('yield ')
self.visit(node.value)
def visit_Lambda(self, node):
self.write('lambda ')
self.signature(node.args)
self.write(': ')
self.visit(node.body)
def visit_Ellipsis(self, node):
self.write('Ellipsis')
def generator_visit(left, right):
def visit(self, node):
self.write(left)
self.visit(node.elt)
for comprehension in node.generators:
self.visit(comprehension)
self.write(right)
return visit
visit_ListComp = generator_visit('[', ']')
visit_GeneratorExp = generator_visit('(', ')')
visit_SetComp = generator_visit('{', '}')
del generator_visit
def visit_DictComp(self, node):
self.write('{')
self.visit(node.key)
self.write(': ')
self.visit(node.value)
for comprehension in node.generators:
self.visit(comprehension)
self.write('}')
def visit_IfExp(self, node):
self.visit(node.body)
self.write(' if ')
self.visit(node.test)
self.write(' else ')
self.visit(node.orelse)
def visit_Starred(self, node):
self.write('*')
self.visit(node.value)
def visit_Repr(self, node):
# XXX: python 2.6 only
self.write('`')
self.visit(node.value)
self.write('`')
# Helper Nodes
def visit_alias(self, node):
self.write(node.name)
if node.asname is not None:
self.write(' as ' + node.asname)
def visit_comprehension(self, node):
self.write(' for ')
self.visit(node.target)
self.write(' in ')
self.visit(node.iter)
if node.ifs:
for if_ in node.ifs:
self.write(' if ')
self.visit(if_)
def visit_excepthandler(self, node):
self.newline(node)
self.write('except')
if node.type is not None:
self.write(' ')
self.visit(node.type)
if node.name is not None:
self.write(' as ')
self.visit(node.name)
self.write(':')
self.body(node.body)

171
gooey/python_bindings/source_parser.py

@ -1,171 +0,0 @@
'''
Created on Dec 11, 2013
@author: Chris
Collection of functions for extracting argparse related statements from the
client code.
'''
import re
import os
import ast
import _ast
from itertools import *
from gooey.python_bindings import codegen, modules
def parse_source_file(file_name):
"""
Parses the AST of Python file for lines containing
references to the argparse module.
returns the collection of ast objects found.
Example client code:
1. parser = ArgumentParser(desc="My help Message")
2. parser.add_argument('filename', help="Name of the file to load")
3. parser.add_argument('-f', '--format', help='Format of output \nOptions: ['md', 'html']
4. args = parser.parse_args()
Variables:
* nodes Primary syntax tree object
* argparse_assignments The assignment of the ArgumentParser (line 1 in example code)
* add_arg_assignments Calls to add_argument() (lines 2-3 in example code)
* parser_var_name The instance variable of the ArgumentParser (line 1 in example code)
* ast_source The curated collection of all parser related nodes in the client code
"""
nodes = ast.parse(_openfile(file_name))
module_imports = get_nodes_by_instance_type(nodes, _ast.Import)
specific_imports = get_nodes_by_instance_type(nodes, _ast.ImportFrom)
assignment_objs = get_nodes_by_instance_type(nodes, _ast.Assign)
call_objects = get_nodes_by_instance_type(nodes, _ast.Call)
argparse_assignments = get_nodes_by_containing_attr(assignment_objs, 'ArgumentParser')
add_arg_assignments = get_nodes_by_containing_attr(call_objects, 'add_argument')
parse_args_assignment = get_nodes_by_containing_attr(call_objects, 'parse_args')
ast_argparse_source = chain(
module_imports,
specific_imports,
argparse_assignments,
add_arg_assignments
# parse_args_assignment
)
return ast_argparse_source
def _openfile(file_name):
with open(file_name, 'rb') as f:
return f.read()
def read_client_module(filename):
with open(filename, 'r') as f:
return f.readlines()
def get_nodes_by_instance_type(nodes, object_type):
return [node for node in walk_tree(nodes) if isinstance(node, object_type)]
def get_nodes_by_containing_attr(nodes, attr):
return [node for node in nodes if attr in walk_tree(node)]
def walk_tree(node):
yield node
d = node.__dict__
for key, value in d.iteritems():
if isinstance(value, list):
for val in value:
for _ in walk_tree(val): yield _
elif 'ast' in str(type(value)):
for _ in walk_tree(value): yield _
else:
yield value
def convert_to_python(ast_source):
"""
Converts the ast objects back into human readable Python code
"""
return map(codegen.to_source, ast_source)
def get_assignment_name(lines):
nodes = ast.parse(''.join(lines))
assignments = get_nodes_by_instance_type(nodes, _ast.Assign)
argparse_var = get_nodes_by_containing_attr(assignments, 'parse_args')
return argparse_var[0].value.func.value.id
def lines_indented(line):
unindented = re.compile("^[a-zA-Z0-9_@]+")
return unindented.match(line) is None
def not_at_main(line):
return 'def main' not in line
def not_at_parse_args(line):
return 'parse_args(' not in line
def get_indent(line):
indent = re.compile("(\t|\s)")
return ''.join(takewhile(lambda char: indent.match(char) is not None, line))
def format_source_to_return_parser(source, cutoff_line, restart_line, col_offset, parser_name):
top = source[:cutoff_line - 1]
bottom = source[restart_line:]
indentation = source[cutoff_line - 1][:col_offset]
return_statement = ['{}return {}\n\n'.format(indentation, parser_name)]
# stitch it all back together excluding the Gooey decorator
new_source = (line for line in chain(top, return_statement, bottom)
if '@gooey' not in line.lower())
return ''.join(new_source)
def extract_parser(modulepath, func_with_argparse):
source = read_client_module(modulepath)
nodes = ast.parse(''.join(source))
funcs = get_nodes_by_instance_type(nodes, _ast.FunctionDef)
assignment_objs = get_nodes_by_instance_type(nodes, _ast.Assign)
main_func = get_nodes_by_containing_attr(funcs, func_with_argparse)[0]
parse_args_assignment = get_nodes_by_containing_attr(main_func.body, 'parse_args')[0]
# ast reports the line no of a block structure as the start of the structure,
# not the end, so we look for the line no of the next node after main()
# and use that as the end of the main() function.
try:
restart_line = nodes.body[nodes.body.index(main_func)+1].lineno - 1
except IndexError:
restart_line = len(source)
module_source = format_source_to_return_parser(
source,
cutoff_line=parse_args_assignment.lineno,
restart_line=restart_line,
col_offset=parse_args_assignment.col_offset,
parser_name=parse_args_assignment.value.func.value.id
)
client_module = modules.load(module_source)
return getattr(client_module, func_with_argparse)()
def has_argparse(source):
return any(['.parse_args(' in line.lower() for line in source.split('\n')])
if __name__ == '__main__':
filepath = os.path.join(os.path.dirname(__file__),
'examples',
'example_argparse_souce_in_main.py')
nodes = ast.parse(_openfile(filepath))
#
ast_source = parse_source_file(filepath)
python_code = convert_to_python(list(ast_source))

55
gooey/tests/code_prep_unittest.py

@ -1,55 +0,0 @@
__author__ = 'Chris'
import unittest
from gooey.python_bindings import code_prep
def test_split_line():
line = "parser = ArgumentParser(description='Example Argparse Program')"
assert "parser" == code_prep.split_line(line)[0]
assert "ArgumentParser(description='Example Argparse Program')" == code_prep.split_line(line)[1]
def test_update_parser_varname_assigns_new_name_to_parser_var():
line = ["parser = ArgumentParser(description='Example Argparse Program')"]
expected = "jarser = ArgumentParser(description='Example Argparse Program')"
result = code_prep.update_parser_varname('jarser', line)[0]
assert result == expected
def test_update_parser_varname_assigns_new_name_to_parser_var__multiline():
lines = '''
import argparse
from argparse import ArgumentParser
parser = ArgumentParser(description='Example Argparse Program')
parser.parse_args()
'''.split('\n')
line = "jarser = ArgumentParser(description='Example Argparse Program')"
result = code_prep.update_parser_varname('jarser', lines)[2]
assert line == result
def test_take_imports_drops_all_non_imports_statements():
lines = '''
import argparse
from argparse import ArgumentParser
parser = ArgumentParser(description='Example Argparse Program')
parser.parse_args()
'''.split('\n')[1:]
assert 2 == len(list(code_prep.take_imports(lines)))
assert 'import argparse' == list(code_prep.take_imports(lines))[0]
def test_drop_imports_excludes_all_imports_statements():
lines = '''
import argparse
from argparse import ArgumentParser
parser = ArgumentParser(description='Example Argparse Program')
parser.parse_args()
'''.split('\n')[1:]
assert 2 == len(list(code_prep.take_imports(lines)))
assert 'parser.parse_args()' == list(code_prep.drop_imports(lines))[1]
Loading…
Cancel
Save