Catch situations where currentframe() returns None. See SF patch #1447410, this is...
[python.git] / Lib / warnings.py
blobe622b9acab489730a77df0af643faa6dd326e218
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 sys, types
7 import linecache
9 __all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",
10 "resetwarnings"]
12 # filters contains a sequence of filter 5-tuples
13 # The components of the 5-tuple are:
14 # - an action: error, ignore, always, default, module, or once
15 # - a compiled regex that must match the warning message
16 # - a class representing the warning category
17 # - a compiled regex that must match the module that is being warned
18 # - a line number for the line being warning, or 0 to mean any line
19 # If either if the compiled regexs are None, match anything.
20 filters = []
21 defaultaction = "default"
22 onceregistry = {}
24 def warn(message, category=None, stacklevel=1):
25 """Issue a warning, or maybe ignore it or raise an exception."""
26 # Check if message is already a Warning object
27 if isinstance(message, Warning):
28 category = message.__class__
29 # Check category argument
30 if category is None:
31 category = UserWarning
32 assert issubclass(category, Warning)
33 # Get context information
34 try:
35 caller = sys._getframe(stacklevel)
36 except ValueError:
37 globals = sys.__dict__
38 lineno = 1
39 else:
40 globals = caller.f_globals
41 lineno = caller.f_lineno
42 if '__name__' in globals:
43 module = globals['__name__']
44 else:
45 module = "<string>"
46 filename = globals.get('__file__')
47 if filename:
48 fnl = filename.lower()
49 if fnl.endswith(".pyc") or fnl.endswith(".pyo"):
50 filename = filename[:-1]
51 else:
52 if module == "__main__":
53 try:
54 filename = sys.argv[0]
55 except AttributeError:
56 # embedded interpreters don't have sys.argv, see bug #839151
57 filename = '__main__'
58 if not filename:
59 filename = module
60 registry = globals.setdefault("__warningregistry__", {})
61 warn_explicit(message, category, filename, lineno, module, registry)
63 def warn_explicit(message, category, filename, lineno,
64 module=None, registry=None):
65 if module is None:
66 module = filename or "<unknown>"
67 if module[-3:].lower() == ".py":
68 module = module[:-3] # XXX What about leading pathname?
69 if registry is None:
70 registry = {}
71 if isinstance(message, Warning):
72 text = str(message)
73 category = message.__class__
74 else:
75 text = message
76 message = category(message)
77 key = (text, category, lineno)
78 # Quick test for common case
79 if registry.get(key):
80 return
81 # Search the filters
82 for item in filters:
83 action, msg, cat, mod, ln = item
84 if ((msg is None or msg.match(text)) and
85 issubclass(category, cat) and
86 (mod is None or mod.match(module)) and
87 (ln == 0 or lineno == ln)):
88 break
89 else:
90 action = defaultaction
91 # Early exit actions
92 if action == "ignore":
93 registry[key] = 1
94 return
95 if action == "error":
96 raise message
97 # Other actions
98 if action == "once":
99 registry[key] = 1
100 oncekey = (text, category)
101 if onceregistry.get(oncekey):
102 return
103 onceregistry[oncekey] = 1
104 elif action == "always":
105 pass
106 elif action == "module":
107 registry[key] = 1
108 altkey = (text, category, 0)
109 if registry.get(altkey):
110 return
111 registry[altkey] = 1
112 elif action == "default":
113 registry[key] = 1
114 else:
115 # Unrecognized actions are errors
116 raise RuntimeError(
117 "Unrecognized action (%r) in warnings.filters:\n %s" %
118 (action, item))
119 # Print message and context
120 showwarning(message, category, filename, lineno)
122 def showwarning(message, category, filename, lineno, file=None):
123 """Hook to write a warning to a file; replace if you like."""
124 if file is None:
125 file = sys.stderr
126 try:
127 file.write(formatwarning(message, category, filename, lineno))
128 except IOError:
129 pass # the file (probably stderr) is invalid - this warning gets lost.
131 def formatwarning(message, category, filename, lineno):
132 """Function to format a warning the standard way."""
133 s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
134 line = linecache.getline(filename, lineno).strip()
135 if line:
136 s = s + " " + line + "\n"
137 return s
139 def filterwarnings(action, message="", category=Warning, module="", lineno=0,
140 append=0):
141 """Insert an entry into the list of warnings filters (at the front).
143 Use assertions to check that all arguments have the right type."""
144 import re
145 assert action in ("error", "ignore", "always", "default", "module",
146 "once"), "invalid action: %r" % (action,)
147 assert isinstance(message, basestring), "message must be a string"
148 assert isinstance(category, (type, types.ClassType)), \
149 "category must be a class"
150 assert issubclass(category, Warning), "category must be a Warning subclass"
151 assert isinstance(module, basestring), "module must be a string"
152 assert isinstance(lineno, int) and lineno >= 0, \
153 "lineno must be an int >= 0"
154 item = (action, re.compile(message, re.I), category,
155 re.compile(module), lineno)
156 if append:
157 filters.append(item)
158 else:
159 filters.insert(0, item)
161 def simplefilter(action, category=Warning, lineno=0, append=0):
162 """Insert a simple entry into the list of warnings filters (at the front).
164 A simple filter matches all modules and messages.
166 assert action in ("error", "ignore", "always", "default", "module",
167 "once"), "invalid action: %r" % (action,)
168 assert isinstance(lineno, int) and lineno >= 0, \
169 "lineno must be an int >= 0"
170 item = (action, None, category, None, lineno)
171 if append:
172 filters.append(item)
173 else:
174 filters.insert(0, item)
176 def resetwarnings():
177 """Clear the list of warning filters, so that no filters are active."""
178 filters[:] = []
180 class _OptionError(Exception):
181 """Exception used by option processing helpers."""
182 pass
184 # Helper to process -W options passed via sys.warnoptions
185 def _processoptions(args):
186 for arg in args:
187 try:
188 _setoption(arg)
189 except _OptionError, msg:
190 print >>sys.stderr, "Invalid -W option ignored:", msg
192 # Helper for _processoptions()
193 def _setoption(arg):
194 import re
195 parts = arg.split(':')
196 if len(parts) > 5:
197 raise _OptionError("too many fields (max 5): %r" % (arg,))
198 while len(parts) < 5:
199 parts.append('')
200 action, message, category, module, lineno = [s.strip()
201 for s in parts]
202 action = _getaction(action)
203 message = re.escape(message)
204 category = _getcategory(category)
205 module = re.escape(module)
206 if module:
207 module = module + '$'
208 if lineno:
209 try:
210 lineno = int(lineno)
211 if lineno < 0:
212 raise ValueError
213 except (ValueError, OverflowError):
214 raise _OptionError("invalid lineno %r" % (lineno,))
215 else:
216 lineno = 0
217 filterwarnings(action, message, category, module, lineno)
219 # Helper for _setoption()
220 def _getaction(action):
221 if not action:
222 return "default"
223 if action == "all": return "always" # Alias
224 for a in ('default', 'always', 'ignore', 'module', 'once', 'error'):
225 if a.startswith(action):
226 return a
227 raise _OptionError("invalid action: %r" % (action,))
229 # Helper for _setoption()
230 def _getcategory(category):
231 import re
232 if not category:
233 return Warning
234 if re.match("^[a-zA-Z0-9_]+$", category):
235 try:
236 cat = eval(category)
237 except NameError:
238 raise _OptionError("unknown warning category: %r" % (category,))
239 else:
240 i = category.rfind(".")
241 module = category[:i]
242 klass = category[i+1:]
243 try:
244 m = __import__(module, None, None, [klass])
245 except ImportError:
246 raise _OptionError("invalid module name: %r" % (module,))
247 try:
248 cat = getattr(m, klass)
249 except AttributeError:
250 raise _OptionError("unknown warning category: %r" % (category,))
251 if (not isinstance(cat, types.ClassType) or
252 not issubclass(cat, Warning)):
253 raise _OptionError("invalid warning category: %r" % (category,))
254 return cat
256 # Module initialization
257 _processoptions(sys.warnoptions)
258 # XXX OverflowWarning should go away for Python 2.5.
259 simplefilter("ignore", category=OverflowWarning, append=1)
260 simplefilter("ignore", category=PendingDeprecationWarning, append=1)