Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@

---

A custom ConfigParser class that preserves comments and option casing when writing loaded config out.
A custom ConfigParser class that preserves comments and most formatting when
writing loaded config out.

This library gives you a custom class of the standard library's `configparser.ConfigParger` which will preserve the comments of a loaded config file when writing that file back out.
This library gives you a custom class of the standard library's
`configparser.ConfigParger` which will preserve the comments of a loaded config
file when writing that file back out.

---

Expand Down Expand Up @@ -58,7 +61,12 @@ with open("myconfig.ini", "w") as savefile:

## Results

We favor the line spacing choices of the `ConfigParser` class so the input format may not be preserved completely. However, the comments will be preserved.
There is the attempt to retain the original format. Known formats that will not
be preserved:

1. Indents will not be preserved outside of multi-line values
2. Spacing around assignments will be normalized.
3. Casing of all options will be written as lowercase.

### Before

Expand All @@ -83,7 +91,6 @@ multi-line=
value03
closing=0
# Trailing comment

```

### After
Expand All @@ -97,9 +104,10 @@ foo = bar
trace = false
logging = true
; This is a comment as well

# so we need to track all of them
; and many could be between things

; and many could be between things
[NEW SECTION]
# Another comment
multi-line =
Expand All @@ -108,5 +116,4 @@ multi-line =
value03
closing = 0
# Trailing comment

```
13 changes: 10 additions & 3 deletions src/commentedconfigparser/commentedconfigparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
__all__ = ["CommentedConfigParser"]

_COMMENT_PATTERN = re.compile(r"^\s*[#|;]\s*(.*)$")
_BLANK_LINE_PATTERN = re.compile(r"^\s*$")
_COMMENT_OPTION_PATTERN = re.compile(r"^(\s*)?__comment_\d+\s?[=|:]\s?(.*)$")
_KEY_PATTERN = re.compile(r"^(.+?)\s?[=|:].*$")
_SECTION_PATTERN = re.compile(r"^\s*\[(.+)\]\s*$")
Expand Down Expand Up @@ -98,6 +99,11 @@ def _translate_comments(self, content: list[str]) -> str:
# are handled by the parent and retain order of insertion.
line = f"__comment_{self.__file_index}{idx}={line.lstrip()}"

elif _BLANK_LINE_PATTERN.match(line):
# Blank lines cannot be stripped or the newline char will
# be lost which causes issues downstream.
line = f"__comment_{self.__file_index}{idx}={line}"

elif _KEY_PATTERN.match(line) or _SECTION_PATTERN.match(line):
# Strip the left whitespace from sections and keys. This will
# leave only multiline values with leading whitespace preventing
Expand All @@ -121,13 +127,14 @@ def _restore_comments(self, content: str) -> str:
rendered += self.__header_block

for line in content.splitlines():
if not line:
# Skip the provided empty lines and use our own instead
continue

comment_match = _COMMENT_OPTION_PATTERN.match(line)
if comment_match:
line = comment_match.group(2)

rendered.append(line + "\n")

# Remove extra trailing newline
rendered[-1] = rendered[-1].rstrip()

return "".join(rendered)
3 changes: 3 additions & 0 deletions tests/empty_comments_expected.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@

[DEFAULT]
foo = bar

# Comment here
#
bar = foo
;
; Comment here too


[BIZ]
baz = bar

1 change: 1 addition & 0 deletions tests/empty_comments_input.ini
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ bar = foo

[BIZ]
baz=bar

1 change: 1 addition & 0 deletions tests/pydocs_expected.ini
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ empty string value here =
[You can use comments]
# like this
; or this

# By default only in an empty line.
# Inline comments can be harmful because they prevent users
# from using the delimiting characters as parts of values.
Expand Down
3 changes: 2 additions & 1 deletion tests/regression_original_expected.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ foo = bar
trace = false
logging = true
; This is a comment as well

# so we need to track all of them
; and many could be between things

; and many could be between things
[NEW SECTION]
foo = bar
# Unique foo
Expand Down