Skip to content

Commit 2a862c6

Browse files
committed
Python part of the warnings subsystem.
1 parent cfd42b5 commit 2a862c6

File tree

1 file changed

+227
-0
lines changed

1 file changed

+227
-0
lines changed

Lib/warnings.py

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
"""Python part of the warnings subsystem."""
2+
3+
import sys, re, types
4+
5+
defaultaction = "default"
6+
filters = []
7+
onceregistry = {}
8+
9+
def 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+
81+
def 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+
87+
def formatwarning(message, category, filename, lineno):
88+
"""Hook to format a warning the standard way."""
89+
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+
96+
def filterwarnings(action, message="", category=Warning, module="", lineno=0):
97+
"""Insert an entry into the list of warnings filters (at the front).
98+
99+
Use assertions to check that all arguments have the right type."""
100+
assert action in ("error", "ignore", "always", "default", "module",
101+
"once"), "invalid action: %s" % `action`
102+
assert isinstance(message, types.StringType), "message must be a string"
103+
assert isinstance(category, types.ClassType), "category must be a class"
104+
assert issubclass(category, Warning), "category must be a Warning subclass"
105+
assert type(module) is types.StringType, "module must be a string"
106+
assert type(lineno) is types.IntType and lineno >= 0, \
107+
"lineno must be an int >= 0"
108+
filters.insert(0, (action, re.compile(message, re.I), category,
109+
re.compile(module), lineno))
110+
111+
def resetwarnings():
112+
"""Reset the list of warnings filters to its default state."""
113+
filters[:] = []
114+
115+
class _OptionError(Exception):
116+
"""Exception used by option processing helpers."""
117+
pass
118+
119+
# Helper to process -W options passed via sys.warnoptions
120+
def _processoptions(args):
121+
for arg in args:
122+
try:
123+
_setoption(arg)
124+
except _OptionError, msg:
125+
print >>sys.stderr, "Invalid -W option ignored:", msg
126+
127+
# Helper for _processoptions()
128+
def _setoption(arg):
129+
parts = arg.split(':')
130+
if len(parts) > 5:
131+
raise _OptionError("unparsable -W option %s" % `arg`)
132+
while len(parts) < 5:
133+
parts.append('')
134+
action, message, category, module, lineno = [s.strip()
135+
for s in parts]
136+
action = _getaction(action)
137+
message = re.escape(message)
138+
category = _getcategory(category)
139+
module = re.escape(module)
140+
if module:
141+
module = module + '$'
142+
if lineno:
143+
try:
144+
lineno = int(lineno)
145+
if lineno < 0:
146+
raise ValueError
147+
except (ValueError, OverflowError):
148+
raise _OptionError("invalid lineno %s" % `lineno`)
149+
else:
150+
lineno = 0
151+
filterwarnings(action, message, category, module, lineno)
152+
153+
# Helper for _setoption()
154+
def _getaction(action):
155+
if not action:
156+
return "default"
157+
if action == "all": return "always" # Alias
158+
for a in ['default', 'always', 'ignore', 'module', 'once', 'error']:
159+
if a.startswith(action):
160+
return a
161+
raise _OptionError("invalid action: %s" % `action`)
162+
163+
# Helper for _setoption()
164+
def _getcategory(category):
165+
if not category:
166+
return Warning
167+
if re.match("^[a-zA-Z0-9_]+$", category):
168+
try:
169+
cat = eval(category)
170+
except KeyError:
171+
raise _OptionError("invalid warning category: %s" % `category`)
172+
else:
173+
i = category.rfind(".")
174+
module = category[:i]
175+
klass = category[i+1:]
176+
m = __import__(module, None, None, [klass])
177+
cat = getattr(m, klass)
178+
if (not isinstance(cat, types.ClassType) or
179+
not issubclass(cat, Warning)):
180+
raise _OptionError("invalid warning category: %s" % `category`)
181+
return cat
182+
183+
# Self-test
184+
def _test():
185+
import getopt
186+
testoptions = []
187+
try:
188+
opts, args = getopt.getopt(sys.argv[1:], "W:")
189+
except getopt.error, msg:
190+
print >>sys.stderr, msg
191+
return
192+
for o, a in opts:
193+
testoptions.append(a)
194+
try:
195+
_processoptions(testoptions)
196+
except _OptionError, msg:
197+
print >>sys.stderr, msg
198+
return
199+
for item in filters: print item
200+
hello = "hello world"
201+
warn(hello); warn(hello); warn(hello); warn(hello)
202+
warn(hello, UserWarning)
203+
warn(hello, DeprecationWarning)
204+
for i in range(3):
205+
warn(hello)
206+
filterwarnings("error", "", Warning, "", 0)
207+
try:
208+
warn(hello)
209+
except Exception, msg:
210+
print "Caught", msg.__class__.__name__ + ":", msg
211+
else:
212+
print "No exception"
213+
resetwarnings()
214+
try:
215+
filterwarnings("booh", "", Warning, "", 0)
216+
except Exception, msg:
217+
print "Caught", msg.__class__.__name__ + ":", msg
218+
else:
219+
print "No exception"
220+
221+
# Module initialization
222+
if __name__ == "__main__":
223+
import __main__
224+
sys.modules['warnings'] = __main__
225+
_test()
226+
else:
227+
_processoptions(sys.warnoptions)

0 commit comments

Comments
 (0)