diff --git a/django-stubs/test/runner.pyi b/django-stubs/test/runner.pyi index 31df7df95..d0eec95fb 100644 --- a/django-stubs/test/runner.pyi +++ b/django-stubs/test/runner.pyi @@ -3,7 +3,7 @@ from argparse import ArgumentParser from collections.abc import Iterator, Sequence from contextlib import contextmanager from io import StringIO -from typing import Any, Literal +from typing import Any, AnyStr, Callable, ClassVar, Generator, Literal from unittest import TestCase, TestLoader, TestSuite, TextTestResult, TextTestRunner from django.db.backends.base.base import BaseDatabaseWrapper @@ -36,14 +36,18 @@ class DebugSQLTextTestResult(TextTestResult): def addError(self, test: Any, err: Any) -> None: ... def addFailure(self, test: Any, err: Any) -> None: ... -class PDBDebugResult(TextTestResult): ... +class PDBDebugResult(TextTestResult): + def debug(self, error: Any) -> None: ... + +class DummyList: + def append(self, item: Any) -> None: ... class RemoteTestResult: events: list[Any] failfast: bool shouldStop: bool testsRun: int - def __init__(self) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: ... @property def test_index(self) -> int: ... def check_picklable(self, test: Any, err: Any) -> None: ... @@ -62,6 +66,7 @@ class RemoteTestResult: def addSkip(self, test: Any, reason: Any) -> None: ... def addExpectedFailure(self, test: Any, err: Any) -> None: ... def addUnexpectedSuccess(self, test: Any) -> None: ... + def wasSuccessful(self) -> bool: ... class RemoteTestRunner: resultclass: Any @@ -71,9 +76,13 @@ class RemoteTestRunner: def run(self, test: Any) -> Any: ... def default_test_processes() -> int: ... +def get_max_test_processes() -> int: ... +def parallel_type(value: str) -> int | Literal["auto"]: ... class ParallelTestSuite(TestSuite): init_worker: Any + process_setup: Callable + process_setup_args: tuple[Any, ...] run_subsuite: Any runner_class: Any subsuites: list[TestSuite] @@ -83,16 +92,30 @@ class ParallelTestSuite(TestSuite): initial_settings: Any serialized_contents: Any def __init__( - self, subsuites: list[TestSuite], processes: int, failfast: bool = ..., buffer: bool = ... + self, + subsuites: list[TestSuite], + processes: int, + failfast: bool = ..., + debug_mode: bool = ..., + buffer: bool = ..., ) -> None: ... def run(self, result: Any) -> Any: ... # type: ignore[override] + def initialize_suite(self) -> None: ... + +class Shuffler: + hash_algorithm: ClassVar[str] + + def __init__(self, seed: int | None = ...) -> None: ... + @property + def seed_display(self) -> str: ... + def shuffle(self, items: list[TestCase], key: Callable[[TestCase], str]) -> list[TestCase]: ... class DiscoverRunner: test_suite: type[TestSuite] parallel_test_suite: type[ParallelTestSuite] test_runner: type[TextTestRunner] test_loader: TestLoader - reorder_by: tuple[SimpleTestCase, ...] + reorder_by: tuple[type[TestCase], type[SimpleTestCase]] pattern: str | None top_level: str | None verbosity: int @@ -138,14 +161,14 @@ class DiscoverRunner: def add_arguments(cls, parser: ArgumentParser) -> None: ... @property def shuffle_seed(self) -> int | None: ... - def log(self, msg: str, level: int | None) -> None: ... + def log(self, msg: str, level: int | None = ...) -> None: ... def setup_test_environment(self, **kwargs: Any) -> None: ... def setup_shuffler(self) -> None: ... @contextmanager def load_with_patterns(self) -> Iterator[None]: ... def load_tests_for_label(self, label: str, discover_kwargs: dict[str, str]) -> TestSuite: ... def build_suite( - self, test_labels: Sequence[str] = ..., extra_tests: list[Any] | None = ..., **kwargs: Any + self, test_labels: Sequence[str] | None = ..., extra_tests: list[Any] | None = ..., **kwargs: Any ) -> TestSuite: ... def setup_databases(self, **kwargs: Any) -> list[tuple[BaseDatabaseWrapper, str, bool]]: ... def get_resultclass(self) -> type[TextTestResult] | None: ... @@ -159,12 +182,23 @@ class DiscoverRunner: def get_databases(self, suite: TestSuite) -> set[str]: ... def run_tests(self, test_labels: list[str], extra_tests: list[Any] | None = ..., **kwargs: Any) -> int: ... -def is_discoverable(label: str) -> bool: ... +def try_importing(label: str) -> bool: ... +def find_top_level(top_level: AnyStr) -> AnyStr: ... +def shuffle_tests(tests: list[TestCase], shuffler: Shuffler) -> Iterator[TestCase]: ... +def reorder_test_bin( + tests: list[TestCase], shuffler: Shuffler | None = ..., reverse: bool = ... +) -> Iterator[TestCase]: ... +def reorder_tests( + tests: list[TestCase], classes: tuple[type[TestCase], ...], reverse: bool = ..., shuffler: Shuffler | None = ... +) -> Iterator[TestCase]: ... def reorder_suite( suite: TestSuite, classes: tuple[type[TestCase], type[SimpleTestCase]], reverse: bool = ... ) -> TestSuite: ... def partition_suite_by_type( suite: TestSuite, classes: tuple[type[TestCase], type[SimpleTestCase]], bins: list[OrderedSet], reverse: bool = ... ) -> None: ... -def partition_suite_by_case(suite: Any) -> list[Any]: ... -def filter_tests_by_tags(suite: TestSuite, tags: set[str], exclude_tags: set[str]) -> TestSuite: ... +def partition_suite_by_case(suite: TestSuite) -> list[TestSuite]: ... +def test_match_tags(test: TestCase, tags: set[str], exclude_tags: set[str]) -> bool: ... +def filter_tests_by_tags( + tests: list[TestCase], tags: set[str], exclude_tags: set[str] +) -> Generator[TestCase, None, None]: ... diff --git a/django-stubs/test/utils.pyi b/django-stubs/test/utils.pyi index a19c4bc0e..172de642e 100644 --- a/django-stubs/test/utils.pyi +++ b/django-stubs/test/utils.pyi @@ -5,7 +5,8 @@ from decimal import Decimal from io import StringIO from logging import Logger from types import TracebackType -from typing import Any, Protocol, SupportsIndex, TypeVar +from typing import Any, Generator, Protocol, SupportsIndex, TypeVar +from unittest import TestCase, TestSuite from django.apps.registry import Apps from django.conf import LazySettings, Settings @@ -165,6 +166,7 @@ def setup_databases( aliases: Mapping[str, Any] | None = ..., **kwargs: Any, ) -> list[tuple[BaseDatabaseWrapper, str, bool]]: ... +def iter_test_cases(tests: TestSuite) -> Generator[TestCase, None, None]: ... def teardown_databases( old_config: Iterable[tuple[Any, str, bool]], verbosity: int, parallel: int = ..., keepdb: bool = ... ) -> None: ... diff --git a/scripts/stubtest/allowlist.txt b/scripts/stubtest/allowlist.txt index 358e9a653..c2d0907b2 100644 --- a/scripts/stubtest/allowlist.txt +++ b/scripts/stubtest/allowlist.txt @@ -145,15 +145,6 @@ django.core.management.color.Style.SQL_TABLE django.core.management.color.Style.SUCCESS django.core.management.color.Style.WARNING -# `error: <...> is not present at runtime` -# This happens often for variables removed in later django version. -# We still keep them in stubs to be a bit more backward compatible. -# RemovedInDjango40: -django.middleware.csrf.REASON_BAD_TOKEN - -# RemovedInDjango41 -django.core.cache.backends.memcached.MemcachedCache - # We re-export `functools.cached_property` which has different semantics django.utils.functional.cached_property.__class_getitem__ django.utils.functional.cached_property.__set__ @@ -395,3 +386,21 @@ django.urls.resolvers.URLPattern.lookup_str django.urls.resolvers.URLResolver.url_patterns django.urls.resolvers.URLResolver.urlconf_module django.utils.connection.BaseConnectionHandler.settings + + +# `error: <...> is not present at runtime` +# This happens often for variables removed in later django version. +# We still keep them in stubs to be a bit more backward compatible. + +# RemovedInDjango40: +django.middleware.csrf.REASON_BAD_TOKEN +django.test.runner.default_test_processes +django.test.runner.partition_suite_by_type +django.test.runner.reorder_suite +django.test.runner.RemoteTestResult.stop_if_failfast + +# RemovedInDjango41 +django.core.cache.backends.memcached.MemcachedCache + +# RemovedInDjango50 +django.test.runner.DiscoverRunner.build_suite diff --git a/scripts/stubtest/allowlist_todo.txt b/scripts/stubtest/allowlist_todo.txt index 4d889688e..782e00dc9 100644 --- a/scripts/stubtest/allowlist_todo.txt +++ b/scripts/stubtest/allowlist_todo.txt @@ -1692,32 +1692,6 @@ django.templatetags.static.StaticNode.__init__ django.test.SimpleTestCase.assertFormError django.test.SimpleTestCase.assertFormSetError django.test.SimpleTestCase.assertTemplateNotUsed -django.test.runner.DiscoverRunner.build_suite -django.test.runner.DiscoverRunner.log -django.test.runner.DiscoverRunner.reorder_by -django.test.runner.DummyList -django.test.runner.PDBDebugResult.debug -django.test.runner.ParallelTestSuite.__init__ -django.test.runner.ParallelTestSuite.initialize_suite -django.test.runner.ParallelTestSuite.process_setup -django.test.runner.ParallelTestSuite.process_setup_args -django.test.runner.RemoteTestResult.__init__ -django.test.runner.RemoteTestResult.stop_if_failfast -django.test.runner.RemoteTestResult.wasSuccessful -django.test.runner.Shuffler -django.test.runner.default_test_processes -django.test.runner.filter_tests_by_tags -django.test.runner.find_top_level -django.test.runner.get_max_test_processes -django.test.runner.is_discoverable -django.test.runner.parallel_type -django.test.runner.partition_suite_by_type -django.test.runner.reorder_suite -django.test.runner.reorder_test_bin -django.test.runner.reorder_tests -django.test.runner.shuffle_tests -django.test.runner.test_match_tags -django.test.runner.try_importing django.test.selenium.SeleniumTestCase django.test.selenium.SeleniumTestCase.external_host django.test.selenium.SeleniumTestCase.tags