diff --git a/src/bonsai/bonsai/core/tool.py b/src/bonsai/bonsai/core/tool.py index 3a7871268f..fc928cf519 100644 --- a/src/bonsai/bonsai/core/tool.py +++ b/src/bonsai/bonsai/core/tool.py @@ -28,7 +28,9 @@ from typing import Optional class Interface(abc.ABC): pass def interface(cls): attrs = {n: classmethod(abc.abstractmethod(f)) for n, f in inspect.getmembers(cls, predicate=inspect.isfunction)} - return type(cls.__name__, (Interface, cls), attrs) + new_cls = type(cls.__name__, (Interface, cls), attrs) + new_cls.__original_qualname__ = cls.__module__ + "." + cls.__qualname__ + return new_cls # ############################################################################ # diff --git a/src/bonsai/test/core/bootstrap.py b/src/bonsai/test/core/bootstrap.py index 1f249e22b7..48722059bd 100644 --- a/src/bonsai/test/core/bootstrap.py +++ b/src/bonsai/test/core/bootstrap.py @@ -272,7 +272,7 @@ class Prophecy: def __getattr__(self, attr: str): if not hasattr(self.subject, attr): - raise AttributeError(f"Prophecy {self.subject} has no attribute {attr}") + raise AttributeError(f"Interface '{self.subject.__original_qualname__}' has no attribute '{attr}'.") # It also returns `Any` but it only happens during `subject.xxx` call. def decorate(*args: Any, **kwargs: Any) -> Self: @@ -317,7 +317,7 @@ class Prophecy: raise Exception(f"Called {count}: {prediction}") else: if prediction["call"] not in self.calls: - error_msg = f"{self.subject} was not called with {prediction['call']['name']}:\n - {prediction}" + error_msg = f"Interface '{self.subject.__original_qualname__}' was not called with {prediction['call']['name']}:\n - {prediction}" # Print all unprocessed calls if pytest was started in verbose mode. if "-v" in sys.argv or "-vv" in sys.argv: