Stop leaking import machinery, and reject non-string colormaps cleanly#288
Conversation
Three small API-surface defects.
`xy.annotations` resolved to the `__future__._Feature` object left behind by
`from __future__ import annotations`, shadowing the annotation components
(`xy.hline`, `xy.callout`, ...) that the docs describe under that word.
`xy.Any`, `xy.TYPE_CHECKING` and `xy.import_module` were reachable the same way.
Delete the bindings once the module body no longer needs them, import `Any`
privately as `_Any`, and narrow `__dir__` to `__all__`.
`is_colormap` called `name.endswith("_r")` on whatever it received, so
`colormap=["#fff", "#f00"]` — the natural first guess for a custom ramp — raised
`AttributeError: 'list' object has no attribute 'endswith'` from library
internals, one line before the same path would have raised a ValueError naming
the supported colormaps. Type-guard it and answer the non-string case with a
message that names the real alternative: an (n, 3)/(n, 4) array as `color=`.
docs/components/facets-and-layers.md used `xy.legend(loc="top left")`. `loc` is
substring-matched against `upper`/`lower`, so `top` matches neither and the
example rendered a vertically centered legend; every other page uses
`upper left`.
`scripts/check_public_api.py` now asserts `dir(xy)` is exactly `__all__` and
that no non-module public name survives in the package globals, so this class of
leak fails CI rather than waiting to be noticed. Submodules are exempt because
importing one binds it on the package and that is import-order dependent.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Merging this PR will not alter performance
Comparing Footnotes
|
Stacked on #287. Three small API-surface defects; no screenshots because none of
these are visual.
1. Import machinery leaked into the public namespace
xy.annotationsresolved to the__future__._Featureobject left behind byfrom __future__ import annotations— shadowing the annotation components(
xy.hline,xy.callout, …) that the docs describe under exactly that word.xy.Any,xy.TYPE_CHECKINGandxy.import_modulewere reachable the same way.Delete the bindings once the module body no longer needs them, import
Anyprivately as
_Any, and narrow__dir__to__all__.2. A non-string
colormap=crashed from library internalsis_colormapcalledname.endswith("_r")on whatever it received, so thenatural first guess for a custom ramp raised an
AttributeErrorone line beforethe same path would have raised a
ValueErrornaming the supported colormaps:The message names the real alternative, which is a working but undocumented
capability.
3.
docs/components/facets-and-layers.mdshipped an invalidlocxy.legend(loc="top left").locis substring-matched againstupper/lower,so
topmatches neither and the example rendered a vertically centeredlegend — confirmed in-browser (
--xy-legend-top: 209pxwithtranslate(0,-50%)on a 420px chart). Every other page usesupper left.Guard
scripts/check_public_api.pynow assertsdir(xy)is exactly__all__andthat no non-module public name survives in the package globals, so this class of
leak fails CI instead of waiting to be noticed. Submodules are exempt —
importing one binds it on the package, which is import-order dependent (that
exemption is load-bearing: without it the check passes alone and fails inside
the full suite).
Found during a customizability audit.