blob: 383e62383aa629ac0da92517675482bc328c927e [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
110 file.write(formatwarning(message, category, filename, lineno))
111
112def formatwarning(message, category, filename, lineno):
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000113 """Function to format a warning the standard way."""
Guido van Rossum2a862c62000-12-15 21:59:53 +0000114 import linecache
115 s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
116 line = linecache.getline(filename, lineno).strip()
117 if line:
118 s = s + " " + line + "\n"
119 return s
120
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000121def filterwarnings(action, message="", category=Warning, module="", lineno=0,
122 append=0):
Guido van Rossum2a862c62000-12-15 21:59:53 +0000123 """Insert an entry into the list of warnings filters (at the front).
124
125 Use assertions to check that all arguments have the right type."""
126 assert action in ("error", "ignore", "always", "default", "module",
127 "once"), "invalid action: %s" % `action`
Walter Dörwald65230a22002-06-03 15:58:32 +0000128 assert isinstance(message, str), "message must be a string"
Guido van Rossum2a862c62000-12-15 21:59:53 +0000129 assert isinstance(category, types.ClassType), "category must be a class"
130 assert issubclass(category, Warning), "category must be a Warning subclass"
Walter Dörwald65230a22002-06-03 15:58:32 +0000131 assert isinstance(module, str), "module must be a string"
132 assert isinstance(lineno, int) and lineno >= 0, \
Guido van Rossum2a862c62000-12-15 21:59:53 +0000133 "lineno must be an int >= 0"
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000134 item = (action, re.compile(message, re.I), category,
135 re.compile(module), lineno)
136 if append:
137 filters.append(item)
138 else:
139 filters.insert(0, item)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000140
141def resetwarnings():
Tim Petersd0cc4f02002-04-16 01:51:25 +0000142 """Clear the list of warning filters, so that no filters are active."""
Guido van Rossum2a862c62000-12-15 21:59:53 +0000143 filters[:] = []
144
145class _OptionError(Exception):
146 """Exception used by option processing helpers."""
147 pass
148
149# Helper to process -W options passed via sys.warnoptions
150def _processoptions(args):
151 for arg in args:
152 try:
153 _setoption(arg)
154 except _OptionError, msg:
155 print >>sys.stderr, "Invalid -W option ignored:", msg
156
157# Helper for _processoptions()
158def _setoption(arg):
Tim Peterse1190062001-01-15 03:34:38 +0000159 parts = arg.split(':')
160 if len(parts) > 5:
161 raise _OptionError("too many fields (max 5): %s" % `arg`)
162 while len(parts) < 5:
163 parts.append('')
164 action, message, category, module, lineno = [s.strip()
165 for s in parts]
166 action = _getaction(action)
167 message = re.escape(message)
168 category = _getcategory(category)
169 module = re.escape(module)
170 if module:
171 module = module + '$'
172 if lineno:
173 try:
174 lineno = int(lineno)
175 if lineno < 0:
176 raise ValueError
177 except (ValueError, OverflowError):
178 raise _OptionError("invalid lineno %s" % `lineno`)
179 else:
180 lineno = 0
181 filterwarnings(action, message, category, module, lineno)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000182
183# Helper for _setoption()
184def _getaction(action):
185 if not action:
186 return "default"
187 if action == "all": return "always" # Alias
188 for a in ['default', 'always', 'ignore', 'module', 'once', 'error']:
189 if a.startswith(action):
190 return a
191 raise _OptionError("invalid action: %s" % `action`)
192
193# Helper for _setoption()
194def _getcategory(category):
195 if not category:
196 return Warning
197 if re.match("^[a-zA-Z0-9_]+$", category):
198 try:
199 cat = eval(category)
Guido van Rossumd1db30b2000-12-19 03:04:50 +0000200 except NameError:
201 raise _OptionError("unknown warning category: %s" % `category`)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000202 else:
203 i = category.rfind(".")
204 module = category[:i]
205 klass = category[i+1:]
Guido van Rossumd1db30b2000-12-19 03:04:50 +0000206 try:
207 m = __import__(module, None, None, [klass])
208 except ImportError:
209 raise _OptionError("invalid module name: %s" % `module`)
210 try:
211 cat = getattr(m, klass)
212 except AttributeError:
213 raise _OptionError("unknown warning category: %s" % `category`)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000214 if (not isinstance(cat, types.ClassType) or
215 not issubclass(cat, Warning)):
216 raise _OptionError("invalid warning category: %s" % `category`)
217 return cat
218
219# Self-test
220def _test():
221 import getopt
222 testoptions = []
223 try:
224 opts, args = getopt.getopt(sys.argv[1:], "W:")
225 except getopt.error, msg:
226 print >>sys.stderr, msg
227 return
228 for o, a in opts:
229 testoptions.append(a)
230 try:
231 _processoptions(testoptions)
232 except _OptionError, msg:
233 print >>sys.stderr, msg
234 return
235 for item in filters: print item
236 hello = "hello world"
237 warn(hello); warn(hello); warn(hello); warn(hello)
238 warn(hello, UserWarning)
239 warn(hello, DeprecationWarning)
240 for i in range(3):
241 warn(hello)
242 filterwarnings("error", "", Warning, "", 0)
243 try:
244 warn(hello)
245 except Exception, msg:
246 print "Caught", msg.__class__.__name__ + ":", msg
247 else:
248 print "No exception"
249 resetwarnings()
250 try:
251 filterwarnings("booh", "", Warning, "", 0)
252 except Exception, msg:
253 print "Caught", msg.__class__.__name__ + ":", msg
254 else:
255 print "No exception"
256
257# Module initialization
258if __name__ == "__main__":
259 import __main__
260 sys.modules['warnings'] = __main__
261 _test()
262else:
263 _processoptions(sys.warnoptions)
Guido van Rossumacc21d82001-08-23 03:07:42 +0000264 filterwarnings("ignore", category=OverflowWarning, append=1)
Neal Norwitzd68f5172002-05-29 15:54:55 +0000265 filterwarnings("ignore", category=PendingDeprecationWarning, append=1)