Skip to content

Commit 36d1f9e

Browse files
authored
Merge pull request #34 from George-Ogden/release
Ready For Release
2 parents d1f28b2 + 685ddc1 commit 36d1f9e

File tree

6 files changed

+103
-7
lines changed

6 files changed

+103
-7
lines changed

.github/workflows/test.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ jobs:
1616
total-shards: [3]
1717
uses: George-Ogden/actions/.github/workflows/python-test.yaml@v3.1.3
1818
with:
19-
python-versions: "['3.13']"
19+
python-versions: "['3.12', '3.13', '3.14']"
2020
timeout-minutes: 15
2121
pytest-flags: -vv mypy_pytest_plugin -n auto --shard-id=${{ matrix.shard }} --num-shards=${{ matrix.total-shards }}
2222

2323
integration_tests:
2424
uses: George-Ogden/actions/.github/workflows/python-test.yaml@v3.1.3
2525
with:
26-
python-versions: "['3.13']"
26+
python-versions: "['3.12', '3.13', '3.14']"
2727
timeout-minutes: 10
2828
pytest-flags: -vv tests -n auto

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 George Ogden
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.

README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Mypy Pytest
2+
3+
A Mypy plugin for type checking Pytest code.
4+
(Not a Pytest plugin for running Mypy.)
5+
6+
## Features
7+
8+
- Check your parametrizations are correct
9+
- [x] You didn't mispel the argnames
10+
- [x] Your test cases have the right type
11+
- [x] You didn't forget any arguments
12+
- Works with fixtures
13+
- [x] Your fixtures have the correct types
14+
- [x] All the fixture arguments are included
15+
- [x] You don't have conflicting fixtures
16+
- Checks your mocks
17+
- [x] Your mock has the correct type (or close enough)
18+
- Checks your marks
19+
- [x] You're using a pre-defined mark
20+
- [x] Your mark is registered
21+
- Checks for `Iterator` bugs
22+
- [x] You're robustly testing methods that want `Iterable` by giving them an `Iterable` and not a `Sequence`
23+
- Works with whatever Pytest configuration
24+
- [x] Only checks your custom test files and test names
25+
- [x] Analyzes third-party Pytest plugins
26+
- [x] Some [limitations](#limitations) because Mypy didn't expect plugins this cool :sunglasses:
27+
- [x] All the rest of Mypy
28+
29+
## Install and Usage
30+
31+
Install with pip
32+
33+
```bash
34+
pip install git+https://github.com/George-Ogden/dbg.git
35+
```
36+
37+
Then register the plugin.
38+
39+
`pyproject.toml`:
40+
41+
```toml
42+
plugins = ["mypy_pytest_plugin.plugin"]
43+
```
44+
45+
`mypy.ini`:
46+
47+
```toml
48+
plugins = mypy_pytest_plugin.plugin
49+
```
50+
51+
See the [Mypy docs](https://mypy.readthedocs.io/en/stable/extending_mypy.html#configuring-mypy-to-use-plugins) for more info.
52+
53+
## Limitations
54+
55+
The Mypy plugin system is fairly limited, so this can only check marked functions.
56+
If you're using parametrized testing, that's fine as you `pytest.mark.parametrize`.
57+
If not, [add a `typed` mark](https://docs.pytest.org/en/stable/how-to/mark.html#registering-marks) then mark any remaining tests you want to check.
58+
59+
```python
60+
import random
61+
import pytest
62+
63+
@pytest.fixture
64+
def random_0_to_10() -> float:
65+
return random.random() * 10
66+
67+
@pytest.mark.typed
68+
def test_random_string_length(random_0_to_10: int) -> None: # 'test_random_string_length' requests 'random_0_to_10' with type "float", but expects type "int"
69+
assert 0 <= random_0_to_10 <= 10
70+
```
71+
72+
## Development
73+
74+
Use the GitHub issue tracker for bugs/feature requests.

mypy_pytest_plugin/plugin.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,6 @@ def get_attribute_hook(self, fullname: str) -> Callable[[AttributeContext], Type
6565

6666
@classmethod
6767
def check_mark(cls, ctx: AttributeContext) -> Type:
68-
if ctx.api.path == "test_samples/mark_test.py":
69-
...
7068
if (
7169
not ctx.is_lvalue
7270
and isinstance(checker := ctx.api, TypeChecker)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "mypy-pytest-plugin"
33
requires-python = ">=3.12,<3.15"
4-
version = "0.8.0"
4+
version = "1.0.0"
55
dynamic = ["dependencies"]
66

77
[tool.setuptools]

test_samples/mock_test.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import sys
44
from typing import TYPE_CHECKING, Any
5-
from unittest.mock import MagicMock, Mock, NonCallableMock, PropertyMock, ThreadingMock
5+
from unittest.mock import MagicMock, Mock, NonCallableMock, PropertyMock
66

77
if TYPE_CHECKING:
88
from mypy_pytest_plugin_types.mock import Mock as _Mock
@@ -42,4 +42,7 @@ def increment_float(x: float) -> float:
4242
Mock() + Mock()
4343
MagicMock() + MagicMock()
4444

45-
ThreadingMock()
45+
if sys.version_info >= (3, 13):
46+
from unittest.mock import ThreadingMock
47+
48+
ThreadingMock()

0 commit comments

Comments
 (0)