pyprojkit 0.2.0__tar.gz → 0.3.1__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.
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/PKG-INFO +3 -3
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/README.md +1 -1
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/pyproject.toml +6 -9
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/__init__.py +2 -2
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/config/__init__.py +2 -2
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/config/base.py +6 -6
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/config/profiles.py +5 -5
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/config/project.py +4 -0
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/config/tools.py +12 -14
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/sync.py +62 -10
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/LICENSE +0 -0
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/_paths.py +0 -0
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/_run.py +0 -0
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/cli.py +0 -0
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/discovery.py +0 -0
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/sessions.py +0 -0
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/tasks.py +0 -0
- {pyprojkit-0.2.0 → pyprojkit-0.3.1}/src/pyprojkit/versions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyprojkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Development workflow toolkit for Python projects: pyproject.toml sync, doit tasks, nox sessions
|
|
5
5
|
Author: mm21
|
|
6
6
|
Author-email: mm21 <mm21.dev@gmail.com>
|
|
@@ -27,7 +27,7 @@ Requires-Dist: pyright>=1.1.329,<2 ; extra == 'analysis'
|
|
|
27
27
|
Requires-Dist: mkinit ; extra == 'doc'
|
|
28
28
|
Requires-Dist: autoflake>=2.3.1,<3 ; extra == 'format'
|
|
29
29
|
Requires-Dist: black>=25.1.0,<26 ; extra == 'format'
|
|
30
|
-
Requires-Dist:
|
|
30
|
+
Requires-Dist: docfmt>=0.2.0,<0.3.0 ; extra == 'format'
|
|
31
31
|
Requires-Dist: isort>=6.0.1,<7 ; extra == 'format'
|
|
32
32
|
Requires-Dist: genbadge[tests,coverage]>=1.1.0,<2 ; extra == 'test'
|
|
33
33
|
Requires-Dist: pytest>=8.4.2,<9 ; extra == 'test'
|
|
@@ -160,7 +160,7 @@ python = PythonVersions(3, (12, 14), patch_overrides={(3, 14): "3.14.7"})
|
|
|
160
160
|
|
|
161
161
|
Tool configurations are grouped by category under `ToolsConfig`, whose defaults constitute the default *profile*:
|
|
162
162
|
|
|
163
|
-
- `formatting`: ordered chain of formatters; by default autoflake → isort →
|
|
163
|
+
- `formatting`: ordered chain of formatters; by default autoflake → isort → docfmt → black → toml-sort
|
|
164
164
|
- `test`: pytest + coverage settings
|
|
165
165
|
- `doit`, `nox`: cache locations and backends
|
|
166
166
|
- `doc`: documentation tools — mkinit (enabled by default) and sphinx (opt-in)
|
|
@@ -117,7 +117,7 @@ python = PythonVersions(3, (12, 14), patch_overrides={(3, 14): "3.14.7"})
|
|
|
117
117
|
|
|
118
118
|
Tool configurations are grouped by category under `ToolsConfig`, whose defaults constitute the default *profile*:
|
|
119
119
|
|
|
120
|
-
- `formatting`: ordered chain of formatters; by default autoflake → isort →
|
|
120
|
+
- `formatting`: ordered chain of formatters; by default autoflake → isort → docfmt → black → toml-sort
|
|
121
121
|
- `test`: pytest + coverage settings
|
|
122
122
|
- `doit`, `nox`: cache locations and backends
|
|
123
123
|
- `doc`: documentation tools — mkinit (enabled by default) and sphinx (opt-in)
|
|
@@ -27,7 +27,7 @@ license-files = ["LICENSE"]
|
|
|
27
27
|
name = "pyprojkit"
|
|
28
28
|
readme = "README.md"
|
|
29
29
|
requires-python = ">=3.12,<3.15" # managed by pyprojkit
|
|
30
|
-
version = "0.
|
|
30
|
+
version = "0.3.1"
|
|
31
31
|
|
|
32
32
|
[project.optional-dependencies]
|
|
33
33
|
all = [
|
|
@@ -43,7 +43,7 @@ doc = [
|
|
|
43
43
|
format = [
|
|
44
44
|
"autoflake>=2.3.1,<3",
|
|
45
45
|
"black>=25.1.0,<26",
|
|
46
|
-
"
|
|
46
|
+
"docfmt>=0.2.0,<0.3.0",
|
|
47
47
|
"isort>=6.0.1,<7"
|
|
48
48
|
]
|
|
49
49
|
test = [
|
|
@@ -90,13 +90,11 @@ exclude_lines = [
|
|
|
90
90
|
[tool.coverage.run] # managed by pyprojkit
|
|
91
91
|
data_file = "__cache__/.coverage"
|
|
92
92
|
|
|
93
|
-
[tool.
|
|
94
|
-
|
|
93
|
+
[tool.docfmt] # managed by pyprojkit
|
|
94
|
+
force-reflow = true
|
|
95
95
|
in-place = true
|
|
96
|
-
make-summary-multi-line = true
|
|
97
|
-
non-strict = true
|
|
98
|
-
pre-summary-newline = true
|
|
99
96
|
recursive = true
|
|
97
|
+
summary-on-own-line = true
|
|
100
98
|
|
|
101
99
|
[tool.doit] # managed by pyprojkit
|
|
102
100
|
dep_file = "__cache__/.doit.db"
|
|
@@ -116,7 +114,7 @@ managed = [
|
|
|
116
114
|
"tool.black",
|
|
117
115
|
"tool.coverage.report",
|
|
118
116
|
"tool.coverage.run",
|
|
119
|
-
"tool.
|
|
117
|
+
"tool.docfmt",
|
|
120
118
|
"tool.doit",
|
|
121
119
|
"tool.isort",
|
|
122
120
|
"tool.nox",
|
|
@@ -139,5 +137,4 @@ sort_table_keys = true
|
|
|
139
137
|
spaces_before_inline_comment = 2
|
|
140
138
|
|
|
141
139
|
[tool.uv.sources]
|
|
142
|
-
docformatter = {git = "https://github.com/mm21/docformatter.git"}
|
|
143
140
|
mkinit = {git = "https://github.com/mm21/mkinit.git"}
|
|
@@ -27,7 +27,7 @@ from .config import (
|
|
|
27
27
|
AutoflakeConfig,
|
|
28
28
|
IsortConfig,
|
|
29
29
|
BlackConfig,
|
|
30
|
-
|
|
30
|
+
DocfmtConfig,
|
|
31
31
|
TomlSortConfig,
|
|
32
32
|
PytestConfig,
|
|
33
33
|
CoverageRunConfig,
|
|
@@ -74,7 +74,7 @@ __all__ = [
|
|
|
74
74
|
"AutoflakeConfig",
|
|
75
75
|
"IsortConfig",
|
|
76
76
|
"BlackConfig",
|
|
77
|
-
"
|
|
77
|
+
"DocfmtConfig",
|
|
78
78
|
"TomlSortConfig",
|
|
79
79
|
"PytestConfig",
|
|
80
80
|
"CoverageRunConfig",
|
|
@@ -20,7 +20,7 @@ from .tools import (
|
|
|
20
20
|
AutoflakeConfig,
|
|
21
21
|
IsortConfig,
|
|
22
22
|
BlackConfig,
|
|
23
|
-
|
|
23
|
+
DocfmtConfig,
|
|
24
24
|
TomlSortConfig,
|
|
25
25
|
PytestConfig,
|
|
26
26
|
CoverageRunConfig,
|
|
@@ -54,7 +54,7 @@ __all__ = [
|
|
|
54
54
|
"AutoflakeConfig",
|
|
55
55
|
"IsortConfig",
|
|
56
56
|
"BlackConfig",
|
|
57
|
-
"
|
|
57
|
+
"DocfmtConfig",
|
|
58
58
|
"TomlSortConfig",
|
|
59
59
|
"PytestConfig",
|
|
60
60
|
"CoverageRunConfig",
|
|
@@ -27,13 +27,13 @@ class ConfigError(Exception):
|
|
|
27
27
|
@dataclass(kw_only=True)
|
|
28
28
|
class BaseToolConfig(ABC):
|
|
29
29
|
"""
|
|
30
|
-
Configuration for a tool which reads its settings from a table in
|
|
31
|
-
|
|
30
|
+
Configuration for a tool which reads its settings from a table in `pyproject.toml`,
|
|
31
|
+
e.g. `[tool.black]`.
|
|
32
32
|
|
|
33
|
-
Dataclass fields map to table entries; a field whose name differs from its
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
Dataclass fields map to table entries; a field whose name differs from its TOML key
|
|
34
|
+
declares the key via `field(metadata={"toml": "some-key"})`. Fields set to `None`
|
|
35
|
+
are omitted. Values derived from project-wide config (e.g. black's `target-version`)
|
|
36
|
+
are contributed by `extra_toml()`.
|
|
37
37
|
"""
|
|
38
38
|
|
|
39
39
|
table_path: ClassVar[str]
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Profile registries: named factories for pre-canned configurations.
|
|
3
3
|
|
|
4
|
-
A tools profile encompasses all tool categories; a formatting profile covers
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
A tools profile encompasses all tool categories; a formatting profile covers just the
|
|
5
|
+
formatter chain. Third parties can register their own profiles and reuse them across
|
|
6
|
+
projects:
|
|
7
7
|
|
|
8
8
|
```python
|
|
9
9
|
from pyprojkit import register_tools_profile
|
|
@@ -21,7 +21,7 @@ from .project import FormattingConfig, ToolsConfig
|
|
|
21
21
|
from .tools import (
|
|
22
22
|
AutoflakeConfig,
|
|
23
23
|
BlackConfig,
|
|
24
|
-
|
|
24
|
+
DocfmtConfig,
|
|
25
25
|
IsortConfig,
|
|
26
26
|
TomlSortConfig,
|
|
27
27
|
)
|
|
@@ -39,7 +39,7 @@ def _default_formatting() -> FormattingConfig:
|
|
|
39
39
|
formatters=(
|
|
40
40
|
AutoflakeConfig(),
|
|
41
41
|
IsortConfig(),
|
|
42
|
-
|
|
42
|
+
DocfmtConfig(),
|
|
43
43
|
BlackConfig(),
|
|
44
44
|
TomlSortConfig(),
|
|
45
45
|
)
|
|
@@ -189,19 +189,23 @@ class ProjectConfig:
|
|
|
189
189
|
"""
|
|
190
190
|
Import name of the package, e.g. `"trilium_alchemy"`.
|
|
191
191
|
"""
|
|
192
|
+
|
|
192
193
|
python: PythonVersions
|
|
193
194
|
"""
|
|
194
195
|
Supported Python versions.
|
|
195
196
|
"""
|
|
197
|
+
|
|
196
198
|
packages_dir: str = "src"
|
|
197
199
|
"""
|
|
198
200
|
Directory containing packages, relative to the project root.
|
|
199
201
|
"""
|
|
202
|
+
|
|
200
203
|
format_paths: Sequence[str] = ("src", "test", "doc", "examples")
|
|
201
204
|
"""
|
|
202
205
|
Directories to format (those which exist), in addition to `*.py` and `*.toml` files
|
|
203
206
|
at the project root.
|
|
204
207
|
"""
|
|
208
|
+
|
|
205
209
|
tools: ToolsConfig = field(default_factory=ToolsConfig.default)
|
|
206
210
|
"""
|
|
207
211
|
Tool configurations.
|
|
@@ -19,7 +19,7 @@ __all__ = [
|
|
|
19
19
|
"AutoflakeConfig",
|
|
20
20
|
"IsortConfig",
|
|
21
21
|
"BlackConfig",
|
|
22
|
-
"
|
|
22
|
+
"DocfmtConfig",
|
|
23
23
|
"TomlSortConfig",
|
|
24
24
|
"PytestConfig",
|
|
25
25
|
"CoverageRunConfig",
|
|
@@ -75,25 +75,23 @@ class BlackConfig(BaseFormatterConfig):
|
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
@dataclass(kw_only=True)
|
|
78
|
-
class
|
|
79
|
-
table_path: ClassVar[str] = "tool.
|
|
78
|
+
class DocfmtConfig(BaseFormatterConfig):
|
|
79
|
+
table_path: ClassVar[str] = "tool.docfmt"
|
|
80
80
|
|
|
81
|
-
#
|
|
82
|
-
|
|
81
|
+
# docfmt returns 0 when it writes changes in-place; 1 means "would change"
|
|
82
|
+
# in check mode and 2 is an error, so only 0 is expected here
|
|
83
|
+
expect_rc: ClassVar[frozenset[int]] = frozenset({0})
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
# line length is left unset: docfmt picks it up from `[tool.black]`
|
|
85
86
|
in_place: bool | None = field(default=True, metadata={"toml": "in-place"})
|
|
86
|
-
make_summary_multi_line: bool | None = field(
|
|
87
|
-
default=True, metadata={"toml": "make-summary-multi-line"}
|
|
88
|
-
)
|
|
89
|
-
non_strict: bool | None = field(default=True, metadata={"toml": "non-strict"})
|
|
90
|
-
pre_summary_newline: bool | None = field(
|
|
91
|
-
default=True, metadata={"toml": "pre-summary-newline"}
|
|
92
|
-
)
|
|
93
87
|
recursive: bool | None = True
|
|
88
|
+
summary_on_own_line: bool | None = field(
|
|
89
|
+
default=True, metadata={"toml": "summary-on-own-line"}
|
|
90
|
+
)
|
|
91
|
+
force_reflow: bool | None = field(default=True, metadata={"toml": "force-reflow"})
|
|
94
92
|
|
|
95
93
|
def command(self, py_paths: list[str], toml_paths: list[str]) -> list[str]:
|
|
96
|
-
return ["
|
|
94
|
+
return ["docfmt"] + py_paths
|
|
97
95
|
|
|
98
96
|
|
|
99
97
|
@dataclass(kw_only=True)
|
|
@@ -5,16 +5,16 @@ Managed content:
|
|
|
5
5
|
|
|
6
6
|
- `project.requires-python`
|
|
7
7
|
- Python version classifiers (`Programming Language :: Python :: 3[.X]`);
|
|
8
|
-
other classifiers are left untouched
|
|
8
|
+
other classifiers are left untouched, as are comments in the list
|
|
9
9
|
- One `[tool.X]` table per enabled tool (fully owned — any hand edits or
|
|
10
10
|
comments inside are overwritten)
|
|
11
11
|
- `[tool.pyprojkit].managed`: bookkeeping list of owned tables, enabling safe
|
|
12
12
|
removal of tables for tools dropped from the configuration
|
|
13
13
|
|
|
14
|
-
Everything else (dependencies, build-system, urls, unmanaged tool tables,
|
|
15
|
-
|
|
16
|
-
the
|
|
17
|
-
|
|
14
|
+
Everything else (dependencies, build-system, urls, unmanaged tool tables, etc.) is
|
|
15
|
+
preserved. Output is normalized with toml-sort (as a library, using the same settings as
|
|
16
|
+
the managed `[tool.tomlsort]` table), so a subsequent `toml-sort` run in the format task
|
|
17
|
+
is a no-op.
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
from __future__ import annotations
|
|
@@ -22,11 +22,11 @@ from __future__ import annotations
|
|
|
22
22
|
import difflib
|
|
23
23
|
import re
|
|
24
24
|
from pathlib import Path
|
|
25
|
-
from typing import Any
|
|
25
|
+
from typing import Any
|
|
26
26
|
|
|
27
27
|
import tomlkit
|
|
28
28
|
from tomlkit import TOMLDocument
|
|
29
|
-
from tomlkit.items import Table
|
|
29
|
+
from tomlkit.items import Null, Table
|
|
30
30
|
|
|
31
31
|
from .config.base import ConfigError
|
|
32
32
|
from .config.project import ProjectConfig
|
|
@@ -140,22 +140,74 @@ def _update_classifiers(project: Table, config: ProjectConfig):
|
|
|
140
140
|
"""
|
|
141
141
|
Replace python version classifiers with those derived from config, preserving all
|
|
142
142
|
others; result is sorted, with managed entries marked by an inline comment.
|
|
143
|
+
|
|
144
|
+
Comments in the existing list are preserved: an inline comment stays with its entry,
|
|
145
|
+
and a standalone comment stays with the entry it precedes (or is emitted at the end
|
|
146
|
+
of the list if it precedes none).
|
|
143
147
|
"""
|
|
144
|
-
existing = cast(list[str], [str(c) for c in project.get("classifiers", [])])
|
|
145
|
-
kept = [c for c in existing if not _CLASSIFIER_RE.match(c)]
|
|
146
148
|
managed = set(config.python.classifiers)
|
|
149
|
+
existing = project.get("classifiers", [])
|
|
150
|
+
kept = [str(c) for c in existing if not _CLASSIFIER_RE.match(str(c))]
|
|
151
|
+
leading, inline, trailing = _collect_classifier_comments(
|
|
152
|
+
existing, set(kept) | managed
|
|
153
|
+
)
|
|
147
154
|
|
|
148
155
|
array = tomlkit.array()
|
|
149
156
|
for entry in sorted(set(kept) | managed):
|
|
157
|
+
for comment in leading.get(entry, []):
|
|
158
|
+
array.add_line(comment=comment, indent=" ")
|
|
150
159
|
array.add_line(
|
|
151
160
|
entry,
|
|
152
161
|
indent=" ",
|
|
153
|
-
comment=_MANAGED_COMMENT if entry in managed else
|
|
162
|
+
comment=_MANAGED_COMMENT if entry in managed else inline.get(entry),
|
|
154
163
|
)
|
|
164
|
+
for comment in trailing:
|
|
165
|
+
array.add_line(comment=comment, indent=" ")
|
|
155
166
|
array.add_line(indent="")
|
|
156
167
|
project["classifiers"] = array
|
|
157
168
|
|
|
158
169
|
|
|
170
|
+
def _collect_classifier_comments(
|
|
171
|
+
array: Any, surviving: set[str]
|
|
172
|
+
) -> tuple[dict[str, list[str]], dict[str, str], list[str]]:
|
|
173
|
+
"""
|
|
174
|
+
Extract comments from an existing classifiers array, anchored to the entries they
|
|
175
|
+
accompany. Comments attached to entries which don't survive the sync are carried
|
|
176
|
+
forward to the next surviving entry.
|
|
177
|
+
"""
|
|
178
|
+
leading: dict[str, list[str]] = {}
|
|
179
|
+
inline: dict[str, str] = {}
|
|
180
|
+
pending: list[str] = []
|
|
181
|
+
|
|
182
|
+
for group in getattr(array, "_value", []):
|
|
183
|
+
comment = _comment_text(group)
|
|
184
|
+
if group.value is None or isinstance(group.value, Null):
|
|
185
|
+
# standalone comment line
|
|
186
|
+
if comment:
|
|
187
|
+
pending.append(comment)
|
|
188
|
+
continue
|
|
189
|
+
|
|
190
|
+
entry = str(group.value)
|
|
191
|
+
if entry in surviving:
|
|
192
|
+
if pending:
|
|
193
|
+
leading.setdefault(entry, []).extend(pending)
|
|
194
|
+
pending = []
|
|
195
|
+
if comment and comment != _MANAGED_COMMENT:
|
|
196
|
+
inline[entry] = comment
|
|
197
|
+
elif comment and comment != _MANAGED_COMMENT:
|
|
198
|
+
# entry is going away; keep its comment as a standalone one
|
|
199
|
+
pending.append(comment)
|
|
200
|
+
|
|
201
|
+
return leading, inline, pending
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _comment_text(group: Any) -> str | None:
|
|
205
|
+
comment = getattr(group, "comment", None)
|
|
206
|
+
if comment is None:
|
|
207
|
+
return None
|
|
208
|
+
return comment.trivia.comment.lstrip("#").strip() or None
|
|
209
|
+
|
|
210
|
+
|
|
159
211
|
def _get_managed_list(doc: TOMLDocument) -> list[str]:
|
|
160
212
|
try:
|
|
161
213
|
return list(doc["tool"]["pyprojkit"]["managed"]) # type: ignore[index]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|