Connect the Animation event source callback in the constructor.
Currently, there is no "official" way of knowing whether a Figure hosts an Animation. Yet, this information can be of interest e.g. for third-party backends. For example, a variant of the ipython inline backend could choose to actually animate its (inline) output in that case; indeed, this feature was already supported by the itermplot backend. itermplot is actually now outdated but the general idea can still be made to work -- I have a working patch for mplterm.
The idea is for the backend to override FigureCanvas.new_timer (on the backend-specific canvas subclass) to internally register any timer that gets created (e.g. by the animation module), then, when the canvas is show()n, to first trigger a fake draw_event so that animation callbacks (if any) get attached to the timer, and then to introspect what callbacks have been attached to the timer and retrieve any Animation instance from that.
While this all works, there is brittleness on a specific point, namely the need to trigger the fake draw_event (as the callback only gets attached in Animation._start) early in show(): at that point there may be no renderer available so one cannot construct a real DrawEvent (in fact, itermplot just sets renderer to None). If there are additional (end-user-provided) draw_event handlers connected, they may well error out on this fake draw_event.
Yet, it is easy to work around this problem, by connecting the animation stepping callback immediately to the timer when the Animation is constructed, rather than waiting for the first draw. The timer is still only started at the first draw, so nothing changes from the point of view of the end user.
Note that this does not create a strong reference holding the Animation in the "usual" case (of backends that don't keep a reference to the timers they create) -- it's just a reference loop of the Animation holding the Timer holding an Animation method as a callback. Furthermore, the callback could easily be replaced by a WeakMethod to completely get rid of the reference loop.
(If we agree on the change here I can also add a test that explicitly checks for this early-binding.)
Edit: Actually, a much simpler and more general issue with the "trigger draw to see what gets connected to the timer" is that that also starts the timer and therefore subsequent introspection becomes racy and may be too slow to catch the first frames.
PR summary
PR checklist
- [ ] "closes #0000" is in the body of the PR description to link the related issue
- [ ] new and changed code is tested
- [ ] Plotting related features are demonstrated in an example
- [ ] New Features and API Changes are noted with a directive and release note
- [ ] Documentation complies with general and docstring guidelines