diff --git a/ultraplot/axes/container.py b/ultraplot/axes/container.py index fdad0e01b..2afd07f4d 100644 --- a/ultraplot/axes/container.py +++ b/ultraplot/axes/container.py @@ -61,6 +61,14 @@ class ExternalAxesContainer(CartesianAxes): ``external_padding=2`` or ``external_padding=0`` to disable padding entirely. """ + _EXTERNAL_DELEGATE_BLOCKLIST = { + # Keep UltraPlot formatting/guide behaviors on the container. + "format", + "colorbar", + "legend", + "set_title", + } + def __init__( self, *args, external_axes_class=None, external_axes_kwargs=None, **kwargs ): @@ -799,28 +807,14 @@ def get_tightbbox(self, renderer, *args, **kwargs): def __getattr__(self, name): """ - Delegate attribute access to the external axes when not found on container. - - This allows the container to act as a transparent wrapper, forwarding - plotting methods and other attributes to the external axes. + Delegate missing attributes to the external axes unless blocked. """ - # Avoid infinite recursion for private attributes - # But allow parent class lookups during initialization - if name.startswith("_"): - # During initialization, let parent class handle private attributes - # This prevents interfering with parent class setup + if name in self._EXTERNAL_DELEGATE_BLOCKLIST: raise AttributeError( f"'{type(self).__name__}' object has no attribute '{name}'" ) - - # Try to get from external axes if it exists - if hasattr(self, "_external_axes") and self._external_axes is not None: - try: - return getattr(self._external_axes, name) - except AttributeError: - pass - - # Not found anywhere + if self._external_axes is not None: + return getattr(self._external_axes, name) raise AttributeError( f"'{type(self).__name__}' object has no attribute '{name}'" )