diff -r ddcf09a348ca Doc/library/warnings.rst --- a/Doc/library/warnings.rst Wed Nov 28 19:24:44 2012 +0200 +++ b/Doc/library/warnings.rst Thu Nov 29 15:51:13 2012 +0100 @@ -382,6 +382,31 @@ and calls to :func:`simplefilter`. +.. function:: process_option(option) + + Parse a comma-separated filter definition, as described for command line + option :option:`-W`, and insert the filter. If the filter definition is + malformed, a :exc:`warnings.WarningsOptParsingException` is raised. Along + with :mod:`argparse`, it is useful to control warnings from the command line + of a program.:: + + import argparse, warnings + + parser = argparse.ArgumentParser(description='Mimic python -W behaviour.') + parser.add_argument('-W', dest='warnings', action='append', metavar='arg', + help='warning control; arg is action:message:category:module:lineno') + + args = parser.parse_args() + + if args.warnings: + for arg in args.warnings: + try: + warnings.process_option(arg) + except WarningsOptParseError as msg: + print("Invalid -W option ignored:", msg, file=sys.stderr) + + + Available Context Managers -------------------------- diff -r ddcf09a348ca Lib/test/test_warnings.py --- a/Lib/test/test_warnings.py Wed Nov 28 19:24:44 2012 +0200 +++ b/Lib/test/test_warnings.py Thu Nov 29 15:51:13 2012 +0100 @@ -381,17 +381,17 @@ class WCmdLineTests(unittest.TestCase): - def test_improper_input(self): - # Uses the private _setoption() function to test the parsing - # of command-line warning arguments + def test_option_parsing(self): + # check if the opt args are properly parsed + self.module.resetwarnings() with original_warnings.catch_warnings(module=self.module): - self.assertRaises(self.module._OptionError, - self.module._setoption, '1:2:3:4:5:6') - self.assertRaises(self.module._OptionError, - self.module._setoption, 'bogus::Warning') - self.assertRaises(self.module._OptionError, - self.module._setoption, 'ignore:2::4:-5') - self.module._setoption('error::Warning::0') + self.assertRaises(self.module.WarningsOptParsingError, + self.module.process_option, '1:2:3:4:5:6') + self.assertRaises(self.module.WarningsOptParsingError, + self.module.process_option, 'bogus::Warning') + self.assertRaises(self.module.WarningsOptParsingError, + self.module.process_option, 'ignore:2::4:-5') + self.module.process_option('error::Warning::0') self.assertRaises(UserWarning, self.module.warn, 'convert to error') def test_improper_option(self): @@ -410,6 +410,7 @@ self.assertFalse(out.strip()) self.assertNotIn(b'RuntimeWarning', err) + class CWCmdLineTests(BaseTest, WCmdLineTests): module = c_warnings diff -r ddcf09a348ca Lib/warnings.py --- a/Lib/warnings.py Wed Nov 28 19:24:44 2012 +0200 +++ b/Lib/warnings.py Thu Nov 29 15:51:13 2012 +0100 @@ -80,24 +80,29 @@ """Clear the list of warning filters, so that no filters are active.""" filters[:] = [] -class _OptionError(Exception): + +class WarningsOptParsingError(Exception): """Exception used by option processing helpers.""" pass + # Helper to process -W options passed via sys.warnoptions def _processoptions(args): for arg in args: try: - _setoption(arg) - except _OptionError as msg: + process_option(arg) + except WarningsOptParsingError as msg: print("Invalid -W option ignored:", msg, file=sys.stderr) # Helper for _processoptions() -def _setoption(arg): +def process_option(opt): + """Parse a comma separated warning filter defintion and insert it. + The filter definition must match python -W option format + """ import re parts = arg.split(':') if len(parts) > 5: - raise _OptionError("too many fields (max 5): %r" % (arg,)) + raise WarningsOptParsingError("too many fields (max 5): %r" % (arg,)) while len(parts) < 5: parts.append('') action, message, category, module, lineno = [s.strip() @@ -114,12 +119,12 @@ if lineno < 0: raise ValueError except (ValueError, OverflowError): - raise _OptionError("invalid lineno %r" % (lineno,)) + raise WarningsOptParsingError("invalid lineno %r" % (lineno,)) else: lineno = 0 filterwarnings(action, message, category, module, lineno) -# Helper for _setoption() +# Helper for process_option() def _getaction(action): if not action: return "default" @@ -127,9 +132,9 @@ for a in ('default', 'always', 'ignore', 'module', 'once', 'error'): if a.startswith(action): return a - raise _OptionError("invalid action: %r" % (action,)) + raise WarningsOptParsingError("invalid action: %r" % (action,)) -# Helper for _setoption() +# Helper for process_option() def _getcategory(category): import re if not category: @@ -138,7 +143,8 @@ try: cat = eval(category) except NameError: - raise _OptionError("unknown warning category: %r" % (category,)) + raise WarningsOptParsingError("unknown warning category: %r" % + (category,)) else: i = category.rfind(".") module = category[:i] @@ -146,13 +152,15 @@ try: m = __import__(module, None, None, [klass]) except ImportError: - raise _OptionError("invalid module name: %r" % (module,)) + raise WarningsOptParsingError("invalid module name: %r" % (module,)) try: cat = getattr(m, klass) except AttributeError: - raise _OptionError("unknown warning category: %r" % (category,)) + raise WarningsOptParsingError("unknown warning category: %r" % + (category,)) if not issubclass(cat, Warning): - raise _OptionError("invalid warning category: %r" % (category,)) + raise WarningsOptParsingError("invalid warning category: %r" % + (category,)) return cat