Chris McDonough's patch to defend against certain DoS attacks on FieldStorage.
[python.git] / Lib / warnings.py
blobb7fac699766c41441f48c55c9a61c1facaee56e5
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", ".pyo")):
50 filename = filename[:-1]
51 else:
52 if module == "__main__":
53 try:
54 filename = sys.argv[0]
55 except AttributeError:
56 # embedded interpreters don't have sys.argv, see bug #839151
57 filename = '__main__'
58 if not filename:
59 filename = module
60 registry = globals.setdefault("__warningregistry__", {})
61 warn_explicit(message, category, filename, lineno, module, registry,
62 globals)
64 def warn_explicit(message, category, filename, lineno,
65 module=None, registry=None, module_globals=None):
66 if module is None:
67 module = filename or "<unknown>"
68 if module[-3:].lower() == ".py":
69 module = module[:-3] # XXX What about leading pathname?
70 if registry is None:
71 registry = {}
72 if isinstance(message, Warning):
73 text = str(message)
74 category = message.__class__
75 else:
76 text = message
77 message = category(message)
78 key = (text, category, lineno)
79 # Quick test for common case
80 if registry.get(key):
81 return
82 # Search the filters
83 for item in filters:
84 action, msg, cat, mod, ln = item
85 if ((msg is None or msg.match(text)) and
86 issubclass(category, cat) and
87 (mod is None or mod.match(module)) and
88 (ln == 0 or lineno == ln)):
89 break
90 else:
91 action = defaultaction
92 # Early exit actions
93 if action == "ignore":
94 registry[key] = 1
95 return
97 # Prime the linecache for formatting, in case the
98 # "file" is actually in a zipfile or something.
99 linecache.getlines(filename, module_globals)
101 if action == "error":
102 raise message
103 # Other actions
104 if action == "once":
105 registry[key] = 1
106 oncekey = (text, category)
107 if onceregistry.get(oncekey):
108 return
109 onceregistry[oncekey] = 1
110 elif action == "always":
111 pass
112 elif action == "module":
113 registry[key] = 1
114 altkey = (text, category, 0)
115 if registry.get(altkey):
116 return
117 registry[altkey] = 1
118 elif action == "default":
119 registry[key] = 1
120 else:
121 # Unrecognized actions are errors
122 raise RuntimeError(
123 "Unrecognized action (%r) in warnings.filters:\n %s" %
124 (action, item))
125 # Print message and context
126 showwarning(message, category, filename, lineno)
128 def showwarning(message, category, filename, lineno, file=None):
129 """Hook to write a warning to a file; replace if you like."""
130 if file is None:
131 file = sys.stderr
132 try:
133 file.write(formatwarning(message, category, filename, lineno))
134 except IOError:
135 pass # the file (probably stderr) is invalid - this warning gets lost.
137 def formatwarning(message, category, filename, lineno):
138 """Function to format a warning the standard way."""
139 s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
140 line = linecache.getline(filename, lineno).strip()
141 if line:
142 s = s + " " + line + "\n"
143 return s
145 def filterwarnings(action, message="", category=Warning, module="", lineno=0,
146 append=0):
147 """Insert an entry into the list of warnings filters (at the front).
149 Use assertions to check that all arguments have the right type."""
150 import re
151 assert action in ("error", "ignore", "always", "default", "module",
152 "once"), "invalid action: %r" % (action,)
153 assert isinstance(message, basestring), "message must be a string"
154 assert isinstance(category, (type, types.ClassType)), \
155 "category must be a class"
156 assert issubclass(category, Warning), "category must be a Warning subclass"
157 assert isinstance(module, basestring), "module must be a string"
158 assert isinstance(lineno, int) and lineno >= 0, \
159 "lineno must be an int >= 0"
160 item = (action, re.compile(message, re.I), category,
161 re.compile(module), lineno)
162 if append:
163 filters.append(item)
164 else:
165 filters.insert(0, item)
167 def simplefilter(action, category=Warning, lineno=0, append=0):
168 """Insert a simple entry into the list of warnings filters (at the front).
170 A simple filter matches all modules and messages.
172 assert action in ("error", "ignore", "always", "default", "module",
173 "once"), "invalid action: %r" % (action,)
174 assert isinstance(lineno, int) and lineno >= 0, \
175 "lineno must be an int >= 0"
176 item = (action, None, category, None, lineno)
177 if append:
178 filters.append(item)
179 else:
180 filters.insert(0, item)
182 def resetwarnings():
183 """Clear the list of warning filters, so that no filters are active."""
184 filters[:] = []
186 class _OptionError(Exception):
187 """Exception used by option processing helpers."""
188 pass
190 # Helper to process -W options passed via sys.warnoptions
191 def _processoptions(args):
192 for arg in args:
193 try:
194 _setoption(arg)
195 except _OptionError, msg:
196 print >>sys.stderr, "Invalid -W option ignored:", msg
198 # Helper for _processoptions()
199 def _setoption(arg):
200 import re
201 parts = arg.split(':')
202 if len(parts) > 5:
203 raise _OptionError("too many fields (max 5): %r" % (arg,))
204 while len(parts) < 5:
205 parts.append('')
206 action, message, category, module, lineno = [s.strip()
207 for s in parts]
208 action = _getaction(action)
209 message = re.escape(message)
210 category = _getcategory(category)
211 module = re.escape(module)
212 if module:
213 module = module + '$'
214 if lineno:
215 try:
216 lineno = int(lineno)
217 if lineno < 0:
218 raise ValueError
219 except (ValueError, OverflowError):
220 raise _OptionError("invalid lineno %r" % (lineno,))
221 else:
222 lineno = 0
223 filterwarnings(action, message, category, module, lineno)
225 # Helper for _setoption()
226 def _getaction(action):
227 if not action:
228 return "default"
229 if action == "all": return "always" # Alias
230 for a in ('default', 'always', 'ignore', 'module', 'once', 'error'):
231 if a.startswith(action):
232 return a
233 raise _OptionError("invalid action: %r" % (action,))
235 # Helper for _setoption()
236 def _getcategory(category):
237 import re
238 if not category:
239 return Warning
240 if re.match("^[a-zA-Z0-9_]+$", category):
241 try:
242 cat = eval(category)
243 except NameError:
244 raise _OptionError("unknown warning category: %r" % (category,))
245 else:
246 i = category.rfind(".")
247 module = category[:i]
248 klass = category[i+1:]
249 try:
250 m = __import__(module, None, None, [klass])
251 except ImportError:
252 raise _OptionError("invalid module name: %r" % (module,))
253 try:
254 cat = getattr(m, klass)
255 except AttributeError:
256 raise _OptionError("unknown warning category: %r" % (category,))
257 if not issubclass(cat, Warning):
258 raise _OptionError("invalid warning category: %r" % (category,))
259 return cat
261 # Module initialization
262 _processoptions(sys.warnoptions)
263 simplefilter("ignore", category=PendingDeprecationWarning, append=1)
264 simplefilter("ignore", category=ImportWarning, append=1)