stolid 2022.3.6.2__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.
@@ -0,0 +1,273 @@
1
+ Metadata-Version: 2.4
2
+ Name: stolid
3
+ Version: 2022.3.6.2
4
+ Summary: Linter enforcing the conventions of the Python standard template
5
+ Author-email: Moshe Zadka <moshez@zadka.club>
6
+ License: Permission is hereby granted, free of charge, to any person obtaining a
7
+ copy of this software and associated documentation files (the "Software"),
8
+ to deal in the Software without restriction, including without limitation the
9
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is furnished
11
+ to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
17
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
18
+ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
21
+ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ Project-URL: Homepage, https://github.com/moshez/stolid
24
+ Description-Content-Type: text/x-rst
25
+ Provides-Extra: tests
26
+ Requires-Dist: virtue; extra == "tests"
27
+ Requires-Dist: pyhamcrest; extra == "tests"
28
+ Requires-Dist: coverage; extra == "tests"
29
+ Provides-Extra: mypy
30
+ Requires-Dist: mypy; extra == "mypy"
31
+ Provides-Extra: lint
32
+ Requires-Dist: flake8; extra == "lint"
33
+ Requires-Dist: black; extra == "lint"
34
+ Provides-Extra: docs
35
+ Requires-Dist: sphinx; extra == "docs"
36
+
37
+ stolid
38
+ ======
39
+
40
+ A flake8 plugin that enforces opinionated Python coding conventions for clean,
41
+ maintainable code.
42
+
43
+ Stolid encourages:
44
+
45
+ - **Composition over inheritance**
46
+ - **Dependency injection over mocking**
47
+ - **Protocol-based typing over abstract base classes**
48
+ - **Immutable dataclasses**
49
+ - **Small, focused functions and classes**
50
+
51
+ Installation
52
+ ------------
53
+
54
+ .. code-block:: bash
55
+
56
+ pip install stolid
57
+
58
+ Usage
59
+ -----
60
+
61
+ Stolid integrates directly with flake8:
62
+
63
+ .. code-block:: bash
64
+
65
+ flake8 your_code.py
66
+
67
+ Error Codes
68
+ -----------
69
+
70
+ SLD1xx - Testing
71
+ ~~~~~~~~~~~~~~~~
72
+
73
+ **SLD102**: Prohibits use of ``patch`` and ``patch.object`` from ``unittest.mock``.
74
+
75
+ Use dependency injection instead of mocking:
76
+
77
+ .. code-block:: python
78
+
79
+ # Bad
80
+ from unittest.mock import patch
81
+
82
+ @patch("mymodule.requests.get")
83
+ def test_fetch(mock_get):
84
+ ...
85
+
86
+ # Good
87
+ class TestFetch(unittest.TestCase):
88
+ def test_fetch(self) -> None:
89
+ fake_client = FakeHTTPClient(response={"data": 1})
90
+ fetcher = DataFetcher(client=fake_client)
91
+ result = fetcher.fetch()
92
+ assert_that(result, equal_to(1))
93
+
94
+ SLD2xx - Abstract Base Classes
95
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
96
+
97
+ **SLD201**: Prohibits importing ``ABC`` from the ``abc`` module.
98
+
99
+ **SLD202**: Prohibits using ``@abstractmethod`` decorator.
100
+
101
+ Use ``typing.Protocol`` for interfaces instead:
102
+
103
+ .. code-block:: python
104
+
105
+ # Bad
106
+ from abc import ABC, abstractmethod
107
+
108
+ class HTTPClient(ABC):
109
+ @abstractmethod
110
+ def get(self, url: str) -> Response:
111
+ ...
112
+
113
+ # Good
114
+ from typing import Protocol
115
+
116
+ class HTTPClient(Protocol):
117
+ def get(self, url: str) -> Response:
118
+ ...
119
+
120
+ SLD3xx - Object-Oriented Design
121
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
122
+
123
+ **SLD301**: Prohibits ``__init__`` methods.
124
+
125
+ Use ``@dataclass`` with ``default_factory`` for attributes, or ``@classmethod``
126
+ for parameter computation:
127
+
128
+ .. code-block:: python
129
+
130
+ # Bad
131
+ class Processor:
132
+ def __init__(self, client, config):
133
+ self.client = client
134
+ self.config = config
135
+
136
+ # Good
137
+ from dataclasses import dataclass
138
+
139
+ @dataclass(frozen=True, slots=True, kw_only=True)
140
+ class Processor:
141
+ client: HTTPClient
142
+ config: Config
143
+
144
+ **SLD302**: Prohibits private methods (starting with ``_``).
145
+
146
+ Extract private methods into separate classes:
147
+
148
+ .. code-block:: python
149
+
150
+ # Bad
151
+ class Processor:
152
+ def _validate(self, data):
153
+ ...
154
+
155
+ # Good
156
+ class Validator:
157
+ def validate(self, data):
158
+ ...
159
+
160
+ **SLD303**: Flags methods that only access public members of ``self``.
161
+
162
+ Convert to module-level functions or use ``functools.singledispatch``:
163
+
164
+ .. code-block:: python
165
+
166
+ # Bad
167
+ class User:
168
+ name: str
169
+
170
+ def display_name(self) -> str:
171
+ return self.name.title()
172
+
173
+ # Good
174
+ def display_name(user: User) -> str:
175
+ return user.name.title()
176
+
177
+ SLD4xx - Inheritance
178
+ ~~~~~~~~~~~~~~~~~~~~
179
+
180
+ **SLD401**: Prohibits inheritance from concrete classes.
181
+
182
+ Allowed base classes:
183
+
184
+ - Typing: ``Protocol``, ``Generic``
185
+ - Exceptions: ``Exception``, ``BaseException``
186
+ - Testing: ``TestCase``
187
+ - Enums: ``Enum``, ``IntEnum``, ``StrEnum``, ``Flag``, ``IntFlag``
188
+ - Other: ``TypedDict``, ``NamedTuple``
189
+
190
+ .. code-block:: python
191
+
192
+ # Bad
193
+ class MyHandler(BaseHandler):
194
+ ...
195
+
196
+ # Good
197
+ @dataclass(frozen=True, slots=True, kw_only=True)
198
+ class MyHandler:
199
+ validator: Validator
200
+ processor: Processor
201
+
202
+ SLD5xx - Dataclass Configuration
203
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
204
+
205
+ All dataclasses must have:
206
+
207
+ **SLD501**: ``frozen=True`` (immutability)
208
+
209
+ **SLD502**: ``slots=True`` (memory efficiency)
210
+
211
+ **SLD503**: ``kw_only=True`` (keyword-only arguments)
212
+
213
+ .. code-block:: python
214
+
215
+ # Bad
216
+ @dataclass
217
+ class Settings:
218
+ timeout: int
219
+
220
+ # Good
221
+ @dataclass(frozen=True, slots=True, kw_only=True)
222
+ class Settings:
223
+ timeout: int
224
+
225
+ SLD6xx - Code Complexity
226
+ ~~~~~~~~~~~~~~~~~~~~~~~~
227
+
228
+ **SLD601**: Functions limited to 30 lines
229
+
230
+ **SLD602**: Functions limited to 4 arguments (excludes ``self``/``cls``)
231
+
232
+ **SLD603**: Classes limited to 15 methods (excludes dunder methods)
233
+
234
+ **SLD604**: Modules limited to 400 lines
235
+
236
+ Configuration
237
+ -------------
238
+
239
+ Stolid follows standard flake8 configuration. Add to your ``setup.cfg`` or
240
+ ``.flake8``:
241
+
242
+ .. code-block:: ini
243
+
244
+ [flake8]
245
+ extend-ignore = SLD301,SLD302
246
+
247
+ Or use per-file ignores:
248
+
249
+ .. code-block:: ini
250
+
251
+ [flake8]
252
+ per-file-ignores =
253
+ tests/*:SLD301,SLD302
254
+
255
+ Development
256
+ -----------
257
+
258
+ .. code-block:: bash
259
+
260
+ pip install nox
261
+
262
+ # Run all checks
263
+ nox
264
+
265
+ # Run specific sessions
266
+ nox -s tests # Run tests with coverage
267
+ nox -s lint # Run black and flake8
268
+ nox -s mypy # Run type checking
269
+
270
+ License
271
+ -------
272
+
273
+ MIT License. See LICENSE for details.
@@ -0,0 +1,237 @@
1
+ stolid
2
+ ======
3
+
4
+ A flake8 plugin that enforces opinionated Python coding conventions for clean,
5
+ maintainable code.
6
+
7
+ Stolid encourages:
8
+
9
+ - **Composition over inheritance**
10
+ - **Dependency injection over mocking**
11
+ - **Protocol-based typing over abstract base classes**
12
+ - **Immutable dataclasses**
13
+ - **Small, focused functions and classes**
14
+
15
+ Installation
16
+ ------------
17
+
18
+ .. code-block:: bash
19
+
20
+ pip install stolid
21
+
22
+ Usage
23
+ -----
24
+
25
+ Stolid integrates directly with flake8:
26
+
27
+ .. code-block:: bash
28
+
29
+ flake8 your_code.py
30
+
31
+ Error Codes
32
+ -----------
33
+
34
+ SLD1xx - Testing
35
+ ~~~~~~~~~~~~~~~~
36
+
37
+ **SLD102**: Prohibits use of ``patch`` and ``patch.object`` from ``unittest.mock``.
38
+
39
+ Use dependency injection instead of mocking:
40
+
41
+ .. code-block:: python
42
+
43
+ # Bad
44
+ from unittest.mock import patch
45
+
46
+ @patch("mymodule.requests.get")
47
+ def test_fetch(mock_get):
48
+ ...
49
+
50
+ # Good
51
+ class TestFetch(unittest.TestCase):
52
+ def test_fetch(self) -> None:
53
+ fake_client = FakeHTTPClient(response={"data": 1})
54
+ fetcher = DataFetcher(client=fake_client)
55
+ result = fetcher.fetch()
56
+ assert_that(result, equal_to(1))
57
+
58
+ SLD2xx - Abstract Base Classes
59
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
60
+
61
+ **SLD201**: Prohibits importing ``ABC`` from the ``abc`` module.
62
+
63
+ **SLD202**: Prohibits using ``@abstractmethod`` decorator.
64
+
65
+ Use ``typing.Protocol`` for interfaces instead:
66
+
67
+ .. code-block:: python
68
+
69
+ # Bad
70
+ from abc import ABC, abstractmethod
71
+
72
+ class HTTPClient(ABC):
73
+ @abstractmethod
74
+ def get(self, url: str) -> Response:
75
+ ...
76
+
77
+ # Good
78
+ from typing import Protocol
79
+
80
+ class HTTPClient(Protocol):
81
+ def get(self, url: str) -> Response:
82
+ ...
83
+
84
+ SLD3xx - Object-Oriented Design
85
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
86
+
87
+ **SLD301**: Prohibits ``__init__`` methods.
88
+
89
+ Use ``@dataclass`` with ``default_factory`` for attributes, or ``@classmethod``
90
+ for parameter computation:
91
+
92
+ .. code-block:: python
93
+
94
+ # Bad
95
+ class Processor:
96
+ def __init__(self, client, config):
97
+ self.client = client
98
+ self.config = config
99
+
100
+ # Good
101
+ from dataclasses import dataclass
102
+
103
+ @dataclass(frozen=True, slots=True, kw_only=True)
104
+ class Processor:
105
+ client: HTTPClient
106
+ config: Config
107
+
108
+ **SLD302**: Prohibits private methods (starting with ``_``).
109
+
110
+ Extract private methods into separate classes:
111
+
112
+ .. code-block:: python
113
+
114
+ # Bad
115
+ class Processor:
116
+ def _validate(self, data):
117
+ ...
118
+
119
+ # Good
120
+ class Validator:
121
+ def validate(self, data):
122
+ ...
123
+
124
+ **SLD303**: Flags methods that only access public members of ``self``.
125
+
126
+ Convert to module-level functions or use ``functools.singledispatch``:
127
+
128
+ .. code-block:: python
129
+
130
+ # Bad
131
+ class User:
132
+ name: str
133
+
134
+ def display_name(self) -> str:
135
+ return self.name.title()
136
+
137
+ # Good
138
+ def display_name(user: User) -> str:
139
+ return user.name.title()
140
+
141
+ SLD4xx - Inheritance
142
+ ~~~~~~~~~~~~~~~~~~~~
143
+
144
+ **SLD401**: Prohibits inheritance from concrete classes.
145
+
146
+ Allowed base classes:
147
+
148
+ - Typing: ``Protocol``, ``Generic``
149
+ - Exceptions: ``Exception``, ``BaseException``
150
+ - Testing: ``TestCase``
151
+ - Enums: ``Enum``, ``IntEnum``, ``StrEnum``, ``Flag``, ``IntFlag``
152
+ - Other: ``TypedDict``, ``NamedTuple``
153
+
154
+ .. code-block:: python
155
+
156
+ # Bad
157
+ class MyHandler(BaseHandler):
158
+ ...
159
+
160
+ # Good
161
+ @dataclass(frozen=True, slots=True, kw_only=True)
162
+ class MyHandler:
163
+ validator: Validator
164
+ processor: Processor
165
+
166
+ SLD5xx - Dataclass Configuration
167
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
168
+
169
+ All dataclasses must have:
170
+
171
+ **SLD501**: ``frozen=True`` (immutability)
172
+
173
+ **SLD502**: ``slots=True`` (memory efficiency)
174
+
175
+ **SLD503**: ``kw_only=True`` (keyword-only arguments)
176
+
177
+ .. code-block:: python
178
+
179
+ # Bad
180
+ @dataclass
181
+ class Settings:
182
+ timeout: int
183
+
184
+ # Good
185
+ @dataclass(frozen=True, slots=True, kw_only=True)
186
+ class Settings:
187
+ timeout: int
188
+
189
+ SLD6xx - Code Complexity
190
+ ~~~~~~~~~~~~~~~~~~~~~~~~
191
+
192
+ **SLD601**: Functions limited to 30 lines
193
+
194
+ **SLD602**: Functions limited to 4 arguments (excludes ``self``/``cls``)
195
+
196
+ **SLD603**: Classes limited to 15 methods (excludes dunder methods)
197
+
198
+ **SLD604**: Modules limited to 400 lines
199
+
200
+ Configuration
201
+ -------------
202
+
203
+ Stolid follows standard flake8 configuration. Add to your ``setup.cfg`` or
204
+ ``.flake8``:
205
+
206
+ .. code-block:: ini
207
+
208
+ [flake8]
209
+ extend-ignore = SLD301,SLD302
210
+
211
+ Or use per-file ignores:
212
+
213
+ .. code-block:: ini
214
+
215
+ [flake8]
216
+ per-file-ignores =
217
+ tests/*:SLD301,SLD302
218
+
219
+ Development
220
+ -----------
221
+
222
+ .. code-block:: bash
223
+
224
+ pip install nox
225
+
226
+ # Run all checks
227
+ nox
228
+
229
+ # Run specific sessions
230
+ nox -s tests # Run tests with coverage
231
+ nox -s lint # Run black and flake8
232
+ nox -s mypy # Run type checking
233
+
234
+ License
235
+ -------
236
+
237
+ MIT License. See LICENSE for details.
@@ -0,0 +1,8 @@
1
+ commit 21b60f6e2a900d1ac9b4b568031db8a284bcfd19
2
+ Merge: 5cf3234 64e5d18
3
+ Author: Moshe Zadka <moshez@users.noreply.github.com>
4
+ Date: 2026-01-24 12:51:21 -0800
5
+
6
+ Merge pull request #10 from moshez/claude/add-readme-docs-config-aiMeg
7
+
8
+ Add comprehensive README and Read the Docs configuration
@@ -0,0 +1,55 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools",
4
+ "autocalver",
5
+ ]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [project]
9
+ name = "stolid"
10
+ version = "2022.3.6.2"
11
+ description = "Linter enforcing the conventions of the Python standard template"
12
+ readme = "README.rst"
13
+ authors = [{name = "Moshe Zadka", email = "moshez@zadka.club"}]
14
+
15
+ [project.optional-dependencies]
16
+ tests = ["virtue", "pyhamcrest", "coverage"]
17
+ mypy = ["mypy"]
18
+ lint = ["flake8", "black"]
19
+ docs = ["sphinx"]
20
+
21
+ [project.license]
22
+ text = """
23
+ Permission is hereby granted, free of charge, to any person obtaining a
24
+ copy of this software and associated documentation files (the "Software"),
25
+ to deal in the Software without restriction, including without limitation the
26
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27
+ copies of the Software, and to permit persons to whom the Software is furnished
28
+ to do so, subject to the following conditions:
29
+
30
+ The above copyright notice and this permission notice shall be included in all
31
+ copies or substantial portions of the Software.
32
+
33
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
34
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
35
+ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
36
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
37
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
38
+ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39
+ """
40
+
41
+ [project.urls]
42
+ Homepage = "https://github.com/moshez/stolid"
43
+
44
+ [tool.autocalver]
45
+ use = true
46
+ log = "git-log-head"
47
+ log_command = "git log -n 1 --date=iso"
48
+ is_main_var = "GITHUB_REF"
49
+ is_main_match = ".*/trunk$"
50
+
51
+ [project.entry-points.gather]
52
+ placeholder = "stolid:__version__"
53
+
54
+ [project.entry-points."flake8.extension"]
55
+ SLD = "stolid.checker:Checker"
@@ -0,0 +1,30 @@
1
+ [metadata]
2
+ name = seasonable
3
+ version = 2021.9.1
4
+ description = API abstractions
5
+ long_description = file: README.rst
6
+ license = BSD 3-Clause License
7
+
8
+ [options]
9
+ package_dir =
10
+ =src
11
+ packages = find:
12
+
13
+ [options.extras_require]
14
+ test =
15
+ coverage
16
+ virtue
17
+ lint =
18
+ black
19
+ mypy
20
+ flake8
21
+ pylint
22
+ doc = sphinx
23
+
24
+ [options.packages.find]
25
+ where = src
26
+
27
+ [egg_info]
28
+ tag_build =
29
+ tag_date = 0
30
+
@@ -0,0 +1,3 @@
1
+ import importlib.metadata
2
+
3
+ __version__ = importlib.metadata.version(__name__)