Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 217e695

Browse files
author
Alon Hershenhorn
committed
1) Added stacklevel=2 to all warnings.warn calls that didn't have stacklevel set. 2) Added new section to contributing.rst adivising to set stacklevel when using warnings.warn
1 parent 3fdf3c0 commit 217e695

39 files changed

+137
-113
lines changed

doc/devel/contributing.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,33 @@ says why.
473473
`logging.debug` is the least likely to be displayed, and hence can
474474
be the most verbose.
475475

476+
Using stacklevel in warnings.warn
477+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
478+
The default code line displayed when calling `warnings.warn` is the line
479+
that has the warning call. This usually isn't more informative than the
480+
warning message itself.
481+
482+
Therefore, when using `warnings.warn`, set *stacklevel=2* (or higher)
483+
so that the source line that's displayed in the warning message is
484+
the line triggering the code. ::
485+
486+
def set_range(bottom, top):
487+
if bottom == top:
488+
warnings.warn('Attempting to set identical bottom==top', stacklevel=2)
489+
490+
set_range(0,0) #set range
491+
492+
will display::
493+
494+
UserWarning: Attempting to set identical bottom==top
495+
set_range(0,0) #set range
496+
497+
instead of the default::
498+
499+
UserWarning: Attempting to set identical bottom==top
500+
warnings.warn('Attempting to set identical bottom==top')
501+
502+
476503
.. _custom_backend:
477504

478505
Developing a new backend

lib/matplotlib/__init__.py

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ def _set_logger_verbose_level(level_str='silent', file_str='sys.stdout'):
247247
except IOError:
248248
warnings.warn('could not open log file "{0}"'
249249
'for writing. Check your '
250-
'matplotlibrc'.format(file_str))
250+
'matplotlibrc'.format(file_str), stacklevel=2)
251251
console = logging.StreamHandler(fileo)
252252
console.setLevel(newlev)
253253
_log.addHandler(console)
@@ -309,7 +309,7 @@ def set_level(self, level):
309309
level = self._commandLineVerbose
310310
if level not in self.levels:
311311
warnings.warn('matplotlib: unrecognized --verbose-* string "%s".'
312-
' Legal values are %s' % (level, self.levels))
312+
' Legal values are %s' % (level, self.levels), stacklevel=2)
313313
else:
314314
self.level = level
315315

@@ -490,7 +490,7 @@ def checkdep_ps_distiller(s):
490490
flag = False
491491
warnings.warn(('matplotlibrc ps.usedistiller option can not be used '
492492
'unless ghostscript-%s or later is installed on your '
493-
'system') % gs_req)
493+
'system') % gs_req, stacklevel=2)
494494

495495
if s == 'xpdf':
496496
pdftops_req = '3.0'
@@ -505,7 +505,7 @@ def checkdep_ps_distiller(s):
505505
flag = False
506506
warnings.warn(('matplotlibrc ps.usedistiller can not be set to '
507507
'xpdf unless xpdf-%s or later is installed on '
508-
'your system') % pdftops_req)
508+
'your system') % pdftops_req, stacklevel=2)
509509

510510
if flag:
511511
return s
@@ -524,21 +524,21 @@ def checkdep_usetex(s):
524524
if shutil.which("tex") is None:
525525
flag = False
526526
warnings.warn('matplotlibrc text.usetex option can not be used unless '
527-
'TeX is installed on your system')
527+
'TeX is installed on your system', stacklevel=2)
528528

529529
dvipng_v = checkdep_dvipng()
530530
if not compare_versions(dvipng_v, dvipng_req):
531531
flag = False
532532
warnings.warn('matplotlibrc text.usetex can not be used with *Agg '
533533
'backend unless dvipng-%s or later is installed on '
534-
'your system' % dvipng_req)
534+
'your system' % dvipng_req, stacklevel=2)
535535

536536
gs_exec, gs_v = checkdep_ghostscript()
537537
if not compare_versions(gs_v, gs_req):
538538
flag = False
539539
warnings.warn('matplotlibrc text.usetex can not be used unless '
540540
'ghostscript-%s or later is installed on your system'
541-
% gs_req)
541+
% gs_req, stacklevel=2)
542542

543543
return flag
544544

@@ -924,7 +924,7 @@ def rc_params(fail_on_error=False):
924924
ret = RcParams([(key, default) for key, (default, _) in
925925
defaultParams.items()
926926
if key not in _all_deprecated])
927-
warnings.warn(message)
927+
warnings.warn(message, stacklevel=2)
928928
return ret
929929

