Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find out if (the source code of) a function contains a call to a method from a specific module?

Let's say, I have a bunch of functions a, b, c, d and e and I want to find out if they call any method from the random module:

def a():
    pass

def b():
    import random

def c():
    import random
    random.randint(0, 1)

def d():
    import random as ra
    ra.randint(0, 1)

def e():
    from random import randint as ra
    ra(0, 1)

I want to write a function uses_module so I can expect these assertions to pass:

assert uses_module(a) == False
assert uses_module(b) == False
assert uses_module(c) == True
assert uses_module(d) == True
assert uses_module(e) == True

(uses_module(b) is False because random is only imported but never one of its methods called.)

I can't modify a, b, c, d and e. So I thought it might be possible to use ast for this and walk along the function's code which I get from inspect.getsource. But I'm open to any other proposals, this was only an idea how it could work.

This is as far as I've come with ast:

def uses_module(function):
    import ast
    import inspect
    nodes = ast.walk(ast.parse(inspect.getsource(function)))
    for node in nodes:
        print(node.__dict__)
like image 691
finefoot Avatar asked Dec 16 '18 00:12

finefoot


People also ask

How do you find the source code of a function in Python?

We use the getsource() method of inspect module to get the source code of the function. Returns the text of the source code for an object. The argument may be a module, class, method, function, traceback, frame, or code object. The source code is returned as a single string.

What is __ main __ in Python?

__main__ is the name of the environment where top-level code is run. “Top-level code” is the first user-specified Python module that starts running. It's “top-level” because it imports all other modules that the program needs. Sometimes “top-level code” is called an entry point to the application.

How do I see what methods are in a Python module?

You can use dir(module) to see all available methods/attributes.

How do you list the functions in a module?

We can list down all the functions present in a Python module by simply using the dir() method in the Python shell or in the command prompt shell.


1 Answers

This is a work in progress, but perhaps it will spark a better idea. I am using the types of nodes in the AST to attempt to assert that a module is imported and some function it provides is used.

I have added what may be the necessary pieces to determine that this is the case to a checker defaultdict which can be evaluated for some set of conditions, but I am not using all key value pairs to establish an assertion for your use cases.

def uses_module(function):
    """
    (WIP) assert that a function uses a module
    """
    import ast
    import inspect
    nodes = ast.walk(ast.parse(inspect.getsource(function)))
    checker = defaultdict(set)
    for node in nodes:
        if type(node) in [ast.alias, ast.Import, ast.Name, ast.Attribute]:
            nd = node.__dict__
            if type(node) == ast.alias:
                checker['alias'].add(nd.get('name'))
            if nd.get('name') and nd.get('asname'):
                checker['name'].add(nd.get('name'))
                checker['asname'].add(nd.get('asname'))
            if nd.get('ctx') and nd.get('attr'):
                checker['attr'].add(nd.get('attr'))
            if nd.get('id'):
                checker['id'].add(hex(id(nd.get('ctx'))))
            if nd.get('value') and nd.get('ctx'):
                checker['value'].add(hex(id(nd.get('ctx'))))

    # print(dict(checker)) for debug

    # This check passes your use cases, but probably needs to be expanded
    if checker.get('alias') and checker.get('id'):
        return True
    return False
like image 86
Wes Doyle Avatar answered Oct 05 '22 00:10

Wes Doyle