Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 53c87d1

Browse files
committed
Merge fix for #19546: configparser exceptions leak implementation details
2 parents ece38d9 + 949053b commit 53c87d1

3 files changed

Lines changed: 62 additions & 6 deletions

File tree

Lib/configparser.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ def _interpolate_some(self, parser, option, accum, rest, section, map,
410410
v = map[var]
411411
except KeyError:
412412
raise InterpolationMissingOptionError(
413-
option, section, rest, var)
413+
option, section, rest, var) from None
414414
if "%" in v:
415415
self._interpolate_some(parser, option, accum, v,
416416
section, map, depth + 1)
@@ -482,7 +482,7 @@ def _interpolate_some(self, parser, option, accum, rest, section, map,
482482
"More than one ':' found: %r" % (rest,))
483483
except (KeyError, NoSectionError, NoOptionError):
484484
raise InterpolationMissingOptionError(
485-
option, section, rest, ":".join(path))
485+
option, section, rest, ":".join(path)) from None
486486
if "$" in v:
487487
self._interpolate_some(parser, opt, accum, v, sect,
488488
dict(parser.items(sect, raw=True)),
@@ -515,7 +515,7 @@ def before_get(self, parser, section, option, value, vars):
515515
value = value % vars
516516
except KeyError as e:
517517
raise InterpolationMissingOptionError(
518-
option, section, rawval, e.args[0])
518+
option, section, rawval, e.args[0]) from None
519519
else:
520520
break
521521
if value and "%(" in value:
@@ -647,7 +647,7 @@ def options(self, section):
647647
try:
648648
opts = self._sections[section].copy()
649649
except KeyError:
650-
raise NoSectionError(section)
650+
raise NoSectionError(section) from None
651651
opts.update(self._defaults)
652652
return list(opts.keys())
653653

@@ -876,7 +876,7 @@ def set(self, section, option, value=None):
876876
try:
877877
sectdict = self._sections[section]
878878
except KeyError:
879-
raise NoSectionError(section)
879+
raise NoSectionError(section) from None
880880
sectdict[self.optionxform(option)] = value
881881

882882
def write(self, fp, space_around_delimiters=True):
@@ -917,7 +917,7 @@ def remove_option(self, section, option):
917917
try:
918918
sectdict = self._sections[section]
919919
except KeyError:
920-
raise NoSectionError(section)
920+
raise NoSectionError(section) from None
921921
option = self.optionxform(option)
922922
existed = option in sectdict
923923
if existed:

Lib/test/test_configparser.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,6 +1763,58 @@ def test_stripping(self):
17631763
self.assertEqual(s['k2'], 'v2')
17641764
self.assertEqual(s['k3'], 'v3;#//still v3# and still v3')
17651765

1766+
class ExceptionContextTestCase(unittest.TestCase):
1767+
""" Test that implementation details doesn't leak
1768+
through raising exceptions. """
1769+
1770+
def test_get_basic_interpolation(self):
1771+
parser = configparser.ConfigParser()
1772+
parser.read_string("""
1773+
[Paths]
1774+
home_dir: /Users
1775+
my_dir: %(home_dir1)s/lumberjack
1776+
my_pictures: %(my_dir)s/Pictures
1777+
""")
1778+
cm = self.assertRaises(configparser.InterpolationMissingOptionError)
1779+
with cm:
1780+
parser.get('Paths', 'my_dir')
1781+
self.assertIs(cm.exception.__suppress_context__, True)
1782+
1783+
def test_get_extended_interpolation(self):
1784+
parser = configparser.ConfigParser(
1785+
interpolation=configparser.ExtendedInterpolation())
1786+
parser.read_string("""
1787+
[Paths]
1788+
home_dir: /Users
1789+
my_dir: ${home_dir1}/lumberjack
1790+
my_pictures: ${my_dir}/Pictures
1791+
""")
1792+
cm = self.assertRaises(configparser.InterpolationMissingOptionError)
1793+
with cm:
1794+
parser.get('Paths', 'my_dir')
1795+
self.assertIs(cm.exception.__suppress_context__, True)
1796+
1797+
def test_missing_options(self):
1798+
parser = configparser.ConfigParser()
1799+
parser.read_string("""
1800+
[Paths]
1801+
home_dir: /Users
1802+
""")
1803+
with self.assertRaises(configparser.NoSectionError) as cm:
1804+
parser.options('test')
1805+
self.assertIs(cm.exception.__suppress_context__, True)
1806+
1807+
def test_missing_section(self):
1808+
config = configparser.ConfigParser()
1809+
with self.assertRaises(configparser.NoSectionError) as cm:
1810+
config.set('Section1', 'an_int', '15')
1811+
self.assertIs(cm.exception.__suppress_context__, True)
1812+
1813+
def test_remove_option(self):
1814+
config = configparser.ConfigParser()
1815+
with self.assertRaises(configparser.NoSectionError) as cm:
1816+
config.remove_option('Section1', 'an_int')
1817+
self.assertIs(cm.exception.__suppress_context__, True)
17661818

17671819
if __name__ == '__main__':
17681820
unittest.main()

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ Core and Builtins
129129
Library
130130
-------
131131

132+
- Issue #19546: configparser exceptions no longer expose implementation details.
133+
Chained KeyErrors are removed, which leads to cleaner tracebacks. Patch by
134+
Claudiu Popa.
135+
132136
- Issue #22051: turtledemo no longer reloads examples to re-run them.
133137
Initialization of variables and gui setup should be done in main(),
134138
which is called each time a demo is run, but not on import.

0 commit comments

Comments
 (0)