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.

117 lines
3.5 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 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 _ast
  10. from itertools import chain
  11. import codegen
  12. from monkey_parser import MonkeyParser
  13. from gooey.gui.action_sorter import ActionSorter
  14. from parser_exceptions import ParserError
  15. def parse_source_file(file_name):
  16. """
  17. Parses the AST of Python file for lines containing
  18. references to the argparse module.
  19. returns the collection of ast objects found.
  20. Example client code:
  21. 1. parser = ArgumentParser(desc="My help Message")
  22. 2. parser.add_argument('filename', help="Name of the file to load")
  23. 3. parser.add_argument('-f', '--format', help='Format of output \nOptions: ['md', 'html']
  24. 4. args = parser.parse_args()
  25. Variables:
  26. * nodes Primary syntax tree object
  27. * argparse_assignments The assignment of the ArgumentParser (line 1 in example code)
  28. * add_arg_assignments Calls to add_argument() (lines 2-3 in example code)
  29. * parser_var_name The instance variable of the ArgumentParser (line 1 in example code)
  30. * ast_source The curated collection of all parser related nodes in the client code
  31. """
  32. nodes = ast.parse(_openfile(file_name))
  33. module_imports = get_nodes_by_instance_type(nodes, _ast.Import)
  34. specific_imports = get_nodes_by_instance_type(nodes, _ast.ImportFrom)
  35. assignment_objs = get_nodes_by_instance_type(nodes, _ast.Assign)
  36. call_objects = get_nodes_by_instance_type(nodes, _ast.Call)
  37. argparse_assignments = get_nodes_by_containing_attr(assignment_objs, 'ArgumentParser')
  38. add_arg_assignments = get_nodes_by_containing_attr(call_objects, 'add_argument')
  39. # parse_args_assignment = get_nodes_by_containing_attr(call_objects, 'parse_args')
  40. ast_argparse_source = chain(
  41. module_imports,
  42. specific_imports,
  43. argparse_assignments,
  44. add_arg_assignments
  45. # parse_args_assignment
  46. )
  47. # for i in ast_argparse_source:
  48. # print i
  49. return ast_argparse_source
  50. def _openfile(file_name):
  51. with open(file_name, 'rb') as f:
  52. return f.read()
  53. def get_nodes_by_instance_type(nodes, object_type):
  54. return [node for node in walk_tree(nodes) if isinstance(node, object_type)]
  55. def get_nodes_by_containing_attr(nodes, attr):
  56. return [node for node in nodes if attr in walk_tree(node)]
  57. def walk_tree(node):
  58. yield node
  59. d = node.__dict__
  60. for key, value in d.iteritems():
  61. if isinstance(value, list):
  62. for val in value:
  63. for _ in walk_tree(val): yield _
  64. elif 'ast' in str(type(value)):
  65. for _ in walk_tree(value): yield _
  66. else:
  67. yield value
  68. def convert_to_python(ast_source):
  69. """
  70. Converts the ast objects back into human readable Python code
  71. """
  72. return map(codegen.to_source, ast_source)
  73. def extract_parser(modulepath):
  74. ast_source = parse_source_file(modulepath)
  75. if ast_source:
  76. python_code = convert_to_python(ast_source)
  77. return MonkeyParser(python_code)
  78. return None
  79. if __name__ == '__main__':
  80. filepath = os.path.join(os.path.dirname(__file__),
  81. 'mockapplications',
  82. 'example_argparse_souce_in_main.py')
  83. nodes = ast.parse(_openfile(filepath))
  84. #
  85. ast_source = parse_source_file(filepath)
  86. python_code = convert_to_python(list(ast_source))
  87. for i in python_code: print i
  88. # parser = MonkeyParser(python_code)
  89. # factory = ActionSorter(parser._actions)
  90. # print factory._positionals