Skip to content

Commit 1952bf9

Browse files
authored
Merge branch 'main' into patch-5
2 parents 6855d08 + 72b13b5 commit 1952bf9

File tree

15 files changed

+211
-145
lines changed

15 files changed

+211
-145
lines changed

.github/workflows/deploy.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
timeout-minutes: 10
1515

1616
steps:
17-
- uses: actions/checkout@v4
17+
- uses: actions/checkout@v5
1818
with:
1919
persist-credentials: false
2020

@@ -34,10 +34,10 @@ jobs:
3434

3535
steps:
3636
- name: Download Package
37-
uses: actions/download-artifact@v4
37+
uses: actions/download-artifact@v5
3838
with:
3939
name: Packages
4040
path: dist
4141

4242
- name: Publish package
43-
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
43+
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0

.github/workflows/main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ jobs:
2929
env:
3030
TOXENV: ${{ matrix.name }}
3131
steps:
32-
- uses: actions/checkout@v4
32+
- uses: actions/checkout@v5
3333
with:
3434
persist-credentials: false
3535

36-
- uses: actions/setup-python@v5
36+
- uses: actions/setup-python@v6
3737
with:
3838
python-version: ${{ matrix.python }}
3939

pyproject.toml

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -198,36 +198,28 @@ extend-select = [
198198
"RUF", # Ruff-specific rules
199199
]
200200
ignore = [
201-
"D100", # Missing docstring in public module
202-
"D101", # Missing docstring in public class
203-
"D102", # Missing docstring in public method
204-
"D103", # Missing docstring in public function
205-
"D104", # Missing docstring in public package
206-
"D105", # Missing docstring in magic method
207-
"D107", # Missing docstring in __init__
208-
"D200", # One-line docstring should fit on one line
209-
"D202", # No blank lines allowed after function docstring
210-
"D203", # Class definitions that are not preceded by a blank line
211-
"D205", # 1 blank line required between summary line and description
212-
"D209", # Multi-line docstring closing quotes should be on a separate line
213-
"D212", # Multi-line docstring summary should start at the first line
214-
"D213", # Multi-line docstring summary should start at the second line
215-
"D400", # First line should end with a period
216-
"D401", # First line of docstring should be in imperative mood
217-
"D404", # First word of the docstring should not be "This"
218-
"D415", # First line should end with a period, question mark, or exclamation point
219-
"S101", # Use of `assert` detected
201+
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
202+
"D100", # Missing docstring in public module
203+
"D101", # Missing docstring in public class
204+
"D102", # Missing docstring in public method
205+
"D103", # Missing docstring in public function
206+
"D104", # Missing docstring in public package
207+
"D105", # Missing docstring in magic method
208+
"D107", # Missing docstring in __init__
209+
"D200", # One-line docstring should fit on one line
210+
"D202", # No blank lines allowed after function docstring
211+
"D203", # Class definitions that are not preceded by a blank line
212+
"D205", # 1 blank line required between summary line and description
213+
"D209", # Multi-line docstring closing quotes should be on a separate line
214+
"D212", # Multi-line docstring summary should start at the first line
215+
"D213", # Multi-line docstring summary should start at the second line
216+
"D400", # First line should end with a period
217+
"D401", # First line of docstring should be in imperative mood
218+
"D404", # First word of the docstring should not be "This"
219+
"D415", # First line should end with a period, question mark, or exclamation point
220+
"S101", # Use of `assert` detected
220221

221222
# TODO - need to fix these
222-
"ANN001", # Missing type annotation for function argument
223-
"ANN002", # Missing type annotation for public function
224-
"ANN003", # Missing type annotation for public method
225-
"ANN201", # Missing return type annotation for public function
226-
"ANN202", # Missing return type annotation for private function
227-
"ANN204", # Missing return type annotation for special method
228-
"ANN401", # Dynamically typed expressions .. are disallowed
229-
"ARG001", # Unused function argument
230-
"ARG002", # Unused method argument
231223
"C901", # .. is too complex
232224
"COM812", # Trailing comma missing
233225
"E501", # Line too long

pytest_django/asserts.py

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class MessagesTestCase(MessagesTestMixin, TestCase):
2727
test_case = TestCase("run")
2828

2929

30-
def _wrapper(name: str):
30+
def _wrapper(name: str) -> Callable[..., Any]:
3131
func = getattr(test_case, name)
3232

3333
@wraps(func)
@@ -66,7 +66,12 @@ def assertion_func(*args, **kwargs):
6666

6767

6868
if TYPE_CHECKING:
69+
from collections.abc import Collection, Iterator, Sequence
70+
from contextlib import AbstractContextManager
71+
from typing import overload
72+
6973
from django import forms
74+
from django.db.models import Model, QuerySet, RawQuerySet
7075
from django.http.response import HttpResponseBase
7176

7277
def assertRedirects(
@@ -121,34 +126,34 @@ def assertTemplateUsed(
121126
template_name: str | None = ...,
122127
msg_prefix: str = ...,
123128
count: int | None = ...,
124-
): ...
129+
) -> None: ...
125130

126131
def assertTemplateNotUsed(
127132
response: HttpResponseBase | str | None = ...,
128133
template_name: str | None = ...,
129134
msg_prefix: str = ...,
130-
): ...
135+
) -> None: ...
131136

