~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Lib/warnings.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Python part of the warnings subsystem."""
 
2
 
 
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 linecache
 
7
import sys
 
8
 
 
9
__all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",
 
10
           "resetwarnings", "catch_warnings"]
 
11
 
 
12
 
 
13
def showwarning(message, category, filename, lineno, file=None, line=None):
 
14
    """Hook to write a warning to a file; replace if you like."""
 
15
    if file is None:
 
16
        file = sys.stderr
 
17
    try:
 
18
        file.write(formatwarning(message, category, filename, lineno, line))
 
19
    except IOError:
 
20
        pass # the file (probably stderr) is invalid - this warning gets lost.
 
21
 
 
22
def formatwarning(message, category, filename, lineno, line=None):
 
23
    """Function to format a warning the standard way."""
 
24
    s =  "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
 
25
    line = linecache.getline(filename, lineno) if line is None else line
 
26
    if line:
 
27
        line = line.strip()
 
28
        s += "  %s\n" % line
 
29
    return s
 
30
 
 
31
def filterwarnings(action, message="", category=Warning, module="", lineno=0,
 
32
                   append=0):
 
33
    """Insert an entry into the list of warnings filters (at the front).
 
34
 
 
35
    Use assertions to check that all arguments have the right type."""
 
36
    import re
 
37
    assert action in ("error", "ignore", "always", "default", "module",
 
38
                      "once"), "invalid action: %r" % (action,)
 
39
    assert isinstance(message, str), "message must be a string"
 
40
    assert isinstance(category, type), "category must be a class"
 
41
    assert issubclass(category, Warning), "category must be a Warning subclass"
 
42
    assert isinstance(module, str), "module must be a string"
 
43
    assert isinstance(lineno, int) and lineno >= 0, \
 
44
           "lineno must be an int >= 0"
 
45
    item = (action, re.compile(message, re.I), category,
 
46
            re.compile(module), lineno)
 
47
    if append:
 
48
        filters.append(item)
 
49
    else:
 
50
        filters.insert(0, item)
 
51
 
 
52
def simplefilter(action, category=Warning, lineno=0, append=0):
 
53
    """Insert a simple entry into the list of warnings filters (at the front).
 
54
 
 
55
    A simple filter matches all modules and messages.
 
