gruff 0.0.1__py3-none-win_amd64.whl

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.
Binary file
@@ -0,0 +1,258 @@
1
+ Metadata-Version: 2.4
2
+ Name: gruff
3
+ Version: 0.0.1
4
+ Classifier: Development Status :: 2 - Pre-Alpha
5
+ Classifier: Environment :: Console
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Programming Language :: Python :: 3 :: Only
8
+ Classifier: Programming Language :: Rust
9
+ Classifier: Topic :: Software Development :: Quality Assurance
10
+ License-File: LICENSE
11
+ Summary: An opinionated deterministic maintainability linter for Python
12
+ License-Expression: MIT
13
+ Requires-Python: >=3.10
14
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
15
+ Project-URL: Repository, https://github.com/wkentaro/gruff
16
+
17
+ # Gruff
18
+
19
+ Gruff is an opinionated, deterministic maintainability linter for Python. It complements Ruff with project policies that make agent-assisted code easier to understand and review; it does not infer who or what wrote the code.
20
+
21
+ The first release tests four theses: private inputs are easier to trace when callers name them, private behavior is easier to review when callers supply every value, package initializer manifests are easier to review when every public import path defines `__all__`, and constants are easier to review when uppercase names and `Final` annotations always appear together.
22
+
23
+ All rules are opt-in. Teams enable policies one at a time as they decide which opinionated constraints fit their codebase. A check with no enabled rules succeeds but warns that it performed no policy analysis.
24
+
25
+ ## Installation
26
+
27
+ Requires Python 3.10 or later.
28
+
29
+ ```bash
30
+ pip install gruff
31
+ ```
32
+
33
+ Or with [uv](https://docs.astral.sh/uv/):
34
+
35
+ ```bash
36
+ uv tool install gruff
37
+ ```
38
+
39
+ Verify it works:
40
+
41
+ ```bash
42
+ gruff --version
43
+ ```
44
+
45
+ > [!TIP]
46
+ > To try the latest development version (the head of `main` on GitHub) before
47
+ > it is published:
48
+ >
49
+ > ```bash
50
+ > uv tool install git+https://github.com/wkentaro/gruff
51
+ > ```
52
+
53
+ ## Rules
54
+
55
+ ### `keyword-only-private-inputs` (GR001)
56
+
57
+ Flags each fixed caller-supplied input to a private module-level function or method that is positional; implicit method receivers and variadic parameters are excluded.
58
+
59
+ Before → after:
60
+
61
+ ```diff
62
+ -def _resize_image(data: bytes, width: int) -> bytes:
63
+ +def _resize_image(*, data: bytes, width: int) -> bytes:
64
+ return resize(data, width=width)
65
+
66
+ def make_thumbnail(data: bytes) -> bytes:
67
+ - return _resize_image(data, width=512)
68
+ + return _resize_image(data=data, width=512)
69
+ ```
70
+
71
+ ### `required-private-inputs` (GR002)
72
+
73
+ Flags each fixed caller-supplied input to a private module-level function or method that has a default; implicit method receivers and variadic parameters are excluded.
74
+
75
+ Before → after:
76
+
77
+ ```diff
78
+ -def _resize_image(*, data: bytes, width: int = 512) -> bytes:
79
+ +def _resize_image(*, data: bytes, width: int) -> bytes:
80
+ return resize(data, width=width)
81
+
82
+ def make_thumbnail(data: bytes) -> bytes:
83
+ - return _resize_image(data=data)
84
+ + return _resize_image(data=data, width=512)
85
+ ```
86
+
87
+ ### `package-dunder-all` (GR003)
88
+
89
+ Flags a package initializer when a successfully completing import path leaves a public binding without `__all__`. The rule covers `__init__.py` and `__init__.pyi`, including bindings in module-level control flow, and reports at most one finding per file. Empty, private-only, type-checking-only, and statically false paths do not require a manifest.
90
+
91
+ Before → after:
92
+
93
+ ```diff
94
+ from .client import Client
95
+ from .errors import GruffError
96
+
97
+ +__all__ = ["Client", "GruffError"]
98
+ ```
99
+
100
+ ### `final-constants` (GR004)
101
+
102
+ Flags simple-name assignments when an uppercase name and a `Final` annotation do not appear together. The rule applies in module, class, and function scopes, including nested control flow. Enum members, type aliases, chained and unpacking assignments, augmented assignments, loop and context-manager targets, attributes, subscripts, and imports are excluded.
103
+
104
+ Before → after:
105
+
106
+ ```diff
107
+ from typing import Final
108
+
109
+ -THUMBNAIL_WIDTH = 512
110
+ -image_format: Final = "png"
111
+ +THUMBNAIL_WIDTH: Final = 512
112
+ +IMAGE_FORMAT: Final = "png"
113
+ ```
114
+
115
+ ### Exceptions
116
+
117
+ Suppress a rule on definitions that must follow an external calling convention or intentionally provide a convenience default:
118
+
119
+ ```python
120
+ def _format_cost(value: float) -> str: # noqa: GR001 -- Callable[[float], str]
121
+ return f"${value:.2f}"
122
+
123
+
124
+ def _render(*, value: float, unit: str = ""): # noqa: GR002 -- optional suffix
125
+ return f"{value}{unit}"
126
+
127
+
128
+ EXTERNAL_NAME = 1 # noqa: GR004 -- public protocol spelling
129
+ ```
130
+
131
+ For a dynamic package manifest, suppress GR003 on the reported public binding and state why deterministic source analysis does not apply:
132
+
133
+ ```python
134
+ public = load_exports() # noqa: GR003 -- exec() defines __all__ below
135
+ ```
136
+
137
+ Prefer an inline suppression because it keeps the exception next to its reason. For files made entirely of protocol implementations, use a per-file ignore instead.
138
+
139
+ ## Recommended Ruff pairing
140
+
141
+ Gruff does not duplicate checks that Ruff already provides. These Ruff rules extend the same theses to code Gruff does not cover:
142
+
143
+ ```toml
144
+ [tool.ruff.lint]
145
+ extend-select = ["ARG", "FBT", "B006", "B008", "PLR2004", "RUF012", "RUF022"]
146
+ ```
147
+
148
+ `F401` and `F822` are in Ruff's default rule set; the pairing below assumes they stay enabled.
149
+
150
+ ### Callable inputs (GR001, GR002)
151
+
152
+ `ARG` flags unused function and method arguments, including arguments on private definitions:
153
+
154
+ ```diff
155
+ -def _resize_image(*, data: bytes, width: int, legacy: bool) -> bytes:
156
+ +def _resize_image(*, data: bytes, width: int) -> bytes:
157
+ return resize(data, width=width)
158
+ ```
159
+
160
+ GR001 makes callers of private callables name every input; `FBT001` and `FBT002` extend that to boolean inputs on public callables:
161
+
162
+ ```diff
163
+ -def resize_image(data: bytes, keep_aspect: bool) -> bytes:
164
+ +def resize_image(data: bytes, *, keep_aspect: bool) -> bytes:
165
+ return resize(data, keep_aspect=keep_aspect)
166
+ ```
167
+
168
+ GR002 removes defaults from private callables; `B006` and `B008` catch shared mutable defaults and import-time call defaults on the public callables that keep theirs:
169
+
170
+ ```diff
171
+ -def make_thumbnails(data: bytes, widths: list[int] = []) -> list[bytes]:
172
+ +def make_thumbnails(data: bytes, widths: list[int] | None = None) -> list[bytes]:
173
+
174
+ -def fetch_image(client: Client = Client()) -> bytes:
175
+ +def fetch_image(client: Client | None = None) -> bytes:
176
+ ```
177
+
178
+ ### Package manifests (GR003)
179
+
180
+ GR003 only requires the manifest to exist. Once it does, `F401` flags re-exports missing from it:
181
+
182
+ ```diff
183
+ from .client import Client
184
+ from .errors import GruffError
185
+
186
+ -__all__ = ["Client"]
187
+ +__all__ = ["Client", "GruffError"]
188
+ ```
189
+
190
+ `F822` finds names in the manifest that are not defined:
191
+
192
+ ```diff
193
+ -__all__ = ["Client", "GruffErorr"]
194
+ +__all__ = ["Client", "GruffError"]
195
+ ```
196
+
197
+ `RUF022` sorts static manifests:
198
+
199
+ ```diff
200
+ -__all__ = ["GruffError", "Client"]
201
+ +__all__ = ["Client", "GruffError"]
202
+ ```
203
+
204
+ ### Constants (GR004)
205
+
206
+ `PLR2004` turns magic values into named constants, which GR004 then requires to be uppercase and `Final`:
207
+
208
+ ```diff
209
+ +MAX_WIDTH: Final = 4096
210
+ +
211
+ def validate_width(width: int) -> None:
212
+ - if width > 4096:
213
+ + if width > MAX_WIDTH:
214
+ raise ValueError(width)
215
+ ```
216
+
217
+ `RUF012` applies the same annotation discipline to mutable class attributes, which GR004 excludes:
218
+
219
+ ```diff
220
+ class ThumbnailWriter:
221
+ - formats = ["png", "jpg"]
222
+ + formats: ClassVar[list[str]] = ["png", "jpg"]
223
+ ```
224
+
225
+ ## Interface
226
+
227
+ Gruff will follow Ruff's familiar command and diagnostic conventions:
228
+
229
+ ```console
230
+ gruff check .
231
+ gruff check --select GR001 .
232
+ gruff check --select GR002 .
233
+ gruff check --select GR003 .
234
+ gruff check --select GR004 .
235
+ gruff check --select GR001,GR002,GR003,GR004 .
236
+ ```
237
+
238
+ Lint findings, including invalid Python syntax, will exit with status 1. Configuration, I/O, and internal failures will exit with status 2.
239
+
240
+ Gruff does not rewrite source code in the first release.
241
+
242
+ ## Configuration
243
+
244
+ Gruff reads configuration only from `pyproject.toml`:
245
+
246
+ ```toml
247
+ [tool.gruff.lint]
248
+ select = ["GR001", "GR002", "GR003", "GR004"]
249
+ ignore = []
250
+ per-file-ignores = { "callbacks.py" = ["GR001"] }
251
+ ```
252
+
253
+ Directory discovery checks `.py`, `.pyi`, and `.pyw` files and respects Git ignore files.
254
+
255
+ ## Distribution
256
+
257
+ Public releases will use PyPI wheels for Linux x86_64 and aarch64, macOS x86_64 and arm64, and Windows x86_64. Gruff is not published to crates.io.
258
+
@@ -0,0 +1,6 @@
1
+ gruff-0.0.1.data/scripts/gruff.exe,sha256=JQAeaCQrdkLDNDV4TR-ArVBE9LycGpWUeo2bhYB3DFY,4363264
2
+ gruff-0.0.1.dist-info/METADATA,sha256=JRrKmtaUdydtA_-G_ZmBDJToha9dfz5kGdgs-F2tEgc,8450
3
+ gruff-0.0.1.dist-info/WHEEL,sha256=8Aej0W0a6Cz6apA3IzJrTnxLRVLAt-w0Oh8SA3Con_c,94
4
+ gruff-0.0.1.dist-info/licenses/LICENSE,sha256=CJJKc1H10DyG0jl-qEWfr64KtWnMaXxfmsruVZ0nD7c,1090
5
+ gruff-0.0.1.dist-info/sboms/gruff.cyclonedx.json,sha256=tbeEwx8Dxt8M3zcryGkkYV-vuzJgalTaGs1-P8oAg1I,132253
6
+ gruff-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.15.0)
3
+ Root-Is-Purelib: false
4
+ Tag: py3-none-win_amd64
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kentaro Wada
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.