I was doing some recursive stuff in python and thought it might be neat to see if you can detect recursion at runtime in python. It turned out to be pretty simple with the help of the standard library’s inspect module.

from functools import wraps
import inspect

class RecursionDetected(RuntimeError):
    """function has been detected to be recursing"""

def not_recursive(f):
    """
    raise an exception if recursive
    """
    @wraps(f)
    def wrapper(*args, **kwargs):
        for frame in inspect.stack():
            if f.__name__ == frame.function:
                raise RecursionDetected(
                    f"function '{f.__name__}' is recursive"
                )

        return f(*args, **kwargs)
    return wrapper

# Examples

@not_recursive
def foo():
    pass

foo()
# works

@not_recursive
def bar(x = 10):
    if x == 0:
        return
    bar(x - 1)

bar()
# RecursionDetected: function 'bar' is recursive

# even works when the function doesn't directly call itself
def call_thunk(thunk):
    thunk()

@not_recursive
def buzz(x = 10):
    if x == 0:
        return
    call_thunk(lambda: buzz(x-1))

buzz()
# RecursionDetected: function 'buzz' is recursive