132137
def assertRaisesMessage(
133138
expected_exception: type[Exception],
134139
expected_message: str,
135-
*args,
136-
**kwargs,
137-
): ...
140+
*args: Any,
141+
**kwargs: Any,
142+
) -> None: ...
138143

139144
def assertWarnsMessage(
140145
expected_warning: Warning,
141146
expected_message: str,
142-
*args,
143-
**kwargs,
144-
): ...
147+
*args: Any,
148+
**kwargs: Any,
149+
) -> None: ...
145150

146151
def assertFieldOutput(
147-
fieldclass,
148-
valid,
149-
invalid,
150-
field_args=...,
151-
field_kwargs=...,
152+
fieldclass: type[forms.Field],
153+
valid: Any,
154+
invalid: Any,
155+
field_args: Any = ...,
156+
field_kwargs: Any = ...,
152157
empty_value: str = ...,
153158
) -> None: ...
154159

@@ -204,34 +209,44 @@ def assertXMLNotEqual(
204209

205210
# Removed in Django 5.1: use assertQuerySetEqual.
206211
def assertQuerysetEqual(
207-
qs,
208-
values,
209-
transform=...,
212+
qs: Iterator[Any] | list[Model] | QuerySet | RawQuerySet,
213+
values: Collection[Any],
214+
transform: Callable[[Model], Any] | type[str] | None = ...,
210215
ordered: bool = ...,
211216
msg: str | None = ...,
212217
) -> None: ...
213218

214219
def assertQuerySetEqual(
215-
qs,
216-
values,
217-
transform=...,
220+
qs: Iterator[Any] | list[Model] | QuerySet | RawQuerySet,
221+
values: Collection[Any],
222+
transform: Callable[[Model], Any] | type[str] | None = ...,
218223
ordered: bool = ...,
219224
msg: str | None = ...,
220225
) -> None: ...
221226

227+
@overload
228+
def assertNumQueries(
229+
num: int, func: None = None, *, using: str = ...
230+
) -> AbstractContextManager[None]: ...
231+
232+
@overload
233+
def assertNumQueries(
234+
num: int, func: Callable[..., Any], *args: Any, using: str = ..., **kwargs: Any
235+
) -> None: ...
236+
222237
def assertNumQueries(
223238
num: int,
224239
func=...,
225-
*args,
240+
*args: Any,
226241
using: str = ...,
227-
**kwargs,
242+
**kwargs: Any,
228243
): ...
229244

230245
# Added in Django 5.0.
231246
def assertMessages(
232247
response: HttpResponseBase,
233248
expected_messages: Sequence[Message],
234-
*args,
249+
*args: Any,
235250
ordered: bool = ...,
236251
) -> None: ...
237252

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

pytest_django/fixtures.py

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from collections.abc import Generator, Iterable, Sequence
77
from contextlib import AbstractContextManager, contextmanager
88
from functools import partial
9-
from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Protocol, Union
9+
from typing import TYPE_CHECKING, Protocol
1010

1111
import pytest
1212

@@ -16,16 +16,18 @@
1616

1717

1818
if TYPE_CHECKING:
19+
from typing import Any, Callable, Literal, Optional, Union
20+
1921
import django
2022
import django.test
2123

2224
from . import DjangoDbBlocker
25+
from .django_compat import _User, _UserModel
2326

24-
25-
_DjangoDbDatabases = Optional[Union[Literal["__all__"], Iterable[str]]]
26-
_DjangoDbAvailableApps = Optional[list[str]]
27-
# transaction, reset_sequences, databases, serialized_rollback, available_apps
28-
_DjangoDb = tuple[bool, bool, _DjangoDbDatabases, bool, _DjangoDbAvailableApps]
27+
_DjangoDbDatabases = Optional[Union[Literal["__all__"], Iterable[str]]]
28+
_DjangoDbAvailableApps = Optional[list[str]]
29+
# transaction, reset_sequences, databases, serialized_rollback, available_apps
30+
_DjangoDb = tuple[bool, bool, _DjangoDbDatabases, bool, _DjangoDbAvailableApps]
2931

3032

3133
__all__ = [
@@ -75,15 +77,15 @@ def django_db_modify_db_settings_xdist_suffix(request: pytest.FixtureRequest) ->
7577

7678
@pytest.fixture(scope="session")
7779
def django_db_modify_db_settings_parallel_suffix(
78-
django_db_modify_db_settings_tox_suffix: None,
79-
django_db_modify_db_settings_xdist_suffix: None,
80+
django_db_modify_db_settings_tox_suffix: None, # noqa: ARG001
81+
django_db_modify_db_settings_xdist_suffix: None, # noqa: ARG001
8082
) -> None:
8183
skip_if_no_django()
8284

8385

8486
@pytest.fixture(scope="session")
8587
def django_db_modify_db_settings(
86-
django_db_modify_db_settings_parallel_suffix: None,
88+
django_db_modify_db_settings_parallel_suffix: None, # noqa: ARG001
8789
) -> None:
8890
"""Modify db settings just before the databases are configured."""
8991
skip_if_no_django()
@@ -162,12 +164,12 @@ def _get_databases_for_setup(
162164
@pytest.fixture(scope="session")
163165
def django_db_setup(
164166
request: pytest.FixtureRequest,
165-
django_test_environment: None,
167+
django_test_environment: None, # noqa: ARG001
166168
django_db_blocker: DjangoDbBlocker,
167169
django_db_use_migrations: bool,
168170
django_db_keepdb: bool,
169171
django_db_createdb: bool,
170-
django_db_modify_db_settings: None,
172+
django_db_modify_db_settings: None, # noqa: ARG001
171173
) -> Generator[None, None, None]:
172174
"""Top level fixture to ensure test databases are available"""
173175
from django.test.utils import setup_databases, teardown_databases
@@ -350,7 +352,7 @@ def __getitem__(self, item: str) -> None:
350352
settings.MIGRATION_MODULES = DisableMigrations()
351353

352354
class MigrateSilentCommand(migrate.Command):
353-
def handle(self, *args, **kwargs):
355+
def handle(self, *args: Any, **kwargs: Any) -> Any:
354356
kwargs["verbosity"] = 0
355357
return super().handle(*args, **kwargs)
356358

@@ -474,26 +476,26 @@ def async_client() -> django.test.AsyncClient:
474476

475477

476478
@pytest.fixture
477-
def django_user_model(db: None):
479+
def django_user_model(db: None) -> _UserModel: # noqa: ARG001
478480
"""The class of Django's user model."""
479481
from django.contrib.auth import get_user_model
480482

481-
return get_user_model()
483+
return get_user_model() # type: ignore[no-any-return]
482484

483485

484486
@pytest.fixture
485-
def django_username_field(django_user_model) -> str:
487+
def django_username_field(django_user_model: _UserModel) -> str:
486488
"""The fieldname for the username used with Django's user model."""
487489
field: str = django_user_model.USERNAME_FIELD
488490
return field
489491

490492

491493
@pytest.fixture
492494
def admin_user(
493-
db: None,
494-
django_user_model,
495+
db: None, # noqa: ARG001
496+
django_user_model: _User,
495497
django_username_field: str,
496-
):
498+
) -> _User:
497499
"""A Django admin user.
498500
499501
This uses an existing user with username "admin", or creates a new one with
@@ -521,8 +523,8 @@ def admin_user(
521523

522524
@pytest.fixture
523525
def admin_client(
524-
db: None,
525-
admin_user,
526+
db: None, # noqa: ARG001
527+
admin_user: _User,
526528
) -> django.test.Client:
527529
"""A Django test client logged in as an admin user."""
528530
from django.test import Client
@@ -568,14 +570,14 @@ def __delattr__(self, attr: str) -> None:
568570

569571
self._to_restore.append(override)
570572

571-
def __setattr__(self, attr: str, value) -> None:
573+
def __setattr__(self, attr: str, value: Any) -> None:
572574
from django.test import override_settings
573575

574576
override = override_settings(**{attr: value})
575577
override.enable()
576578
self._to_restore.append(override)
577579

578-
def __getattr__(self, attr: str):
580+
def __getattr__(self, attr: str) -> Any:
579581
from django.conf import settings
580582

581583
return getattr(settings, attr)
@@ -588,7 +590,7 @@ def finalize(self) -> None:
588590

589591

590592
@pytest.fixture
591-
def settings():
593+
def settings() -> Generator[SettingsWrapper, None, None]:
592594
"""A Django settings object which restores changes after the testrun"""
593595
skip_if_no_django()
594596

@@ -598,7 +600,9 @@ def settings():
598600

599601

600602
@pytest.fixture(scope="session")
601-
def live_server(request: pytest.FixtureRequest):
603+
def live_server(
604+
request: pytest.FixtureRequest,
605+
) -> Generator[live_server_helper.LiveServer, None, None]:
602606
"""Run a live Django server in the background during tests
603607
604608
The address the server is started from is taken from the

0 commit comments

Comments
 (0)