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