Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calculate correct stack level for deprecation warnings to show them to the user #3569

Merged
merged 12 commits into from
Oct 4, 2022

Conversation

jasongrout
Copy link
Member

@jasongrout jasongrout commented Aug 26, 2022

Generating deprecation warnings with the correct stacklevel is tricky to get right. Up to now, users have not been seeing these deprecation warnings because we had incorrect stacklevels. See python/cpython#68493 and python/cpython#67998 for good discussions, as well as ipython/ipython#8478 (comment) and ipython/ipython#8480 (comment) for more context.

We see these issues directly. Normally stacklevel=2 might be enough to target the caller of a function. However, in our deprecation warning in the init method, each level of subclasses adds one stack frame, so depending on the subclass, the appropriate stacklevel is different. Thus this PR implements a trick from a discussion in Python to calculate the first stack frame that is external to the ipywidgets library, and use that as the target stack frame for the deprecation warning.

This code should now produce 6 deprecation warnings in Jupyter Notebook or JupyterLab, whereas before it was producing no visible deprecation warnings.

import ipywidgets as w
def f(): pass
x=w.Text(description_tooltip='fda')
x.on_submit(f)
x.description_tooltip
x.description_tooltip='asdf'
w.FileUpload(description_tooltip='asdf')
w.Button(icon='fa-gear')

Screen Shot 2022-08-26 at 04 35 19

…o the user.

Generating deprecation warnings with the correct stacklevel is tricky to get right. Up to now, users have not been seeing these deprecation warnigns because they had incorrect stacklevels. See python/cpython#68493 and python/cpython#67998 for good discussions, as well as ipython/ipython#8478 (comment) and ipython/ipython#8480 (comment) for more context.

We see these issues directly. Normally stacklevel=2 might be enough to target the caller of a function. However, in our deprecation warning in the __init__ method, each level of subclasses adds one stack frame, so depending on the subclass, the appropriate stacklevel is different. Thus this PR implements a trick from a discussion in Python to calculate the first stack frame that is external to the ipywidgets library, and use that as the target stack frame for the deprecation warning.
@github-actions
Copy link

Binder 👈 Launch a binder notebook on branch jasongrout/ipywidgets/stacklevel

Copy link
Member

@vidartf vidartf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had two minor lints, but other than that this looks good!

Co-authored-by: Vidar Tonaas Fauske <vidartf@gmail.com>
@jasongrout jasongrout modified the milestones: 8.0, 8.0.x Aug 30, 2022
…vel deeper than it is being used.

Also, make the stack level calculator private until there is a need to make it public.
…vel deeper than it is being used.

    
Also, make the stack level calculator private until there is a need to make it public.
@jasongrout jasongrout requested a review from vidartf September 3, 2022 09:53
vidartf and others added 3 commits September 7, 2022 13:40
…venience in the default, and adjust default deprecation stacklevel

Also put in workaround if sys._getframe doesn't work
@jasongrout
Copy link
Member Author

I was about to push my tests and another fix as well - I'll work on incorporating your changes, especially your path separator fix - thanks!

@jasongrout
Copy link
Member Author

I see you are still pushing tests. Please let me know when you are done and I'll work on merging my tests and your tests.

@vidartf
Copy link
Member

vidartf commented Sep 7, 2022

I'm done, but please look at the bit there I removed the -1: AFAIU, the stack level is 1-based, not 0-based.

@vidartf
Copy link
Member

vidartf commented Sep 7, 2022

And sorry for not commenting that I was working on it!

@jasongrout
Copy link
Member Author

I'm done, but please look at the bit there I removed the -1: AFAIU, the stack level is 1-based, not 0-based.

I think it's more that stacklevel 0 is actually inside the warn function: https://github.com/python/cpython/blob/main/Lib/warnings.py#L298-L310

…ized

Because deprecated attributes of the Widget class are static attributes, they will be accessed when initializing this class by traitlets. In that case, since a user did not explicitly try to use these attributes, we do not want to throw a deprecation warning. So we check if the thing calling these static properties is one of the known initialization functions in traitlets.
@jasongrout
Copy link
Member Author

@vidartf - I merged your changes in and I think this is ready for another review from you.

@jasongrout jasongrout requested review from vidartf and removed request for vidartf September 16, 2022 17:25
Copy link
Member

@maartenbreddels maartenbreddels left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, also on the traitlet path (a complexity I guess I introduced), I've also checked it on the python repl:

>>> w.Text(description_tooltip="fda")
<stdin>:1: DeprecationWarning: the description_tooltip argument is deprecated, use tooltip instead
Text(value='', tooltip='fda')

👍

@ibdafna ibdafna merged commit e3d8fe5 into jupyter-widgets:master Oct 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants