This commit was manufactured by cvs2svn to create tag 'r221c2'.
[python/dscho.git] / Lib / warnings.py
blob5bb00c19758cf846f9e15fa98dd8c79ea4155b13
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 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
27 if globals.has_key('__name__'):
28 module = globals['__name__']
29 else:
30 module = "<string>"
31 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
41 registry = globals.setdefault("__warningregistry__", {})
42 warn_explicit(message, category, filename, lineno, module, registry)
44 def 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 = {}
52 key = (message, category, lineno)
53 # Quick test for common case
54 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)
97 def 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))
103 def formatwarning(message, category, filename, lineno):
104 """Function to format a warning the standard way."""
105 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
112 def filterwarnings(action, message="", category=Warning, module="", lineno=0,
113 append=0):
114 """Insert an entry into the list of warnings filters (at the front).
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"
125 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)
132 def resetwarnings():
133 """Reset the list of warnings filters to its default state."""
134 filters[:] = []
136 class _OptionError(Exception):
137 """Exception used by option processing helpers."""
138 pass
140 # Helper to process -W options passed via sys.warnoptions
141 def _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
148 # Helper for _processoptions()
149 def _setoption(arg):
150 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)
174 # Helper for _setoption()
175 def _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`)
184 # Helper for _setoption()
185 def _getcategory(category):
186 if not category:
187 return Warning
188 if re.match("^[a-zA-Z0-9_]+$", category):
189 try:
190 cat = eval(category)
191 except NameError:
192 raise _OptionError("unknown warning category: %s" % `category`)
193 else:
194 i = category.rfind(".")
195 module = category[:i]
196 klass = category[i+1:]
197 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`)
205 if (not isinstance(cat, types.ClassType) or
206 not issubclass(cat, Warning)):
207 raise _OptionError("invalid warning category: %s" % `category`)
208 return cat
210 # Self-test
211 def _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"
248 # Module initialization
249 if __name__ == "__main__":
250 import __main__
251 sys.modules['warnings'] = __main__
252 _test()
253 else:
254 _processoptions(sys.warnoptions)
255 filterwarnings("ignore", category=OverflowWarning, append=1)