The silencing of DeprecationWarning was not taking -3 into consideration. Since
[python.git] / Lib / warnings.py
blob70b3d4361959309cfb3145e60a857281f7d2cf6d
1 """Python part of the warnings subsystem."""
3 # Note: function level imports should *not* be used
4 # in this module as it may cause import lock deadlock.
5 # See bug 683658.
6 import linecache
7 import sys
8 import types
10 __all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",
11 "resetwarnings", "catch_warnings"]
14 def warnpy3k(message, category=None, stacklevel=1):
15 """Issue a deprecation warning for Python 3.x related changes.
17 Warnings are omitted unless Python is started with the -3 option.
18 """
19 if sys.py3kwarning:
20 if category is None:
21 category = DeprecationWarning
22 warn(message, category, stacklevel+1)
24 def _show_warning(message, category, filename, lineno, file=None, line=None):
25 """Hook to write a warning to a file; replace if you like."""
26 if file is None:
27 file = sys.stderr
28 try:
29 file.write(formatwarning(message, category, filename, lineno, line))
30 except IOError:
31 pass # the file (probably stderr) is invalid - this warning gets lost.
32 # Keep a worrking version around in case the deprecation of the old API is
33 # triggered.
34 showwarning = _show_warning
36 def formatwarning(message, category, filename, lineno, line=None):
37 """Function to format a warning the standard way."""
38 s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
39 line = linecache.getline(filename, lineno) if line is None else line
40 if line:
41 line = line.strip()
42 s += " %s\n" % line
43 return s
45 def filterwarnings(action, message="", category=Warning, module="", lineno=0,
46 append=0):
47 """Insert an entry into the list of warnings filters (at the front).
49 'action' -- one of "error", "ignore", "always", "default", "module",
50 or "once"
51 'message' -- a regex that the warning message must match
52 'category' -- a class that the warning must be a subclass of
53 'module' -- a regex that the module name must match
54 'lineno' -- an integer line number, 0 matches all warnings
55 'append' -- if true, append to the list of filters
56 """
57 import re
58 assert action in ("error", "ignore", "always", "default", "module",
59 "once"), "invalid action: %r" % (action,)
60 assert isinstance(message, basestring), "message must be a string"
61 assert isinstance(category, (type, types.ClassType)), \
62 "category must be a class"
63 assert issubclass(category, Warning), "category must be a Warning subclass"
64 assert isinstance(module, basestring), "module must be a string"
65 assert isinstance(lineno, int) and lineno >= 0, \
66 "lineno must be an int >= 0"
67 item = (action, re.compile(message, re.I), category,
68 re.compile(module), lineno)
69 if append:
70 filters.append(item)
71 else:
72 filters.insert(0, item)
74 def simplefilter(action, category=Warning, lineno=0, append=0):
75 """Insert a simple entry into the list of warnings filters (at the front).
77 A simple filter matches all modules and messages.
78 'action' -- one of "error", "ignore", "always", "default", "module",
79 or "once"
80 'category' -- a class that the warning must be a subclass of
81 'lineno' -- an integer line number, 0 matches all warnings
82 'append' -- if true, append to the list of filters
83 """
84 assert action in ("error", "ignore", "always", "default", "module",
85 "once"), "invalid action: %r" % (action,)
86 assert isinstance(lineno, int) and lineno >= 0, \
87 "lineno must be an int >= 0"
88 item = (action, None, category, None, lineno)
89 if append:
90 filters.append(item)
91 else:
92 filters.insert(0, item)
94 def resetwarnings():
95 """Clear the list of warning filters, so that no filters are active."""
96 filters[:] = []
98 class _OptionError(Exception):
99 """Exception used by option processing helpers."""
100 pass
102 # Helper to process -W options passed via sys.warnoptions
103 def _processoptions(args):
104 for arg in args:
105 try:
106 _setoption(arg)
107 except _OptionError, msg:
108 print >>sys.stderr, "Invalid -W option ignored:", msg
110 # Helper for _processoptions()
111 def _setoption(arg):
112 import re
113 parts = arg.split(':')
114 if len(parts) > 5:
115 raise _OptionError("too many fields (max 5): %r" % (arg,))
116 while len(parts) < 5:
117 parts.append('')
118 action, message, category, module, lineno = [s.strip()
119 for s in parts]
120 action = _getaction(action)
121 message = re.escape(message)
122 category = _getcategory(category)
123 module = re.escape(module)
124 if module:
125 module = module + '$'
126 if lineno:
127 try:
128 lineno = int(lineno)
129 if lineno < 0:
130 raise ValueError
131 except (ValueError, OverflowError):
132 raise _OptionError("invalid lineno %r" % (lineno,))
133 else:
134 lineno = 0
135 filterwarnings(action, message, category, module, lineno)
137 # Helper for _setoption()
138 def _getaction(action):
139 if not action:
140 return "default"
141 if action == "all": return "always" # Alias
142 for a in ('default', 'always', 'ignore', 'module', 'once', 'error'):
143 if a.startswith(action):
144 return a
145 raise _OptionError("invalid action: %r" % (action,))
147 # Helper for _setoption()
148 def _getcategory(category):
149 import re
150 if not category:
151 return Warning
152 if re.match("^[a-zA-Z0-9_]+$", category):
153 try:
154 cat = eval(category)
155 except NameError:
156 raise _OptionError("unknown warning category: %r" % (category,))
157 else:
158 i = category.rfind(".")
159 module = category[:i]
160 klass = category[i+1:]
161 try:
162 m = __import__(module, None, None, [klass])
163 except ImportError:
164 raise _OptionError("invalid module name: %r" % (module,))
165 try:
166 cat = getattr(m, klass)
167 except AttributeError:
168 raise _OptionError("unknown warning category: %r" % (category,))
169 if not issubclass(cat, Warning):
170 raise _OptionError("invalid warning category: %r" % (category,))
171 return cat
174 # Code typically replaced by _warnings
175 def warn(message, category=None, stacklevel=1):
176 """Issue a warning, or maybe ignore it or raise an exception."""
177 # Check if message is already a Warning object
178 if isinstance(message, Warning):
179 category = message.__class__
180 # Check category argument
181 if category is None:
182 category = UserWarning
183 assert issubclass(category, Warning)
184 # Get context information
185 try:
186 caller = sys._getframe(stacklevel)
187 except ValueError:
188 globals = sys.__dict__
189 lineno = 1
190 else:
191 globals = caller.f_globals
192 lineno = caller.f_lineno
193 if '__name__' in globals:
194 module = globals['__name__']
195 else:
196 module = "<string>"
197 filename = globals.get('__file__')
198 if filename:
199 fnl = filename.lower()
200 if fnl.endswith((".pyc", ".pyo")):
201 filename = filename[:-1]
202 else:
203 if module == "__main__":
204 try:
205 filename = sys.argv[0]
206 except AttributeError:
207 # embedded interpreters don't have sys.argv, see bug #839151
208 filename = '__main__'
209 if not filename:
210 filename = module
211 registry = globals.setdefault("__warningregistry__", {})
212 warn_explicit(message, category, filename, lineno, module, registry,
213 globals)
215 def warn_explicit(message, category, filename, lineno,
216 module=None, registry=None, module_globals=None):
217 lineno = int(lineno)
218 if module is None:
219 module = filename or "<unknown>"
220 if module[-3:].lower() == ".py":
221 module = module[:-3] # XXX What about leading pathname?
222 if registry is None:
223 registry = {}
224 if isinstance(message, Warning):
225 text = str(message)
226 category = message.__class__
227 else:
228 text = message
229 message = category(message)
230 key = (text, category, lineno)
231 # Quick test for common case
232 if registry.get(key):
233 return
234 # Search the filters
235 for item in filters:
236 action, msg, cat, mod, ln = item
237 if ((msg is None or msg.match(text)) and
238 issubclass(category, cat) and
239 (mod is None or mod.match(module)) and
240 (ln == 0 or lineno == ln)):
241 break
242 else:
243 action = defaultaction
244 # Early exit actions
245 if action == "ignore":
246 registry[key] = 1
247 return
249 # Prime the linecache for formatting, in case the
250 # "file" is actually in a zipfile or something.
251 linecache.getlines(filename, module_globals)
253 if action == "error":
254 raise message
255 # Other actions
256 if action == "once":
257 registry[key] = 1
258 oncekey = (text, category)
259 if onceregistry.get(oncekey):
260 return
261 onceregistry[oncekey] = 1
262 elif action == "always":
263 pass
264 elif action == "module":
265 registry[key] = 1
266 altkey = (text, category, 0)
267 if registry.get(altkey):
268 return
269 registry[altkey] = 1
270 elif action == "default":
271 registry[key] = 1
272 else:
273 # Unrecognized actions are errors
274 raise RuntimeError(
275 "Unrecognized action (%r) in warnings.filters:\n %s" %
276 (action, item))
277 # Print message and context
278 showwarning(message, category, filename, lineno)
281 class WarningMessage(object):
283 """Holds the result of a single showwarning() call."""
285 _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
286 "line")
288 def __init__(self, message, category, filename, lineno, file=None,
289 line=None):
290 local_values = locals()
291 for attr in self._WARNING_DETAILS:
292 setattr(self, attr, local_values[attr])
293 self._category_name = category.__name__ if category else None
295 def __str__(self):
296 return ("{message : %r, category : %r, filename : %r, lineno : %s, "
297 "line : %r}" % (self.message, self._category_name,
298 self.filename, self.lineno, self.line))
301 class catch_warnings(object):
303 """A context manager that copies and restores the warnings filter upon
304 exiting the context.
306 The 'record' argument specifies whether warnings should be captured by a
307 custom implementation of warnings.showwarning() and be appended to a list
308 returned by the context manager. Otherwise None is returned by the context
309 manager. The objects appended to the list are arguments whose attributes
310 mirror the arguments to showwarning().
312 The 'module' argument is to specify an alternative module to the module
313 named 'warnings' and imported under that name. This argument is only useful
314 when testing the warnings module itself.
318 def __init__(self, record=False, module=None):
319 """Specify whether to record warnings and if an alternative module
320 should be used other than sys.modules['warnings'].
322 For compatibility with Python 3.0, please consider all arguments to be
323 keyword-only.
326 self._record = record
327 self._module = sys.modules['warnings'] if module is None else module
328 self._entered = False
330 def __repr__(self):
331 args = []
332 if self._record:
333 args.append("record=True")
334 if self._module is not sys.modules['warnings']:
335 args.append("module=%r" % self._module)
336 name = type(self).__name__
337 return "%s(%s)" % (name, ", ".join(args))
339 def __enter__(self):
340 if self._entered:
341 raise RuntimeError("Cannot enter %r twice" % self)
342 self._entered = True
343 self._filters = self._module.filters
344 self._module.filters = self._filters[:]
345 self._showwarning = self._module.showwarning
346 if self._record:
347 log = []
348 def showwarning(*args, **kwargs):
349 log.append(WarningMessage(*args, **kwargs))
350 self._module.showwarning = showwarning
351 return log
352 else:
353 return None
355 def __exit__(self, *exc_info):
356 if not self._entered:
357 raise RuntimeError("Cannot exit %r without entering first" % self)
358 self._module.filters = self._filters
359 self._module.showwarning = self._showwarning
362 # filters contains a sequence of filter 5-tuples
363 # The components of the 5-tuple are:
364 # - an action: error, ignore, always, default, module, or once
365 # - a compiled regex that must match the warning message
366 # - a class representing the warning category
367 # - a compiled regex that must match the module that is being warned
368 # - a line number for the line being warning, or 0 to mean any line
369 # If either if the compiled regexs are None, match anything.
370 _warnings_defaults = False
371 try:
372 from _warnings import (filters, default_action, once_registry,
373 warn, warn_explicit)
374 defaultaction = default_action
375 onceregistry = once_registry
376 _warnings_defaults = True
377 except ImportError:
378 filters = []
379 defaultaction = "default"
380 onceregistry = {}
383 # Module initialization
384 _processoptions(sys.warnoptions)
385 if not _warnings_defaults:
386 silence = [ImportWarning, PendingDeprecationWarning]
387 if not sys.py3kwarning: # Don't silence DeprecationWarning if -3 was used.
388 silence.append(DeprecationWarning)
389 for cls in silence:
390 simplefilter("ignore", category=cls)
391 bytes_warning = sys.flags.bytes_warning
392 if bytes_warning > 1:
393 bytes_action = "error"
394 elif bytes_warning:
395 bytes_action = "default"
396 else:
397 bytes_action = "ignore"
398 simplefilter(bytes_action, category=BytesWarning, append=1)
399 del _warnings_defaults