Found while reviewing #698 (SubplotManager extraction). Not a regression — the signatures are correct today. This is about a trap that has already fired once.
The coupling
ultraplot/ui.py uses _pop_params to decide which keyword arguments belong to the subplot and which belong to the figure, and it does so by introspecting the signature of two Figure methods:
# ui.py:185
kwsub.update(_pop_params(kwargs, pfigure.Figure._parse_proj))
# ui.py:230
kwsubs.update(_pop_params(kwargs, pfigure.Figure._add_subplots))
After #698, Figure._parse_proj and Figure._add_subplots are pure delegators to SubplotManager. Their bodies do nothing but forward. Their only remaining job is to carry a parameter list that mirrors the manager's — a contract enforced by nothing but a docstring NOTE:.
Why this is not hypothetical
It already broke. During #698, an earlier commit collapsed _parse_proj to (*args, **kwargs). _pop_params then saw no proj/projection/proj_kw parameters, routed proj= to the figure instead of the subplot, and uplt.subplot(proj='polar') silently raised from Figure.set(). Commit 537f794 fixed it by spelling the parameters back out.
So the failure mode is: a reasonable-looking cleanup of a method that appears to be a trivial pass-through silently breaks projection handling, with no type error and no local test failure.
Suggested fix
Point _pop_params at the functions that actually own the parameters, so the signature and its meaning live in one place:
from ._subplots import SubplotManager
kwsub.update(_pop_params(kwargs, SubplotManager.parse_proj))
kwsubs.update(_pop_params(kwargs, SubplotManager.add_subplots))
Figure._parse_proj / ._add_subplots can then go back to thin (*args, **kwargs) delegators and the drift hazard disappears entirely.
This matters more as the rest of the manager split in #677 lands — each future extraction is exactly the kind of change that steps on this.
Found while reviewing #698 (SubplotManager extraction). Not a regression — the signatures are correct today. This is about a trap that has already fired once.
The coupling
ultraplot/ui.pyuses_pop_paramsto decide which keyword arguments belong to the subplot and which belong to the figure, and it does so by introspecting the signature of twoFiguremethods:After #698,
Figure._parse_projandFigure._add_subplotsare pure delegators toSubplotManager. Their bodies do nothing but forward. Their only remaining job is to carry a parameter list that mirrors the manager's — a contract enforced by nothing but a docstringNOTE:.Why this is not hypothetical
It already broke. During #698, an earlier commit collapsed
_parse_projto(*args, **kwargs)._pop_paramsthen saw noproj/projection/proj_kwparameters, routedproj=to the figure instead of the subplot, anduplt.subplot(proj='polar')silently raised fromFigure.set(). Commit537f794fixed it by spelling the parameters back out.So the failure mode is: a reasonable-looking cleanup of a method that appears to be a trivial pass-through silently breaks projection handling, with no type error and no local test failure.
Suggested fix
Point
_pop_paramsat the functions that actually own the parameters, so the signature and its meaning live in one place:Figure._parse_proj/._add_subplotscan then go back to thin(*args, **kwargs)delegators and the drift hazard disappears entirely.This matters more as the rest of the manager split in #677 lands — each future extraction is exactly the kind of change that steps on this.