pythonstatic-analysismethod-signature

Python: Making a function signature *without* inspect


I am working on a static code analyzer. Given the python file defining classes and methods, I'd like to construct a Signature object for all functions.

For instance, given the following function:

def method_with_args(self, param_a: str, param_b: int = 123) -> str:
        """
        Method with arguments and a return value.

        Args:
            param_a (str): A string parameter.
            param_b (int): An integer parameter.

        Returns:
            str: Concatenation of param1 and string representation of param2.
        """
        return param_a + str(param_b)

I want to get something like:

<Signature (self, param_a: str, param_b: int = 123) -> str>

I know I can achieve this using inspect, however, I do not want to import the analyzed code, and this must be done statically.

Is there a straightforward way to do this?


Solution

  • You can use Python's ast module to treat the code as text and parse it into an abstract syntax tree:

    import ast
    
    s = '''
    def method_with_args(self, param_a: str, param_b: int = 123) -> str:
        """
        Method with arguments and a return value.
    
        Args:
            param_a (str): A string parameter.
            param_b (int): An integer parameter.
    
        Returns:
            str: Concatenation of param1 and string representation of param2.
        """
        return param_a + str(param_b)
    '''
    
    tree = ast.parse(s)
    

    Then you can iterate over the nodes in the tree and look for classes, methods, functions or whatever else you are interested in and inspect its contents to construct a signature:

    
    for node in tree.body:
        if isinstance(node, ast.FunctionDef):
            print([x.arg for x in node.args.args])
            print([x.arg for x in node.args.kwonlyargs])
            print(node.args.vararg)
            print(node.args.kwarg)
            ...