Skip to content

Commit 5482959

Browse files
committed
Add tests and fix level
1 parent 77e609d commit 5482959

File tree

3 files changed

+67
-4
lines changed

3 files changed

+67
-4
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
2+
from pathlib import Path
3+
from unittest.mock import patch
4+
5+
import pytest
6+
7+
from ipywidgets.widgets.utils import deprecation
8+
from ipywidgets.widgets.tests.utils import call_method
9+
10+
@patch("ipywidgets.widgets.utils._IPYWIDGETS_INTERNAL", [])
11+
def test_deprecation_direct():
12+
with pytest.warns(DeprecationWarning) as record:
13+
deprecation("test message")
14+
assert len(record) == 1
15+
assert record[0].filename == __file__
16+
17+
@patch("ipywidgets.widgets.utils._IPYWIDGETS_INTERNAL", [])
18+
def test_deprecation_indirect():
19+
# If the line that calls "deprecation" is not internal, it is considered the source:
20+
with pytest.warns(DeprecationWarning) as record:
21+
call_method(deprecation, "test message")
22+
assert len(record) == 1
23+
assert Path(record[0].filename) == Path(__file__, '..', 'utils.py').resolve()
24+
25+
@patch("ipywidgets.widgets.utils._IPYWIDGETS_INTERNAL", [str(Path(__file__, '..', 'utils.py').resolve())])
26+
def test_deprecation_indirect_internal():
27+
# If the line that calls "deprecation" is internal, it is not considered the source:
28+
with pytest.warns(DeprecationWarning) as record:
29+
call_method(deprecation, "test message")
30+
assert len(record) == 1
31+
assert record[0].filename == __file__
32+
33+
@patch("ipywidgets.widgets.utils._IPYWIDGETS_INTERNAL", [])
34+
def test_deprecation_nested1():
35+
def level1():
36+
deprecation("test message")
37+
38+
with pytest.warns(DeprecationWarning) as record:
39+
call_method(level1)
40+
41+
assert len(record) == 1
42+
assert record[0].filename == __file__
43+
44+
@patch("ipywidgets.widgets.utils._IPYWIDGETS_INTERNAL", [])
45+
def test_deprecation_nested2():
46+
def level2():
47+
deprecation("test message")
48+
def level1():
49+
level2()
50+
51+
with pytest.warns(DeprecationWarning) as record:
52+
call_method(level1)
53+
54+
assert len(record) == 1
55+
assert record[0].filename == __file__
56+

python/ipywidgets/ipywidgets/widgets/tests/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,6 @@ def setup():
4545

4646
def teardown():
4747
teardown_test_comm()
48+
49+
def call_method(method, *args, **kwargs):
50+
method(*args, **kwargs)

python/ipywidgets/ipywidgets/widgets/utils.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
# Copyright (c) Jupyter Development Team.
22
# Distributed under the terms of the Modified BSD License.
33

4+
from pathlib import Path
45
import sys
56
import warnings
67

8+
_IPYWIDGETS_INTERNAL = ['ipywidgets/widgets/']
9+
710
# This function is from https://github.com/python/cpython/issues/67998
811
# (https://bugs.python.org/file39550/deprecated_module_stacklevel.diff) and
912
# calculates the appropriate stacklevel for deprecations to target the
@@ -20,19 +23,20 @@ def _external_stacklevel(internal):
2023
# Get the level of my caller's caller
2124
level = 2
2225
frame = sys._getframe(level)
23-
while frame and any(s in frame.f_code.co_filename for s in internal):
26+
# Normalize the path separators:
27+
while frame and any(str(Path(s)) in str(Path(frame.f_code.co_filename)) for s in internal):
2428
level +=1
2529
frame = frame.f_back
2630
# the returned value will be used one level up from here, so subtract one
27-
return level-1
31+
return level
2832

2933
def deprecation(message, internal=None):
3034
"""Generate a deprecation warning targeting the first frame outside the ipywidgets library.
31-
35+
3236
internal is a list of strings, which if they appear in filenames in the
3337
frames, the frames will also be considered internal. This can be useful if we know that ipywidgets
3438
is calling out to, for example, traitlets internally.
3539
"""
3640
if internal is None:
3741
internal = []
38-
warnings.warn(message, DeprecationWarning, stacklevel=_external_stacklevel(internal+['ipywidgets/widgets/']))
42+
warnings.warn(message, DeprecationWarning, stacklevel=_external_stacklevel(internal + _IPYWIDGETS_INTERNAL))

0 commit comments

Comments
 (0)