From f27c1a1eaa5b512be21af062280c5b765e6955b0 Mon Sep 17 00:00:00 2001 From: hanjinpeng Date: Sun, 13 Sep 2026 21:48:47 -0400 Subject: [PATCH] config: raise NotImplementedError from abstract ConfigNamespace methods ConfigNamespace._getitem() and __iter__() returned a NotImplementedError instance instead of raising it (see the FIXME). As a result 'key in ConfigNamespace()' was always True and iter() failed with a confusing TypeError. Raise the exception as intended. --- iniparse/config.py | 5 ++--- tests/test_ini.py | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/iniparse/config.py b/iniparse/config.py index 00800c3..5c408dd 100644 --- a/iniparse/config.py +++ b/iniparse/config.py @@ -23,7 +23,7 @@ class ConfigNamespace: # Methods that must be implemented by subclasses def _getitem(self, key: str) -> object: - return NotImplementedError(key) + raise NotImplementedError(key) def __setitem__(self, key: str, value: object): raise NotImplementedError(key, value) @@ -32,8 +32,7 @@ def __delitem__(self, key: str) -> None: raise NotImplementedError(key) def __iter__(self) -> Iterable[str]: - # FIXME Raise instead return - return NotImplementedError() + raise NotImplementedError() def _new_namespace(self, name: str) -> "ConfigNamespace": raise NotImplementedError(name) diff --git a/tests/test_ini.py b/tests/test_ini.py index 359a2b9..5b23b41 100644 --- a/tests/test_ini.py +++ b/tests/test_ini.py @@ -833,3 +833,25 @@ def test_option_continuation_single(self): ip.section.option = '\n'.join(['', '', '', 'foo', '', '', '']) ip.section.another = 'baz' self.assertEqual(str(ip), self.s6) + + +class TestConfigNamespaceAbstract(unittest.TestCase): + def test_abstract_methods_raise(self): + """ + :id: 855cbd60-05d1-449f-91c0-d77a8dfa2e59 + :title: Abstract ConfigNamespace methods raise NotImplementedError + :description: + Verifies that the abstract _getitem() and __iter__() methods of + ConfigNamespace raise NotImplementedError instead of returning + the exception object (which made `key in ns` always True). + :tags: Tier 3 + :steps: + 1. Create a bare ConfigNamespace. + 2. Check membership and iterate over it. + :expectedresults: + 1. Object is created. + 2. NotImplementedError is raised in both cases. + """ + ns = config.ConfigNamespace() + self.assertRaises(NotImplementedError, lambda: 'key' in ns) + self.assertRaises(NotImplementedError, iter, ns)