Issue #4686 - add .args to exceptions in the configparsermodule
diff --git a/Lib/configparser.py b/Lib/configparser.py
index d0b03f9..d11164f 100644
--- a/Lib/configparser.py
+++ b/Lib/configparser.py
@@ -142,6 +142,7 @@
     def __init__(self, section):
         Error.__init__(self, 'No section: %r' % (section,))
         self.section = section
+        self.args = (section, )
 
 class DuplicateSectionError(Error):
     """Raised when a section is multiply-created."""
@@ -149,6 +150,7 @@
     def __init__(self, section):
         Error.__init__(self, "Section %r already exists" % section)
         self.section = section
+        self.args = (section, )
 
 class NoOptionError(Error):
     """A requested option was not found."""
@@ -158,6 +160,7 @@
                        (option, section))
         self.option = option
         self.section = section
+        self.args = (option, section)
 
 class InterpolationError(Error):
     """Base class for interpolation-related exceptions."""
@@ -166,6 +169,7 @@
         Error.__init__(self, msg)
         self.option = option
         self.section = section
+        self.args = (option, section, msg)
 
 class InterpolationMissingOptionError(InterpolationError):
     """A string substitution required a setting which was not available."""
@@ -179,6 +183,7 @@
                % (section, option, reference, rawval))
         InterpolationError.__init__(self, option, section, msg)
         self.reference = reference
+        self.args = (option, section, rawval, reference)
 
 class InterpolationSyntaxError(InterpolationError):
     """Raised when the source text into which substitutions are made
@@ -194,6 +199,7 @@
                "\trawval : %s\n"
                % (section, option, rawval))
         InterpolationError.__init__(self, option, section, msg)
+        self.args = (option, section, rawval)
 
 class ParsingError(Error):
     """Raised when a configuration file does not follow legal syntax."""
@@ -202,6 +208,7 @@
         Error.__init__(self, 'File contains parsing errors: %s' % filename)
         self.filename = filename
         self.errors = []
+        self.args = (filename, )
 
     def append(self, lineno, line):
         self.errors.append((lineno, line))
@@ -218,7 +225,7 @@
         self.filename = filename
         self.lineno = lineno
         self.line = line
-
+        self.args = (filename, lineno, line)
 
 class RawConfigParser:
     def __init__(self, defaults=None, dict_type=_default_dict,
diff --git a/Lib/test/test_cfgparser.py b/Lib/test/test_cfgparser.py
index 6acab6b..5494bfc 100644
--- a/Lib/test/test_cfgparser.py
+++ b/Lib/test/test_cfgparser.py
@@ -107,8 +107,9 @@
                     "remove_option() failed to report non-existence of option"
                     " that was removed")
 
-        self.assertRaises(configparser.NoSectionError,
-                          cf.remove_option, 'No Such Section', 'foo')
+        with self.assertRaises(configparser.NoSectionError) as cm:
+            cf.remove_option('No Such Section', 'foo')
+        self.assertEqual(cm.exception.args, ('No Such Section',))
 
         eq(cf.get('Long Line', 'foo'),
            'this line is much, much longer than my editor\nlikes it.')
@@ -160,20 +161,24 @@
 
     def test_parse_errors(self):
         self.newconfig()
-        self.parse_error(configparser.ParsingError,
+        e = self.parse_error(configparser.ParsingError,
                          "[Foo]\n  extra-spaces: splat\n")
+        self.assertEqual(e.args, ('<???>',))
         self.parse_error(configparser.ParsingError,
                          "[Foo]\n  extra-spaces= splat\n")
         self.parse_error(configparser.ParsingError,
                          "[Foo]\n:value-without-option-name\n")
         self.parse_error(configparser.ParsingError,
                          "[Foo]\n=value-without-option-name\n")
-        self.parse_error(configparser.MissingSectionHeaderError,
+        e = self.parse_error(configparser.MissingSectionHeaderError,
                          "No Section!\n")
+        self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
 
     def parse_error(self, exc, src):
         sio = io.StringIO(src)
-        self.assertRaises(exc, self.cf.readfp, sio)
+        with self.assertRaises(exc) as cm:
+            self.cf.readfp(sio)
+        return cm.exception
 
     def test_query_errors(self):
         cf = self.newconfig()
@@ -181,13 +186,15 @@
                          "new ConfigParser should have no defined sections")
         self.assertFalse(cf.has_section("Foo"),
                     "new ConfigParser should have no acknowledged sections")
-        self.assertRaises(configparser.NoSectionError,
-                          cf.options, "Foo")
-        self.assertRaises(configparser.NoSectionError,
-                          cf.set, "foo", "bar", "value")
-        self.get_error(configparser.NoSectionError, "foo", "bar")
+        with self.assertRaises(configparser.NoSectionError) as cm:
+            cf.options("Foo")
+        with self.assertRaises(configparser.NoSectionError) as cm:
+            cf.set("foo", "bar", "value")
+        e = self.get_error(configparser.NoSectionError, "foo", "bar")
+        self.assertEqual(e.args, ("foo",))
         cf.add_section("foo")
-        self.get_error(configparser.NoOptionError, "foo", "bar")
+        e = self.get_error(configparser.NoOptionError, "foo", "bar")
+        self.assertEqual(e.args, ("bar", "foo"))
 
     def get_error(self, exc, section, option):
         try:
@@ -226,8 +233,9 @@
     def test_weird_errors(self):
         cf = self.newconfig()
         cf.add_section("Foo")
-        self.assertRaises(configparser.DuplicateSectionError,
-                          cf.add_section, "Foo")
+        with self.assertRaises(configparser.DuplicateSectionError) as cm:
+            cf.add_section("Foo")
+        self.assertEqual(cm.exception.args, ("Foo",))
 
     def test_write(self):
         config_string = (
@@ -346,6 +354,11 @@
     config_class = configparser.ConfigParser
 
     def test_interpolation(self):
+        rawval = {
+            configparser.ConfigParser: "something %(with11)s "\
+                                           "lots of interpolation (11 steps)",
+            configparser.SafeConfigParser: "%(with1)s",
+        }
         cf = self.get_interpolation_config()
         eq = self.assertEqual
         eq(cf.get("Foo", "getname"), "Foo")
@@ -354,15 +367,22 @@
            "something with lots of interpolation (9 steps)")
         eq(cf.get("Foo", "bar10"),
            "something with lots of interpolation (10 steps)")
-        self.get_error(configparser.InterpolationDepthError, "Foo", "bar11")
+        e = self.get_error(configparser.InterpolationDepthError, "Foo", "bar11")
+        self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class]))
 
     def test_interpolation_missing_value(self):
+        rawval = {
+            configparser.ConfigParser: '%(reference)s',
+            configparser.SafeConfigParser: '',
+        }
         self.get_interpolation_config()
-        e = self.get_error(configparser.InterpolationError,
+        e = self.get_error(configparser.InterpolationMissingOptionError,
                            "Interpolation Error", "name")
         self.assertEqual(e.reference, "reference")
         self.assertEqual(e.section, "Interpolation Error")
         self.assertEqual(e.option, "name")
+        self.assertEqual(e.args, ('name', 'Interpolation Error',
+                                  rawval[self.config_class], 'reference'))
 
     def test_items(self):
         self.check_items_config([('default', '<default>'),