blob: 5bb00c19758cf846f9e15fa98dd8c79ea4155b13 [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."""
14 # Check category argument
15 if category is None:
16 category = UserWarning
17 assert issubclass(category, Warning)
18 # Get context information
19 try:
20 caller = sys._getframe(stacklevel)
21 except ValueError:
22 globals = sys.__dict__
23 lineno = 1
24 else:
25 globals = caller.f_globals
26 lineno = caller.f_lineno
Guido van Rossum8031bbe2001-08-31 17:46:35 +000027 if globals.has_key('__name__'):
28 module = globals['__name__']
29 else:
30 module = "<string>"
Guido van Rossum2a862c62000-12-15 21:59:53 +000031 filename = globals.get('__file__')
32 if filename:
33 fnl = filename.lower()
34 if fnl.endswith(".pyc") or fnl.endswith(".pyo"):
35 filename = filename[:-1]
36 else:
37 if module == "__main__":
38 filename = sys.argv[0]
39 if not filename:
40 filename = module
Guido van Rossum2a862c62000-12-15 21:59:53 +000041 registry = globals.setdefault("__warningregistry__", {})
Guido van Rossum9e263182001-02-28 21:43:40 +000042 warn_explicit(message, category, filename, lineno, module, registry)
43
44def warn_explicit(message, category, filename, lineno,
45 module=None, registry=None):
46 if module is None:
47 module = filename
48 if module[-3:].lower() == ".py":
49 module = module[:-3] # XXX What about leading pathname?
50 if registry is None:
51 registry = {}
Guido van Rossum2a862c62000-12-15 21:59:53 +000052 key = (message, category, lineno)
Guido van Rossum3756fa32001-02-28 22:26:36 +000053 # Quick test for common case
Guido van Rossum2a862c62000-12-15 21:59:53 +000054 if registry.get(key):
55 return
56 # Search the filters
57 for item in filters:
58 action, msg, cat, mod, ln = item
59 if (msg.match(message) and
60 issubclass(category, cat) and
61 mod.match(module) and
62 (ln == 0 or lineno == ln)):
63 break
64 else:
65 action = defaultaction
66 # Early exit actions
67 if action == "ignore":
68 registry[key] = 1
69 return
70 if action == "error":
71 raise category(message)
72 # Other actions
73 if action == "once":
74 registry[key] = 1
75 oncekey = (message, category)
76 if onceregistry.get(oncekey):
77 return
78 onceregistry[oncekey] = 1
79 elif action == "always":
80 pass
81 elif action == "module":
82 registry[key] = 1
83 altkey = (message, category, 0)
84 if registry.get(altkey):
85 return
86 registry[altkey] = 1
87 elif action == "default":
88 registry[key] = 1
89 else:
90 # Unrecognized actions are errors
91 raise RuntimeError(
92 "Unrecognized action (%s) in warnings.filters:\n %s" %
93 (`action`, str(item)))
94 # Print message and context
95 showwarning(message, category, filename, lineno)
96
97def showwarning(message, category, filename, lineno, file=None):
98 """Hook to write a warning to a file; replace if you like."""
99 if file is None:
100 file = sys.stderr
101 file.write(formatwarning(message, category, filename, lineno))
102
103def formatwarning(message, category, filename, lineno):
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000104 """Function to format a warning the standard way."""
Guido van Rossum2a862c62000-12-15 21:59:53 +0000105 import linecache
106 s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
107 line = linecache.getline(filename, lineno).strip()
108 if line:
109 s = s + " " + line + "\n"
110 return s
111
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000112def filterwarnings(action, message="", category=Warning, module="", lineno=0,
113 append=0):
Guido van Rossum2a862c62000-12-15 21:59:53 +0000114 """Insert an entry into the list of warnings filters (at the front).
115
116 Use assertions to check that all arguments have the right type."""
117 assert action in ("error", "ignore", "always", "default", "module",
118 "once"), "invalid action: %s" % `action`
119 assert isinstance(message, types.StringType), "message must be a string"
120 assert isinstance(category, types.ClassType), "category must be a class"
121 assert issubclass(category, Warning), "category must be a Warning subclass"
122 assert type(module) is types.StringType, "module must be a string"
123 assert type(lineno) is types.IntType and lineno >= 0, \
124 "lineno must be an int >= 0"
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000125 item = (action, re.compile(message, re.I), category,
126 re.compile(module), lineno)
127 if append:
128 filters.append(item)
129 else:
130 filters.insert(0, item)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000131
132def resetwarnings():
133 """Reset the list of warnings filters to its default state."""
134 filters[:] = []
135
136class _OptionError(Exception):
137 """Exception used by option processing helpers."""
138 pass
139
140# Helper to process -W options passed via sys.warnoptions
141def _processoptions(args):
142 for arg in args:
143 try:
144 _setoption(arg)
145 except _OptionError, msg:
146 print >>sys.stderr, "Invalid -W option ignored:", msg
147
148# Helper for _processoptions()
149def _setoption(arg):
Tim Peterse1190062001-01-15 03:34:38 +0000150 parts = arg.split(':')
151 if len(parts) > 5:
152 raise _OptionError("too many fields (max 5): %s" % `arg`)
153 while len(parts) < 5:
154 parts.append('')
155 action, message, category, module, lineno = [s.strip()
156 for s in parts]
157 action = _getaction(action)
158 message = re.escape(message)
159 category = _getcategory(category)
160 module = re.escape(module)
161 if module:
162 module = module + '$'
163 if lineno:
164 try:
165 lineno = int(lineno)
166 if lineno < 0:
167 raise ValueError
168 except (ValueError, OverflowError):
169 raise _OptionError("invalid lineno %s" % `lineno`)
170 else:
171 lineno = 0
172 filterwarnings(action, message, category, module, lineno)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000173
174# Helper for _setoption()
175def _getaction(action):
176 if not action:
177 return "default"
178 if action == "all": return "always" # Alias
179 for a in ['default', 'always', 'ignore', 'module', 'once', 'error']:
180 if a.startswith(action):
181 return a
182 raise _OptionError("invalid action: %s" % `action`)
183
184# Helper for _setoption()
185def _getcategory(category):
186 if not category:
187 return Warning
188 if re.match("^[a-zA-Z0-9_]+$", category):
189 try:
190 cat = eval(category)
Guido van Rossumd1db30b2000-12-19 03:04:50 +0000191 except NameError:
192 raise _OptionError("unknown warning category: %s" % `category`)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000193 else:
194 i = category.rfind(".")
195 module = category[:i]
196 klass = category[i+1:]
Guido van Rossumd1db30b2000-12-19 03:04:50 +0000197 try:
198 m = __import__(module, None, None, [klass])
199 except ImportError:
200 raise _OptionError("invalid module name: %s" % `module`)
201 try:
202 cat = getattr(m, klass)
203 except AttributeError:
204 raise _OptionError("unknown warning category: %s" % `category`)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000205 if (not isinstance(cat, types.ClassType) or
206 not issubclass(cat, Warning)):
207 raise _OptionError("invalid warning category: %s" % `category`)
208 return cat
209
210# Self-test
211def _test():
212 import getopt
213 testoptions = []
214 try:
215 opts, args = getopt.getopt(sys.argv[1:], "W:")
216 except getopt.error, msg:
217 print >>sys.stderr, msg
218 return
219 for o, a in opts:
220 testoptions.append(a)
221 try:
222 _processoptions(testoptions)
223 except _OptionError, msg:
224 print >>sys.stderr, msg
225 return
226 for item in filters: print item
227 hello = "hello world"
228 warn(hello); warn(hello); warn(hello); warn(hello)
229 warn(hello, UserWarning)
230 warn(hello, DeprecationWarning)
231 for i in range(3):
232 warn(hello)
233 filterwarnings("error", "", Warning, "", 0)
234 try:
235 warn(hello)
236 except Exception, msg:
237 print "Caught", msg.__class__.__name__ + ":", msg
238 else:
239 print "No exception"
240 resetwarnings()
241 try:
242 filterwarnings("booh", "", Warning, "", 0)
243 except Exception, msg:
244 print "Caught", msg.__class__.__name__ + ":", msg
245 else:
246 print "No exception"
247
248# Module initialization
249if __name__ == "__main__":
250 import __main__
251 sys.modules['warnings'] = __main__
252 _test()
253else:
254 _processoptions(sys.warnoptions)
Guido van Rossumacc21d82001-08-23 03:07:42 +0000255 filterwarnings("ignore", category=OverflowWarning, append=1)