commented-configparser 2.2.0__tar.gz → 3.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/.github/workflows/pypi-publish.yml +19 -14
- commented_configparser-3.0.0/.github/workflows/pypi-test-publish.yml +62 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/.github/workflows/python-tests.yml +8 -8
- commented_configparser-3.0.0/.pre-commit-config.yaml +11 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/CONTRIBUTING.md +0 -9
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/PKG-INFO +16 -10
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/README.md +14 -8
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/noxfile.py +22 -24
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/pyproject.toml +1 -1
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/src/commented_configparser.egg-info/PKG-INFO +16 -10
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/src/commented_configparser.egg-info/SOURCES.txt +3 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/src/commentedconfigparser/commentedconfigparser.py +36 -18
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/tests/commentedconfigparser_test.py +10 -7
- commented_configparser-3.0.0/tests/empty_comments_expected.ini +17 -0
- commented_configparser-3.0.0/tests/empty_comments_input.ini +17 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/tests/header_expected.ini +0 -1
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/tests/multi_expected.ini +0 -1
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/tests/pydocs_expected.ini +2 -2
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/tests/regression_original_expected.ini +3 -2
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/tests/regression_original_input.ini +1 -0
- commented_configparser-2.2.0/.pre-commit-config.yaml +0 -32
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/.flake8 +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/.gitignore +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/LICENSE +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/requirements/constraints.txt +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/requirements/requirements-dev.txt +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/requirements/requirements-test.txt +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/requirements/requirements.txt +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/setup.cfg +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/src/commented_configparser.egg-info/dependency_links.txt +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/src/commented_configparser.egg-info/requires.txt +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/src/commented_configparser.egg-info/top_level.txt +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/src/commentedconfigparser/__init__.py +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/src/commentedconfigparser/py.typed +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/tests/header_input.ini +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/tests/multi01_input.ini +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/tests/multi02_input.ini +0 -0
- {commented_configparser-2.2.0 → commented_configparser-3.0.0}/tests/pydocs_input.ini +0 -0
{commented_configparser-2.2.0 → commented_configparser-3.0.0}/.github/workflows/pypi-publish.yml
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
name: "Publish Python distribution to PyPI"
|
|
2
2
|
# Uses:
|
|
3
|
-
# https://github.com/actions/setup-python :
|
|
3
|
+
# https://github.com/actions/setup-python : a26af69be951a213d495a4c3e4e4022e16d87065
|
|
4
4
|
# https://github.com/actions/checkout : 11bd71901bbe5b1630ceea73d27597364c9af683
|
|
5
|
-
# https://github.com/actions/download-artifact :
|
|
6
|
-
# https://github.com/actions/upload-artifact :
|
|
5
|
+
# https://github.com/actions/download-artifact : d3f86a106a0bac45b974a628896c90dbdf5c8093
|
|
6
|
+
# https://github.com/actions/upload-artifact : ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
7
7
|
# https://github.com/actions/pypa/gh-action-pypi-publish : 76f52bc884231f62b9a034ebfe128415bbaabdfc
|
|
8
8
|
|
|
9
9
|
on:
|
|
@@ -12,8 +12,10 @@ on:
|
|
|
12
12
|
|
|
13
13
|
jobs:
|
|
14
14
|
build:
|
|
15
|
-
name: "Build
|
|
15
|
+
name: "Build package"
|
|
16
16
|
runs-on: "ubuntu-latest"
|
|
17
|
+
outputs:
|
|
18
|
+
artifact-id: "${{ steps.upload-artifact.outputs.artifact-id }}"
|
|
17
19
|
|
|
18
20
|
steps:
|
|
19
21
|
- uses: "actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683"
|
|
@@ -21,36 +23,39 @@ jobs:
|
|
|
21
23
|
persist-credentials: false
|
|
22
24
|
|
|
23
25
|
- name: "Set up Python"
|
|
24
|
-
uses: "actions/setup-python@
|
|
26
|
+
uses: "actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065"
|
|
25
27
|
with:
|
|
26
28
|
python-version: "3.12"
|
|
27
29
|
|
|
28
30
|
- name: "Build the package"
|
|
29
|
-
run: "python -m pip install nox; nox
|
|
31
|
+
run: "python -m pip install nox; nox -s build"
|
|
30
32
|
|
|
31
33
|
- name: "Store the distribution packages"
|
|
32
|
-
|
|
34
|
+
id: "upload-artifact"
|
|
35
|
+
uses: "actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02"
|
|
33
36
|
with:
|
|
34
|
-
|
|
35
|
-
path: "dist/"
|
|
37
|
+
path: "./dist"
|
|
36
38
|
|
|
37
39
|
publish-to-pypi:
|
|
38
40
|
name: "Publish Python Distribution to PyPI"
|
|
39
|
-
if: startsWith(github.ref, 'refs/tags/')
|
|
40
41
|
needs: ["build"]
|
|
41
42
|
runs-on: "ubuntu-latest"
|
|
42
43
|
environment:
|
|
43
44
|
name: "pypi"
|
|
44
|
-
url: "https://pypi.org/
|
|
45
|
+
url: "https://pypi.org/project/commented-configparser/"
|
|
45
46
|
permissions:
|
|
46
47
|
id-token: "write"
|
|
47
48
|
|
|
48
49
|
steps:
|
|
49
50
|
- name: "Download all the dists"
|
|
50
|
-
uses: "actions/download-artifact@
|
|
51
|
+
uses: "actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093"
|
|
51
52
|
with:
|
|
52
|
-
|
|
53
|
-
path: "dist
|
|
53
|
+
artifact-ids: "${{ needs.build.outputs.artifact-id }}"
|
|
54
|
+
path: "./dist"
|
|
55
|
+
merge-multiple: true
|
|
54
56
|
|
|
55
57
|
- name: "Publish distribution to PyPI"
|
|
56
58
|
uses: "pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc"
|
|
59
|
+
with:
|
|
60
|
+
repository-url: "https://upload.pypi.org/legacy/"
|
|
61
|
+
verbose: true
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: "Publish Python distribution to PyPI Test"
|
|
2
|
+
# Uses:
|
|
3
|
+
# https://github.com/actions/setup-python : a26af69be951a213d495a4c3e4e4022e16d87065
|
|
4
|
+
# https://github.com/actions/checkout : 11bd71901bbe5b1630ceea73d27597364c9af683
|
|
5
|
+
# https://github.com/actions/download-artifact : d3f86a106a0bac45b974a628896c90dbdf5c8093
|
|
6
|
+
# https://github.com/actions/upload-artifact : ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
7
|
+
# https://github.com/actions/pypa/gh-action-pypi-publish : 76f52bc884231f62b9a034ebfe128415bbaabdfc
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
tags:
|
|
12
|
+
- "[0-9]+.[0-9]+.[a-z]+[0-9]+"
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build:
|
|
16
|
+
name: "Build package"
|
|
17
|
+
runs-on: "ubuntu-latest"
|
|
18
|
+
outputs:
|
|
19
|
+
artifact-id: "${{ steps.upload-artifact.outputs.artifact-id }}"
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- uses: "actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683"
|
|
23
|
+
with:
|
|
24
|
+
persist-credentials: false
|
|
25
|
+
|
|
26
|
+
- name: "Set up Python"
|
|
27
|
+
uses: "actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065"
|
|
28
|
+
with:
|
|
29
|
+
python-version: "3.12"
|
|
30
|
+
|
|
31
|
+
- name: "Build the package"
|
|
32
|
+
run: "python -m pip install nox; nox -s build"
|
|
33
|
+
|
|
34
|
+
- name: "Store the distribution packages"
|
|
35
|
+
id: "upload-artifact"
|
|
36
|
+
uses: "actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02"
|
|
37
|
+
with:
|
|
38
|
+
path: "./dist"
|
|
39
|
+
|
|
40
|
+
publish-to-pypi:
|
|
41
|
+
name: "Publish Python Distribution to PyPI"
|
|
42
|
+
needs: ["build"]
|
|
43
|
+
runs-on: "ubuntu-latest"
|
|
44
|
+
environment:
|
|
45
|
+
name: "testpypi"
|
|
46
|
+
url: "https://test.pypi.org/project/commented-configparser/"
|
|
47
|
+
permissions:
|
|
48
|
+
id-token: "write"
|
|
49
|
+
|
|
50
|
+
steps:
|
|
51
|
+
- name: "Download all the dists"
|
|
52
|
+
uses: "actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093"
|
|
53
|
+
with:
|
|
54
|
+
artifact-ids: "${{ needs.build.outputs.artifact-id }}"
|
|
55
|
+
path: "./dist"
|
|
56
|
+
merge-multiple: true
|
|
57
|
+
|
|
58
|
+
- name: "Publish distribution to PyPI"
|
|
59
|
+
uses: "pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc"
|
|
60
|
+
with:
|
|
61
|
+
repository-url: "https://test.pypi.org/legacy/"
|
|
62
|
+
verbose: true
|
{commented_configparser-2.2.0 → commented_configparser-3.0.0}/.github/workflows/python-tests.yml
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
name: "python tests and coverage"
|
|
2
2
|
# Uses:
|
|
3
|
-
# https://github.com/actions/setup-python :
|
|
3
|
+
# https://github.com/actions/setup-python : a26af69be951a213d495a4c3e4e4022e16d87065
|
|
4
4
|
# https://github.com/actions/checkout : 11bd71901bbe5b1630ceea73d27597364c9af683
|
|
5
|
-
# https://github.com/actions/download-artifact :
|
|
6
|
-
# https://github.com/actions/upload-artifact :
|
|
5
|
+
# https://github.com/actions/download-artifact : d3f86a106a0bac45b974a628896c90dbdf5c8093
|
|
6
|
+
# https://github.com/actions/upload-artifact : ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
7
7
|
|
|
8
8
|
on:
|
|
9
9
|
pull_request:
|
|
@@ -46,7 +46,7 @@ jobs:
|
|
|
46
46
|
uses: "actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683"
|
|
47
47
|
|
|
48
48
|
- name: "Set up Python ${{ matrix.python-version }}"
|
|
49
|
-
uses: "actions/setup-python@
|
|
49
|
+
uses: "actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065"
|
|
50
50
|
with:
|
|
51
51
|
python-version: "${{ matrix.python-version }}"
|
|
52
52
|
allow-prereleases: true
|
|
@@ -60,7 +60,7 @@ jobs:
|
|
|
60
60
|
nox --session test -- partial-coverage
|
|
61
61
|
|
|
62
62
|
- name: "Save coverage artifact"
|
|
63
|
-
uses: "actions/upload-artifact@
|
|
63
|
+
uses: "actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02"
|
|
64
64
|
with:
|
|
65
65
|
name: "coverage-artifact-${{ matrix.os}}-${{ matrix.python-version}}"
|
|
66
66
|
path: ".coverage.*"
|
|
@@ -76,7 +76,7 @@ jobs:
|
|
|
76
76
|
uses: "actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683"
|
|
77
77
|
|
|
78
78
|
- name: "Set up Python"
|
|
79
|
-
uses: "actions/setup-python@
|
|
79
|
+
uses: "actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065"
|
|
80
80
|
with:
|
|
81
81
|
python-version: "${{ needs.settings.outputs.default-python-version }}"
|
|
82
82
|
|
|
@@ -85,7 +85,7 @@ jobs:
|
|
|
85
85
|
python -m pip install --upgrade nox
|
|
86
86
|
|
|
87
87
|
- name: "Download coverage artifacts"
|
|
88
|
-
uses: "actions/download-artifact@
|
|
88
|
+
uses: "actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093"
|
|
89
89
|
with:
|
|
90
90
|
pattern: "coverage-artifact-*"
|
|
91
91
|
merge-multiple: true
|
|
@@ -106,7 +106,7 @@ jobs:
|
|
|
106
106
|
uses: "actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683"
|
|
107
107
|
|
|
108
108
|
- name: "Set up Python"
|
|
109
|
-
uses: "actions/setup-python@
|
|
109
|
+
uses: "actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065"
|
|
110
110
|
with:
|
|
111
111
|
python-version: "${{ needs.settings.outputs.default-python-version }}"
|
|
112
112
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
ci:
|
|
2
|
+
autoupdate_schedule: monthly
|
|
3
|
+
exclude: ^.+\.ini$
|
|
4
|
+
repos:
|
|
5
|
+
# Batch of helpful formatters and patterns
|
|
6
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
7
|
+
rev: "v5.0.0"
|
|
8
|
+
hooks:
|
|
9
|
+
- id: trailing-whitespace
|
|
10
|
+
- id: end-of-file-fixer
|
|
11
|
+
- id: mixed-line-ending
|
|
@@ -109,12 +109,3 @@ nox -s update-deps
|
|
|
109
109
|
```bash
|
|
110
110
|
nox -s upgrade-deps
|
|
111
111
|
```
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
## [pre-commit](https://pre-commit.com)
|
|
116
|
-
|
|
117
|
-
> A framework for managing and maintaining multi-language pre-commit hooks.
|
|
118
|
-
|
|
119
|
-
This repo is setup with a `.pre-commit-config.yaml` with the expectation that
|
|
120
|
-
any code submitted for review already passes all selected pre-commit checks.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: commented-configparser
|
|
3
|
-
Version:
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: A custom ConfigParser class that preserves comments and most formatting when writing loaded config out.
|
|
5
5
|
Author-email: Preocts <preocts@preocts.com>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: homepage, https://github.com/Preocts/commented-configparser
|
|
@@ -38,9 +38,12 @@ Dynamic: license-file
|
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
41
|
-
A custom ConfigParser class that preserves comments and
|
|
41
|
+
A custom ConfigParser class that preserves comments and most formatting when
|
|
42
|
+
writing loaded config out.
|
|
42
43
|
|
|
43
|
-
This library gives you a custom class of the standard library's
|
|
44
|
+
This library gives you a custom class of the standard library's
|
|
45
|
+
`configparser.ConfigParger` which will preserve the comments of a loaded config
|
|
46
|
+
file when writing that file back out.
|
|
44
47
|
|
|
45
48
|
---
|
|
46
49
|
|
|
@@ -84,7 +87,11 @@ with open("myconfig.ini", "w") as savefile:
|
|
|
84
87
|
|
|
85
88
|
## Results
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
There is the attempt to retain the original format. Known formats that will not
|
|
91
|
+
be preserved:
|
|
92
|
+
|
|
93
|
+
1. Indents will not be preserved outside of multi-line values
|
|
94
|
+
2. Spacing around assignments will be normalized.
|
|
88
95
|
|
|
89
96
|
### Before
|
|
90
97
|
|
|
@@ -103,13 +110,12 @@ logging=true
|
|
|
103
110
|
; and many could be between things
|
|
104
111
|
[NEW SECTION]
|
|
105
112
|
# Another comment
|
|
106
|
-
|
|
113
|
+
multiLine=
|
|
107
114
|
value01
|
|
108
115
|
value02
|
|
109
116
|
value03
|
|
110
117
|
closing=0
|
|
111
118
|
# Trailing comment
|
|
112
|
-
|
|
113
119
|
```
|
|
114
120
|
|
|
115
121
|
### After
|
|
@@ -123,16 +129,16 @@ foo = bar
|
|
|
123
129
|
trace = false
|
|
124
130
|
logging = true
|
|
125
131
|
; This is a comment as well
|
|
132
|
+
|
|
126
133
|
# so we need to track all of them
|
|
127
|
-
; and many could be between things
|
|
128
134
|
|
|
135
|
+
; and many could be between things
|
|
129
136
|
[NEW SECTION]
|
|
130
137
|
# Another comment
|
|
131
|
-
|
|
138
|
+
multiLine =
|
|
132
139
|
value01
|
|
133
140
|
value02
|
|
134
141
|
value03
|
|
135
142
|
closing = 0
|
|
136
143
|
# Trailing comment
|
|
137
|
-
|
|
138
144
|
```
|
|
@@ -12,9 +12,12 @@
|
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
A custom ConfigParser class that preserves comments and
|
|
15
|
+
A custom ConfigParser class that preserves comments and most formatting when
|
|
16
|
+
writing loaded config out.
|
|
16
17
|
|
|
17
|
-
This library gives you a custom class of the standard library's
|
|
18
|
+
This library gives you a custom class of the standard library's
|
|
19
|
+
`configparser.ConfigParger` which will preserve the comments of a loaded config
|
|
20
|
+
file when writing that file back out.
|
|
18
21
|
|
|
19
22
|
---
|
|
20
23
|
|
|
@@ -58,7 +61,11 @@ with open("myconfig.ini", "w") as savefile:
|
|
|
58
61
|
|
|
59
62
|
## Results
|
|
60
63
|
|
|
61
|
-
|
|
64
|
+
There is the attempt to retain the original format. Known formats that will not
|
|
65
|
+
be preserved:
|
|
66
|
+
|
|
67
|
+
1. Indents will not be preserved outside of multi-line values
|
|
68
|
+
2. Spacing around assignments will be normalized.
|
|
62
69
|
|
|
63
70
|
### Before
|
|
64
71
|
|
|
@@ -77,13 +84,12 @@ logging=true
|
|
|
77
84
|
; and many could be between things
|
|
78
85
|
[NEW SECTION]
|
|
79
86
|
# Another comment
|
|
80
|
-
|
|
87
|
+
multiLine=
|
|
81
88
|
value01
|
|
82
89
|
value02
|
|
83
90
|
value03
|
|
84
91
|
closing=0
|
|
85
92
|
# Trailing comment
|
|
86
|
-
|
|
87
93
|
```
|
|
88
94
|
|
|
89
95
|
### After
|
|
@@ -97,16 +103,16 @@ foo = bar
|
|
|
97
103
|
trace = false
|
|
98
104
|
logging = true
|
|
99
105
|
; This is a comment as well
|
|
106
|
+
|
|
100
107
|
# so we need to track all of them
|
|
101
|
-
; and many could be between things
|
|
102
108
|
|
|
109
|
+
; and many could be between things
|
|
103
110
|
[NEW SECTION]
|
|
104
111
|
# Another comment
|
|
105
|
-
|
|
112
|
+
multiLine =
|
|
106
113
|
value01
|
|
107
114
|
value02
|
|
108
115
|
value03
|
|
109
116
|
closing = 0
|
|
110
117
|
# Trailing comment
|
|
111
|
-
|
|
112
118
|
```
|
|
@@ -16,6 +16,24 @@ VENV_PATH = "./.venv"
|
|
|
16
16
|
LINT_PATH = "./src"
|
|
17
17
|
REQUIREMENTS_PATH = "./requirements"
|
|
18
18
|
|
|
19
|
+
LINTING_COMMANDS = (
|
|
20
|
+
(
|
|
21
|
+
"isort",
|
|
22
|
+
"--verbose",
|
|
23
|
+
"--force-single-line-imports",
|
|
24
|
+
"--profile",
|
|
25
|
+
"black",
|
|
26
|
+
"--add-import",
|
|
27
|
+
"from __future__ import annotations",
|
|
28
|
+
LINT_PATH,
|
|
29
|
+
TESTS_PATH,
|
|
30
|
+
),
|
|
31
|
+
("black", "--verbose", LINT_PATH, TESTS_PATH),
|
|
32
|
+
("flake8", "--show-source", "--verbose", LINT_PATH, TESTS_PATH),
|
|
33
|
+
("mypy", "--no-incremental", "--package", MODULE_NAME),
|
|
34
|
+
("mypy", "--no-incremental", TESTS_PATH),
|
|
35
|
+
)
|
|
36
|
+
|
|
19
37
|
# What we allowed to clean (delete)
|
|
20
38
|
CLEANABLE_TARGETS = [
|
|
21
39
|
"./dist",
|
|
@@ -55,13 +73,7 @@ def dev(session: nox.Session) -> None:
|
|
|
55
73
|
python = partial(session.run, f"{venv_path}/python", "-m")
|
|
56
74
|
contraint = ("--constraint", f"{REQUIREMENTS_PATH}/constraints.txt")
|
|
57
75
|
|
|
58
|
-
|
|
59
|
-
python("pip", "install", "-r", requirement_file, *contraint, external=True)
|
|
60
|
-
|
|
61
|
-
python("pip", "install", "--editable", ".", *contraint, external=True)
|
|
62
|
-
|
|
63
|
-
python("pip", "install", "pre-commit", external=True)
|
|
64
|
-
session.run(f"{venv_path}/pre-commit", "install", external=True)
|
|
76
|
+
python("pip", "install", "--editable", ".[dev,test]", *contraint, external=True)
|
|
65
77
|
|
|
66
78
|
if not os.environ.get("VIRTUAL_ENV"):
|
|
67
79
|
session.log(f"\n\nRun '{activate_command}' to enter the virtual environment.\n")
|
|
@@ -109,26 +121,12 @@ def run_linters_and_formatters(session: nox.Session) -> None:
|
|
|
109
121
|
print_standard_logs(session)
|
|
110
122
|
|
|
111
123
|
contraint = ("--constraint", f"{REQUIREMENTS_PATH}/constraints.txt")
|
|
112
|
-
session.install(".[dev]", *contraint)
|
|
124
|
+
session.install(".[dev,test]", *contraint)
|
|
113
125
|
|
|
114
126
|
python = partial(session.run, "python", "-m")
|
|
115
127
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
"isort",
|
|
119
|
-
"--verbose",
|
|
120
|
-
"--force-single-line-imports",
|
|
121
|
-
"--profile",
|
|
122
|
-
"black",
|
|
123
|
-
"--add-import",
|
|
124
|
-
"from __future__ import annotations",
|
|
125
|
-
LINT_PATH,
|
|
126
|
-
)
|
|
127
|
-
python("black", "--verbose", LINT_PATH)
|
|
128
|
-
|
|
129
|
-
# Linters: aka, things that yell but want you to fix things
|
|
130
|
-
python("flake8", "--show-source", "--verbose", LINT_PATH)
|
|
131
|
-
python("mypy", "--no-incremental", "--package", MODULE_NAME)
|
|
128
|
+
for linter_command in LINTING_COMMANDS:
|
|
129
|
+
python(*linter_command)
|
|
132
130
|
|
|
133
131
|
|
|
134
132
|
@nox.session()
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "commented-configparser"
|
|
7
7
|
requires-python = ">=3.9"
|
|
8
|
-
description = "
|
|
8
|
+
description = "A custom ConfigParser class that preserves comments and most formatting when writing loaded config out."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
11
11
|
authors = [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: commented-configparser
|
|
3
|
-
Version:
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: A custom ConfigParser class that preserves comments and most formatting when writing loaded config out.
|
|
5
5
|
Author-email: Preocts <preocts@preocts.com>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: homepage, https://github.com/Preocts/commented-configparser
|
|
@@ -38,9 +38,12 @@ Dynamic: license-file
|
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
41
|
-
A custom ConfigParser class that preserves comments and
|
|
41
|
+
A custom ConfigParser class that preserves comments and most formatting when
|
|
42
|
+
writing loaded config out.
|
|
42
43
|
|
|
43
|
-
This library gives you a custom class of the standard library's
|
|
44
|
+
This library gives you a custom class of the standard library's
|
|
45
|
+
`configparser.ConfigParger` which will preserve the comments of a loaded config
|
|
46
|
+
file when writing that file back out.
|
|
44
47
|
|
|
45
48
|
---
|
|
46
49
|
|
|
@@ -84,7 +87,11 @@ with open("myconfig.ini", "w") as savefile:
|
|
|
84
87
|
|
|
85
88
|
## Results
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
There is the attempt to retain the original format. Known formats that will not
|
|
91
|
+
be preserved:
|
|
92
|
+
|
|
93
|
+
1. Indents will not be preserved outside of multi-line values
|
|
94
|
+
2. Spacing around assignments will be normalized.
|
|
88
95
|
|
|
89
96
|
### Before
|
|
90
97
|
|
|
@@ -103,13 +110,12 @@ logging=true
|
|
|
103
110
|
; and many could be between things
|
|
104
111
|
[NEW SECTION]
|
|
105
112
|
# Another comment
|
|
106
|
-
|
|
113
|
+
multiLine=
|
|
107
114
|
value01
|
|
108
115
|
value02
|
|
109
116
|
value03
|
|
110
117
|
closing=0
|
|
111
118
|
# Trailing comment
|
|
112
|
-
|
|
113
119
|
```
|
|
114
120
|
|
|
115
121
|
### After
|
|
@@ -123,16 +129,16 @@ foo = bar
|
|
|
123
129
|
trace = false
|
|
124
130
|
logging = true
|
|
125
131
|
; This is a comment as well
|
|
132
|
+
|
|
126
133
|
# so we need to track all of them
|
|
127
|
-
; and many could be between things
|
|
128
134
|
|
|
135
|
+
; and many could be between things
|
|
129
136
|
[NEW SECTION]
|
|
130
137
|
# Another comment
|
|
131
|
-
|
|
138
|
+
multiLine =
|
|
132
139
|
value01
|
|
133
140
|
value02
|
|
134
141
|
value03
|
|
135
142
|
closing = 0
|
|
136
143
|
# Trailing comment
|
|
137
|
-
|
|
138
144
|
```
|
|
@@ -7,6 +7,7 @@ README.md
|
|
|
7
7
|
noxfile.py
|
|
8
8
|
pyproject.toml
|
|
9
9
|
.github/workflows/pypi-publish.yml
|
|
10
|
+
.github/workflows/pypi-test-publish.yml
|
|
10
11
|
.github/workflows/python-tests.yml
|
|
11
12
|
requirements/constraints.txt
|
|
12
13
|
requirements/requirements-dev.txt
|
|
@@ -21,6 +22,8 @@ src/commentedconfigparser/__init__.py
|
|
|
21
22
|
src/commentedconfigparser/commentedconfigparser.py
|
|
22
23
|
src/commentedconfigparser/py.typed
|
|
23
24
|
tests/commentedconfigparser_test.py
|
|
25
|
+
tests/empty_comments_expected.ini
|
|
26
|
+
tests/empty_comments_input.ini
|
|
24
27
|
tests/header_expected.ini
|
|
25
28
|
tests/header_input.ini
|
|
26
29
|
tests/multi01_input.ini
|
|
@@ -16,10 +16,11 @@ if TYPE_CHECKING:
|
|
|
16
16
|
|
|
17
17
|
__all__ = ["CommentedConfigParser"]
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
_COMMENT_PATTERN = re.compile(r"^\s*[#|;]\s*(.*)$")
|
|
20
|
+
_BLANK_LINE_PATTERN = re.compile(r"^\s*$")
|
|
21
|
+
_COMMENT_OPTION_PATTERN = re.compile(r"^(\s*)?__comment_\d+\s?[=|:]\s?(.*)$")
|
|
22
|
+
_KEY_PATTERN = re.compile(r"^(.+?)\s?[=|:].*$")
|
|
23
|
+
_SECTION_PATTERN = re.compile(r"^\s*\[(.+)\]\s*$")
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
class CommentedConfigParser(ConfigParser):
|
|
@@ -57,7 +58,15 @@ class CommentedConfigParser(ConfigParser):
|
|
|
57
58
|
|
|
58
59
|
def read_file(self, f: Iterable[str], source: str | None = None) -> None:
|
|
59
60
|
content = self._translate_comments([line for line in f])
|
|
60
|
-
|
|
61
|
+
self.__is_reading = True
|
|
62
|
+
super().read_file(content.splitlines(), source)
|
|
63
|
+
self.__is_reading = False
|
|
64
|
+
|
|
65
|
+
def optionxform(self, optionstr: str) -> str:
|
|
66
|
+
if hasattr(self, "_CommentedConfigParser__is_reading") and self.__is_reading:
|
|
67
|
+
return optionstr
|
|
68
|
+
|
|
69
|
+
return super().optionxform(optionstr)
|
|
61
70
|
|
|
62
71
|
def write(
|
|
63
72
|
self,
|
|
@@ -76,29 +85,34 @@ class CommentedConfigParser(ConfigParser):
|
|
|
76
85
|
|
|
77
86
|
# To save the pain of mirroring ConfigParser's __init__ these two
|
|
78
87
|
# attributes are created in the instance here, when needed.
|
|
79
|
-
if not hasattr(self, "
|
|
80
|
-
self.
|
|
88
|
+
if not hasattr(self, "_CommentedConfigParser__header_block"):
|
|
89
|
+
self.__header_block: list[str] = []
|
|
81
90
|
|
|
82
|
-
if not hasattr(self, "
|
|
83
|
-
self.
|
|
91
|
+
if not hasattr(self, "_CommentedConfigParser__file_index"):
|
|
92
|
+
self.__file_index = 0
|
|
84
93
|
|
|
85
94
|
translated_lines = []
|
|
86
95
|
for idx, line in enumerate(content):
|
|
87
|
-
if
|
|
96
|
+
if _SECTION_PATTERN.match(line):
|
|
88
97
|
seen_section = True
|
|
89
98
|
|
|
90
99
|
if not seen_section:
|
|
91
100
|
# Assume lines before a section are comments. If they are not
|
|
92
101
|
# the parent class will raise the needed exceptions for an
|
|
93
102
|
# invalid config format.
|
|
94
|
-
self.
|
|
103
|
+
self.__header_block.append(line)
|
|
95
104
|
|
|
96
|
-
elif
|
|
105
|
+
elif _COMMENT_PATTERN.match(line):
|
|
97
106
|
# Translate the comment into an option for the section. These
|
|
98
107
|
# are handled by the parent and retain order of insertion.
|
|
99
|
-
line = f"__comment_{self.
|
|
108
|
+
line = f"__comment_{self.__file_index}{idx}={line.lstrip()}"
|
|
109
|
+
|
|
110
|
+
elif _BLANK_LINE_PATTERN.match(line):
|
|
111
|
+
# Blank lines cannot be stripped or the newline char will
|
|
112
|
+
# be lost which causes issues downstream.
|
|
113
|
+
line = f"__comment_{self.__file_index}{idx}={line}"
|
|
100
114
|
|
|
101
|
-
elif
|
|
115
|
+
elif _KEY_PATTERN.match(line) or _SECTION_PATTERN.match(line):
|
|
102
116
|
# Strip the left whitespace from sections and keys. This will
|
|
103
117
|
# leave only multiline values with leading whitespace preventing
|
|
104
118
|
# the saved output from incorrectly indenting after a comment
|
|
@@ -109,7 +123,7 @@ class CommentedConfigParser(ConfigParser):
|
|
|
109
123
|
|
|
110
124
|
# If additional configuration files are loaded, comments may end up sharing
|
|
111
125
|
# idx values which will clobber previously loaded comments.
|
|
112
|
-
self.
|
|
126
|
+
self.__file_index += 1
|
|
113
127
|
|
|
114
128
|
return "".join(translated_lines)
|
|
115
129
|
|
|
@@ -117,11 +131,15 @@ class CommentedConfigParser(ConfigParser):
|
|
|
117
131
|
"""Restore comment options to comments."""
|
|
118
132
|
# Apply the headers before parsing the config lines
|
|
119
133
|
rendered = []
|
|
120
|
-
if hasattr(self, "
|
|
121
|
-
rendered += self.
|
|
134
|
+
if hasattr(self, "_CommentedConfigParser__header_block"):
|
|
135
|
+
rendered += self.__header_block
|
|
122
136
|
|
|
123
137
|
for line in content.splitlines():
|
|
124
|
-
|
|
138
|
+
if not line:
|
|
139
|
+
# Skip the provided empty lines and use our own instead
|
|
140
|
+
continue
|
|
141
|
+
|
|
142
|
+
comment_match = _COMMENT_OPTION_PATTERN.match(line)
|
|
125
143
|
if comment_match:
|
|
126
144
|
line = comment_match.group(2)
|
|
127
145
|
|
{commented_configparser-2.2.0 → commented_configparser-3.0.0}/tests/commentedconfigparser_test.py
RENAMED
|
@@ -20,10 +20,12 @@ from commentedconfigparser.commentedconfigparser import CommentedConfigParser
|
|
|
20
20
|
(" \tThis is a comment", False),
|
|
21
21
|
("", False),
|
|
22
22
|
(" \t", False),
|
|
23
|
+
("#", True),
|
|
24
|
+
("#\t", True),
|
|
23
25
|
),
|
|
24
26
|
)
|
|
25
27
|
def test_comment_pattern(line: str, expected: bool) -> None:
|
|
26
|
-
result = commentedconfigparser.
|
|
28
|
+
result = commentedconfigparser._COMMENT_PATTERN.match(line)
|
|
27
29
|
|
|
28
30
|
assert bool(result) is expected
|
|
29
31
|
|
|
@@ -40,7 +42,7 @@ def test_comment_pattern(line: str, expected: bool) -> None:
|
|
|
40
42
|
),
|
|
41
43
|
)
|
|
42
44
|
def test_section_pattern(line: str, expected: bool) -> None:
|
|
43
|
-
result = commentedconfigparser.
|
|
45
|
+
result = commentedconfigparser._SECTION_PATTERN.match(line)
|
|
44
46
|
|
|
45
47
|
assert bool(result) is expected
|
|
46
48
|
|
|
@@ -61,7 +63,7 @@ def test_section_pattern(line: str, expected: bool) -> None:
|
|
|
61
63
|
)
|
|
62
64
|
def test_key_pattern(line: str, expected: str) -> None:
|
|
63
65
|
|
|
64
|
-
match = commentedconfigparser.
|
|
66
|
+
match = commentedconfigparser._KEY_PATTERN.match(line)
|
|
65
67
|
|
|
66
68
|
assert match
|
|
67
69
|
assert match.group(1) == expected
|
|
@@ -77,7 +79,7 @@ def test_key_pattern(line: str, expected: str) -> None:
|
|
|
77
79
|
)
|
|
78
80
|
def test_comment_option_pattern(line: str, expected: str) -> None:
|
|
79
81
|
|
|
80
|
-
match = commentedconfigparser.
|
|
82
|
+
match = commentedconfigparser._COMMENT_OPTION_PATTERN.match(line)
|
|
81
83
|
|
|
82
84
|
assert match
|
|
83
85
|
assert match.group(2) == expected
|
|
@@ -126,7 +128,7 @@ def test_regression_read_dict_loads_normally() -> None:
|
|
|
126
128
|
|
|
127
129
|
def test_regression_write_normally() -> None:
|
|
128
130
|
cc = CommentedConfigParser()
|
|
129
|
-
expected = "[TEST]\ntest=pass\n
|
|
131
|
+
expected = "[TEST]\ntest=pass\n"
|
|
130
132
|
cc.read_string(expected)
|
|
131
133
|
mock_file = StringIO()
|
|
132
134
|
|
|
@@ -137,7 +139,7 @@ def test_regression_write_normally() -> None:
|
|
|
137
139
|
|
|
138
140
|
def test_write_with_no_comments() -> None:
|
|
139
141
|
cc = CommentedConfigParser()
|
|
140
|
-
expected = "[TEST]\ntest=pass\n
|
|
142
|
+
expected = "[TEST]\ntest=pass\n"
|
|
141
143
|
cc.read_dict({"TEST": {"test": "pass"}})
|
|
142
144
|
mock_file = StringIO()
|
|
143
145
|
|
|
@@ -149,6 +151,7 @@ def test_write_with_no_comments() -> None:
|
|
|
149
151
|
@pytest.mark.parametrize(
|
|
150
152
|
("ini_in", "ini_expected"),
|
|
151
153
|
(
|
|
154
|
+
(["empty_comments_input.ini"], "empty_comments_expected.ini"),
|
|
152
155
|
(["header_input.ini"], "header_expected.ini"),
|
|
153
156
|
(["pydocs_input.ini"], "pydocs_expected.ini"),
|
|
154
157
|
(["regression_original_input.ini"], "regression_original_expected.ini"),
|
|
@@ -178,7 +181,7 @@ def test_issue_46_duplicating_sections(tmp_path: Path) -> None:
|
|
|
178
181
|
# https://github.com/Preocts/commented-configparser/issues/46
|
|
179
182
|
tmp_file = tmp_path / "issue46_test_file.ini"
|
|
180
183
|
starting_config = "[example]\nfoo = 0\n"
|
|
181
|
-
expected = "[example]\nfoo = 9\n
|
|
184
|
+
expected = "[example]\nfoo = 9\n"
|
|
182
185
|
tmp_file.write_text(starting_config, "utf-8")
|
|
183
186
|
cc = CommentedConfigParser()
|
|
184
187
|
cc.read(tmp_file)
|
|
@@ -12,7 +12,7 @@ values like this = 1000000
|
|
|
12
12
|
or this = 3.14159265359
|
|
13
13
|
are they treated as numbers? = no
|
|
14
14
|
integers, floats and booleans are held as = strings
|
|
15
|
-
can use the
|
|
15
|
+
can use the API to get converted values directly = true
|
|
16
16
|
|
|
17
17
|
[Multiline Values]
|
|
18
18
|
chorus = I'm a lumberjack, and I'm okay
|
|
@@ -25,6 +25,7 @@ empty string value here =
|
|
|
25
25
|
[You can use comments]
|
|
26
26
|
# like this
|
|
27
27
|
; or this
|
|
28
|
+
|
|
28
29
|
# By default only in an empty line.
|
|
29
30
|
# Inline comments can be harmful because they prevent users
|
|
30
31
|
# from using the delimiting characters as parts of values.
|
|
@@ -40,4 +41,3 @@ multiline_values = are
|
|
|
40
41
|
deeper than the first line
|
|
41
42
|
of a value
|
|
42
43
|
# Did I mention we can indent comments, too?
|
|
43
|
-
|
{commented_configparser-2.2.0 → commented_configparser-3.0.0}/tests/regression_original_expected.ini
RENAMED
|
@@ -6,9 +6,10 @@ foo = bar
|
|
|
6
6
|
trace = false
|
|
7
7
|
logging = true
|
|
8
8
|
; This is a comment as well
|
|
9
|
+
|
|
9
10
|
# so we need to track all of them
|
|
10
|
-
; and many could be between things
|
|
11
11
|
|
|
12
|
+
; and many could be between things
|
|
12
13
|
[NEW SECTION]
|
|
13
14
|
foo = bar
|
|
14
15
|
# Unique foo
|
|
@@ -17,5 +18,5 @@ multi-line =
|
|
|
17
18
|
value02
|
|
18
19
|
value03
|
|
19
20
|
closing = 0
|
|
21
|
+
caseVariant = 0
|
|
20
22
|
# Trailing comment
|
|
21
|
-
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
ci:
|
|
2
|
-
autoupdate_schedule: monthly
|
|
3
|
-
exclude: ^.+\.ini$
|
|
4
|
-
repos:
|
|
5
|
-
# Batch of helpful formatters and patterns
|
|
6
|
-
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
7
|
-
rev: "v5.0.0"
|
|
8
|
-
hooks:
|
|
9
|
-
- id: check-json
|
|
10
|
-
- id: check-toml
|
|
11
|
-
- id: check-yaml
|
|
12
|
-
- id: trailing-whitespace
|
|
13
|
-
- id: end-of-file-fixer
|
|
14
|
-
- id: check-docstring-first
|
|
15
|
-
|
|
16
|
-
# Adds a standard feel to import segments
|
|
17
|
-
- repo: https://github.com/pycqa/isort
|
|
18
|
-
rev: 6.0.1
|
|
19
|
-
hooks:
|
|
20
|
-
- id: isort
|
|
21
|
-
args:
|
|
22
|
-
- "--force-single-line-imports"
|
|
23
|
-
- "--add-import"
|
|
24
|
-
- "from __future__ import annotations"
|
|
25
|
-
- "--profile"
|
|
26
|
-
- "black"
|
|
27
|
-
|
|
28
|
-
# Format code. No, I don't like everything black does either.
|
|
29
|
-
- repo: https://github.com/psf/black-pre-commit-mirror
|
|
30
|
-
rev: 25.1.0
|
|
31
|
-
hooks:
|
|
32
|
-
- id: black
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{commented_configparser-2.2.0 → commented_configparser-3.0.0}/requirements/requirements-dev.txt
RENAMED
|
File without changes
|
{commented_configparser-2.2.0 → commented_configparser-3.0.0}/requirements/requirements-test.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{commented_configparser-2.2.0 → commented_configparser-3.0.0}/src/commentedconfigparser/__init__.py
RENAMED
|
File without changes
|
{commented_configparser-2.2.0 → commented_configparser-3.0.0}/src/commentedconfigparser/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|