diff options
Diffstat (limited to 'Demo/parser/example.py')
-rw-r--r-- | Demo/parser/example.py | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/Demo/parser/example.py b/Demo/parser/example.py new file mode 100644 index 0000000..c428aff --- /dev/null +++ b/Demo/parser/example.py @@ -0,0 +1,163 @@ +"""Simple code to extract class & function docstrings from a module. + + +""" + +import symbol +import token +import types + + +def get_docs(fileName): + """Retrieve information from the parse tree of a source file. + + fileName + Name of the file to read Python source code from. + """ + source = open(fileName).read() + import os + basename = os.path.basename(os.path.splitext(fileName)[0]) + import parser + ast = parser.suite(source) + tup = parser.ast2tuple(ast) + return ModuleInfo(tup, basename) + + +class DefnInfo: + _docstring = '' + _name = '' + + def __init__(self, tree): + self._name = tree[2][1] + + def get_docstring(self): + return self._docstring + + def get_name(self): + return self._name + +class SuiteInfoBase(DefnInfo): + def __init__(self): + self._class_info = {} + self._function_info = {} + + def get_class_names(self): + return self._class_info.keys() + + def get_class_info(self, name): + return self._class_info[name] + + def _extract_info(self, tree): + if len(tree) >= 4: + found, vars = match(DOCSTRING_STMT_PATTERN, tree[3]) + if found: + self._docstring = eval(vars['docstring']) + for node in tree[1:]: + if (node[0] == symbol.stmt + and node[1][0] == symbol.compound_stmt): + if node[1][1][0] == symbol.funcdef: + name = node[1][1][2][1] + self._function_info[name] = \ + FunctionInfo(node[1][1]) + elif node[1][1][0] == symbol.classdef: + name = node[1][1][2][1] + self._class_info[name] = ClassInfo(node[1][1]) + + +class SuiteInfo(SuiteInfoBase): + def __init__(self, tree): + SuiteInfoBase.__init__(self) + self._extract_info(tree) + + def get_function_names(self): + return self._function_info.keys() + + def get_function_info(self, name): + return self._function_info[name] + + +class FunctionInfo(SuiteInfo): + def __init__(self, tree): + DefnInfo.__init__(self, tree) + suite = tree[-1] + if len(suite) >= 4: + found, vars = match(DOCSTRING_STMT_PATTERN, suite[3]) + if found: + self._docstring = eval(vars['docstring']) + SuiteInfoBase.__init__(self) + self._extract_info(suite) + + +class ClassInfo(SuiteInfoBase): + def __init__(self, tree): + SuiteInfoBase.__init__(self) + DefnInfo.__init__(self, tree) + self._extract_info(tree[-1]) + + def get_method_names(self): + return self._function_info.keys() + + def get_method_info(self, name): + return self._function_info[name] + + +class ModuleInfo(SuiteInfo): + def __init__(self, tree, name="<string>"): + self._name = name + SuiteInfo.__init__(self, tree) + found, vars = match(DOCSTRING_STMT_PATTERN, tree[1]) + if found: + self._docstring = vars["docstring"] + + +from types import ListType, TupleType + +def match(pattern, data, vars=None): + """ + """ + if vars is None: + vars = {} + if type(pattern) is ListType: # 'variables' are ['varname'] + vars[pattern[0]] = data + return 1, vars + if type(pattern) is not TupleType: + return (pattern == data), vars + if len(data) != len(pattern): + return 0, vars + for pattern, data in map(None, pattern, data): + same, vars = match(pattern, data, vars) + if not same: + break + return same, vars + + +# This pattern will match a 'stmt' node which *might* represent a docstring; +# docstrings require that the statement which provides the docstring be the +# first statement in the class or function, which this pattern does not check. +# +DOCSTRING_STMT_PATTERN = ( + symbol.stmt, + (symbol.simple_stmt, + (symbol.small_stmt, + (symbol.expr_stmt, + (symbol.testlist, + (symbol.test, + (symbol.and_test, + (symbol.not_test, + (symbol.comparison, + (symbol.expr, + (symbol.xor_expr, + (symbol.and_expr, + (symbol.shift_expr, + (symbol.arith_expr, + (symbol.term, + (symbol.factor, + (symbol.power, + (symbol.atom, + (token.STRING, ['docstring']) + )))))))))))))))), + (token.NEWLINE, '') + )) + +# +# end of file |