930930
return rc_params_from_file(fname, fail_on_error)
@@ -973,21 +973,21 @@ def _rc_params_in_file(fname, fail_on_error=False):
973973
tup = strippedline.split(':', 1)
974974
if len(tup) != 2:
975975
error_details = _error_details_fmt % (cnt, line, fname)
976-
warnings.warn('Illegal %s' % error_details)
976+
warnings.warn('Illegal %s' % error_details, stacklevel=2)
977977
continue
978978
key, val = tup
979979
key = key.strip()
980980
val = val.strip()
981981
if key in rc_temp:
982982
warnings.warn('Duplicate key in file "%s", line #%d' %
983-
(fname, cnt))
983+
(fname, cnt), stacklevel=2)
984984
rc_temp[key] = (val, line, cnt)
985985
except UnicodeDecodeError:
986986
warnings.warn(
987987
('Cannot decode configuration file %s with '
988988
'encoding %s, check LANG and LC_* variables')
989989
% (fname, locale.getpreferredencoding(do_setlocale=False) or
990-
'utf-8 (default)'))
990+
'utf-8 (default)'), stacklevel=2)
991991
raise
992992

993993
config = RcParams()
@@ -1003,7 +1003,7 @@ def _rc_params_in_file(fname, fail_on_error=False):
10031003
except Exception as msg:
10041004
error_details = _error_details_fmt % (cnt, line, fname)
10051005
warnings.warn('Bad val "%s" on %s\n\t%s' %
1006-
(val, error_details, msg))
1006+
(val, error_details, msg), stacklevel=2)
10071007

10081008
for key, (val, line, cnt) in rc_temp.items():
10091009
if key in defaultParams:
@@ -1015,7 +1015,7 @@ def _rc_params_in_file(fname, fail_on_error=False):
10151015
except Exception as msg:
10161016
error_details = _error_details_fmt % (cnt, line, fname)
10171017
warnings.warn('Bad val "%s" on %s\n\t%s' %
1018-
(val, error_details, msg))
1018+
(val, error_details, msg), stacklevel=2)
10191019
elif key in _deprecated_ignore_map:
10201020
version, alt_key = _deprecated_ignore_map[key]
10211021
cbook.warn_deprecated(
@@ -1349,8 +1349,7 @@ def use(arg, warn=True, force=False):
13491349
if (not force) and warn:
13501350
warnings.warn(
13511351
("matplotlib.pyplot as already been imported, "
1352-
"this call will have no effect."),
1353-
stacklevel=2)
1352+
"this call will have no effect."), stacklevel=2)
13541353

13551354
# if we are going to force switching the backend, pull in
13561355
# `switch_backend` from pyplot. This will only happen if
@@ -1434,8 +1433,7 @@ def _init_tests():
14341433
LOCAL_FREETYPE_VERSION,
14351434
ft2font.__freetype_version__,
14361435
"" if ft2font.__freetype_build_type__ == 'local' else "not "
1437-
)
1438-
)
1436+
), stacklevel=2)
14391437

14401438
try:
14411439
import pytest

lib/matplotlib/_constrained_layout.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad,
155155
if len(gss) == 0:
156156
warnings.warn('There are no gridspecs with layoutboxes. '
157157
'Possibly did not call parent GridSpec with the figure= '
158-
'keyword')
158+
'keyword', stacklevel=2)
159159

160160
if fig._layoutbox.constrained_layout_called < 1:
161161
for gs in gss:
@@ -222,7 +222,7 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad,
222222
ax._set_position(newpos, which='original')
223223
else:
224224
warnings.warn('constrained_layout not applied. At least '
225-
'one axes collapsed to zero width or height.')
225+
'one axes collapsed to zero width or height.', stacklevel=2)
226226

227227

228228
def _make_ghost_gridspec_slots(fig, gs):

lib/matplotlib/artist.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ def contains(self, mouseevent):
416416
"""
417417
if callable(self._contains):
418418
return self._contains(self, mouseevent)
419-
warnings.warn("'%s' needs 'contains' method" % self.__class__.__name__)
419+
warnings.warn("'%s' needs 'contains' method" % self.__class__.__name__, stacklevel=2)
420420
return False, {}
421421

422422
def set_contains(self, picker):
@@ -866,7 +866,7 @@ def set_rasterized(self, rasterized):
866866
rasterized : bool or None
867867
"""
868868
if rasterized and not hasattr(self.draw, "_supports_rasterization"):
869-
warnings.warn("Rasterization of '%s' will be ignored" % self)
869+
warnings.warn("Rasterization of '%s' will be ignored" % self, stacklevel=2)
870870

871871
self._rasterized = rasterized
872872

