Skip to content

Commit 19505bc

Browse files
author
Lode Rosseel
committed
Merge remote-tracking branch 'refs/remotes/origin/main' into fix/async_fixture
# Conflicts: # pytest_django/plugin.py
2 parents 9aff5fd + e495504 commit 19505bc

File tree

14 files changed

+344
-130
lines changed

14 files changed

+344
-130
lines changed

.editorconfig-checker.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
"pytest_django/fixtures.py",
44
".tox/*",
55
".ruff_cache/*",
6-
"pytest_django.egg-info/*"
6+
".mypy_cache/*",
7+
".pytest_cache/*",
8+
"pytest_django.egg-info/*",
9+
"__pycache__/*",
10+
"zizmor.sarif",
11+
"docs/_build/*"
712
],
813
"Disable": {
914
"MaxLineLength": true

pyproject.toml

Lines changed: 150 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,16 @@ postgres = [
6161
"psycopg[binary]",
6262
]
6363
mysql = [
64-
"mysqlclient==2.1.0",
64+
"mysqlclient==2.2.7",
6565
]
6666
xdist = [
6767
"pytest-xdist",
6868
]
6969
linting = [
7070
"editorconfig-checker==3.2.1",
71-
"mypy==1.15.0",
72-
"ruff==0.9.5",
73-
"zizmor==1.9.0",
71+
"mypy==1.17.1",
72+
"ruff==0.12.8",
73+
"zizmor==1.11.0",
7474
]
7575
[project.urls]
7676
Documentation = "https://pytest-django.readthedocs.io/"
@@ -133,33 +133,169 @@ exclude_lines = [
133133
]
134134

135135
[tool.ruff]
136+
# preview = true # TODO: Enable this when we have the bandwidth
136137
line-length = 99
137138
extend-exclude = [
138139
"pytest_django/_version.py",
139140
]
140141

141142
[tool.ruff.lint]
142143
extend-select = [
143-
"B", # flake8-bugbear
144+
"AIR", # Airflow
145+
"ERA", # eradicate
146+
"FAST", # FastAPI
147+
"YTT", # flake8-2020
148+
"ANN", # flake8-annotations
149+
"ASYNC", # flake8-async
150+
"S", # flake8-bandit
144151
"BLE", # flake8-blind-except
152+
"FBT", # flake8-boolean-trap
153+
"B", # flake8-bugbear
154+
"A", # flake8-builtins
155+
"COM", # flake8-commas
156+
"C4", # flake8-comprehensions
157+
"CPY", # flake8-copyright
145158
"DTZ", # flake8-datetimez
159+
"T10", # flake8-debugger
160+
"DJ", # flake8-django
161+
"EM", # flake8-errmsg
162+
"EXE", # flake8-executable
163+
"FIX", # flake8-fixme
146164
"FA", # flake8-future-annotations
165+
"INT", # flake8-gettext
166+
"ISC", # flake8-implicit-str-concat
167+
"ICN", # flake8-import-conventions
168+
"LOG", # flake8-logging
147169
"G", # flake8-logging-format
148-
"I", # isort
149-
"PGH", # pygrep-hooks
170+
"INP", # flake8-no-pep420
150171
"PIE", # flake8-pie
151-
"PL", # pylint
152-
"PT", # flake8-pytest-style
172+
"T20", # flake8-print
153173
"PYI", # flake8-pyi
154-
"RUF", # Ruff-specific rules
174+
"PT", # flake8-pytest-style
175+
"Q", # flake8-quotes
176+
"RSE", # flake8-raise
177+
"RET", # flake8-return
178+
"SLF", # flake8-self
179+
"SIM", # flake8-simplify
155180
"SLOT", # flake8-slots
156-
"T10", # flake8-debugger
181+
"TID", # flake8-tidy-imports
182+
"TD", # flake8-todos
183+
"TC", # flake8-type-checking
184+
"ARG", # flake8-unused-arguments
185+
"PTH", # flake8-use-pathlib
186+
"FLY", # flynt
187+
"I", # isort
188+
"C90", # mccabe
189+
"PD", # pandas-vet
190+
"N", # pep8-naming
191+
"PERF", # Perflint
192+
"E", # pycodestyle Error
193+
"W", # pycodestyle Warning
194+
"DOC", # pydoclint
195+
"D", # pydocstyle
196+
"F", # Pyflakes
197+
"PGH", # pygrep-hooks
198+
"PL", # Pylint
157199
"UP", # pyupgrade
158-
"YTT", # flake8-2020
200+
"FURB", # refurb
201+
"TRY", # tryceratops
202+
"RUF", # Ruff-specific rules
159203
]
160204
ignore = [
161-
"PLR0913", # Too many arguments in function definition
162-
"PLR2004", # Magic value used in comparison, consider replacing 3 with a constant variable
205+
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
206+
"D100", # Missing docstring in public module
207+
"D101", # Missing docstring in public class
208+
"D102", # Missing docstring in public method
209+
"D103", # Missing docstring in public function
210+
"D104", # Missing docstring in public package
211+
"D105", # Missing docstring in magic method
212+
"D107", # Missing docstring in __init__
213+
"D200", # One-line docstring should fit on one line
214+
"D202", # No blank lines allowed after function docstring
215+
"D203", # Class definitions that are not preceded by a blank line
216+
"D205", # 1 blank line required between summary line and description
217+
"D209", # Multi-line docstring closing quotes should be on a separate line
218+
"D212", # Multi-line docstring summary should start at the first line
219+
"D213", # Multi-line docstring summary should start at the second line
220+
"D400", # First line should end with a period
221+
"D401", # First line of docstring should be in imperative mood
222+
"D404", # First word of the docstring should not be "This"
223+
"D415", # First line should end with a period, question mark, or exclamation point
224+
"S101", # Use of `assert` detected
225+
226+
# TODO - need to fix these
227+
"C901", # .. is too complex
228+
"COM812", # Trailing comma missing
229+
"E501", # Line too long
230+
"EM101", # Exception must not use a string literal, assign to variable first
231+
"EM102", # Exception must not use an f-string literal, assign to variable first
232+
"FBT001", # Boolean-typed positional argument in function definition
233+
"FBT002", # Boolean default positional argument in function definition
234+
"FBT003", # Boolean positional value in function call
235+
"N802", # Function name `assertRedirects` should be lowercase
236+
"N806", # Variable `UserModel` in function should be lowercase
237+
"PLC0415", # `import` should be at the top-level of a file
238+
"PLR0913", # Too many arguments in function definition
239+
"PLR2004", # Magic value used in comparison, consider replacing .. with a constant variable
240+
"RET504", # Unnecessary assignment to .. before `return` statement
241+
"RET505", # Unnecessary `elif` after `return` statement
242+
"S105", # Possible hardcoded password assigned
243+
"SIM102", # Use a single `if` statement instead of nested `if` statements
244+
"SIM108", # Use ternary operator .. instead of `if`-`else`-block
245+
"SIM114", # Combine `if` branches using logical `or` operator
246+
"SLF001", # Private member accessed
247+
"TC002", # Move third-party import `django.contrib.messages.Message` into a type-checking block
248+
"TC003", # Move standard library import `collections.abc.Sequence` into a type-checking block
249+
"TRY003", # Avoid specifying long messages outside the exception class
250+
]
251+
[tool.ruff.lint.per-file-ignores]
252+
"tests/*.py" = [
253+
"ANN", # Disable all annotations
254+
"FIX003", # Line contains XXX, consider resolving the issue
255+
"DJ008", # Model does not define .. method
256+
"N801", # Class name should use CapWords convention
257+
"N802", # Function name should be lowercase
258+
"S", # Disable all security checks
259+
"TD001", # Invalid TODO tag
260+
"TD002", # Missing author in TODO
261+
"TD003", # Missing issue link for this TODO
262+
263+
# TODO - need to fix these
264+
"ARG005", # Unused lambda argument
265+
"D300", # Use triple double quotes `"""`
266+
"D403", # First word of the docstring should be capitalized
267+
"ERA001", # Found commented-out code
268+
"SIM117", # Use a single `with` statement with multiple contexts instead of nested `with` statements
269+
"TC001", # Move application import .. into a type-checking block
270+
"TC006", # Add quotes to type expression in `typing.cast()`
271+
"PTH108", # `os.unlink()` should be replaced by `Path.unlink()`
272+
"PTH110", # `os.path.exists()` should be replaced by `Path.exists()`
273+
"RET503", # Missing explicit `return` at the end of function able to return non-`None` value
274+
"RSE102", # Unnecessary parentheses on raised exception
275+
]
276+
"pytest_django_test/*.py" = [
277+
"ANN", # Disable all annotations
278+
"FIX003", # Line contains XXX, consider resolving the issue
279+
"DJ008", # Model does not define .. method
280+
"N801", # Class name should use CapWords convention
281+
"N802", # Function name should be lowercase
282+
"S", # Disable all security checks
283+
"TD001", # Invalid TODO tag
284+
"TD002", # Missing author in TODO
285+
"TD003", # Missing issue link for this TODO
286+
287+
# TODO - need to fix these
288+
"ARG005", # Unused lambda argument
289+
"D300", # Use triple double quotes `"""`
290+
"D403", # First word of the docstring should be capitalized
291+
"ERA001", # Found commented-out code
292+
"SIM117", # Use a single `with` statement with multiple contexts instead of nested `with` statements
293+
"TC001", # Move application import .. into a type-checking block
294+
"TC006", # Add quotes to type expression in `typing.cast()`
295+
"PTH108", # `os.unlink()` should be replaced by `Path.unlink()`
296+
"PTH110", # `os.path.exists()` should be replaced by `Path.exists()`
297+
"RET503", # Missing explicit `return` at the end of function able to return non-`None` value
298+
"RSE102", # Unnecessary parentheses on raised exception
163299
]
164300

165301
[tool.ruff.lint.isort]

pytest_django/asserts.py

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
from __future__ import annotations
66

7-
from collections.abc import Sequence
87
from functools import wraps
98
from typing import TYPE_CHECKING, Any, Callable
109

@@ -26,11 +25,11 @@ class MessagesTestCase(MessagesTestMixin, TestCase):
2625
test_case = TestCase("run")
2726

2827

29-
def _wrapper(name: str):
28+
def _wrapper(name: str) -> Callable[..., Any]:
3029
func = getattr(test_case, name)
3130

3231
@wraps(func)
33-
def assertion_func(*args, **kwargs):
32+
def assertion_func(*args: Any, **kwargs: Any) -> Any:
3433
return func(*args, **kwargs)
3534

3635
return assertion_func
@@ -56,7 +55,12 @@ def assertion_func(*args, **kwargs):
5655

5756

5857
if TYPE_CHECKING:
58+
from collections.abc import Collection, Iterator, Sequence
59+
from contextlib import AbstractContextManager
60+
from typing import overload
61+
5962
from django import forms
63+
from django.db.models import Model, QuerySet, RawQuerySet
6064
from django.http.response import HttpResponseBase
6165

6266
def assertRedirects(
@@ -111,34 +115,34 @@ def assertTemplateUsed(
111115
template_name: str | None = ...,
112116
msg_prefix: str = ...,
113117
count: int | None = ...,
114-
): ...
118+
) -> None: ...
115119

116120
def assertTemplateNotUsed(
117121
response: HttpResponseBase | str | None = ...,
118122
template_name: str | None = ...,
119123
msg_prefix: str = ...,
120-
): ...
124+
) -> None: ...
121125

