Parse Python Function's Class Name

1.9k Views Asked by At

I am trying to find the class name where a function name is called.

E.g. suppose I have:

class foo1(object):
    bar1()

class foo2(object):
    bar2()

class foo3(object):
    bar3()

If I am searching for bar2() I want to receive:

class foo2(object):
    bar2()

I tried regex class[\s\S]*bar2\(\)(?!class) with the idea being that I would negative lookahead for another appearance of class. Unfortunately it looks like the [\s\S] is already matching everything: https://regex101.com/r/kZ7eE5/1

Is there a way to match if "class" appears only one time while matching on all other chars (including new line and tab)?

Also alternatives that do not require regex would be accepted.

3

There are 3 best solutions below

3
On BEST ANSWER

The RE approach can be error prone (the expressive power of Python language is more that those of the regular languages recognized by REs).

Use Python's ast module to parse Python code:

code = '''
class foo1(object):
    bar1()

class foo2(object):
    bar2()

class foo3(object):
    bar3()
'''

>>> import ast
>>> tree = ast.parse(code)
>>> for i in tree.body:
...     if isinstance(i, ast.ClassDef):
...         print('class: %s' % i.name)
...
class: foo1
class: foo2
class: foo3
>>>

and you can do many other things, check the docs at https://greentreesnakes.readthedocs.org/en/latest/

Edit: a more complete example:

>>> for i in tree.body:
...     if isinstance(i, ast.ClassDef):
...         for j in i.body:
...             if isinstance(j, ast.Expr):
...                 print('found a call to function %s in class %s' % (j.value.func.id, i.name))
...
found a call to function bar1 in class foo1
found a call to function bar2 in class foo2
found a call to function bar3 in class foo3
1
On

The reason [\s\S]* matches everything is because you are telling is to match either any space character (\s) or any non-space character (\S) any number of times. You can just match space with space in regex. Usually. There are exceptions, but python demands this form, so it should be fine.

You can use

^class ([\w]+)\([^)]+\):

Demo: https://regex101.com/r/aB9pX4/2

4
On

The following code prints the class that contains the method call that is stored in function variable .Here's what you need to do :

import re

data = """
class foo1(object):
    bar1()

class foo2(object):
    bar2()

class foo3(object):
    bar3()
"""

classes = re.findall('(class[\s\S]*?)(?=class|$)',data)
function = "bar2()"
for x in classes:
    if function in x:
        matched_class = x
        break
print(matched_class)

Output:

class foo2(object):
    bar2()