from typing import Any
import inspect
import builtins


def to_import_string(attr: Any) -> str:
    """Retrieve import string from attribute.

    Parameters
    ----------
    attr : Any
        Any python function, class or method
    """
    if inspect.ismodule(attr):
        return attr.__name__
    module = inspect.getmodule(attr)
    if module is None:
        raise ValueError(f"Unable to resolve module of {attr}")

    # If class, method or function, use __qualname__
    if inspect.isclass(attr) or inspect.ismethod(attr) or inspect.isfunction(attr):
        if module is builtins:
            return attr.__qualname__
        else:
            return f"{module.__name__}.{attr.__qualname__}"

    # Look for the instance's name in the user-defined module
    for name, member in inspect.getmembers(module):
        if id(member) == id(attr):
            return f"{module.__name__}.{name}"

    raise ValueError(f"Unable to resolve import string of {attr}")