blob: 9763dc67af8d6753e223ae5040acd89b5e5583b4 [file] [log] [blame]
Guido van Rossum2a862c62000-12-15 21:59:53 +00001"""Python part of the warnings subsystem."""
2
3import sys, re, types
4
5defaultaction = "default"
6filters = []
7onceregistry = {}
8
9def warn(message, category=None, stacklevel=1):
10 """Issue a warning, or maybe ignore it or raise an exception."""
11 # Check category argument
12 if category is None:
13 category = UserWarning
14 assert issubclass(category, Warning)
15 # Get context information
16 try:
17 caller = sys._getframe(stacklevel)
18 except ValueError:
19 globals = sys.__dict__
20 lineno = 1
21 else:
22 globals = caller.f_globals
23 lineno = caller.f_lineno
24 module = globals['__name__']
25 filename = globals.get('__file__')
26 if filename:
27 fnl = filename.lower()
28 if fnl.endswith(".pyc") or fnl.endswith(".pyo"):
29 filename = filename[:-1]
30 else:
31 if module == "__main__":
32 filename = sys.argv[0]
33 if not filename:
34 filename = module
35 # Quick test for common case
36 registry = globals.setdefault("__warningregistry__", {})
37 key = (message, category, lineno)
38 if registry.get(key):
39 return
40 # Search the filters
41 for item in filters:
42 action, msg, cat, mod, ln = item
43 if (msg.match(message) and
44 issubclass(category, cat) and
45 mod.match(module) and
46 (ln == 0 or lineno == ln)):
47 break
48 else:
49 action = defaultaction
50 # Early exit actions
51 if action == "ignore":
52 registry[key] = 1
53 return
54 if action == "error":
55 raise category(message)
56 # Other actions
57 if action == "once":
58 registry[key] = 1
59 oncekey = (message, category)
60 if onceregistry.get(oncekey):
61 return
62 onceregistry[oncekey] = 1
63 elif action == "always":
64 pass
65 elif action == "module":
66 registry[key] = 1
67 altkey = (message, category, 0)
68 if registry.get(altkey):
69 return
70 registry[altkey] = 1
71 elif action == "default":
72 registry[key] = 1
73 else:
74 # Unrecognized actions are errors
75 raise RuntimeError(
76 "Unrecognized action (%s) in warnings.filters:\n %s" %
77 (`action`, str(item)))
78 # Print message and context
79 showwarning(message, category, filename, lineno)
80
81def showwarning(message, category, filename, lineno, file=None):
82 """Hook to write a warning to a file; replace if you like."""
83 if file is None:
84 file = sys.stderr
85 file.write(formatwarning(message, category, filename, lineno))
86
87def formatwarning(message, category, filename, lineno):
Guido van Rossum9464a7d2001-01-14 14:08:40 +000088 """Function to format a warning the standard way."""
Guido van Rossum2a862c62000-12-15 21:59:53 +000089 import linecache
90 s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
91 line = linecache.getline(filename, lineno).strip()
92 if line:
93 s = s + " " + line + "\n"
94 return s
95
Guido van Rossum9464a7d2001-01-14 14:08:40 +000096def filterwarnings(action, message="", category=Warning, module="", lineno=0,
97 append=0):
Guido van Rossum2a862c62000-12-15 21:59:53 +000098 """Insert an entry into the list of warnings filters (at the front).
99
100 Use assertions to check that all arguments have the right type."""
101 assert action in ("error", "ignore", "always", "default", "module",
102 "once"), "invalid action: %s" % `action`
103 assert isinstance(message, types.StringType), "message must be a string"
104 assert isinstance(category, types.ClassType), "category must be a class"
105 assert issubclass(category, Warning), "category must be a Warning subclass"
106 assert type(module) is types.StringType, "module must be a string"
107 assert type(lineno) is types.IntType and lineno >= 0, \
108 "lineno must be an int >= 0"
Guido van Rossum9464a7d2001-01-14 14:08:40 +0000109 item = (action, re.compile(message, re.I), category,
110 re.compile(module), lineno)
111 if append:
112 filters.append(item)
113 else:
114 filters.insert(0, item)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000115
116def resetwarnings():
117 """Reset the list of warnings filters to its default state."""
118 filters[:] = []
119
120class _OptionError(Exception):
121 """Exception used by option processing helpers."""
122 pass
123
124# Helper to process -W options passed via sys.warnoptions
125def _processoptions(args):
126 for arg in args:
127 try:
128 _setoption(arg)
129 except _OptionError, msg:
130 print >>sys.stderr, "Invalid -W option ignored:", msg
131
132# Helper for _processoptions()
133def _setoption(arg):
Tim Peterse1190062001-01-15 03:34:38 +0000134 parts = arg.split(':')
135 if len(parts) > 5:
136 raise _OptionError("too many fields (max 5): %s" % `arg`)
137 while len(parts) < 5:
138 parts.append('')
139 action, message, category, module, lineno = [s.strip()
140 for s in parts]
141 action = _getaction(action)
142 message = re.escape(message)
143 category = _getcategory(category)
144 module = re.escape(module)
145 if module:
146 module = module + '$'
147 if lineno:
148 try:
149 lineno = int(lineno)
150 if lineno < 0:
151 raise ValueError
152 except (ValueError, OverflowError):
153 raise _OptionError("invalid lineno %s" % `lineno`)
154 else:
155 lineno = 0
156 filterwarnings(action, message, category, module, lineno)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000157
158# Helper for _setoption()
159def _getaction(action):
160 if not action:
161 return "default"
162 if action == "all": return "always" # Alias
163 for a in ['default', 'always', 'ignore', 'module', 'once', 'error']:
164 if a.startswith(action):
165 return a
166 raise _OptionError("invalid action: %s" % `action`)
167
168# Helper for _setoption()
169def _getcategory(category):
170 if not category:
171 return Warning
172 if re.match("^[a-zA-Z0-9_]+$", category):
173 try:
174 cat = eval(category)
Guido van Rossumd1db30b2000-12-19 03:04:50 +0000175 except NameError:
176 raise _OptionError("unknown warning category: %s" % `category`)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000177 else:
178 i = category.rfind(".")
179 module = category[:i]
180 klass = category[i+1:]
Guido van Rossumd1db30b2000-12-19 03:04:50 +0000181 try:
182 m = __import__(module, None, None, [klass])
183 except ImportError:
184 raise _OptionError("invalid module name: %s" % `module`)
185 try:
186 cat = getattr(m, klass)
187 except AttributeError:
188 raise _OptionError("unknown warning category: %s" % `category`)
Guido van Rossum2a862c62000-12-15 21:59:53 +0000189 if (not isinstance(cat, types.ClassType) or
190 not issubclass(cat, Warning)):
191 raise _OptionError("invalid warning category: %s" % `category`)
192 return cat
193
194# Self-test
195def _test():
196 import getopt
197 testoptions = []
198 try:
199 opts, args = getopt.getopt(sys.argv[1:], "W:")
200 except getopt.error, msg:
201 print >>sys.stderr, msg
202 return
203 for o, a in opts:
204 testoptions.append(a)
205 try:
206 _processoptions(testoptions)
207 except _OptionError, msg:
208 print >>sys.stderr, msg
209 return
210 for item in filters: print item
211 hello = "hello world"
212 warn(hello); warn(hello); warn(hello); warn(hello)
213 warn(hello, UserWarning)
214 warn(hello, DeprecationWarning)
215 for i in range(3):
216 warn(hello)
217 filterwarnings("error", "", Warning, "", 0)
218 try:
219 warn(hello)
220 except Exception, msg:
221 print "Caught", msg.__class__.__name__ + ":", msg
222 else:
223 print "No exception"
224 resetwarnings()
225 try:
226 filterwarnings("booh", "", Warning, "", 0)
227 except Exception, msg:
228 print "Caught", msg.__class__.__name__ + ":", msg
229 else:
230 print "No exception"
231
232# Module initialization
233if __name__ == "__main__":
234 import __main__
235 sys.modules['warnings'] = __main__
236 _test()
237else:
238 _processoptions(sys.warnoptions)