pytest-eo 0.5.1__py3-none-any.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.
- pytest_eo/__init__.py +1 -0
- pytest_eo/angry_tests.py +44 -0
- pytest_eo/assertion.py +30 -0
- pytest_eo/assigned.py +32 -0
- pytest_eo/blank_lines.py +42 -0
- pytest_eo/bodies.py +36 -0
- pytest_eo/bundled.py +20 -0
- pytest_eo/callee.py +23 -0
- pytest_eo/capacity.py +50 -0
- pytest_eo/check.py +17 -0
- pytest_eo/command.py +13 -0
- pytest_eo/comment.py +42 -0
- pytest_eo/comments.py +42 -0
- pytest_eo/config/flake8.ini +23 -0
- pytest_eo/config/mypy.ini +5 -0
- pytest_eo/config/ruff.toml +43 -0
- pytest_eo/edges.py +28 -0
- pytest_eo/encapsulation.py +30 -0
- pytest_eo/ending.py +30 -0
- pytest_eo/eo_item.py +41 -0
- pytest_eo/eo_table.py +29 -0
- pytest_eo/excludes.py +25 -0
- pytest_eo/extension.py +12 -0
- pytest_eo/fields.py +40 -0
- pytest_eo/files.py +12 -0
- pytest_eo/final_assertion.py +46 -0
- pytest_eo/flake_check.py +49 -0
- pytest_eo/heading.py +35 -0
- pytest_eo/inline_comments.py +44 -0
- pytest_eo/layout.py +15 -0
- pytest_eo/margin.py +42 -0
- pytest_eo/message.py +60 -0
- pytest_eo/module_constants.py +32 -0
- pytest_eo/mypy_check.py +43 -0
- pytest_eo/narrow_suppressions.py +72 -0
- pytest_eo/negative_messages.py +40 -0
- pytest_eo/output.py +37 -0
- pytest_eo/owned.py +28 -0
- pytest_eo/place.py +21 -0
- pytest_eo/plugin.py +45 -0
- pytest_eo/printout.py +18 -0
- pytest_eo/profile.py +13 -0
- pytest_eo/project.py +37 -0
- pytest_eo/project_files.py +39 -0
- pytest_eo/python_module.py +36 -0
- pytest_eo/raising.py +27 -0
- pytest_eo/remark.py +25 -0
- pytest_eo/ruff_check.py +50 -0
- pytest_eo/ruff_format_check.py +46 -0
- pytest_eo/rule.py +12 -0
- pytest_eo/shared.py +35 -0
- pytest_eo/span.py +28 -0
- pytest_eo/strict.py +112 -0
- pytest_eo/style_violations_error.py +15 -0
- pytest_eo/suppression_check.py +44 -0
- pytest_eo/table.py +11 -0
- pytest_eo/text.py +28 -0
- pytest_eo/tool_failed_error.py +15 -0
- pytest_eo/trial.py +37 -0
- pytest_eo/verified.py +28 -0
- pytest_eo/violation.py +24 -0
- pytest_eo/wide_suppressions.py +45 -0
- pytest_eo-0.5.1.dist-info/METADATA +177 -0
- pytest_eo-0.5.1.dist-info/RECORD +67 -0
- pytest_eo-0.5.1.dist-info/WHEEL +4 -0
- pytest_eo-0.5.1.dist-info/entry_points.txt +7 -0
- pytest_eo-0.5.1.dist-info/licenses/LICENSE.txt +21 -0
pytest_eo/trial.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""The test functions pytest would run."""
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import final
|
|
6
|
+
|
|
7
|
+
from typing_extensions import override
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@final
|
|
11
|
+
@dataclass(frozen=True, slots=True)
|
|
12
|
+
class Trial(ast.NodeVisitor): # noqa: ENC100 - a visitor holds no state, ast dispatches on the node
|
|
13
|
+
"""A function whose name makes pytest run it; nothing for other nodes."""
|
|
14
|
+
|
|
15
|
+
@override
|
|
16
|
+
def generic_visit(
|
|
17
|
+
self,
|
|
18
|
+
node: ast.AST,
|
|
19
|
+
) -> tuple[ast.FunctionDef | ast.AsyncFunctionDef, ...]:
|
|
20
|
+
"""Find no test in a node that isnt a function."""
|
|
21
|
+
return ()
|
|
22
|
+
|
|
23
|
+
@override
|
|
24
|
+
def visit_FunctionDef(
|
|
25
|
+
self,
|
|
26
|
+
node: ast.FunctionDef,
|
|
27
|
+
) -> tuple[ast.FunctionDef | ast.AsyncFunctionDef, ...]:
|
|
28
|
+
"""Find the function when its name starts with ``test``."""
|
|
29
|
+
return (node,) if node.name.startswith("test") else ()
|
|
30
|
+
|
|
31
|
+
@override
|
|
32
|
+
def visit_AsyncFunctionDef(
|
|
33
|
+
self,
|
|
34
|
+
node: ast.AsyncFunctionDef,
|
|
35
|
+
) -> tuple[ast.FunctionDef | ast.AsyncFunctionDef, ...]:
|
|
36
|
+
"""Find the coroutine when its name starts with ``test``."""
|
|
37
|
+
return (node,) if node.name.startswith("test") else ()
|
pytest_eo/verified.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""A command that fails loudly unless it exits as expected."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import final
|
|
5
|
+
|
|
6
|
+
from typing_extensions import override
|
|
7
|
+
|
|
8
|
+
from pytest_eo.command import Command
|
|
9
|
+
from pytest_eo.printout import Printout
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@final
|
|
13
|
+
@dataclass(frozen=True, slots=True)
|
|
14
|
+
class Verified(Command):
|
|
15
|
+
"""A tool run that refuses any exit status its reader does not expect."""
|
|
16
|
+
|
|
17
|
+
_origin: Command
|
|
18
|
+
_tool: str
|
|
19
|
+
_allowed: tuple[int, ...]
|
|
20
|
+
|
|
21
|
+
@override
|
|
22
|
+
def run(self) -> Printout:
|
|
23
|
+
"""Run the command and fail on a status outside of the allowed ones."""
|
|
24
|
+
output = self._origin.run()
|
|
25
|
+
if not output.exited(self._allowed):
|
|
26
|
+
reason = f"{self._tool} exited unexpectedly"
|
|
27
|
+
raise output.failure(reason)
|
|
28
|
+
return output
|
pytest_eo/violation.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""A single style violation reported by one of the aggregated tools."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import final
|
|
5
|
+
|
|
6
|
+
from typing_extensions import override
|
|
7
|
+
|
|
8
|
+
from pytest_eo.place import Place
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@final
|
|
12
|
+
@dataclass(frozen=True, slots=True)
|
|
13
|
+
class Violation:
|
|
14
|
+
"""What is wrong, where, and which tool says so."""
|
|
15
|
+
|
|
16
|
+
_tool: str
|
|
17
|
+
_code: str
|
|
18
|
+
_place: Place
|
|
19
|
+
_message: str
|
|
20
|
+
|
|
21
|
+
@override
|
|
22
|
+
def __str__(self) -> str:
|
|
23
|
+
"""Render as ``path:line:col: [tool:code] message``."""
|
|
24
|
+
return f"{self._place}: [{self._tool}:{self._code}] {self._message}"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""The suppressions that reach beyond their own line."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from collections.abc import Iterable, Iterator
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import final
|
|
7
|
+
|
|
8
|
+
from typing_extensions import override
|
|
9
|
+
|
|
10
|
+
from pytest_eo.remark import Remark
|
|
11
|
+
from pytest_eo.violation import Violation
|
|
12
|
+
|
|
13
|
+
_SPREAD = r"ruff:\s*(?:noqa|file-ignore|disable)\b|flake8:\s*noqa\b|mypy:"
|
|
14
|
+
_WIDE = re.compile(rf"#\s*(?P<kind>{_SPREAD})")
|
|
15
|
+
_BARE = re.compile(r"#\s*(?P<kind>type:\s*ignore\b(?!\[))")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@final
|
|
19
|
+
@dataclass(frozen=True, slots=True)
|
|
20
|
+
class WideSuppressions(Iterable[Violation]):
|
|
21
|
+
"""File-wide and range forms of ruff, flake8 and mypy in one comment.
|
|
22
|
+
|
|
23
|
+
Above the first code a bare ``# type: ignore`` silences the whole file,
|
|
24
|
+
so there it counts as one of them.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
_tool: str
|
|
28
|
+
_comment: Remark
|
|
29
|
+
|
|
30
|
+
@override
|
|
31
|
+
def __iter__(self) -> Iterator[Violation]:
|
|
32
|
+
"""Report every form of the comment that suppresses beyond its line."""
|
|
33
|
+
return (
|
|
34
|
+
Violation(
|
|
35
|
+
self._tool,
|
|
36
|
+
"SUP003",
|
|
37
|
+
place,
|
|
38
|
+
f"`# {match['kind']}` suppresses beyond its own line: "
|
|
39
|
+
"suppress on that one line instead, with a reason",
|
|
40
|
+
)
|
|
41
|
+
for place, match in (
|
|
42
|
+
*self._comment.matches(_WIDE),
|
|
43
|
+
*self._comment.heading(_BARE),
|
|
44
|
+
)
|
|
45
|
+
)
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pytest-eo
|
|
3
|
+
Version: 0.5.1
|
|
4
|
+
Summary: pytest --eo: strict style gate over ruff, mypy --strict and pyeo
|
|
5
|
+
Author: RaulIQ
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE.txt
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Requires-Dist: eo-styleguide==0.2.0
|
|
10
|
+
Requires-Dist: flake8-override==0.1.1
|
|
11
|
+
Requires-Dist: flake8==7.4.1
|
|
12
|
+
Requires-Dist: mypy==2.4.0
|
|
13
|
+
Requires-Dist: pyhamcrest>=2.1
|
|
14
|
+
Requires-Dist: pytest>=8
|
|
15
|
+
Requires-Dist: ruff==0.17.1
|
|
16
|
+
Requires-Dist: typing-extensions>=4.4
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: coverage>=7.10; extra == 'dev'
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# pytest-eo
|
|
22
|
+
|
|
23
|
+
[](https://codecov.io/gh/RaulIQ/pytest-eo)
|
|
24
|
+
|
|
25
|
+
`pytest --eo` is a strict quality gate in the spirit of
|
|
26
|
+
[Qulice](https://github.com/yegor256/qulice), built from ready-made tools.
|
|
27
|
+
The plugin runs the tools, reads their reports, and shows each tool as a
|
|
28
|
+
separate test; its own rules cover only tests and suppressions.
|
|
29
|
+
|
|
30
|
+
| Test | Tool |
|
|
31
|
+
|-------------------|------------------------------------------------|
|
|
32
|
+
| `eo::ruff` | `ruff check`, all rules (`select = ["ALL"]`) |
|
|
33
|
+
| `eo::ruff-format` | `ruff format --check` |
|
|
34
|
+
| `eo::mypy` | `mypy --strict` |
|
|
35
|
+
| `eo::flake8` | `flake8` with [pyeo](https://pypi.org/project/eo-styleguide/) (Elegant Objects rules) |
|
|
36
|
+
| `eo::suppressions`| `# noqa` and `# ruff: ignore` comments |
|
|
37
|
+
|
|
38
|
+
The Elegant Objects rules enabled so far, most of them from
|
|
39
|
+
[pyeo](https://github.com/blablatdinov/pyeo) and the rest from its sibling
|
|
40
|
+
packages:
|
|
41
|
+
|
|
42
|
+
| Code | Rule | Package |
|
|
43
|
+
|----------|----------------------------------------------|---------|
|
|
44
|
+
| `FIN100` | every class is `@final` | pyeo |
|
|
45
|
+
| `PEO101` | `__init__` contains only assignments | pyeo |
|
|
46
|
+
| `PEO102` | `@classmethod` contains only a `cls()` call | pyeo |
|
|
47
|
+
| `PEO200` | every class is frozen (immutable) | pyeo |
|
|
48
|
+
| `PEO300` | no class names ending in "-er" | pyeo |
|
|
49
|
+
| `PEO301` | no public attributes | pyeo |
|
|
50
|
+
| `PEO400` | no static methods | pyeo |
|
|
51
|
+
| `PEO500` | no `@property`, a getter in disguise | pyeo |
|
|
52
|
+
| `PEO601` | no methods starting with `get` | pyeo |
|
|
53
|
+
| `PEO602` | no getter methods | pyeo |
|
|
54
|
+
| `PEO700` | no introspection, casting, or reflection | pyeo |
|
|
55
|
+
| `NPM100` | no private functions or methods | [flake8-no-private-methods](https://github.com/blablatdinov/flake8-no-private-methods) |
|
|
56
|
+
| `OVR100` | every public method is an `@override` of an interface method | [flake8-override](https://github.com/blablatdinov/flake8-override) |
|
|
57
|
+
| `FOC100` | one public class per module | [flake8-one-class](https://github.com/blablatdinov/flake8-one-class) |
|
|
58
|
+
|
|
59
|
+
mypy runs with `explicit-override` and `warn_unreachable` on top of
|
|
60
|
+
`--strict`: an `@override` must override a real method, every overriding
|
|
61
|
+
method must say so, and code that can never run is an error.
|
|
62
|
+
Python 3.11 has no `typing.override`; import it from `typing_extensions`.
|
|
63
|
+
|
|
64
|
+
The package also brings a flake8 plugin of its own, with rules in the spirit
|
|
65
|
+
of "Angry Tests" for the files pytest collects (`test_*.py`, `*_test.py`):
|
|
66
|
+
|
|
67
|
+
| Code | Rule |
|
|
68
|
+
|----------|----------------------------------------------------------|
|
|
69
|
+
| `TST100` | a test ends with its only assertion, or with `pytest.raises` |
|
|
70
|
+
| `TST200` | a test module keeps no constants, except `pytest_plugins` |
|
|
71
|
+
| `TST300` | an assertion carries a negative message, such as `"x doesnt y"` |
|
|
72
|
+
|
|
73
|
+
More rules of its own cover every file, tests or not:
|
|
74
|
+
|
|
75
|
+
| Code | Rule |
|
|
76
|
+
|----------|----------------------------------------------------------|
|
|
77
|
+
| `ENC100` | a class encapsulates one to four attributes; a `Protocol` is exempt |
|
|
78
|
+
| `BOD100` | a function body holds no blank lines, except around a nested `def` or `class` |
|
|
79
|
+
| `BOD200` | a function body holds no comments, except suppressions |
|
|
80
|
+
|
|
81
|
+
As in Qulice, which rejects plain JUnit assertions, a test asserts through a
|
|
82
|
+
Hamcrest matcher, never through a plain `assert`; ruff's `S101` stays on in
|
|
83
|
+
tests too. PyHamcrest comes with the package:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from hamcrest import assert_that, equal_to
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_checks_the_whole_directory_by_default(tmp_path: Path) -> None:
|
|
90
|
+
assert_that(
|
|
91
|
+
Project(EoTable(tmp_path / "pyproject.toml"), tmp_path).paths(),
|
|
92
|
+
equal_to((".",)),
|
|
93
|
+
"Project doesnt check the whole directory by default",
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
A rule may be suppressed on one line only, with a reason:
|
|
98
|
+
`# noqa: PEO200 - pytest.Item is mutable by design`, or
|
|
99
|
+
`# ruff: ignore[unused-import] - re-exported for plugins`.
|
|
100
|
+
`eo::suppressions` enforces it:
|
|
101
|
+
|
|
102
|
+
| Code | Rule |
|
|
103
|
+
|----------|----------------------------------------------------------|
|
|
104
|
+
| `SUP001` | a suppression gives a reason after ` - ` |
|
|
105
|
+
| `SUP002` | a suppression never names `TID251` (`banned-api`), the ban on mocks |
|
|
106
|
+
| `SUP003` | nothing suppresses past one line: no `# ruff: noqa`, `file-ignore` or `disable`, no `# flake8: noqa`, no `# mypy:` comment, no `# type: ignore` above the code |
|
|
107
|
+
|
|
108
|
+
ruff already rejects a bare `# noqa` (`PGH004`), a bare `# type: ignore`
|
|
109
|
+
(`PGH003`) and an unused `# noqa` for its own codes (`RUF100`).
|
|
110
|
+
|
|
111
|
+
The configuration is bundled with the package (`src/pytest_eo/config/`)
|
|
112
|
+
and cannot be overridden by a project. A project may only say what to
|
|
113
|
+
check and what to skip:
|
|
114
|
+
|
|
115
|
+
```toml
|
|
116
|
+
[tool.eo]
|
|
117
|
+
paths = ["src", "tests"] # default: src and tests, if they exist
|
|
118
|
+
exclude = ["generated/"]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Usage
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
pip install 'pytest-eo==0.5.1'
|
|
125
|
+
pytest --eo
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Without `--eo` the plugin does nothing. Pin an exact version: every version
|
|
129
|
+
of the rules is a version of the package, so pip installs new rules only
|
|
130
|
+
when the version in the requirement changes.
|
|
131
|
+
|
|
132
|
+
## Claude Code hooks
|
|
133
|
+
|
|
134
|
+
This repository runs the gate on every Claude Code session that works in it:
|
|
135
|
+
after Claude edits a `.py`, `.toml`, `.ini` or `.cfg` file, and again before
|
|
136
|
+
it finishes. When the gate is red, the findings go back to Claude and it has
|
|
137
|
+
to fix them. If the gate is still red after one retry, Claude may stop, and
|
|
138
|
+
you see a warning instead.
|
|
139
|
+
|
|
140
|
+
To get the same in another project:
|
|
141
|
+
|
|
142
|
+
1. Install pytest-eo into the project's `.venv`.
|
|
143
|
+
2. Copy `.claude/hooks/eo-gate.sh` into the same place in that project and
|
|
144
|
+
make it executable.
|
|
145
|
+
3. Copy the `hooks` block of `.claude/settings.json` into that project's
|
|
146
|
+
`.claude/settings.json`, merging it with what is already there.
|
|
147
|
+
4. Commit both files, so everyone who opens the project with Claude Code gets
|
|
148
|
+
the gate, and run `/hooks` once in an open session to load them.
|
|
149
|
+
|
|
150
|
+
## Development
|
|
151
|
+
|
|
152
|
+
```sh
|
|
153
|
+
python3 -m venv .venv
|
|
154
|
+
.venv/bin/pip install -e '.[dev]'
|
|
155
|
+
make check
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`make check` runs the tests and `pytest --eo` on the plugin itself; Rultor
|
|
159
|
+
merges on it. `make coverage` measures lines and branches, counting the
|
|
160
|
+
pytest subprocesses of the end-to-end tests too, and writes `coverage.xml`,
|
|
161
|
+
which GitHub Actions sends to Codecov on every push and pull request.
|
|
162
|
+
|
|
163
|
+
`pyproject.toml` on `main` always says `version = "0.0.0"`; a real version
|
|
164
|
+
exists only in a tag. To release, comment in any issue, with the version in
|
|
165
|
+
backticks, since Rultor reads nothing else:
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
@rultor release, tag is `0.3.0`
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Rultor writes the version into `pyproject.toml`, runs
|
|
172
|
+
`make check`, commits the result on a side branch and pushes only the tag.
|
|
173
|
+
GitHub Actions builds that tag and uploads it to PyPI through Trusted
|
|
174
|
+
Publishing, so no token is stored anywhere.
|
|
175
|
+
Every change to the rules or the bundled configuration ships in a release:
|
|
176
|
+
raise the minor number for a new or stricter rule and the patch number for a
|
|
177
|
+
fix.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
pytest_eo/__init__.py,sha256=3rmPJGpub_1Gi1GNn-2SRWudJqrWUik011WgAs6sNd4,73
|
|
2
|
+
pytest_eo/angry_tests.py,sha256=v13cAE_Wux3w4-iKiD4c4-kWypgsWO9dyeo2-QYMRjE,1544
|
|
3
|
+
pytest_eo/assertion.py,sha256=Iot15iPLIYa9HXB03EKFomjmcZ4CxgjzVTALz7sc-5M,908
|
|
4
|
+
pytest_eo/assigned.py,sha256=lO7ZaLEQ29GXXtkSSwnNOjPQHsH881vJRUXc6fZwcHk,1070
|
|
5
|
+
pytest_eo/blank_lines.py,sha256=p9YWpvxpkrlQ2WHgU-48utBsCFF9Jf1vfSVVVV5VJ3U,1300
|
|
6
|
+
pytest_eo/bodies.py,sha256=9cWFgtMkjX_MxrmbdWss1qTcMLHxAJNuf9cfP5KFx2Q,1215
|
|
7
|
+
pytest_eo/bundled.py,sha256=uo_-nFVL-hhV-Ok3-dmEJpOAD770mIz6sSTw253-y3o,528
|
|
8
|
+
pytest_eo/callee.py,sha256=pQ7MrdQFRfo4unelaRYVy12xsJ1zlf-xEH9Cf4EInFM,682
|
|
9
|
+
pytest_eo/capacity.py,sha256=s1rXY3NmRRAzGkN-JiUlAwZuaVppTZZkPkq-sp_U5c8,1459
|
|
10
|
+
pytest_eo/check.py,sha256=Y4Y6fzIeP93P9QajG-XRHcKKxebFxEuFVbAy9IfOzGE,420
|
|
11
|
+
pytest_eo/command.py,sha256=vxiLthNF6l0a0hFhbKVIzZs_UWEdbYBBZKx9mm6az2s,313
|
|
12
|
+
pytest_eo/comment.py,sha256=JGX1_CJbJCFmBqewTb45nmsM5UOWQDEGmpmC1pOgcGM,1110
|
|
13
|
+
pytest_eo/comments.py,sha256=RVbecuThDG_CEmRMpSpagQs1Pgkm_odcJd7izqXEBck,1293
|
|
14
|
+
pytest_eo/edges.py,sha256=ut4IjmmfwtYVodSi2PaEjd6Z46NiP2rRzcn16Aethj8,775
|
|
15
|
+
pytest_eo/encapsulation.py,sha256=jtRam6UpQ8mo2dR3McpUPlPDwS6T7upw1DpT1d1aVng,984
|
|
16
|
+
pytest_eo/ending.py,sha256=anvKCy0leLYtkbe-8Dho8MI1j1SqD5kgvdzJ3NfRwII,910
|
|
17
|
+
pytest_eo/eo_item.py,sha256=AIqmLvyi0tvW8wID4-RbrJIb4Hf2JYZXRjUTfdBbIwE,1368
|
|
18
|
+
pytest_eo/eo_table.py,sha256=91IlQVyVqwWa_RkF-vOXepdgFSAECuFNflIa3Gwr6cs,1028
|
|
19
|
+
pytest_eo/excludes.py,sha256=9hVp_LHrnaF1Kte87WqQpn9CpG3Hj06kr6i0_8M6P2o,715
|
|
20
|
+
pytest_eo/extension.py,sha256=fixHQ6qmAMoON2jVYoJiy_A7T2t8xo7QKdkD6T9AKjg,359
|
|
21
|
+
pytest_eo/fields.py,sha256=jWsu_IVQ-SXjdDuVtyPlUJZEyzUuLs5KYoGZY1iXaxg,1387
|
|
22
|
+
pytest_eo/files.py,sha256=Oaun13ttiKk76sA7xTuPKGjvC2MonXgujhVJfUX4OSw,297
|
|
23
|
+
pytest_eo/final_assertion.py,sha256=Qqp_hHSnq5LHUUJAQiAgsCJgNAz9xM1PM6M0uiMvS90,1393
|
|
24
|
+
pytest_eo/flake_check.py,sha256=ABX_2GpYiPuwp895mltXNkKBmJq1UrqKA6liBiknXaE,1468
|
|
25
|
+
pytest_eo/heading.py,sha256=luAGlGj0fIS44TCWaoLKXMY4A6-CporthWRZAuBhMiM,914
|
|
26
|
+
pytest_eo/inline_comments.py,sha256=uvYzQdkUxioWFKwOCtgakhXhWCRweteeTMB8U4RED8k,1218
|
|
27
|
+
pytest_eo/layout.py,sha256=l22k1o4WKVP8siY7Cyx-oJ4MsvnNOna6j61tntZ8iKo,390
|
|
28
|
+
pytest_eo/margin.py,sha256=8yRlJf0grWr-BwUXjhKSAylyXeUeUcqb9p9OjeDRbhg,1364
|
|
29
|
+
pytest_eo/message.py,sha256=v_Q6HE-E1wpMf8ctgdcTzh5gp6j7G7KJxgeaVxvL8gk,1833
|
|
30
|
+
pytest_eo/module_constants.py,sha256=8nWaVyC34QAry9uZHMzlcsaMD9EpRmRcW2x5e6p5nXY,876
|
|
31
|
+
pytest_eo/mypy_check.py,sha256=w3nHQ-aZhh63OEfwzpux4s7A_hwDaiTa7dndt0L3nOs,1234
|
|
32
|
+
pytest_eo/narrow_suppressions.py,sha256=SgKNNJN3TPuJ60lfPmO9WWQY5VlZWDhS1CE6ppkU1Eg,2174
|
|
33
|
+
pytest_eo/negative_messages.py,sha256=0kt213fA0EYXJf3yz5ZpMuBYCC-7J0iguva7gZWi8ZI,1092
|
|
34
|
+
pytest_eo/output.py,sha256=31qAit03k7GKZhuSGu7-nG_DNEihHdwA3GO5-2cfR2M,1095
|
|
35
|
+
pytest_eo/owned.py,sha256=Y0WazRWj3Yqki2kQh_eK5F6Sza97QhFEOxL71uxT6CM,1016
|
|
36
|
+
pytest_eo/place.py,sha256=B0G-d0_qroVJ2VGtUe8OJ72lIHQa8k9U6zaK4RognKw,476
|
|
37
|
+
pytest_eo/plugin.py,sha256=EVnyOfAu-NaTqEYt2jDZKwOd67Kyumg8C5uUiK0QFxw,1160
|
|
38
|
+
pytest_eo/printout.py,sha256=rG3T4kZmFnyJ8NvRqVwQhxJm08dSto-0SNh6ALTBuYM,577
|
|
39
|
+
pytest_eo/profile.py,sha256=IFOi6lYL0bDOLqNbpRmqk4LN0OvvURYkGseyO1WWItE,320
|
|
40
|
+
pytest_eo/project.py,sha256=lbjBFFKo0m8E70pHY9HU_10wleJoAGvNPJK23DwnEVg,955
|
|
41
|
+
pytest_eo/project_files.py,sha256=td42X4YOJs9UlhfwuuBBvOMobaiL6YlmVWiqFRf1zjg,1062
|
|
42
|
+
pytest_eo/python_module.py,sha256=_WllphQs5kXrc00JJnEMFFCgfibHwLtB0CVCMsLoLOw,1130
|
|
43
|
+
pytest_eo/raising.py,sha256=GmYtDzpCOQ5_KFc3DF4c3LnJddWRQUUB13Lz-lRWn-4,830
|
|
44
|
+
pytest_eo/remark.py,sha256=iIYyooDxx3cQqunBPaa2FUz3dhee04rjRgUHGMXWBfo,662
|
|
45
|
+
pytest_eo/ruff_check.py,sha256=C0OuzPxSRbj35WtYU0lWLF_d_AMU53WDpL4X3YYKMzQ,1466
|
|
46
|
+
pytest_eo/ruff_format_check.py,sha256=sMNsRByys0uOoVZZbqFx-FmpcBQLSJyhFT-b88Ynfcw,1340
|
|
47
|
+
pytest_eo/rule.py,sha256=0orHF-iiQN67i8uhTKxgexzSYO6VxaGqZzShQO7fSNE,371
|
|
48
|
+
pytest_eo/shared.py,sha256=iMsGEjtR_S8t6ZM_mLbbEefQMirecoEaWElpnngyuO8,1182
|
|
49
|
+
pytest_eo/span.py,sha256=5bqUarD2Kt5LN3pUjIedz-fk2JEvTgggEinVJnSRUUs,938
|
|
50
|
+
pytest_eo/strict.py,sha256=u7eEN1RnRqRriO2Ww-AyWCnxWxkag5PwD0IPapDqy4I,3489
|
|
51
|
+
pytest_eo/style_violations_error.py,sha256=Fz771ldN3Lpe-h3-kHMGdcfwmOFcX6ft16rnR9RoKJA,459
|
|
52
|
+
pytest_eo/suppression_check.py,sha256=l1k-xPDX_HftKKDJu3IU1jdnpkqZ0DmHKc7GQw0qolU,1389
|
|
53
|
+
pytest_eo/table.py,sha256=80-QnqaqBex_vWL_YvQXGQOL7voBfdJzkJPCFCyQZkg,304
|
|
54
|
+
pytest_eo/text.py,sha256=67ZYl_CvJ6KkbPHuNoC64D56c77zY6_zAorpRSvPFgk,887
|
|
55
|
+
pytest_eo/tool_failed_error.py,sha256=zKC7XtmckGG-kKgiZ4JCLkQEcjIRI4ChimTbD3l00BY,468
|
|
56
|
+
pytest_eo/trial.py,sha256=Z3BSMwYsg1wsRmxX0hZgnf_33NlZAYjlT4vDMwa6Rsc,1160
|
|
57
|
+
pytest_eo/verified.py,sha256=ViAUWHbenW_BTgEORFVcCwLBQBnwQkMIksB44QwDkB4,784
|
|
58
|
+
pytest_eo/violation.py,sha256=JPgNLcHulIqCOT3hMu2c-GGr-UTk5vj-xR8exUk8Lh0,578
|
|
59
|
+
pytest_eo/wide_suppressions.py,sha256=5qyiW8ioQmv2BTXf4dlrYP2I3uvyA7v2rLr_2KCozms,1367
|
|
60
|
+
pytest_eo/config/flake8.ini,sha256=7AEG-U6qzQW2xl7FXHnmXgTDu0q9TIlgiP8SFEPz6Kg,1293
|
|
61
|
+
pytest_eo/config/mypy.ini,sha256=dyih1DDGQx2NnTyVkdk2zEL9uf8LnlYA2hH9uIt-QtE,98
|
|
62
|
+
pytest_eo/config/ruff.toml,sha256=aF6-MM1bUVd7PE_3mm53pj0U2XJXhbY0taxeYlU_BKU,1549
|
|
63
|
+
pytest_eo-0.5.1.dist-info/METADATA,sha256=n_6gtwD0dB5nA1EVL-GdM9lOlm-AVKG-rWuWat_JGXE,7969
|
|
64
|
+
pytest_eo-0.5.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
65
|
+
pytest_eo-0.5.1.dist-info/entry_points.txt,sha256=kz2JTYjRLRHI0I5pddKFDjgNY2odA956kHiq-HqqD0Y,166
|
|
66
|
+
pytest_eo-0.5.1.dist-info/licenses/LICENSE.txt,sha256=6v7Og1usuuSqeiAL4u3DlOFfkGza0C98bFZFHKFWCO4,1063
|
|
67
|
+
pytest_eo-0.5.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 RaulIQ
|
|
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.
|