Configurable should warn on unrecognized arguments
Currently direct HasTraits subclasses warn when they receive unrecognized arguments:
https://github.com/ipython/traitlets/blob/b0eaa6aa77e198cff68644a388400db850670c7d/tests/test_traitlets.py#L2802-L2810
However, this does not work with Configurable and its subclasses, although it is a subclass of HasTraits:
https://github.com/ipython/traitlets/blob/b0eaa6aa77e198cff68644a388400db850670c7d/traitlets/config/configurable.py#L53
Context
This is implemented in:
https://github.com/ipython/traitlets/blob/b0eaa6aa77e198cff68644a388400db850670c7d/traitlets/traitlets.py#L1381-L1399
Related to https://github.com/ipython/traitlets/issues/145.
I think this may be specific to IPython's handling of deprecation warnings, which I believe tries to only show deprecations caused directly by the interactive session, and not transitively.
stacklevel=2 in the warning means the warning points to Configurable.__init__, which IPython doesn't show by default. But running a regular script with PYTHONWARNINGS=d does show the warning:
from traitlets.config import Configurable
c = Configurable(x=1)
> PYTHONWARNINGS=d python test.py
lib/python3.12/site-packages/traitlets/traitlets.py:1385: DeprecationWarning: Passing unrecognized arguments to super(Configurable).__init__(x=1).
object.__init__() takes exactly one argument (the instance to initialize)
This is deprecated in traitlets 4.2.This error will be raised in a future release of traitlets.
warn(
In fact, I think the correct stacklevel for HasTraits is 3 and for Configurable it should be 4. 2 isn't right like it is for a typical method, though I don't really understand why not.
What should we do about this? The leads to some mistakes when IPython.embed() is run and users make typos in keyword arguments, so I suppose this is an IPython issue?
Besides, should it be a DeprecationWarning, or a UserWarning? It is both, but I feel like this should never be suppressed.
This warning is displayed where DeprecationWarnings are enabled when you call e.g. IPython.embed(a=5).
But I think it's fine to switch it to a UserWarning, since it is always a bug in the calling code when this happens.
FWIW, this warning was initially a RuntimeWarning in #177 but demoted to DeprecationWarning in #188 because of how often it was triggered and not actionable. But that was 10 years ago, so turning it back to RuntimeWarning or UserWarning now probably makes sense (I still have no clear grasp on what most warning classes are for).