def get_signatures_using_eval(
    document: Document, locals: dict[str, Any], globals: dict[str, Any]
) -> list[Signature]:
    """
    Look for the signature of the function before the cursor position without
    use of Jedi. This uses a similar approach as the `DictionaryCompleter` of
    running `eval()` over the detected function name.
    """
    # Look for open parenthesis, before cursor position.
    pos = document.cursor_position - 1

    paren_mapping = {")": "(", "}": "{", "]": "["}
    paren_stack = [
        ")"
    ]  # Start stack with closing ')'. We are going to look for the matching open ')'.
    comma_count = 0  # Number of comma's between start of function call and cursor pos.
    found_start = False  # Found something.

    while pos >= 0:
        char = document.text[pos]
        if char in ")]}":
            paren_stack.append(char)
        elif char in "([{":
            if not paren_stack:
                # Open paren, while no closing paren was found. Mouse cursor is
                # positioned in nested parentheses. Not at the "top-level" of a
                # function call.
                break
            if paren_mapping[paren_stack[-1]] != char:
                # Unmatching parentheses: syntax error?
                break

            paren_stack.pop()

            if len(paren_stack) == 0:
                found_start = True
                break

        elif char == "," and len(paren_stack) == 1:
            comma_count += 1

        pos -= 1

    if not found_start:
        return []

    # We found the start of the function call. Now look for the object before
    # this position on which we can do an 'eval' to retrieve the function
    # object.
    obj = DictionaryCompleter(lambda: globals, lambda: locals).eval_expression(
        Document(document.text, cursor_position=pos), locals
    )
    if obj is None:
        return []

    try:
        name = obj.__name__  # type:ignore
    except Exception:
        name = obj.__class__.__name__

    try:
        signature = inspect.signature(obj)  # type: ignore
    except TypeError:
        return []  # Not a callable object.
    except ValueError:
        return []  # No signature found, like for build-ins like "print".

    try:
        doc = obj.__doc__ or ""
    except:
        doc = ""

    # TODO: `index` is not yet correct when dealing with keyword-only arguments.
    return [Signature.from_inspect_signature(name, doc, signature, index=comma_count)]

    Look for the signature of the function before the cursor position without
    use of Jedi. This uses a similar approach as the `DictionaryCompleter` of
    running `eval()` over the detected function name.
    
src/ptpython/signatures.py