Fix sf bug 666219: assertion error in httplib.
[python/dscho.git] / Lib / warnings.py
blob1c55fb23ae5ab6fe04df3fb2a2608597ba3027be
1 """Python part of the warnings subsystem."""
3 # Note: function level imports should *not* be used
4 # in this module as it may cause import lock deadlock.
5 # See bug 683658.
6 import sys, types
7 import linecache
9 __all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",
10 "resetwarnings"]
12 defaultaction = "default"
13 filters = []
14 onceregistry = {}
16 def warn(message, category=None, stacklevel=1):
17 """Issue a warning, or maybe ignore it or raise an exception."""
18 # Check if message is already a Warning object
19 if isinstance(message, Warning):
20 category = message.__class__
21 # 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
34 if '__name__' in globals:
35 module = globals['__name__']
36 else:
37 module = "<string>"
38 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
48 registry = globals.setdefault("__warningregistry__", {})
49 warn_explicit(message, category, filename, lineno, module, registry)
51 def 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 = {}
59 if isinstance(message, Warning):
60 text = str(message)
61 category = message.__class__
62 else:
63 text = message
64 message = category(message)
65 key = (text, category, lineno)
66 # Quick test for common case
67 if registry.get(key):
68 return
69 # Search the filters
70 for item in filters:
71 action, msg, cat, mod, ln = item
72 if (msg.match(text) and
73 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":
84 raise message
85 # Other actions
86 if action == "once":
87 registry[key] = 1
88 oncekey = (text, category)
89 if onceregistry.get(oncekey):
90 return
91 onceregistry[oncekey] = 1
92 elif action == "always":
93 pass
94 elif action == "module":
95 registry[key] = 1
96 altkey = (text, category, 0)
97 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)
110 def 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
114 try:
115 file.write(formatwarning(message, category, filename, lineno))
116 except IOError:
117 pass # the file (probably stderr) is invalid - this warning gets lost.
119 def formatwarning(message, category, filename, lineno):
120 """Function to format a warning the standard way."""
121 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
127 def filterwarnings(action, message="", category=Warning, module="", lineno=0,
128 append=0):
129 """Insert an entry into the list of warnings filters (at the front).
131 Use assertions to check that all arguments have the right type."""
132 import re
133 assert action in ("error", "ignore", "always", "default", "module",
134 "once"), "invalid action: %s" % `action`
135 assert isinstance(message, basestring), "message must be a string"
136 assert isinstance(category, types.ClassType), "category must be a class"
137 assert issubclass(category, Warning), "category must be a Warning subclass"
138 assert isinstance(module, basestring), "module must be a string"
139 assert isinstance(lineno, int) and lineno >= 0, \
140 "lineno must be an int >= 0"
141 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)
148 def resetwarnings():
149 """Clear the list of warning filters, so that no filters are active."""
150 filters[:] = []
152 class _OptionError(Exception):
153 """Exception used by option processing helpers."""
154 pass
156 # Helper to process -W options passed via sys.warnoptions
157 def _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
164 # Helper for _processoptions()
165 def _setoption(arg):
166 import re
167 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)
191 # Helper for _setoption()
192 def _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`)
201 # Helper for _setoption()
202 def _getcategory(category):
203 import re
204 if not category:
205 return Warning
206 if re.match("^[a-zA-Z0-9_]+$", category):
207 try:
208 cat = eval(category)
209 except NameError:
210 raise _OptionError("unknown warning category: %s" % `category`)
211 else:
212 i = category.rfind(".")
213 module = category[:i]
214 klass = category[i+1:]
215 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`)
223 if (not isinstance(cat, types.ClassType) or
224 not issubclass(cat, Warning)):
225 raise _OptionError("invalid warning category: %s" % `category`)
226 return cat
228 # Self-test
229 def _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"
266 # Module initialization
267 if __name__ == "__main__":
268 import __main__
269 sys.modules['warnings'] = __main__
270 _test()
271 else:
272 _processoptions(sys.warnoptions)
273 filterwarnings("ignore", category=OverflowWarning, append=1)
274 filterwarnings("ignore", category=PendingDeprecationWarning, append=1)