Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update django.test.runner stubs #1888

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 44 additions & 10 deletions django-stubs/test/runner.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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: ...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add a TODO entry to sync this signature with unittest.TestResult?

@property
def test_index(self) -> int: ...
def check_picklable(self, test: Any, err: Any) -> None: ...
Expand All @@ -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
Expand All @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we type it better?

process_setup_args: tuple[Any, ...]
run_subsuite: Any
runner_class: Any
subsuites: list[TestSuite]
Expand All @@ -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]]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it should be tuple[type[X], ...], where X is a proper type name.

Why? Because it would be easier to subclass and change. Or maybe even Iterable / Sequence.

pattern: str | None
top_level: str | None
verbosity: int
Expand Down Expand Up @@ -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: ...
Expand All @@ -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: ...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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]: ...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you use Iterator here and Generator in iter_test_cases? They should be similar

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]: ...
4 changes: 3 additions & 1 deletion django-stubs/test/utils.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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: ...
Expand Down
27 changes: 18 additions & 9 deletions scripts/stubtest/allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down Expand Up @@ -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
26 changes: 0 additions & 26 deletions scripts/stubtest/allowlist_todo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down