122126
def assertRaisesMessage(
123127
expected_exception: type[Exception],
124128
expected_message: str,
125-
*args,
126-
**kwargs,
127-
): ...
129+
*args: Any,
130+
**kwargs: Any,
131+
) -> None: ...
128132

129133
def assertWarnsMessage(
130134
expected_warning: Warning,
131135
expected_message: str,
132-
*args,
133-
**kwargs,
134-
): ...
136+
*args: Any,
137+
**kwargs: Any,
138+
) -> None: ...
135139

136140
def assertFieldOutput(
137-
fieldclass,
138-
valid,
139-
invalid,
140-
field_args=...,
141-
field_kwargs=...,
141+
fieldclass: type[forms.Field],
142+
valid: Any,
143+
invalid: Any,
144+
field_args: Any = ...,
145+
field_kwargs: Any = ...,
142146
empty_value: str = ...,
143147
) -> None: ...
144148

@@ -194,34 +198,44 @@ def assertXMLNotEqual(
194198

195199
# Removed in Django 5.1: use assertQuerySetEqual.
196200
def assertQuerysetEqual(
197-
qs,
198-
values,
199-
transform=...,
201+
qs: Iterator[Any] | list[Model] | QuerySet | RawQuerySet,
202+
values: Collection[Any],
203+
transform: Callable[[Model], Any] | type[str] | None = ...,
200204
ordered: bool = ...,
201205
msg: str | None = ...,
202206
) -> None: ...
203207

204208
def assertQuerySetEqual(
205-
qs,
206-
values,
207-
transform=...,
209+
qs: Iterator[Any] | list[Model] | QuerySet | RawQuerySet,
210+
values: Collection[Any],
211+
transform: Callable[[Model], Any] | type[str] | None = ...,
208212
ordered: bool = ...,
209213
msg: str | None = ...,
210214
) -> None: ...
211215

216+
@overload
217+
def assertNumQueries(
218+
num: int, func: None = None, *, using: str = ...
219+
) -> AbstractContextManager[None]: ...
220+
221+
@overload
222+
def assertNumQueries(
223+
num: int, func: Callable[..., Any], *args: Any, using: str = ..., **kwargs: Any
224+
) -> None: ...
225+
212226
def assertNumQueries(
213227
num: int,
214228
func=...,
215-
*args,
229+
*args: Any,
216230
using: str = ...,
217-
**kwargs,
231+
**kwargs: Any,
218232
): ...
219233

220234
# Added in Django 5.0.
221235
def assertMessages(
222236
response: HttpResponseBase,
223237
expected_messages: Sequence[Message],
224-
*args,
238+
*args: Any,
225239
ordered: bool = ...,
226240
) -> None: ...
227241

pytest_django/django_compat.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,23 @@
22
# this is the case before you call them.
33
from __future__ import annotations
44

5+
from typing import TYPE_CHECKING
6+
57
import pytest
68

79

10+
if TYPE_CHECKING:
11+
from typing import TypeAlias
12+
13+
from django.contrib.auth.models import AbstractBaseUser
14+
15+
_User: TypeAlias = AbstractBaseUser
16+
17+
_UserModel: TypeAlias = type[_User]
18+
19+
__all__ = ("_User", "_UserModel")
20+
21+
822
def is_django_unittest(request_or_item: pytest.FixtureRequest | pytest.Item) -> bool:
923
"""Returns whether the request or item is a Django test case."""
1024
from django.test import SimpleTestCase

0 commit comments

Comments
 (0)