Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 12 additions & 18 deletions ultraplot/axes/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
):
Expand Down Expand Up @@ -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}'"
)
Expand Down
Loading