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