You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
4.4 KiB

'''
Created on Dec 11, 2013
@author: Chris
Collection of functions for extracting argparse related statements from the
client code.
'''
import os
import ast
import codegen
from itertools import chain
from monkey_parser import MonkeyParser
from app.dialogs.action_sorter import ActionSorter
from parser_exceptions import ParserError
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
* _mainfunc_block main() method as found in the ast nodes
* _try_blocks Try/except/finally blocks found in the main method
* main_block The code block in which the ArgumentParser statements are located
* argparse_assign_obj The assignment of the ArgumentParser (line 1 in example code)
* parser_nodes Nodes which have parser references (lines 1-4 in example code)
* parser_var_name The instance variable of the ArgumentParser (line 1 in example code)
* ast_source The currated colleciton of all parser related nodes in the client code
'''
nodes = ast.parse(_openfile(file_name))
_mainfunc_block = find_main(nodes)
_try_blocks = find_try_blocks(_mainfunc_block)
search_locations = chain([_mainfunc_block], _try_blocks)
main_block = find_argparse_location(search_locations)
if not main_block:
raise ParserError("Could not locate AugmentParser.")
argparse_assign_obj = [node for node in main_block.body
if has_instantiator(node, 'ArgumentParser')]
parser_nodes = [node for node in main_block.body
if has_assignment(node, 'add_argument')]
ast_source = chain(argparse_assign_obj, parser_nodes)
return ast_source
def find_try_blocks(block):
# Finds all try/catch/finally expressions in a given function block
_types = [ast.TryExcept, ast.TryFinally]
return [node for node in block.body
if any([isinstance(node, x) for x in _types])]
def find_main(nodes):
# Finds main function in the tree
for node in nodes.body:
if isinstance(node, ast.FunctionDef) and node.name == 'main':
return node
raise ParserError('Could not find main function')
def get_assignment_name(node):
# return the variable name to which
# ArgumentParser is assigned
return node.targets[0].id
def _openfile(file_name):
with open(file_name, 'rb') as f:
return f.read()
def find_statement(block, name):
return [node for node in block.body
if has_instantiator(node, name)]
def has_instantiator(x, name):
# Checks if the astObject is one with an
# instantiation of the ArgParse class
try: return x.value.func.id == name
except: return False # Wrong type. Contine.
def has_assignment(x, name):
# Checks if the astObject is contains a
# function with a name of name
try: return x.value.func.attr == name
except: return False # Wrong type. Contine.
def is_found(stmnt):
return len(stmnt)
def has_argparse_assignment(block):
# Checks a given node for presence of an instantiation
argparse_assignment = find_statement(block, 'ArgumentParser')
return is_found(argparse_assignment)
def find_argparse_location(locations):
# Browser a collection of Nodes for the one
# containing the Argparse instantiation
for location in locations:
if has_argparse_assignment(location):
return location
return None
def convert_to_python(ast_source):
'''
Converts the ast objects back into Python code
'''
return map(codegen.to_source, ast_source)
def extract_parser(modulepath):
ast_source = parse_source_file(modulepath)
if ast_source:
python_code = convert_to_python(ast_source)
return MonkeyParser(python_code)
return None
if __name__ == '__main__':
filepath = os.path.join(os.path.dirname(__file__),
'mockapplications',
'example_argparse_souce.py')
ast_source = parse_source_file(filepath)
python_code = convert_to_python(ast_source)
parser = MonkeyParser(python_code)
factory = ActionSorter(parser._actions)
print factory._positionals
#