56
    """
 
57
    assert action in ("error", "ignore", "always", "default", "module",
 
58
                      "once"), "invalid action: %r" % (action,)
 
59
    assert isinstance(lineno, int) and lineno >= 0, \
 
60
           "lineno must be an int >= 0"
 
61
    item = (action, None, category, None, lineno)
 
62
    if append:
 
63
        filters.append(item)
 
64
    else:
 
65
        filters.insert(0, item)
 
66
 
 
67
def resetwarnings():
 
68
    """Clear the list of warning filters, so that no filters are active."""
 
69
    filters[:] = []
 
70
 
 
71
class _OptionError(Exception):
 
72
    """Exception used by option processing helpers."""
 
73
    pass
 
74
 
 
75
# Helper to process -W options passed via sys.warnoptions
 
76
def _processoptions(args):
 
77
    for arg in args:
 
78
        try:
 
79
            _setoption(arg)
 
80
        except _OptionError as msg:
 
81
            print("Invalid -W option ignored:", msg, file=sys.stderr)
 
82
 
 
83
# Helper for _processoptions()
 
84
def _setoption(arg):
 
85
    import re
 
86
    parts = arg.split(':')
 
87
    if len(parts) > 5:
 
88
        raise _OptionError("too many fields (max 5): %r" % (arg,))
 
89
    while len(parts) < 5:
 
90
        parts.append('')
 
91
    action, message, category, module, lineno = [s.strip()
 
92
                                                 for s in parts]
 
93
    action = _getaction(action)
 
94
    message = re.escape(message)
 
95
    category = _getcategory(category)
 
96
    module = re.escape(module)
 
97
    if module:
 
98
        module = module + '$'
 
99
    if lineno:
 
100
        try:
 
101
            lineno = int(lineno)
 
102
            if lineno < 0:
 
103
                raise ValueError
 
104
        except (ValueError, OverflowError):
 
105
            raise _OptionError("invalid lineno %r" % (lineno,))
 
106
    else:
 
107
        lineno = 0
 
108
    filterwarnings(action, message, category, module, lineno)
 
109
 
 
110
# Helper for _setoption()
 
111
def _getaction(action):
 
112
    if not action:
 
113
        return "default"
 
114
    if action == "all": return "always" # Alias
 
115
    for a in ('default', 'always', 'ignore', 'module', 'once', 'error'):
 
116
        if a.startswith(action):
 
117
            return a
 
118
    raise _OptionError("invalid action: %r" % (action,))
 
119
 
 
120
# Helper for _setoption()
 
121
def _getcategory(category):
 
122
    import re
 
123
    if not category:
 
124
        return Warning
 
125
    if re.match("^[a-zA-Z0-9_]+$", category):
 
126
        try:
 
127
            cat = eval(category)
 
128
        except NameError:
 
129
            raise _OptionError("unknown warning category: %r" % (category,))
 
130
    else:
 
131
        i = category.rfind(".")
 
132
        module = category[:i]
 
133
        klass = category[i+1:]
 
134
        try:
 
135
            m = __import__(module, None, None, [klass])
 
136
        except ImportError:
 
137
            raise _OptionError("invalid module name: %r" % (module,))
 
138
        try:
 
139
            cat = getattr(m, klass)
 
140
        except AttributeError:
 
141
            raise _OptionError("unknown warning category: %r" % (category,))
 
142
    if not issubclass(cat, Warning):
 
143
        raise _OptionError("invalid warning category: %r" % (category,))
 
144
    return cat
 
145
 
 
146
 
 
147
# Code typically replaced by _warnings
 
148
def warn(message, category=None, stacklevel=1):
 
149
    """Issue a warning, or maybe ignore it or raise an exception."""
 
150
    # Check if message is already a Warning object
 
151
    if isinstance(message, Warning):
 
152
        category = message.__class__
 
153
    # Check category argument
 
154
    if category is None:
 
155
        category = UserWarning
 
156
    assert issubclass(category, Warning)
 
157
    # Get context information
 
158
    try:
 
159
        caller = sys._getframe(stacklevel)
 
160
    except ValueError:
 
161
        globals = sys.__dict__
 
162
        lineno = 1
 
163
    else:
 
164
        globals = caller.f_globals
 
165
        lineno = caller.f_lineno
 
166
    if '__name__' in globals:
 
167
        module = globals['__name__']
 
168
    else:
 
169
        module = "<string>"
 
170
    filename = globals.get('__file__')
 
171
    if filename:
 
172
        fnl = filename.lower()
 
173
        if fnl.endswith((".pyc", ".pyo")):
 
174
            filename = filename[:-1]
 
175
    else:
 
176
        if module == "__main__":
 
177
            try:
 
178
                filename = sys.argv[0]
 
179
            except AttributeError:
 
180
                # embedded interpreters don't have sys.argv, see bug #839151
 
181
                filename = '__main__'
 
182
        if not filename:
 
183
            filename = module
 
184
    registry = globals.setdefault("__warningregistry__", {})
 
185
    warn_explicit(message, category, filename, lineno, module, registry,
 
186
                  globals)
 
187
 
 
188
def warn_explicit(message, category, filename, lineno,
 
189
                  module=None, registry=None, module_globals=None):
 
190
    lineno = int(lineno)
 
191
    if module is None:
 
192
        module = filename or "<unknown>"
 
193
        if module[-3:].lower() == ".py":
 
194
            module = module[:-3] # XXX What about leading pathname?
 
195
    if registry is None:
 
196
        registry = {}
 
197
    if isinstance(message, Warning):
 
198
        text = str(message)
 
199
        category = message.__class__
 
200
    else:
 
201
        text = message
 
202
        message = category(message)
 
203
    key = (text, category, lineno)
 
204
    # Quick test for common case
 
205
    if registry.get(key):
 
206
        return
 
207
    # Search the filters
 
208
    for item in filters:
 
209
        action, msg, cat, mod, ln = item
 
210
        if ((msg is None or msg.match(text)) and
 
211
            issubclass(category, cat) and
 
212
            (mod is None or mod.match(module)) and
 
213
            (ln == 0 or lineno == ln)):
 
214
            break
 
215
    else:
 
216
        action = defaultaction
 
217
    # Early exit actions
 
218
    if action == "ignore":
 
219
        registry[key] = 1
 
220
        return
 
221
 
 
222
    # Prime the linecache for formatting, in case the
 
223
    # "file" is actually in a zipfile or something.
 
224
    linecache.getlines(filename, module_globals)
 
225
 
 
226
    if action == "error":
 
227
        raise message
 
228
    # Other actions
 
229
    if action == "once":
 
230
        registry[key] = 1
 
231
        oncekey = (text, category)
 
232
        if onceregistry.get(oncekey):
 
233
            return
 
234
        onceregistry[oncekey] = 1
 
235
    elif action == "always":
 
236
        pass
 
237
    elif action == "module":
 
238
        registry[key] = 1
 
239
        altkey = (text, category, 0)
 
240
        if registry.get(altkey):
 
241
            return
 
242
        registry[altkey] = 1
 
243
    elif action == "default":
 
244
        registry[key] = 1
 
245
    else:
 
246
        # Unrecognized actions are errors
 
247
        raise RuntimeError(
 
248
              "Unrecognized action (%r) in warnings.filters:\n %s" %
 
249
              (action, item))
 
250
    if not hasattr(showwarning, "__call__"):
 
251
        raise TypeError("warnings.showwarning() must be set to a "
 
252
                        "function or method")
 
253
    # Print message and context
 
254
    showwarning(message, category, filename, lineno)
 
255
 
 
256
 
 
257
class WarningMessage(object):
 
258
 
 
259
    """Holds the result of a single showwarning() call."""
 
260
 
 
261
    _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
 
262
                        "line")
 
263
 
 
264
    def __init__(self, message, category, filename, lineno, file=None,
 
265
                    line=None):
 
266
        local_values = locals()
 
267
        for attr in self._WARNING_DETAILS:
 
268
            setattr(self, attr, local_values[attr])
 
269
        self._category_name = category.__name__ if category else None
 
270
 
 
271
    def __str__(self):
 
272
        return ("{message : %r, category : %r, filename : %r, lineno : %s, "
 
273
                    "line : %r}" % (self.message, self._category_name,
 
274
                                    self.filename, self.lineno, self.line))
 
275
 
 
276
 
 
277
class catch_warnings(object):
 
278
 
 
279
    """A context manager that copies and restores the warnings filter upon
 
