blob: 1c55fb23ae5ab6fe04df3fb2a2608597ba3027be [file] [log] [blame]
Guido van Rossum2a862c62000-12-15 21:59:53 +00001"""Python part of the warnings subsystem."""
2
Mark Hammonda43fd0c2003-02-19 00:33:33 +00003# Note: function level imports should *not* be used
4# in this module as it may cause import lock deadlock.
5# See bug 683658.
Skip Montanarod8f21202003-05-14 17:33:53 +00006import sys, types
Mark Hammonda43fd0c2003-02-19 00:33:33 +00007import linecache
Guido van Rossum2a862c62000-12-15 21:59:53 +00008
Skip Montanaro40fc1602001-03-01 04:27:19 +00009__all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",
10 "resetwarnings"]
11
Guido van Rossum2a862c62000-12-15 21:59:53 +000012defaultaction = "default"
13filters = []
14onceregistry = {}
15
16def warn(message, category=None, stacklevel=1):
17 """Issue a warning, or maybe ignore it or raise an exception."""
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000018 # Check if message is already a Warning object
19 if isinstance(message, Warning):
Tim Peters863ac442002-04-16 01:38:40 +000020 category = message.__class__
Guido van Rossum2a862c62000-12-15 21:59:53 +000021 # Check category argument
22 if category is None:
23 category = UserWarning
24 assert issubclass(category, Warning)
25 # Get context information
26 try:
27 caller = sys._getframe(stacklevel)
28 except ValueError:
29 globals = sys.__dict__
30 lineno = 1
31 else:
32 globals = caller.f_globals
33 lineno = caller.f_lineno
Raymond Hettinger54f02222002-06-01 14:18:47 +000034 if '__name__' in globals:
Guido van Rossum8031bbe2001-08-31 17:46:35 +000035 module = globals['__name__']
36 else:
37 module = "<string>"
Guido van Rossum2a862c62000-12-15 21:59:53 +000038 filename = globals.get('__file__')
39 if filename:
40 fnl = filename.lower()
41 if fnl.endswith(".pyc") or fnl.endswith(".pyo"):
42 filename = filename[:-1]
43 else:
44 if module == "__main__":
45 filename = sys.argv[0]
46 if not filename:
47 filename = module
Guido van Rossum2a862c62000-12-15 21:59:53 +000048 registry = globals.setdefault("__warningregistry__", {})
Guido van Rossum9e263182001-02-28 21:43:40 +000049 warn_explicit(message, category, filename, lineno, module, registry)
50
51def warn_explicit(message, category, filename, lineno,
52 module=None, registry=None):
53 if module is None:
54 module = filename
55 if module[-3:].lower() == ".py":
56 module = module[:-3] # XXX What about leading pathname?
57 if registry is None:
58 registry = {}
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000059 if isinstance(message, Warning):
Tim Peters863ac442002-04-16 01:38:40 +000060 text = str(message)
61 category = message.__class__
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000062 else:
Tim Peters863ac442002-04-16 01:38:40 +000063 text = message
64 message = category(message)
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000065 key = (text, category, lineno)
Guido van Rossum3756fa32001-02-28 22:26:36 +000066 # Quick test for common case
Guido van Rossum2a862c62000-12-15 21:59:53 +000067 if registry.get(key):
68 return
69 # Search the filters
70 for item in filters:
71 action, msg, cat, mod, ln = item
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000072 if (msg.match(text) and
Guido van Rossum2a862c62000-12-15 21:59:53 +000073 issubclass(category, cat) and
74 mod.match(module) and
75 (ln == 0 or lineno == ln)):
76 break
77 else:
78 action = defaultaction
79 # Early exit actions
80 if action == "ignore":
81 registry[key] = 1
82 return
83 if action == "error":
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000084 raise message
Guido van Rossum2a862c62000-12-15 21:59:53 +000085 # Other actions
86 if action == "once":
87 registry[key] = 1
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000088 oncekey = (text, category)
Guido van Rossum2a862c62000-12-15 21:59:53 +000089 if onceregistry.get(oncekey):
90 return
91 onceregistry[oncekey] = 1
92 elif action == "always":
93 pass
94 elif action == "module":
95 registry[key] = 1
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000096 altkey = (text, category, 0)
Guido van Rossum2a862c62000-12-15 21:59:53 +000097 if registry.get(altkey):
98 return
99 registry[altkey] = 1
100 elif action == "default":
101 registry[key] = 1
102 else:
103 # Unrecognized actions are errors
104 raise RuntimeError(
105 "Unrecognized action (%s) in warnings.filters:\n %s" %
106 (`action`, str(item)))
107 # Print message and context
108 showwarning(message, category, filename, lineno)
109
110def showwarning(message, category, filename, lineno, file=None):
111 """Hook to write a warning to a file; replace if you like."""
112 if file is None:
113 file = sys.stderr
Mark Hammond51a0ae32002-09-11 13:22:35 +0000114 try:
115 file.write(formatwarning(message, category, filename, lineno))
116 except IOError:
117 pass # the file (probably stderr) is invalid - this warning gets lost.
Guido van Rossum2a862c62000-12-15 21:59:53 +0000118
119def formatwarning(message, category, filename, lineno):
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000120 """Function to format a warning the standard way."""
Guido van Rossum2a862c62000-12-15 21:59:53 +0000121 s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
122 line = linecache.getline(filename, lineno).strip()
123 if line:
124 s = s + " " + line + "\n"
125 return s
126
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000127def filterwarnings(action, message="", category=Warning, module="", lineno=0,
128 append=0):
Guido van Rossum2a862c62000-12-15 21:59:53 +0000129 """Insert an entry into the list of warnings filters (at the front).
130
131 Use assertions to check that all arguments have the right type."""
Skip Montanarod8f21202003-05-14 17:33:53 +0000132 import re
Guido van Rossum2a862c62000-12-15 21:59:53 +0000133 assert action in ("error", "ignore", "always", "default", "module",
134 "once"), "invalid action: %s" % `action`
Martin v. Löwisff9284bc22002-10-14 21:06:02 +0000135 assert isinstance(message, basestring), "message must be a string"
Guido van Rossum2a862c62000-12-15 21:59:53 +0000136 assert isinstance(category, types.ClassType), "category must be a class"
137 assert issubclass(category, Warning), "category must be a Warning subclass"
Martin v. Löwisff9284bc22002-10-14 21:06:02 +0000138 assert isinstance(module, basestring), "module must be a string"
Walter Dörwald65230a22002-06-03 15:58:32 +0000139 assert isinstance(lineno, int) and lineno >= 0, \
Guido van Rossum2a862c62000-12-15 21:59:53 +0000140 "lineno must be an int >= 0"
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000141 item = (action, re.compile(message, re.I), category,
142 re.compile(module), lineno)
143 if append:
144 filters.append(item)
145 else:
146 filters.insert(0, item)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000147
148def resetwarnings():
Tim Petersd0cc4f02002-04-16 01:51:25 +0000149 """Clear the list of warning filters, so that no filters are active."""
Guido van Rossum2a862c62000-12-15 21:59:53 +0000150 filters[:] = []
151
152class _OptionError(Exception):
153 """Exception used by option processing helpers."""
154 pass
155
156# Helper to process -W options passed via sys.warnoptions
157def _processoptions(args):
158 for arg in args:
159 try:
160 _setoption(arg)
161 except _OptionError, msg:
162 print >>sys.stderr, "Invalid -W option ignored:", msg
163
164# Helper for _processoptions()
165def _setoption(arg):
Skip Montanarod8f21202003-05-14 17:33:53 +0000166 import re
Tim Peterse1190062001-01-15 03:34:38 +0000167 parts = arg.split(':')
168 if len(parts) > 5:
169 raise _OptionError("too many fields (max 5): %s" % `arg`)
170 while len(parts) < 5:
171 parts.append('')
172 action, message, category, module, lineno = [s.strip()
173 for s in parts]
174 action = _getaction(action)
175 message = re.escape(message)
176 category = _getcategory(category)
177 module = re.escape(module)
178 if module:
179 module = module + '$'
180 if lineno:
181 try:
182 lineno = int(lineno)
183 if lineno < 0:
184 raise ValueError
185 except (ValueError, OverflowError):
186 raise _OptionError("invalid lineno %s" % `lineno`)
187 else:
188 lineno = 0
189 filterwarnings(action, message, category, module, lineno)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000190
191# Helper for _setoption()
192def _getaction(action):
193 if not action:
194 return "default"
195 if action == "all": return "always" # Alias
196 for a in ['default', 'always', 'ignore', 'module', 'once', 'error']:
197 if a.startswith(action):
198 return a
199 raise _OptionError("invalid action: %s" % `action`)
200
201# Helper for _setoption()
202def _getcategory(category):
Skip Montanarod8f21202003-05-14 17:33:53 +0000203 import re
Guido van Rossum2a862c62000-12-15 21:59:53 +0000204 if not category:
205 return Warning
206 if re.match("^[a-zA-Z0-9_]+$", category):
207 try:
208 cat = eval(category)
Guido van Rossumd1db30b2000-12-19 03:04:50 +0000209 except NameError:
210 raise _OptionError("unknown warning category: %s" % `category`)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000211 else:
212 i = category.rfind(".")
213 module = category[:i]
214 klass = category[i+1:]
Guido van Rossumd1db30b2000-12-19 03:04:50 +0000215 try:
216 m = __import__(module, None, None, [klass])
217 except ImportError:
218 raise _OptionError("invalid module name: %s" % `module`)
219 try:
220 cat = getattr(m, klass)
221 except AttributeError:
222 raise _OptionError("unknown warning category: %s" % `category`)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000223 if (not isinstance(cat, types.ClassType) or
224 not issubclass(cat, Warning)):
225 raise _OptionError("invalid warning category: %s" % `category`)
226 return cat
227
228# Self-test
229def _test():
230 import getopt
231 testoptions = []
232 try:
233 opts, args = getopt.getopt(sys.argv[1:], "W:")
234 except getopt.error, msg:
235 print >>sys.stderr, msg
236 return
237 for o, a in opts:
238 testoptions.append(a)
239 try:
240 _processoptions(testoptions)
241 except _OptionError, msg:
242 print >>sys.stderr, msg
243 return
244 for item in filters: print item
245 hello = "hello world"
246 warn(hello); warn(hello); warn(hello); warn(hello)
247 warn(hello, UserWarning)
248 warn(hello, DeprecationWarning)
249 for i in range(3):
250 warn(hello)
251 filterwarnings("error", "", Warning, "", 0)
252 try:
253 warn(hello)
254 except Exception, msg:
255 print "Caught", msg.__class__.__name__ + ":", msg
256 else:
257 print "No exception"
258 resetwarnings()
259 try:
260 filterwarnings("booh", "", Warning, "", 0)
261 except Exception, msg:
262 print "Caught", msg.__class__.__name__ + ":", msg
263 else:
264 print "No exception"
265
266# Module initialization
267if __name__ == "__main__":
268 import __main__
269 sys.modules['warnings'] = __main__
270 _test()
271else:
272 _processoptions(sys.warnoptions)
Guido van Rossumacc21d82001-08-23 03:07:42 +0000273 filterwarnings("ignore", category=OverflowWarning, append=1)
Neal Norwitzd68f5172002-05-29 15:54:55 +0000274 filterwarnings("ignore", category=PendingDeprecationWarning, append=1)