This commit was manufactured by cvs2svn to create tag 'r241c1'.
[python/dscho.git] / Lib / warnings.py
blob06d7685ece1109876b4d75e2b812fdc0c2df68e1
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 # filters contains a sequence of filter 5-tuples
13 # The components of the 5-tuple are:
14 # - an action: error, ignore, always, default, module, or once
15 # - a compiled regex that must match the warning message
16 # - a class representing the warning category
17 # - a compiled regex that must match the module that is being warned
18 # - a line number for the line being warning, or 0 to mean any line
19 # If either if the compiled regexs are None, match anything.
20 filters = []
21 defaultaction = "default"
22 onceregistry = {}
24 def warn(message, category=None, stacklevel=1):
25 """Issue a warning, or maybe ignore it or raise an exception."""
26 # Check if message is already a Warning object
27 if isinstance(message, Warning):
28 category = message.__class__
29 # Check category argument
30 if category is None:
31 category = UserWarning
32 assert issubclass(category, Warning)
33 # Get context information
34 try:
35 caller = sys._getframe(stacklevel)
36 except ValueError:
37 globals = sys.__dict__
38 lineno = 1
39 else:
40 globals = caller.f_globals
41 lineno = caller.f_lineno
42 if '__name__' in globals:
43 module = globals['__name__']
44 else:
45 module = "<string>"
46 filename = globals.get('__file__')
47 if filename:
48 fnl = filename.lower()
49 if fnl.endswith(".pyc") or fnl.endswith(".pyo"):
50 filename = filename[:-1]
51 else:
52 if module == "__main__":
53 filename = sys.argv[0]
54 if not filename:
55 filename = module
56 registry = globals.setdefault("__warningregistry__", {})
57 warn_explicit(message, category, filename, lineno, module, registry)
59 def warn_explicit(message, category, filename, lineno,
60 module=None, registry=None):
61 if module is None:
62 module = filename
63 if module[-3:].lower() == ".py":
64 module = module[:-3] # XXX What about leading pathname?
65 if registry is None:
66 registry = {}
67 if isinstance(message, Warning):
68 text = str(message)
69 category = message.__class__
70 else:
71 text = message
72 message = category(message)
73 key = (text, category, lineno)
74 # Quick test for common case
75 if registry.get(key):
76 return
77 # Search the filters
78 for item in filters:
79 action, msg, cat, mod, ln = item
80 if ((msg is None or msg.match(text)) and
81 issubclass(category, cat) and
82 (mod is None or mod.match(module)) and
83 (ln == 0 or lineno == ln)):
84 break
85 else:
86 action = defaultaction
87 # Early exit actions
88 if action == "ignore":
89 registry[key] = 1
90 return
91 if action == "error":
92 raise message
93 # Other actions
94 if action == "once":
95 registry[key] = 1
96 oncekey = (text, category)
97 if onceregistry.get(oncekey):
98 return
99 onceregistry[oncekey] = 1
100 elif action == "always":
101 pass
102 elif action == "module":
103 registry[key] = 1
104 altkey = (text, category, 0)
105 if registry.get(altkey):
106 return
107 registry[altkey] = 1
108 elif action == "default":
109 registry[key] = 1
110 else:
111 # Unrecognized actions are errors
112 raise RuntimeError(
113 "Unrecognized action (%r) in warnings.filters:\n %s" %
114 (action, item))
115 # Print message and context
116 showwarning(message, category, filename, lineno)
118 def showwarning(message, category, filename, lineno, file=None):
119 """Hook to write a warning to a file; replace if you like."""
120 if file is None:
121 file = sys.stderr
122 try:
123 file.write(formatwarning(message, category, filename, lineno))
124 except IOError:
125 pass # the file (probably stderr) is invalid - this warning gets lost.
127 def formatwarning(message, category, filename, lineno):
128 """Function to format a warning the standard way."""
129 s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
130 line = linecache.getline(filename, lineno).strip()
131 if line:
132 s = s + " " + line + "\n"
133 return s
135 def filterwarnings(action, message="", category=Warning, module="", lineno=0,
136 append=0):
137 """Insert an entry into the list of warnings filters (at the front).
139 Use assertions to check that all arguments have the right type."""
140 import re
141 assert action in ("error", "ignore", "always", "default", "module",
142 "once"), "invalid action: %r" % (action,)
143 assert isinstance(message, basestring), "message must be a string"
144 assert isinstance(category, types.ClassType), "category must be a class"
145 assert issubclass(category, Warning), "category must be a Warning subclass"
146 assert isinstance(module, basestring), "module must be a string"
147 assert isinstance(lineno, int) and lineno >= 0, \
148 "lineno must be an int >= 0"
149 item = (action, re.compile(message, re.I), category,
150 re.compile(module), lineno)
151 if append:
152 filters.append(item)
153 else:
154 filters.insert(0, item)
156 def simplefilter(action, category=Warning, lineno=0, append=0):
157 """Insert a simple entry into the list of warnings filters (at the front).
159 A simple filter matches all modules and messages.
161 assert action in ("error", "ignore", "always", "default", "module",
162 "once"), "invalid action: %r" % (action,)
163 assert isinstance(lineno, int) and lineno >= 0, \
164 "lineno must be an int >= 0"
165 item = (action, None, category, None, lineno)
166 if append:
167 filters.append(item)
168 else:
169 filters.insert(0, item)
171 def resetwarnings():
172 """Clear the list of warning filters, so that no filters are active."""
173 filters[:] = []
175 class _OptionError(Exception):
176 """Exception used by option processing helpers."""
177 pass
179 # Helper to process -W options passed via sys.warnoptions
180 def _processoptions(args):
181 for arg in args:
182 try:
183 _setoption(arg)
184 except _OptionError, msg:
185 print >>sys.stderr, "Invalid -W option ignored:", msg
187 # Helper for _processoptions()
188 def _setoption(arg):
189 import re
190 parts = arg.split(':')
191 if len(parts) > 5:
192 raise _OptionError("too many fields (max 5): %r" % (arg,))
193 while len(parts) < 5:
194 parts.append('')
195 action, message, category, module, lineno = [s.strip()
196 for s in parts]
197 action = _getaction(action)
198 message = re.escape(message)
199 category = _getcategory(category)
200 module = re.escape(module)
201 if module:
202 module = module + '$'
203 if lineno:
204 try:
205 lineno = int(lineno)
206 if lineno < 0:
207 raise ValueError
208 except (ValueError, OverflowError):
209 raise _OptionError("invalid lineno %r" % (lineno,))
210 else:
211 lineno = 0
212 filterwarnings(action, message, category, module, lineno)
214 # Helper for _setoption()
215 def _getaction(action):
216 if not action:
217 return "default"
218 if action == "all": return "always" # Alias
219 for a in ['default', 'always', 'ignore', 'module', 'once', 'error']:
220 if a.startswith(action):
221 return a
222 raise _OptionError("invalid action: %r" % (action,))
224 # Helper for _setoption()
225 def _getcategory(category):
226 import re
227 if not category:
228 return Warning
229 if re.match("^[a-zA-Z0-9_]+$", category):
230 try:
231 cat = eval(category)
232 except NameError:
233 raise _OptionError("unknown warning category: %r" % (category,))
234 else:
235 i = category.rfind(".")
236 module = category[:i]
237 klass = category[i+1:]
238 try:
239 m = __import__(module, None, None, [klass])
240 except ImportError:
241 raise _OptionError("invalid module name: %r" % (module,))
242 try:
243 cat = getattr(m, klass)
244 except AttributeError:
245 raise _OptionError("unknown warning category: %r" % (category,))
246 if (not isinstance(cat, types.ClassType) or
247 not issubclass(cat, Warning)):
248 raise _OptionError("invalid warning category: %r" % (category,))
249 return cat
251 # Module initialization
252 _processoptions(sys.warnoptions)
253 # XXX OverflowWarning should go away for Python 2.5.
254 simplefilter("ignore", category=OverflowWarning, append=1)
255 simplefilter("ignore", category=PendingDeprecationWarning, append=1)