append(): Fixing the test for convertability after consultation with
[python/dscho.git] / Lib / warnings.py
bloba74e1bab8006bcb2b8322db15d3ac06caa687e4f
1 """Python part of the warnings subsystem."""
3 import sys, re, types
5 __all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",
6 "resetwarnings"]
8 defaultaction = "default"
9 filters = []
10 onceregistry = {}
12 def warn(message, category=None, stacklevel=1):
13 """Issue a warning, or maybe ignore it or raise an exception."""
14 # Check if message is already a Warning object
15 if isinstance(message, Warning):
16 category = message.__class__
17 # 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
30 if '__name__' in globals:
31 module = globals['__name__']
32 else:
33 module = "<string>"
34 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
44 registry = globals.setdefault("__warningregistry__", {})
45 warn_explicit(message, category, filename, lineno, module, registry)
47 def 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 = {}
55 if isinstance(message, Warning):
56 text = str(message)
57 category = message.__class__
58 else:
59 text = message
60 message = category(message)
61 key = (text, category, lineno)
62 # Quick test for common case
63 if registry.get(key):
64 return
65 # Search the filters
66 for item in filters:
67 action, msg, cat, mod, ln = item
68 if (msg.match(text) and
69 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":
80 raise message
81 # Other actions
82 if action == "once":
83 registry[key] = 1
84 oncekey = (text, category)
85 if onceregistry.get(oncekey):
86 return
87 onceregistry[oncekey] = 1
88 elif action == "always":
89 pass
90 elif action == "module":
91 registry[key] = 1
92 altkey = (text, category, 0)
93 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)
106 def 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 try:
111 file.write(formatwarning(message, category, filename, lineno))
112 except IOError:
113 pass # the file (probably stderr) is invalid - this warning gets lost.
115 def formatwarning(message, category, filename, lineno):
116 """Function to format a warning the standard way."""
117 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
124 def filterwarnings(action, message="", category=Warning, module="", lineno=0,
125 append=0):
126 """Insert an entry into the list of warnings filters (at the front).
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`
131 assert isinstance(message, str), "message must be a string"
132 assert isinstance(category, types.ClassType), "category must be a class"
133 assert issubclass(category, Warning), "category must be a Warning subclass"
134 assert isinstance(module, str), "module must be a string"
135 assert isinstance(lineno, int) and lineno >= 0, \
136 "lineno must be an int >= 0"
137 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)
144 def resetwarnings():
145 """Clear the list of warning filters, so that no filters are active."""
146 filters[:] = []
148 class _OptionError(Exception):
149 """Exception used by option processing helpers."""
150 pass
152 # Helper to process -W options passed via sys.warnoptions
153 def _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
160 # Helper for _processoptions()
161 def _setoption(arg):
162 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)
186 # Helper for _setoption()
187 def _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`)
196 # Helper for _setoption()
197 def _getcategory(category):
198 if not category:
199 return Warning
200 if re.match("^[a-zA-Z0-9_]+$", category):
201 try:
202 cat = eval(category)
203 except NameError:
204 raise _OptionError("unknown warning category: %s" % `category`)
205 else:
206 i = category.rfind(".")
207 module = category[:i]
208 klass = category[i+1:]
209 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`)
217 if (not isinstance(cat, types.ClassType) or
218 not issubclass(cat, Warning)):
219 raise _OptionError("invalid warning category: %s" % `category`)
220 return cat
222 # Self-test
223 def _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"
260 # Module initialization
261 if __name__ == "__main__":
262 import __main__
263 sys.modules['warnings'] = __main__
264 _test()
265 else:
266 _processoptions(sys.warnoptions)
267 filterwarnings("ignore", category=OverflowWarning, append=1)
268 filterwarnings("ignore", category=PendingDeprecationWarning, append=1)