mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-11 22:41:55 +08:00
* Fix CI
* Fix CI
* Fix CI
* Fix CI
* APply black
* APply black
* Fix mypy
* Fix mypy errors in django-stubs
* Fix format
* Fix plugin
* Do not patch builtins by default
* Fix mypy
* Only run mypy on 3.10 for now
* Only run mypy on 3.10 for now
* WHAT THE HELL
* Enable strict mode in mypy
* Enable strict mode in mypy
* Fix tests
* Fix tests
* Debug
* Debug
* Fix tests
* Fix tests
* Add TYPE_CHECKING debug
* Caching maybe?
* Caching maybe?
* Try explicit `${{ matrix.python-version }}`
* Remove debug
* Fix typing
* Finally
122 lines
4.1 KiB
Python
122 lines
4.1 KiB
Python
import itertools
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from argparse import ArgumentParser
|
|
from collections import defaultdict
|
|
from distutils import spawn
|
|
from typing import DefaultDict, List, Pattern, Union
|
|
|
|
from scripts.enabled_test_modules import EXTERNAL_MODULES, IGNORED_ERRORS, IGNORED_MODULES, MOCK_OBJECTS
|
|
from scripts.git_helpers import checkout_django_branch
|
|
from scripts.paths import DJANGO_SOURCE_DIRECTORY, PROJECT_DIRECTORY
|
|
|
|
DJANGO_COMMIT_REFS = {
|
|
"2.2": "44e7cca62382f2535ed0f5d2842b433f0bd23a57",
|
|
"3.2": "0153a63a674937e4a56d9d5e4ca2d629b011fbde",
|
|
"4.0": "67d0c4644acfd7707be4a31e8976f865509b09ac",
|
|
}
|
|
DEFAULT_DJANGO_VERSION = "3.2"
|
|
|
|
_DictToSearch = DefaultDict[str, DefaultDict[Union[str, Pattern[str]], int]]
|
|
|
|
|
|
def get_unused_ignores(ignored_message_freq: _DictToSearch) -> List[str]:
|
|
unused_ignores = []
|
|
for root_key, patterns in IGNORED_ERRORS.items():
|
|
for pattern in patterns:
|
|
if ignored_message_freq[root_key][pattern] == 0 and pattern not in itertools.chain(
|
|
EXTERNAL_MODULES, MOCK_OBJECTS
|
|
):
|
|
unused_ignores.append(f"{root_key}: {pattern}")
|
|
return unused_ignores
|
|
|
|
|
|
def does_pattern_fit(pattern: Union[Pattern[str], str], line: str) -> bool:
|
|
if isinstance(pattern, Pattern):
|
|
if pattern.search(line):
|
|
return True
|
|
else:
|
|
if pattern in line:
|
|
return True
|
|
return False
|
|
|
|
|
|
def is_ignored(line: str, test_folder_name: str, *, ignored_message_freqs: _DictToSearch) -> bool:
|
|
if "runtests" in line:
|
|
return True
|
|
|
|
if test_folder_name in IGNORED_MODULES:
|
|
return True
|
|
|
|
for pattern in IGNORED_ERRORS.get(test_folder_name, []):
|
|
if does_pattern_fit(pattern, line):
|
|
ignored_message_freqs[test_folder_name][pattern] += 1
|
|
return True
|
|
|
|
for pattern in IGNORED_ERRORS["__common__"]:
|
|
if does_pattern_fit(pattern, line):
|
|
ignored_message_freqs["__common__"][pattern] += 1
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = ArgumentParser()
|
|
parser.add_argument("--django_version", default=DEFAULT_DJANGO_VERSION)
|
|
django_version = parser.parse_args().django_version
|
|
subprocess.check_call([sys.executable, "-m", "pip", "install", f"Django=={django_version}.*"])
|
|
commit_sha = DJANGO_COMMIT_REFS[django_version]
|
|
repo = checkout_django_branch(django_version, commit_sha)
|
|
mypy_config_file = (PROJECT_DIRECTORY / "mypy.ini").absolute()
|
|
mypy_cache_dir = PROJECT_DIRECTORY / ".mypy_cache"
|
|
tests_root = DJANGO_SOURCE_DIRECTORY / "tests"
|
|
global_rc = 0
|
|
|
|
try:
|
|
mypy_options = [
|
|
"--cache-dir",
|
|
str(mypy_cache_dir),
|
|
"--config-file",
|
|
str(mypy_config_file),
|
|
"--show-traceback",
|
|
"--no-error-summary",
|
|
"--hide-error-context",
|
|
]
|
|
mypy_options += [str(tests_root)]
|
|
mypy_executable = spawn.find_executable("mypy")
|
|
mypy_argv = [mypy_executable, *mypy_options]
|
|
completed = subprocess.run(
|
|
mypy_argv, # type: ignore
|
|
env={"PYTHONPATH": str(tests_root), "TYPECHECK_TESTS": "1"},
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
)
|
|
output = completed.stdout.decode()
|
|
|
|
ignored_message_freqs: _DictToSearch = defaultdict(lambda: defaultdict(int))
|
|
|
|
sorted_lines = sorted(output.splitlines())
|
|
for line in sorted_lines:
|
|
try:
|
|
path_to_error = line.split(":")[0]
|
|
test_folder_name = path_to_error.split("/")[2]
|
|
except IndexError:
|
|
test_folder_name = "unknown"
|
|
|
|
if not is_ignored(line, test_folder_name, ignored_message_freqs=ignored_message_freqs):
|
|
global_rc = 1
|
|
print(line)
|
|
|
|
unused_ignores = get_unused_ignores(ignored_message_freqs)
|
|
if unused_ignores:
|
|
print("UNUSED IGNORES ------------------------------------------------")
|
|
print("\n".join(unused_ignores))
|
|
|
|
sys.exit(global_rc)
|
|
|
|
except BaseException as exc:
|
|
shutil.rmtree(mypy_cache_dir, ignore_errors=True)
|
|
raise exc
|