280
    exiting the context.
 
281
 
 
282
    The 'record' argument specifies whether warnings should be captured by a
 
283
    custom implementation of warnings.showwarning() and be appended to a list
 
284
    returned by the context manager. Otherwise None is returned by the context
 
285
    manager. The objects appended to the list are arguments whose attributes
 
286
    mirror the arguments to showwarning().
 
287
 
 
288
    The 'module' argument is to specify an alternative module to the module
 
289
    named 'warnings' and imported under that name. This argument is only useful
 
290
    when testing the warnings module itself.
 
291
 
 
292
    """
 
293
 
 
294
    def __init__(self, *, record=False, module=None):
 
295
        """Specify whether to record warnings and if an alternative module
 
296
        should be used other than sys.modules['warnings'].
 
297
 
 
298
        For compatibility with Python 3.0, please consider all arguments to be
 
299
        keyword-only.
 
300
 
 
301
        """
 
302
        self._record = record
 
303
        self._module = sys.modules['warnings'] if module is None else module
 
304
        self._entered = False
 
305
 
 
306
    def __repr__(self):
 
307
        args = []
 
308
        if self._record:
 
309
            args.append("record=True")
 
310
        if self._module is not sys.modules['warnings']:
 
311
            args.append("module=%r" % self._module)
 
312
        name = type(self).__name__
 
313
        return "%s(%s)" % (name, ", ".join(args))
 
314
 
 
315
    def __enter__(self):
 
316
        if self._entered:
 
317
            raise RuntimeError("Cannot enter %r twice" % self)
 
318
        self._entered = True
 
319
        self._filters = self._module.filters
 
320
        self._module.filters = self._filters[:]
 
321
        self._showwarning = self._module.showwarning
 
322
        if self._record:
 
323
            log = []
 
324
            def showwarning(*args, **kwargs):
 
325
                log.append(WarningMessage(*args, **kwargs))
 
326
            self._module.showwarning = showwarning
 
327
            return log
 
328
        else:
 
329
            return None
 
330
 
 
331
    def __exit__(self, *exc_info):
 
332
        if not self._entered:
 
333
            raise RuntimeError("Cannot exit %r without entering first" % self)
 
334
        self._module.filters = self._filters
 
335
        self._module.showwarning = self._showwarning
 
336
 
 
337
 
 
338
# filters contains a sequence of filter 5-tuples
 
339
# The components of the 5-tuple are:
 
340
# - an action: error, ignore, always, default, module, or once
 
341
# - a compiled regex that must match the warning message
 
342
# - a class representing the warning category
 
343
# - a compiled regex that must match the module that is being warned
 
344
# - a line number for the line being warning, or 0 to mean any line
 
345
# If either if the compiled regexs are None, match anything.
 
346
_warnings_defaults = False
 
347
try:
 
348
    from _warnings import (filters, default_action, once_registry,
 
349
                            warn, warn_explicit)
 
350
    defaultaction = default_action
 
351
    onceregistry = once_registry
 
352
    _warnings_defaults = True
 
353
except ImportError:
 
354
    filters = []
 
355
    defaultaction = "default"
 
356
    onceregistry = {}
 
357
 
 
358
 
 
359
# Module initialization
 
360
_processoptions(sys.warnoptions)
 
361
if not _warnings_defaults:
 
362
    simplefilter("ignore", category=PendingDeprecationWarning, append=1)
 
363
    simplefilter("ignore", category=ImportWarning, append=1)
 
364
    bytes_warning = sys.flags.bytes_warning
 
365
    if bytes_warning > 1:
 
366
        bytes_action = "error"
 
367
    elif bytes_warning:
 
368
        bytes_action = "default"
 
369
    else:
 
370
        bytes_action = "ignore"
 
371
    simplefilter(bytes_action, category=BytesWarning, append=1)
 
372
del _warnings_defaults