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

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
  1. '''
  2. Created on Dec 11, 2013
  3. @author: Chris
  4. Collection of functions for extracting argparse related statements from the
  5. client code.
  6. '''
  7. import os
  8. import ast
  9. import codegen
  10. from itertools import chain
  11. from monkey_parser import MonkeyParser
  12. from app.dialogs.action_sorter import ActionSorter
  13. from parser_exceptions import ParserError
  14. def parse_source_file(file_name):
  15. '''
  16. Parses the AST of Python file for lines containing
  17. references to the argparse module.
  18. returns the collection of ast objects found.
  19. Example client code:
  20. 1. parser = ArgumentParser(desc="My help Message")
  21. 2. parser.add_argument('filename', help="Name of the file to load")
  22. 3. parser.add_argument('-f', '--format', help='Format of output \nOptions: ['md', 'html']
  23. 4. args = parser.parse_args()
  24. Variables:
  25. * nodes Primary syntax tree object
  26. * _mainfunc_block main() method as found in the ast nodes
  27. * _try_blocks Try/except/finally blocks found in the main method
  28. * main_block The code block in which the ArgumentParser statements are located
  29. * argparse_assign_obj The assignment of the ArgumentParser (line 1 in example code)
  30. * parser_nodes Nodes which have parser references (lines 1-4 in example code)
  31. * parser_var_name The instance variable of the ArgumentParser (line 1 in example code)
  32. * ast_source The currated colleciton of all parser related nodes in the client code
  33. '''
  34. nodes = ast.parse(_openfile(file_name))
  35. _mainfunc_block = find_main(nodes)
  36. _try_blocks = find_try_blocks(_mainfunc_block)
  37. search_locations = chain([_mainfunc_block], _try_blocks)
  38. main_block = find_argparse_location(search_locations)
  39. if not main_block:
  40. raise ParserError("Could not locate AugmentParser.")
  41. argparse_assign_obj = [node for node in main_block.body
  42. if has_instantiator(node, 'ArgumentParser')]
  43. parser_nodes = [node for node in main_block.body
  44. if has_assignment(node, 'add_argument')]
  45. ast_source = chain(argparse_assign_obj, parser_nodes)
  46. return ast_source
  47. def find_try_blocks(block):
  48. # Finds all try/catch/finally expressions in a given function block
  49. _types = [ast.TryExcept, ast.TryFinally]
  50. return [node for node in block.body
  51. if any([isinstance(node, x) for x in _types])]
  52. def find_main(nodes):
  53. # Finds main function in the tree
  54. for node in nodes.body:
  55. if isinstance(node, ast.FunctionDef) and node.name == 'main':
  56. return node
  57. raise ParserError('Could not find main function')
  58. def get_assignment_name(node):
  59. # return the variable name to which
  60. # ArgumentParser is assigned
  61. return node.targets[0].id
  62. def _openfile(file_name):
  63. with open(file_name, 'rb') as f:
  64. return f.read()
  65. def find_statement(block, name):
  66. return [node for node in block.body
  67. if has_instantiator(node, name)]
  68. def has_instantiator(x, name):
  69. # Checks if the astObject is one with an
  70. # instantiation of the ArgParse class
  71. try: return x.value.func.id == name
  72. except: return False # Wrong type. Contine.
  73. def has_assignment(x, name):
  74. # Checks if the astObject is contains a
  75. # function with a name of name
  76. try: return x.value.func.attr == name
  77. except: return False # Wrong type. Contine.
  78. def is_found(stmnt):
  79. return len(stmnt)
  80. def has_argparse_assignment(block):
  81. # Checks a given node for presence of an instantiation
  82. argparse_assignment = find_statement(block, 'ArgumentParser')
  83. return is_found(argparse_assignment)
  84. def find_argparse_location(locations):
  85. # Browser a collection of Nodes for the one
  86. # containing the Argparse instantiation
  87. for location in locations:
  88. if has_argparse_assignment(location):
  89. return location
  90. return None
  91. def convert_to_python(ast_source):
  92. '''
  93. Converts the ast objects back into Python code
  94. '''
  95. return map(codegen.to_source, ast_source)
  96. def extract_parser(modulepath):
  97. ast_source = parse_source_file(modulepath)
  98. if ast_source:
  99. python_code = convert_to_python(ast_source)
  100. return MonkeyParser(python_code)
  101. return None
  102. if __name__ == '__main__':
  103. filepath = os.path.join(os.path.dirname(__file__),
  104. 'mockapplications',
  105. 'example_argparse_souce.py')
  106. ast_source = parse_source_file(filepath)
  107. python_code = convert_to_python(ast_source)
  108. parser = MonkeyParser(python_code)
  109. factory = ActionSorter(parser._actions)
  110. print factory._positionals
  111. #