Skip to content

Commit 7d237c6

Browse files
committed
Change deprecation function to take string or list of strings for convenience in the default, and adjust default deprecation stacklevel
Also put in workaround if sys._getframe doesn't work
1 parent 3b2a8b1 commit 7d237c6

File tree

3 files changed

+31
-11
lines changed

3 files changed

+31
-11
lines changed

python/ipywidgets/ipywidgets/widgets/tests/test_utils.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,8 @@ def test_deprecation():
1515
deprecation('Deprecated call', ['ipywidgets/widgets/tests'])
1616
# Make sure the deprecation pointed to the external function calling this test function
1717
assert w[0].filename.endswith('_pytest/python.py')
18+
19+
with pytest.deprecated_call() as w:
20+
deprecation('Deprecated call', 'ipywidgets/widgets/tests')
21+
# Make sure the deprecation pointed to the external function calling this test function
22+
assert w[0].filename.endswith('_pytest/python.py')

python/ipywidgets/ipywidgets/widgets/utils.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# Distributed under the terms of the Modified BSD License.
33

44
import sys
5+
import inspect
56
import warnings
67

78
# This function is from https://github.com/python/cpython/issues/67998
@@ -19,20 +20,34 @@ def _external_stacklevel(internal):
1920
"""
2021
# Get the level of my caller's caller
2122
level = 2
22-
frame = sys._getframe(level)
23+
24+
# sys._getframe is much faster than inspect.stack, but isn't guaranteed to
25+
# exist in all python implementations, so we fall back to inspect.stack()
26+
if hasattr(sys, '_getframe'):
27+
frame = sys._getframe(level)
28+
else:
29+
frame = inspect.stack(context=0)[level].frame
30+
31+
# climb the stack frames while we see internal frames
2332
while frame and any(s in frame.f_code.co_filename for s in internal):
2433
level +=1
2534
frame = frame.f_back
26-
# the returned value will be used one level up from here, so subtract one
35+
36+
# Return the stack level from the perspective of whoever called us (i.e., one level up)
2737
return level-1
2838

29-
def deprecation(message, internal=None):
30-
"""Generate a deprecation warning targeting the first frame outside the ipywidgets library.
39+
def deprecation(message, internal='ipywidgets/widgets/'):
40+
"""Generate a deprecation warning targeting the first frame that is not 'internal'
3141
32-
internal is a list of strings, which if they appear in filenames in the
33-
frames, the frames will also be considered internal. This can be useful if we know that ipywidgets
34-
is calling out to, for example, traitlets internally.
42+
internal is a string or list of strings, which if they appear in filenames in the
43+
frames, the frames will be considered internal. Changing this can be useful if, for examnple,
44+
we know that ipywidgets is calling out to traitlets internally.
3545
"""
36-
if internal is None:
37-
internal = []
38-
warnings.warn(message, DeprecationWarning, stacklevel=_external_stacklevel(internal+['ipywidgets/widgets/']))
46+
if isinstance(internal, str):
47+
internal = [internal]
48+
49+
# stack level of the first external frame from here
50+
stacklevel = _external_stacklevel(internal)
51+
52+
# The call to .warn adds one frame, so bump the stacklevel up by one
53+
warnings.warn(message, DeprecationWarning, stacklevel=stacklevel+1)

python/ipywidgets/ipywidgets/widgets/widget_button.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def _validate_icon(self, proposal):
7272
if 'fa-' in value:
7373
deprecation("icons names no longer need 'fa-', "
7474
"just use the class names themselves (for example, 'gear spin' instead of 'fa-gear fa-spin')",
75-
internal=['traitlets/traitlets.py', '/contextlib.py'])
75+
internal=['ipywidgets/widgets/', 'traitlets/traitlets.py', '/contextlib.py'])
7676
value = value.replace('fa-', '')
7777
return value
7878

0 commit comments

Comments
 (0)