diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index 22c804b88da5..8323d7e67373 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -1990,6 +1990,9 @@ def _warn_external(message, category=None): """ frame = sys._getframe() for stacklevel in itertools.count(1): # lgtm[py/unused-loop-variable] + if frame is None: + # when called in embedded context may hit frame is None + break if not re.match(r"\A(matplotlib|mpl_toolkits)(\Z|\.)", # Work around sphinx-gallery not setting __name__. frame.f_globals.get("__name__", "")): diff --git a/lib/matplotlib/tests/test_cbook.py b/lib/matplotlib/tests/test_cbook.py index 69b887020d91..6c250ed524e5 100644 --- a/lib/matplotlib/tests/test_cbook.py +++ b/lib/matplotlib/tests/test_cbook.py @@ -2,6 +2,7 @@ import pickle from weakref import ref import warnings +from unittest.mock import patch, Mock from datetime import datetime @@ -350,6 +351,15 @@ def test_normalize_kwargs_pass(inp, expected, kwargs_to_norm): assert len(w) == 0 +def test_warn_external_frame_embedded_python(): + with patch.object(cbook, "sys") as mock_sys: + mock_sys._getframe = Mock(return_value=None) + with warnings.catch_warnings(record=True) as w: + cbook._warn_external("dummy") + assert len(w) == 1 + assert str(w[0].message) == "dummy" + + def test_to_prestep(): x = np.arange(4) y1 = np.arange(4)