2
2
# Distributed under the terms of the Modified BSD License.
3
3
4
4
import sys
5
+ import inspect
5
6
import warnings
6
7
7
8
# This function is from https://github.com/python/cpython/issues/67998
@@ -19,20 +20,34 @@ def _external_stacklevel(internal):
19
20
"""
20
21
# Get the level of my caller's caller
21
22
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
23
32
while frame and any (s in frame .f_code .co_filename for s in internal ):
24
33
level += 1
25
34
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)
27
37
return level - 1
28
38
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'
31
41
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.
35
45
"""
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 )
0 commit comments