lib/matplotlib/axes/_axes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4614,7 +4614,7 @@ def hexbin(self, x, y, C=None, gridsize=100, bins=None,
46144614
if bins == 'log':
46154615
if norm is not None:
46164616
warnings.warn("Only one of 'bins' and 'norm' arguments can be "
4617-
"supplied, ignoring bins={}".format(bins))
4617+
"supplied, ignoring bins={}".format(bins), stacklevel=2)
46184618
else:
46194619
norm = mcolors.LogNorm()
46204620
bins = None

lib/matplotlib/axis.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,7 @@ def _update_ticks(self, renderer):
10801080
except Exception:
10811081
warnings.warn("Unable to find pixel distance along axis "
10821082
"for interval padding of ticks; assuming no "
1083-
"interval padding needed.")
1083+
"interval padding needed.", stacklevel=2)
10841084
ds1 = 0.0
10851085
if np.isnan(ds1):
10861086
ds1 = 0.0
@@ -1090,7 +1090,7 @@ def _update_ticks(self, renderer):
10901090
except Exception:
10911091
warnings.warn("Unable to find pixel distance along axis "
10921092
"for interval padding of ticks; assuming no "
1093-
"interval padding needed.")
1093+
"interval padding needed.", stacklevel=2)
10941094
ds2 = 0.0
10951095
if np.isnan(ds2):
10961096
ds2 = 0.0
@@ -1441,7 +1441,7 @@ def grid(self, b=None, which='major', **kwargs):
14411441
if not b and b is not None: # something false-like but not None
14421442
warnings.warn('First parameter to grid() is false, but line '
14431443
'properties are supplied. The grid will be '
1444-
'enabled.')
1444+
'enabled.', stacklevel=2)
14451445
b = True
14461446
which = which.lower()
14471447
if which not in ['major', 'minor', 'both']:

lib/matplotlib/backend_bases.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2395,7 +2395,7 @@ def _get_uniform_gridstate(ticks):
23952395
try:
23962396
ax.set_yscale('log')
23972397
except ValueError as exc:
2398-
warnings.warn(str(exc))
2398+
warnings.warn(str(exc), stacklevel=2)
23992399
ax.set_yscale('linear')
24002400
ax.figure.canvas.draw_idle()
24012401
# toggle scaling of x-axes between 'log and 'linear' (default key 'k')
@@ -2408,7 +2408,7 @@ def _get_uniform_gridstate(ticks):
24082408
try:
24092409
ax.set_xscale('log')
24102410
except ValueError as exc:
2411-
warnings.warn(str(exc))
2411+
warnings.warn(str(exc), stacklevel=2)
24122412
ax.set_xscale('linear')
24132413
ax.figure.canvas.draw_idle()
24142414

lib/matplotlib/backend_managers.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class ToolManager(object):
5656
def __init__(self, figure=None):
5757
warnings.warn('Treat the new Tool classes introduced in v1.5 as ' +
5858
'experimental for now, the API will likely change in ' +
59-
'version 2.1 and perhaps the rcParam as well')
59+
'version 2.1 and perhaps the rcParam as well', stacklevel=2)
6060

6161
self._key_press_handler_id = None
6262

@@ -203,7 +203,7 @@ def update_keymap(self, name, *keys):
203203
for k in validate_stringlist(key):
204204
if k in self._keys:
205205
warnings.warn('Key %s changed from %s to %s' %
206-
(k, self._keys[k], name))
206+
(k, self._keys[k], name), stacklevel=2)
207207
self._keys[k] = name
208208

209209
def remove_tool(self, name):
@@ -261,7 +261,7 @@ def add_tool(self, name, tool, *args, **kwargs):
261261

262262
if name in self._tools:
263263
warnings.warn('A "Tool class" with the same name already exists, '
264-
'not added')
264+
'not added', stacklevel=2)
265265
return self._tools[name]
266266

267267
tool_obj = tool_cls(self, name, *args, **kwargs)
@@ -428,6 +428,6 @@ def get_tool(self, name, warn=True):
428428
return name
429429
if name not in self._tools:
430430
if warn:
431-
warnings.warn("ToolManager does not control tool %s" % name)
431+
warnings.warn("ToolManager does not control tool %s" % name, stacklevel=2)
432432
return None
433433
return self._tools[name]

lib/matplotlib/backend_tools.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class ToolBase(object):
7777
def __init__(self, toolmanager, name):
7878
warnings.warn('Treat the new Tool classes introduced in v1.5 as ' +
7979
'experimental for now, the API will likely change in ' +
80-
'version 2.1, and some tools might change name')
80+
'version 2.1, and some tools might change name', stacklevel=2)
8181
self._name = name
8282
self._toolmanager = toolmanager
8383
self._figure = None

lib/matplotlib/bezier.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ def get_parallels(bezier2, width):
343343

