Source code for pyfileconf.io.file.load.parsers.funcdef
import ast
from typing import List, Union
FunctionDefOrNone = Union[ast.FunctionDef, None]
FunctionDefs = List[ast.FunctionDef]
[docs]class FunctionDefinitionExtractor(ast.NodeVisitor):
# don't go into children, so won't extract nested functions
# don't go into children, so won't extract class methods
[docs]def extract_function_definitions_from_ast(module: ast.AST) -> FunctionDefs:
fe = FunctionDefinitionExtractor()
fe.visit(module)
return fe.defs
[docs]class FunctionDefinitionByNameExtractor(FunctionDefinitionExtractor):
[docs] def visit_FunctionDef(self, node):
if node.name == self.func_name:
super().visit_FunctionDef(node)
[docs]def extract_function_definitions_from_ast_by_name(module: ast.AST, name: str) -> FunctionDefs:
fe = FunctionDefinitionByNameExtractor(name)
fe.visit(module)
return fe.defs
[docs]def extract_function_definition_from_ast_by_name(module: ast.AST, name: str) -> FunctionDefOrNone:
defs = extract_function_definitions_from_ast_by_name(module, name)
if len(defs) == 0:
return None
if len(defs) > 1:
raise ValueError(f'found more than one function definition with the name {name} in module {module}')
return defs[0]
[docs]class FunctionDefinitionOrClassInitByNameExtractor(FunctionDefinitionByNameExtractor):
[docs] def visit_ClassDef(self, node):
if node.name == self.func_name:
# Found a class definition matching the name we're looking for
# Now look for the init method of that class
# TODO [#11]: deal with subclassing where __init__ will not be in class definition
orig_name = self.func_name
self.func_name = '__init__'
self.generic_visit(node)
self.func_name = orig_name
# Set back to looking for original name. Don't want to pull other inits
[docs]def extract_function_definitions_or_class_inits_from_ast_by_name(module: ast.AST, name: str) -> FunctionDefs:
fe = FunctionDefinitionOrClassInitByNameExtractor(name)
fe.visit(module)
return fe.defs
[docs]def extract_function_definition_or_class_init_from_ast_by_name(module: ast.AST, name: str) -> FunctionDefOrNone:
defs = extract_function_definitions_or_class_inits_from_ast_by_name(module, name)
if len(defs) == 0:
return None
if len(defs) > 1:
raise ValueError(f'found more than one function definition with the name {name} in module {module}')
return defs[0]