Skip to content

gh-127011: Add __str__ and __repr__ to ConfigParser #127014

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b3ce3f3
gh-127011: Add __str__ and __repr__ to ConfigParser
Agent-Hellboy Nov 19, 2024
d603aa8
Add test
Agent-Hellboy Nov 19, 2024
91db566
Remove unnecessary comments
Agent-Hellboy Nov 19, 2024
7f3633d
Fix whitespaces
Agent-Hellboy Nov 19, 2024
5cd1d1f
Revert unittest
Agent-Hellboy Nov 19, 2024
5255025
Remove unnecessary changes
Agent-Hellboy Nov 19, 2024
dc71b39
change approach for repr
Agent-Hellboy Nov 22, 2024
c59d4fa
📜🤖 Added by blurb_it.
blurb-it[bot] Nov 23, 2024
d5e944f
Add test and fix parsing error of news
Agent-Hellboy Nov 23, 2024
0883b52
Remove extra whitespace
Agent-Hellboy Nov 23, 2024
d76eec4
Track all config source for repr
Agent-Hellboy Nov 23, 2024
433432b
Remove extra whitespaces
Agent-Hellboy Nov 23, 2024
acd31ae
Change str response
Agent-Hellboy Nov 25, 2024
43b7ff3
Merge branch 'main' into fix-issue-127011
Agent-Hellboy Nov 25, 2024
79e4892
Add my name Misc/ACKS
Agent-Hellboy Nov 25, 2024
913c2a4
Fix alphabetical order in Misc/ACKS
Agent-Hellboy Nov 25, 2024
e60ffe4
gh-127011: Add __str__ and __repr__ to ConfigParser
Agent-Hellboy Nov 19, 2024
0ed179a
Add test
Agent-Hellboy Nov 19, 2024
726b152
Remove unnecessary comments
Agent-Hellboy Nov 19, 2024
70fb9a5
Fix whitespaces
Agent-Hellboy Nov 19, 2024
38809c9
Revert unittest
Agent-Hellboy Nov 19, 2024
081c340
Remove unnecessary changes
Agent-Hellboy Nov 19, 2024
50838d5
change approach for repr
Agent-Hellboy Nov 22, 2024
2560eb9
📜🤖 Added by blurb_it.
blurb-it[bot] Nov 23, 2024
cb53ff2
Add test and fix parsing error of news
Agent-Hellboy Nov 23, 2024
155b8ef
Remove extra whitespace
Agent-Hellboy Nov 23, 2024
1a03c72
Track all config source for repr
Agent-Hellboy Nov 23, 2024
acfa969
Remove extra whitespaces
Agent-Hellboy Nov 23, 2024
8415943
Change str response
Agent-Hellboy Nov 25, 2024
ee219a6
Add my name Misc/ACKS
Agent-Hellboy Nov 25, 2024
63d58e0
Fix alphabetical order in Misc/ACKS
Agent-Hellboy Nov 25, 2024
9b107e2
fix merge conflicts
Agent-Hellboy Apr 25, 2025
50fdb2b
Merge branch 'main' into fix-issue-127011
Agent-Hellboy Apr 25, 2025
6427a0d
fix test
Agent-Hellboy Apr 25, 2025
d547497
Merge branch 'fix-issue-127011' of github.com:Agent-Hellboy/cpython i…
Agent-Hellboy Apr 25, 2025
3817877
Merge branch 'python:main' into fix-issue-127011
Agent-Hellboy Apr 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions Lib/configparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,7 @@ def __init__(self, defaults=None, dict_type=_default_dict,
self._optcre = re.compile(self._OPT_TMPL.format(delim=d),
re.VERBOSE)
self._comments = _CommentSpec(comment_prefixes or (), inline_comment_prefixes or ())
self._loaded_sources = []
self._strict = strict
self._allow_no_value = allow_no_value
self._empty_lines_in_values = empty_lines_in_values
Expand All @@ -690,6 +691,7 @@ def __init__(self, defaults=None, dict_type=_default_dict,
self._read_defaults(defaults)
self._allow_unnamed_section = allow_unnamed_section


def defaults(self):
return self._defaults

Expand Down Expand Up @@ -752,6 +754,7 @@ def read(self, filenames, encoding=None):
try:
with open(filename, encoding=encoding) as fp:
self._read(fp, filename)
self._loaded_sources.append(filename)
except OSError:
continue
if isinstance(filename, os.PathLike):
Expand All @@ -773,11 +776,13 @@ def read_file(self, f, source=None):
except AttributeError:
source = '<???>'
self._read(f, source)
self._loaded_sources.append(source)

def read_string(self, string, source='<string>'):
"""Read configuration from a given string."""
sfile = io.StringIO(string)
self.read_file(sfile, source)
self._loaded_sources.append(source)

def read_dict(self, dictionary, source='<dict>'):
"""Read configuration from a dictionary.
Expand Down Expand Up @@ -809,6 +814,7 @@ def read_dict(self, dictionary, source='<dict>'):
raise DuplicateOptionError(section, key, source)
elements_added.add((section, key))
self.set(section, key, value)
self._loaded_sources.append(source)

def get(self, section, option, *, raw=False, vars=None, fallback=_UNSET):
"""Get an option value for a given section.
Expand Down Expand Up @@ -1048,6 +1054,38 @@ def __iter__(self):
# XXX does it break when underlying container state changed?
return itertools.chain((self.default_section,), self._sections.keys())

def __str__(self):
config_dict = {
section: {key: value for key, value in self.items(section, raw=True)}
for section in self.sections()
}
return f"<ConfigParser: {config_dict}>"


def __repr__(self):
init_params = {
"defaults": self._defaults if self._defaults else None,
"dict_type": type(self._dict).__name__,
"allow_no_value": self._allow_no_value,
"delimiters": self._delimiters,
"strict": self._strict,
"default_section": self.default_section,
"interpolation": type(self._interpolation).__name__,
}
init_params = {k: v for k, v in init_params.items() if v is not None}
state_summary = {
"loaded_sources": self._loaded_sources,
"sections_count": len(self._sections),
"sections": list(self._sections.keys())[:5], # Limit to 5 section names for readability
}

if len(self._sections) > 5:
state_summary["sections_truncated"] = f"...and {len(self._sections) - 5} more"

return (f"<{self.__class__.__name__}("
f"params={init_params}, "
f"state={state_summary})>")

def _read(self, fp, fpname):
"""Parse a sectioned configuration file.

Expand Down
33 changes: 33 additions & 0 deletions Lib/test/test_configparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,39 @@ def test_set_nonstring_types(self):
self.assertRaises(TypeError, cf.set, "sect", 123, "invalid opt name!")
self.assertRaises(TypeError, cf.add_section, 123)

def test_str_and_repr(self):
self.maxDiff = None
cf = self.config_class(allow_no_value=True, delimiters=('=',), strict=True)
cf.add_section("sect1")
cf.add_section("sect2")
cf.add_section("sect3")
cf.add_section("sect4")
cf.add_section("sect5")
cf.add_section("sect6")
cf.set("sect1", "option1", "foo")
cf.set("sect2", "option2", "bar")


expected_str = (
"<ConfigParser: {'sect1': {'option1': 'foo'}, 'sect2': {'option2': 'bar'}, "
"'sect3': {}, 'sect4': {}, 'sect5': {}, 'sect6': {}}>"
)
self.assertEqual(str(cf), expected_str)


dict_type = type(cf._dict).__name__

expected_repr = (
f"<{cf.__class__.__name__}("
f"params={{'dict_type': '{dict_type}', 'allow_no_value': True, "
"'delimiters': ('=',), 'strict': True, 'default_section': 'DEFAULT', "
"'interpolation': 'BasicInterpolation'}, "
"state={'loaded_sources': [], 'sections_count': 6, "
"'sections': ['sect1', 'sect2', 'sect3', 'sect4', 'sect5'], "
"'sections_truncated': '...and 1 more'})>"
)
self.assertEqual(repr(cf), expected_repr)

def test_add_section_default(self):
cf = self.newconfig()
self.assertRaises(ValueError, cf.add_section, self.default_section)
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1599,6 +1599,7 @@ Erik Rose
Mark Roseman
Josh Rosenberg
Jim Roskind
Prince Roshan
Comment on lines 1601 to +1602
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Jim Roskind
Prince Roshan
Prince Roshan
Jim Roskind

Ordering

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @StanFromIreland , how do we order these?

Brian Rosner
Ignacio Rossi
Guido van Rossum
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The ``__str__`` and ``__repr__`` methods have been added to the :class:`configparser.RawConfigParser`
Loading