344344
if parallel_test == -1:
345345
warnings.warn(
346-
"Lines do not intersect. A straight line is used instead.")
346+
"Lines do not intersect. A straight line is used instead.", stacklevel=2)
347347
cos_t1, sin_t1 = get_cos_sin(c1x, c1y, c2x, c2y)
348348
cos_t2, sin_t2 = cos_t1, sin_t1
349349
else:

lib/matplotlib/cbook/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ def local_over_kwdict(local_var, kwargs, *keys):
300300
out = kwarg_val
301301
else:
302302
warnings.warn('"%s" keyword argument will be ignored' % key,
303-
IgnoredKeywordWarning)
303+
IgnoredKeywordWarning, stacklevel=2)
304304
return out
305305

306306

@@ -1724,7 +1724,7 @@ def normalize_kwargs(kw, alias_mapping=None, required=(), forbidden=(),
17241724
if len(tmp) > 1:
17251725
warnings.warn("Saw kwargs {seen!r} which are all aliases for "
17261726
"{canon!r}. Kept value from {used!r}".format(
1727-
seen=seen, canon=canonical, used=seen[-1]))
1727+
seen=seen, canon=canonical, used=seen[-1]), stacklevel=2)
17281728

17291729
# at this point we know that all keys which are aliased are removed, update
17301730
# the return dictionary from the cleaned local copy of the input

lib/matplotlib/colorbar.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@
212212
def _set_ticks_on_axis_warn(*args, **kw):
213213
# a top level function which gets put in at the axes'
214214
# set_xticks set_yticks by _patch_ax
215-
warnings.warn("Use the colorbar set_ticks() method instead.")
215+
warnings.warn("Use the colorbar set_ticks() method instead.", stacklevel=2)
216216

217217

218218
class _ColorbarAutoLocator(ticker.MaxNLocator):
@@ -583,7 +583,7 @@ def set_ticklabels(self, ticklabels, update_ticks=True):
583583
if update_ticks:
584584
self.update_ticks()
585585
else:
586-
warnings.warn("set_ticks() must have been called.")
586+
warnings.warn("set_ticks() must have been called.", stacklevel=2)
587587
self.stale = True
588588

589589
def _config_axes(self, X, Y):
@@ -1201,7 +1201,7 @@ def minorticks_on(self):
12011201

12021202
if long_axis.get_scale() == 'log':
12031203
warnings.warn('minorticks_on() has no effect on a '
1204-
'logarithmic colorbar axis')
1204+
'logarithmic colorbar axis', stacklevel=2)
12051205
else:
12061206
long_axis.set_minor_locator(_ColorbarAutoMinorLocator(self))
12071207

@@ -1214,7 +1214,7 @@ def minorticks_off(self):
12141214

12151215
if long_axis.get_scale() == 'log':
12161216
warnings.warn('minorticks_off() has no effect on a '
1217-
'logarithmic colorbar axis')
1217+
'logarithmic colorbar axis', stacklevel=2)
12181218
else:
12191219
long_axis.set_minor_locator(ticker.NullLocator())
12201220

lib/matplotlib/contour.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,7 @@ def __init__(self, ax, *args,
939939

940940
if self.filled:
941941
if self.linewidths is not None:
942-
warnings.warn('linewidths is ignored by contourf')
942+
warnings.warn('linewidths is ignored by contourf', stacklevel=2)
943943

944944
# Lower and upper contour levels.
945945
lowers, uppers = self._get_lowers_and_uppers()
@@ -997,7 +997,7 @@ def __init__(self, ax, *args,
997997
if kwargs:
998998
s = ", ".join(map(repr, kwargs))
999999
warnings.warn('The following kwargs were not used by contour: ' +
1000-
s)
1000+
s, stacklevel=2)
10011001

10021002
def get_transform(self):
10031003
"""
@@ -1237,7 +1237,7 @@ def _contour_level_args(self, z, args):
12371237
if len(levels_in) == 0:
12381238
self.levels = [self.zmin]
12391239
warnings.warn("No contour levels were found"
1240-
" within the data range.")
1240+
" within the data range.", stacklevel=2)
12411241

12421242
if self.filled and len(self.levels) < 2:
12431243
raise ValueError("Filled contours require at least 2 levels.")
@@ -1554,7 +1554,7 @@ def _contour_args(self, args, kwargs):
15541554
self.zmin = float(z.min())
15551555
if self.logscale and self.zmin <= 0:
15561556
z = ma.masked_where(z <= 0, z)
1557-
warnings.warn('Log scale: values of z <= 0 have been masked')
1557+
warnings.warn('Log scale: values of z <= 0 have been masked', stacklevel=2)
15581558
self.zmin = float(z.min())
15591559
self._contour_level_args(z, args)
15601560
return (x, y, z)

0 commit comments

Comments
 (0)