import inspect
from typing import Any, Callable


class private:
    """Decorator that raises if a _-prefixed method is called from outside its class."""

    func: Callable[..., Any]
    name: str
    owner: type

    def __init__(self, func: Callable[..., Any]) -> None:
        self.func = func
        self.name = getattr(func, "__name__", "<anonymous>")

    def __set_name__(self, owner: type, name: str) -> None:
        self.owner = owner

    def __get__(self, instance: Any, owner: type) -> Callable[..., Any]:
        # Walk up one frame to see who's calling
        frame = inspect.currentframe()
        if frame is None or frame.f_back is None:
            raise RuntimeError("cannot inspect caller frame")
        caller_frame = frame.f_back
        caller_self = caller_frame.f_locals.get("self")

        if not isinstance(caller_self, self.owner):
            raise RuntimeError(
                f"{self.owner.__name__}.{self.name} is private; "
                f"called from {caller_frame.f_code.co_name}"
            )

        return getattr(self.func, "__get__")(instance, owner)
