blob: 16ae3314b845475ee953a635045e7e6b2fc58d28 [file] [log] [blame]
Guido van Rossum2a862c62000-12-15 21:59:53 +00001"""Python part of the warnings subsystem."""
2
3import sys, re, types
4
Skip Montanaro40fc1602001-03-01 04:27:19 +00005__all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",
6 "resetwarnings"]
7
Guido van Rossum2a862c62000-12-15 21:59:53 +00008defaultaction = "default"
9filters = []
10onceregistry = {}
11
12def warn(message, category=None, stacklevel=1):
13 """Issue a warning, or maybe ignore it or raise an exception."""
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000014 # Check if message is already a Warning object
15 if isinstance(message, Warning):
Tim Peters863ac442002-04-16 01:38:40 +000016 category = message.__class__
Guido van Rossum2a862c62000-12-15 21:59:53 +000017 # Check category argument
18 if category is None:
19 category = UserWarning
20 assert issubclass(category, Warning)
21 # Get context information
22 try:
23 caller = sys._getframe(stacklevel)
24 except ValueError:
25 globals = sys.__dict__
26 lineno = 1
27 else:
28 globals = caller.f_globals
29 lineno = caller.f_lineno
Raymond Hettinger54f02222002-06-01 14:18:47 +000030 if '__name__' in globals:
Guido van Rossum8031bbe2001-08-31 17:46:35 +000031 module = globals['__name__']
32 else:
33 module = "<string>"
Guido van Rossum2a862c62000-12-15 21:59:53 +000034 filename = globals.get('__file__')
35 if filename:
36 fnl = filename.lower()
37 if fnl.endswith(".pyc") or fnl.endswith(".pyo"):
38 filename = filename[:-1]
39 else:
40 if module == "__main__":
41 filename = sys.argv[0]
42 if not filename:
43 filename = module
Guido van Rossum2a862c62000-12-15 21:59:53 +000044 registry = globals.setdefault("__warningregistry__", {})
Guido van Rossum9e263182001-02-28 21:43:40 +000045 warn_explicit(message, category, filename, lineno, module, registry)
46
47def warn_explicit(message, category, filename, lineno,
48 module=None, registry=None):
49 if module is None:
50 module = filename
51 if module[-3:].lower() == ".py":
52 module = module[:-3] # XXX What about leading pathname?
53 if registry is None:
54 registry = {}
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000055 if isinstance(message, Warning):
Tim Peters863ac442002-04-16 01:38:40 +000056 text = str(message)
57 category = message.__class__
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000058 else:
Tim Peters863ac442002-04-16 01:38:40 +000059 text = message
60 message = category(message)
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000061 key = (text, category, lineno)
Guido van Rossum3756fa32001-02-28 22:26:36 +000062 # Quick test for common case
Guido van Rossum2a862c62000-12-15 21:59:53 +000063 if registry.get(key):
64 return
65 # Search the filters
66 for item in filters:
67 action, msg, cat, mod, ln = item
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000068 if (msg.match(text) and
Guido van Rossum2a862c62000-12-15 21:59:53 +000069 issubclass(category, cat) and
70 mod.match(module) and
71 (ln == 0 or lineno == ln)):
72 break
73 else:
74 action = defaultaction
75 # Early exit actions
76 if action == "ignore":
77 registry[key] = 1
78 return
79 if action == "error":
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000080 raise message
Guido van Rossum2a862c62000-12-15 21:59:53 +000081 # Other actions
82 if action == "once":
83 registry[key] = 1
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000084 oncekey = (text, category)
Guido van Rossum2a862c62000-12-15 21:59:53 +000085 if onceregistry.get(oncekey):
86 return
87 onceregistry[oncekey] = 1
88 elif action == "always":
89 pass
90 elif action == "module":
91 registry[key] = 1
Walter Dörwaldb25c2b02002-03-21 10:38:40 +000092 altkey = (text, category, 0)
Guido van Rossum2a862c62000-12-15 21:59:53 +000093 if registry.get(altkey):
94 return
95 registry[altkey] = 1
96 elif action == "default":
97 registry[key] = 1
98 else:
99 # Unrecognized actions are errors
100 raise RuntimeError(
101 "Unrecognized action (%s) in warnings.filters:\n %s" %
102 (`action`, str(item)))
103 # Print message and context
104 showwarning(message, category, filename, lineno)
105
106def showwarning(message, category, filename, lineno, file=None):
107 """Hook to write a warning to a file; replace if you like."""
108 if file is None:
109 file = sys.stderr
Mark Hammond51a0ae32002-09-11 13:22:35 +0000110 try:
111 file.write(formatwarning(message, category, filename, lineno))
112 except IOError:
113 pass # the file (probably stderr) is invalid - this warning gets lost.
Guido van Rossum2a862c62000-12-15 21:59:53 +0000114
115def formatwarning(message, category, filename, lineno):
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000116 """Function to format a warning the standard way."""
Guido van Rossum2a862c62000-12-15 21:59:53 +0000117 import linecache
118 s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
119 line = linecache.getline(filename, lineno).strip()
120 if line:
121 s = s + " " + line + "\n"
122 return s
123
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000124def filterwarnings(action, message="", category=Warning, module="", lineno=0,
125 append=0):
Guido van Rossum2a862c62000-12-15 21:59:53 +0000126 """Insert an entry into the list of warnings filters (at the front).
127
128 Use assertions to check that all arguments have the right type."""
129 assert action in ("error", "ignore", "always", "default", "module",
130 "once"), "invalid action: %s" % `action`
Martin v. Löwisff9284bc22002-10-14 21:06:02 +0000131 assert isinstance(message, basestring), "message must be a string"
Guido van Rossum2a862c62000-12-15 21:59:53 +0000132 assert isinstance(category, types.ClassType), "category must be a class"
133 assert issubclass(category, Warning), "category must be a Warning subclass"
Martin v. Löwisff9284bc22002-10-14 21:06:02 +0000134 assert isinstance(module, basestring), "module must be a string"
Walter Dörwald65230a22002-06-03 15:58:32 +0000135 assert isinstance(lineno, int) and lineno >= 0, \
Guido van Rossum2a862c62000-12-15 21:59:53 +0000136 "lineno must be an int >= 0"
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000137 item = (action, re.compile(message, re.I), category,
138 re.compile(module), lineno)
139 if append:
140 filters.append(item)
141 else:
142 filters.insert(0, item)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000143
144def resetwarnings():
Tim Petersd0cc4f02002-04-16 01:51:25 +0000145 """Clear the list of warning filters, so that no filters are active."""
Guido van Rossum2a862c62000-12-15 21:59:53 +0000146 filters[:] = []
147
148class _OptionError(Exception):
149 """Exception used by option processing helpers."""
150 pass
151
152# Helper to process -W options passed via sys.warnoptions
153def _processoptions(args):
154 for arg in args:
155 try:
156 _setoption(arg)
157 except _OptionError, msg:
158 print >>sys.stderr, "Invalid -W option ignored:", msg
159
160# Helper for _processoptions()
161def _setoption(arg):
Tim Peterse1190062001-01-15 03:34:38 +0000162 parts = arg.split(':')
163 if len(parts) > 5:
164 raise _OptionError("too many fields (max 5): %s" % `arg`)
165 while len(parts) < 5:
166 parts.append('')
167 action, message, category, module, lineno = [s.strip()
168 for s in parts]
169 action = _getaction(action)
170 message = re.escape(message)
171 category = _getcategory(category)
172 module = re.escape(module)
173 if module:
174 module = module + '$'
175 if lineno:
176 try:
177 lineno = int(lineno)
178 if lineno < 0:
179 raise ValueError
180 except (ValueError, OverflowError):
181 raise _OptionError("invalid lineno %s" % `lineno`)
182 else:
183 lineno = 0
184 filterwarnings(action, message, category, module, lineno)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000185
186# Helper for _setoption()
187def _getaction(action):
188 if not action:
189 return "default"
190 if action == "all": return "always" # Alias
191 for a in ['default', 'always', 'ignore', 'module', 'once', 'error']:
192 if a.startswith(action):
193 return a
194 raise _OptionError("invalid action: %s" % `action`)
195
196# Helper for _setoption()
197def _getcategory(category):
198 if not category:
199 return Warning
200 if re.match("^[a-zA-Z0-9_]+$", category):
201 try:
202 cat = eval(category)
Guido van Rossumd1db30b2000-12-19 03:04:50 +0000203 except NameError:
204 raise _OptionError("unknown warning category: %s" % `category`)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000205 else:
206 i = category.rfind(".")
207 module = category[:i]
208 klass = category[i+1:]
Guido van Rossumd1db30b2000-12-19 03:04:50 +0000209 try:
210 m = __import__(module, None, None, [klass])
211 except ImportError:
212 raise _OptionError("invalid module name: %s" % `module`)
213 try:
214 cat = getattr(m, klass)
215 except AttributeError:
216 raise _OptionError("unknown warning category: %s" % `category`)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000217 if (not isinstance(cat, types.ClassType) or
218 not issubclass(cat, Warning)):
219 raise _OptionError("invalid warning category: %s" % `category`)
220 return cat
221
222# Self-test
223def _test():
224 import getopt
225 testoptions = []
226 try:
227 opts, args = getopt.getopt(sys.argv[1:], "W:")
228 except getopt.error, msg:
229 print >>sys.stderr, msg
230 return
231 for o, a in opts:
232 testoptions.append(a)
233 try:
234 _processoptions(testoptions)
235 except _OptionError, msg:
236 print >>sys.stderr, msg
237 return
238 for item in filters: print item
239 hello = "hello world"
240 warn(hello); warn(hello); warn(hello); warn(hello)
241 warn(hello, UserWarning)
242 warn(hello, DeprecationWarning)
243 for i in range(3):
244 warn(hello)
245 filterwarnings("error", "", Warning, "", 0)
246 try:
247 warn(hello)
248 except Exception, msg:
249 print "Caught", msg.__class__.__name__ + ":", msg
250 else:
251 print "No exception"
252 resetwarnings()
253 try:
254 filterwarnings("booh", "", Warning, "", 0)
255 except Exception, msg:
256 print "Caught", msg.__class__.__name__ + ":", msg
257 else:
258 print "No exception"
259
260# Module initialization
261if __name__ == "__main__":
262 import __main__
263 sys.modules['warnings'] = __main__
264 _test()
265else:
266 _processoptions(sys.warnoptions)
Guido van Rossumacc21d82001-08-23 03:07:42 +0000267 filterwarnings("ignore", category=OverflowWarning, append=1)
Neal Norwitzd68f5172002-05-29 15:54:55 +0000268 filterwarnings("ignore", category=PendingDeprecationWarning, append=1)