AutomaticHourglass
AutomaticHourglass

Reputation: 158

Accessing all functions recursively in globals()

I have managed to recursively go over the globals() and gather the functions recursively.

Here is the code so far:

def extract_functions(self, module_globals, depth=1, parent_name=''):
    """Extract all functions recursively from modules, starting from depth k down to 0."""
    if depth <= 0:  # Base case: stop when depth goes below 0
        # Return None only for the top-level call, otherwise empty dict for recursion
        if parent_name == '':
            return None
        return {}  # Return empty dict for recursive calls to avoid update() errors

    functions = {}
    
    # Add handling for module objects
    if hasattr(module_globals, '__dict__'):
        module_globals = module_globals.__dict__
    
    # Now handle dictionary-like objects
    if not hasattr(module_globals, 'items'):
        return functions
    
    # Create a copy of the dictionary so it's safe if the original dictionary changes
    items_to_process = list(module_globals.items())
    
    for name, obj in items_to_process:
        if name == '__builtins__':
            continue
        
        if parent_name == '':
            cur_name = name
        else:
            cur_name = f'{parent_name}.{name}'
        
        if inspect.isfunction(obj):
            substr = '.'.join(cur_name.split('.')[-3:])
            if substr in self.name_set:
                continue
            self.function_map[substr] = obj
            functions[substr] = obj
            
            # Analyze function body to find calls and imports
            try:
                source = inspect.getsource(obj)
                tree = ast.parse(source)
                self._analyze_function_body(tree, depth)
                
                # Also look for imports within the function
                self._process_imports_in_function(tree, module_globals)
            except (OSError, TypeError, SyntaxError):
                # Continue if source code can't be retrieved or parsed
                pass
        
        elif inspect.ismodule(obj):
            if name in self.module_list:
                continue
            else:
                self.module_list += [name]
            # Recursively search in submodule with decremented depth
            subfunctions = self.extract_functions(
                obj.__dict__,
                depth=depth - 1,
                parent_name=cur_name
            )
            functions.update(subfunctions)
    
    return self.function_map

when called as obj.extract_functions(globals(),2) it successfully traverses all libraries, (I hope) and returns as a dict.

However, when I try to parse the ast Tree from those functions, I cannot access to the other functions' trees, only able to access itself.

Is it possible to make this work by making ast trees traversable between functions?

Upvotes: 0

Views: 46

Answers (0)

Related Questions