fix: trplot/trplot2 silently swallowed unknown keyword arguments - #230
Open
petercorke wants to merge 1 commit into
Open
petercorke wants to merge 1 commit into
petercorke wants to merge 1 commit into
Conversation
Both trplot() and trplot2() ended with a bare **kwargs that was never read anywhere in their bodies, so a typo'd keyword (e.g. framelabel= instead of frame=) was silently accepted and ignored instead of raising -- it drew the frame with no error and no label at all. Removing the dead sink lets Python's own unexpected-keyword-argument check do its job. While rewriting the two places that used to lean on this catch-all: - trplot's anaglyph branch only forwarded a small fixed subset of parameters to each eye's recursive call, silently dropping textcolor, labels, originsize, origincolor, axislabel, axissubscript, width and projection; it also never returned ax and never actually called plt.show(block=...), so anaglyph mode ignored block entirely. - trplot's "T is an iterable of transforms" branch forwarded every parameter except axissubscript, and also never returned ax. - tranimate/tranimate2 were splatting the same unfiltered kwargs dict into Animate()/Animate2()'s constructor, the drawing call, and run()'s animation-control call, relying on each one's own dead **kwargs sink to drop what it didn't need. Once trplot/trplot2 validate strictly, run()-only parameters (movie, repeat, interval, nframes, wait) needed to be split off before the drawing call. Also fixes a long-standing typo in test_pose2d.py::test_graphics (T0=T2, which was never a real parameter -- animate()'s documented one is start=) that this same silent-swallow bug had been quietly masking. Adds tests/base/test_animate.py: constructing a FuncAnimation under a non-interactive backend doesn't actually run its per-frame update() callback (confirmed directly -- Animate2's frame counter never advances past its initial value), so existing animate() tests only proved construction didn't raise. These tests force every frame through the real callback via FuncAnimation.save() (PillowWriter, no external ffmpeg dependency) and assert trinterp/trinterp2 actually ran across a real s: 0->1 sweep. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
trplot()andtrplot2()both ended with a bare**kwargsthat was never read anywhere in their bodies, so a typo'd keyword (e.g.framelabel=instead offrame=) was silently accepted and ignored instead of raising — it drew the frame with no error and no label at all. This surfaced downstream in petercorke/RVC3-python#50, where a notebook had exactly this typo for years with no test ever catching it.**kwargssink from both functions so an unrecognized keyword now raisesTypeError, same as any normal Python call.trplot'sanaglyphbranch only forwarded a small fixed subset of parameters to each eye's recursive call, silently droppingtextcolor,labels,originsize,origincolor,axislabel,axissubscript,widthandprojection. It also never returnedaxand never actually calledplt.show(block=...), so anaglyph mode ignoredblockentirely. Fixed to forward the full applicable parameter set, returnax, and callplt.show()once after both eyes are drawn.trplot's "T is an iterable of transforms" branch forwarded every parameter exceptaxissubscript, and also never returnedax. Fixed.tranimate/tranimate2were splatting the same unfiltered kwargs dict intoAnimate()/Animate2()'s constructor, the drawing call, andrun()'s animation-control call, relying on each one's own dead**kwargssink to drop what it didn't need. Now thattrplot/trplot2validate strictly,run()-only parameters (movie,repeat,interval,nframes,wait) are split off before the drawing call.test_pose2d.py::test_graphics(T0=T2, which was never a real parameter —animate()'s documented one isstart=) that this same silent-swallow bug had been quietly masking since the test was written.New test coverage
Added
tests/base/test_animate.py. While chasing thetranimate/tranimate2regression above, I found that constructing aFuncAnimationunder a non-interactive backend (the Agg backend this repo's whole test suite runs under) doesn't actually run its per-frameupdate()callback — confirmed directly by checkingAnimate2's internal frame counter, which never advances past its initial value unless something drives the animation. So the existinganimate()/tranimate()tests only ever proved construction didn't raise, not that interpolation/drawing works.The new tests force every frame through the real callback via
FuncAnimation.save()withPillowWriter(pure Python, no externalffmpegdependency) and asserttrinterp/trinterp2actually ran across a reals: 0→1sweep. This is what caught thetranimate/tranimate2kwargs-splitting bug above in the first place.Test plan
353 passed, 3 skipped(skips are pre-existing, display-dependent)SE3/SE2.plot()/.animate()wrapper methods (which forward*args, **kwargsstraight through) verified to propagate the stricter validation correctly🤖 Generated with Claude Code