From 8e7e4707c18ad359bda09a8e989bc46b25bc947b Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 21 Jun 2023 13:54:54 +0300 Subject: [PATCH] Remove typecheck test and clean things up (#1556) --- .github/workflows/test.yml | 3 - CONTRIBUTING.md | 7 - mypy.ini | 23 +- requirements.txt | 2 - scripts/django_tests_settings.py | 239 +------------- scripts/enabled_test_modules.py | 539 ------------------------------- scripts/git_helpers.py | 34 -- scripts/paths.py | 4 - scripts/stubgen-django.py | 15 - scripts/typecheck_tests.py | 122 ------- 10 files changed, 14 insertions(+), 974 deletions(-) delete mode 100644 scripts/enabled_test_modules.py delete mode 100644 scripts/git_helpers.py delete mode 100644 scripts/paths.py delete mode 100644 scripts/stubgen-django.py delete mode 100755 scripts/typecheck_tests.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 40761e96d..4ac181d1b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -92,6 +92,3 @@ jobs: - name: Run django-stubs-ext tests run: PYTHONPATH='.' pytest django_stubs_ext - - - name: Run typecheck - run: python ./scripts/typecheck_tests.py --django_version="${{ matrix.django-version }}" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 916ef94b5..e5fc9a85e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -76,13 +76,6 @@ If you get some unexpected results or want to be sure that tests run is not affe rm -r .mypy_cache ``` -We also test the stubs against Django's own test suite. This is done in CI but you can also do this locally. -To execute the script run: - -```bash -python ./scripts/typecheck_tests.py --django_version 3.2 -``` - ### Generating Stubs using Stubgen diff --git a/mypy.ini b/mypy.ini index fa0b71fc6..641e18c17 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,21 +1,22 @@ # Regular configuration file (can be used as base in other projects, runs in CI) [mypy] -allow_redefinition = True -check_untyped_defs = True -ignore_missing_imports = True -incremental = True -strict_optional = True -show_traceback = True -warn_unused_ignores = True -warn_redundant_casts = True -warn_unused_configs = True -warn_unreachable = True +allow_redefinition = true +check_untyped_defs = true +ignore_missing_imports = true +incremental = true +strict_optional = true +show_traceback = true +warn_unused_ignores = true +warn_redundant_casts = true +warn_unused_configs = true +warn_unreachable = true disallow_untyped_defs = true disallow_incomplete_defs = true -show_error_codes = False +show_error_codes = false disable_error_code = empty-body + plugins = mypy_django_plugin.main diff --git a/requirements.txt b/requirements.txt index 887f4d1e8..24140407b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,4 @@ black==23.3.0 -requests==2.31.0 -gitpython==3.1.31 pre-commit==3.3.3 pytest==7.3.2 pytest-mypy-plugins==1.11.1 diff --git a/scripts/django_tests_settings.py b/scripts/django_tests_settings.py index cd0cdc501..ce86785c1 100644 --- a/scripts/django_tests_settings.py +++ b/scripts/django_tests_settings.py @@ -1,237 +1,2 @@ -import os - -import django - -SECRET_KEY = "1" -SITE_ID = 1 - -INSTALLED_APPS = [ - "django.contrib.contenttypes", - "django.contrib.auth", - "django.contrib.sites", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.admin.apps.SimpleAdminConfig", - "django.contrib.staticfiles", -] - -test_modules = [ - "absolute_url_overrides", - "admin_autodiscover", - "admin_changelist", - "admin_checks", - "admin_custom_urls", - "admin_default_site", - "admin_docs", - "admin_filters", - "admin_inlines", - "admin_ordering", - "admin_registration", - "admin_scripts", - "admin_utils", - "admin_views", - "admin_widgets", - "aggregation", - "aggregation_regress", - "annotations", - "app_loading", - "apps", - "auth_tests", - "backends", - "base", - "bash_completion", - "basic", - "builtin_server", - "bulk_create", - "cache", - "check_framework", - "conditional_processing", - "constraints", - "contenttypes_tests", - "context_processors", - "csrf_tests", - "custom_columns", - "custom_lookups", - "custom_managers", - "custom_methods", - "custom_migration_operations", - "custom_pk", - "datatypes", - "dates", - "datetimes", - "db_functions", - "db_typecasts", - "db_utils", - "dbshell", - "decorators", - "defer", - "defer_regress", - "delete", - "delete_regress", - "deprecation", - "dispatch", - "distinct_on_fields", - "empty", - "expressions", - "expressions_case", - "expressions_window", - "extra_regress", - "field_deconstruction", - "field_defaults", - "field_subclassing", - "file_storage", - "file_uploads", - "files", - "filtered_relation", - "fixtures", - "fixtures_model_package", - "fixtures_regress", - "flatpages_tests", - "force_insert_update", - "foreign_object", - "forms_tests", - "from_db_value", - "generic_inline_admin", - "generic_relations", - "generic_relations_regress", - "generic_views", - "get_earliest_or_latest", - "get_object_or_404", - "get_or_create", - "gis_tests", - "handlers", - "httpwrappers", - "humanize_tests", - "i18n", - "import_error_package", - "indexes", - "inline_formsets", - "inspectdb", - "introspection", - "invalid_models_tests", - "known_related_objects", - "logging_tests", - "lookup", - "m2m_and_m2o", - "m2m_intermediary", - "m2m_multiple", - "m2m_recursive", - "m2m_regress", - "m2m_signals", - "m2m_through", - "m2m_through_regress", - "m2o_recursive", - "mail", - "managers_regress", - "many_to_many", - "many_to_one", - "many_to_one_null", - "max_lengths", - "messages_tests", - "middleware", - "middleware_exceptions", - "migrate_signals", - "migration_test_data_persistence", - "migrations", - "migrations2", - "model_fields", - "model_forms", - "model_formsets", - "model_formsets_regress", - "model_indexes", - "model_inheritance", - "model_inheritance_regress", - "model_meta", - "model_options", - "model_package", - "model_regress", - "modeladmin", - "multiple_database", - "mutually_referential", - "nested_foreign_keys", - "no_models", - "null_fk", - "null_fk_ordering", - "null_queries", - "one_to_one", - "or_lookups", - "order_with_respect_to", - "ordering", - "pagination", - "postgres_tests", - "prefetch_related", - "project_template", - "properties", - "proxy_model_inheritance", - "proxy_models", - "queries", - "queryset_pickle", - "raw_query", - "redirects_tests", - "requests", - "reserved_names", - "resolve_url", - "responses", - "reverse_lookup", - "save_delete_hooks", - "schema", - "select_for_update", - "select_related", - "select_related_onetoone", - "select_related_regress", - "serializers", - "servers", - "sessions_tests", - "settings_tests", - "shell", - "shortcuts", - "signals", - "signed_cookies_tests", - "signing", - "sitemaps_tests", - "sites_framework", - "sites_tests", - "staticfiles_tests", - "str", - "string_lookup", - "swappable_models", - "syndication_tests", - "template_backends", - "template_loader", - "template_tests", - "test_client", - "test_client_regress", - "test_exceptions", - "test_runner", - "test_runner_apps", - "test_utils", - "timezones", - "transaction_hooks", - "transactions", - "unmanaged_models", - "update", - "update_only_fields", - "urlpatterns", - "urlpatterns_reverse", - "user_commands", - "utils_tests", - "validation", - "validators", - "version", - "view_tests", - "wsgi", -] - -if django.VERSION[0] == 2: - test_modules += ["choices"] - -invalid_apps = { - "import_error_package", -} - -for app in invalid_apps: - test_modules.remove(app) - - -if os.environ.get("TYPECHECK_TESTS"): - INSTALLED_APPS += test_modules +# It is used in `mypy.ini` only. +# It is empty, because we don't need any specific values. diff --git a/scripts/enabled_test_modules.py b/scripts/enabled_test_modules.py deleted file mode 100644 index d29126595..000000000 --- a/scripts/enabled_test_modules.py +++ /dev/null @@ -1,539 +0,0 @@ -# Some errors occur for the test suite itself, and cannot be addressed via django-stubs. They should be ignored -# using this constant. -import re -from typing import Any, Dict, List - -IGNORED_MODULES = { - "schema", - "gis_tests", - "admin_widgets", - "admin_filters", - "sitemaps_tests", - "staticfiles_tests", - "modeladmin", - "generic_views", - "forms_tests", - "flatpages_tests", - "admin_ordering", - "admin_changelist", - "admin_views", - "invalid_models_tests", - "i18n", - "model_formsets", - "template_tests", - "template_backends", - "test_runner", - "admin_scripts", - "inline_formsets", - "foreign_object", - "cache", -} - -MOCK_OBJECTS = [ - "MockRequest", - "MockCompiler", - "MockModelAdmin", - "modelz", - "call_count", - "call_args_list", - "call_args", - "MockUser", - "Xtemplate", - "DummyRequest", - "DummyUser", - "MinimalUser", - "DummyNode", -] -EXTERNAL_MODULES = [ - "psycopg2", - "PIL", - "selenium", - "oracle", - "mysql", - "sqlparse", - "tblib", - "numpy", - "bcrypt", - "argon2", - "xml.dom", -] -IGNORED_ERRORS: Dict[str, List[Any]] = { - "__common__": [ - *MOCK_OBJECTS, - *EXTERNAL_MODULES, - "Need type annotation for", - 'has no attribute "getvalue"', - "Cannot assign to a method", - "already defined", - "Cannot assign to a type", - '"HttpResponseBase" has no attribute', - '"object" has no attribute', - re.compile(r'"Callable\[.+, Any\]" has no attribute'), - 'has no attribute "deconstruct"', - # private members - re.compile(r'has no attribute ("|\')_[a-zA-Z_]+("|\')'), - "'Settings' object has no attribute", - "**Dict", - 'has incompatible type "object"', - "undefined in superclass", - "Argument after ** must be a mapping", - "note:", - re.compile(r'Item "None" of "[a-zA-Z_ ,\[\]]+" has no attribute'), - '"Callable[..., None]" has no attribute', - "does not return a value", - 'has no attribute "alternatives"', - "gets multiple values for keyword argument", - '"Handler" has no attribute', - "Module has no attribute", - "namedtuple", - # TODO: see test in managers/test_managers.yml - "Cannot determine type of", - "cache_clear", - "cache_info", - 'Incompatible types in assignment (expression has type "None", variable has type Module)', - "Module 'django.contrib.messages.storage.fallback' has no attribute 'CookieStorage'", - # TODO: not supported yet - "GenericRelation", - "RelatedObjectDoesNotExist", - re.compile( - r'"Field\[Any, Any\]" has no attribute ' - r'"(through|field_name|field|get_related_field|related_model|related_name' - r'|get_accessor_name|empty_strings_allowed|many_to_many)"' - ), - # TODO: multitable inheritance - "ptr", - 'Incompatible types in assignment (expression has type "Callable[', - "SimpleLazyObject", - "Test", - 'Mixin" has no attribute', - "Incompatible types in string interpolation", - '"None" has no attribute', - 'has no attribute "assert', - "Unsupported dynamic base class", - 'error: "HttpResponse" has no attribute "streaming_content"', - 'error: "HttpResponse" has no attribute "context_data"', - 'Duplicate module named "apps"', - "Function is missing a return type annotation", - "Function is missing a type annotation", - "Library stubs not installed for ", - ], - "admin_checks": ['Argument 1 to "append" of "list" has incompatible type "str"; expected "CheckMessage"'], - "admin_default_site": [ - 'Incompatible types in assignment (expression has type "DefaultAdminSite", variable has type "AdminSite")' - ], - "admin_inlines": [ - 'error: "HttpResponse" has no attribute "rendered_content"', - ], - "admin_registration": [ - 'Argument "site" to "register" has incompatible type "Type[Traveler]"; expected "Optional[AdminSite]"', - ], - "admin_utils": [ - '"Article" has no attribute "non_field"', - ], - "aggregation": [ - re.compile(r'got "Optional\[(Author|Publisher)\]", expected "Union\[(Author|Publisher), Combinable\]"'), - 'Argument 2 for "super" not an instance of argument 1', - ], - "annotations": [ - 'Incompatible type for "store" of "Employee" (got "Optional[Store]", expected "Union[Store, Combinable]")' - ], - "apps": [ - 'Incompatible types in assignment (expression has type "str", target has type "type")', - ], - "auth_tests": [ - '"PasswordValidator" has no attribute "min_length"', - "AbstractBaseUser", - 'Argument "password_validators" to "password_changed" has incompatible type "Tuple[Validator]"; ' - + 'expected "Optional[Sequence[PasswordValidator]]"', - 'Unsupported right operand type for in ("object")', - "mock_getpass", - 'Unsupported left operand type for + ("Sequence[str]")', - "AuthenticationFormWithInactiveUsersOkay", - 'Incompatible types in assignment (expression has type "Dict[str, Any]", variable has type "QueryDict")', - 'No overload variant of "int" matches argument type "AnonymousUser"', - 'expression has type "AnonymousUser", variable has type "User"', - ], - "basic": [ - 'Unexpected keyword argument "unknown_kwarg" for "refresh_from_db" of "Model"', - 'Unexpected attribute "foo" for model "Article"', - 'has no attribute "touched"', - 'Incompatible types in assignment (expression has type "Type[CustomQuerySet]"', - '"Manager[Article]" has no attribute "do_something"', - ], - "backends": ['"DatabaseError" has no attribute "pgcode"'], - "builtin_server": [ - '"ServerHandler" has no attribute', - 'Incompatible types in assignment (expression has type "Tuple[BytesIO, BytesIO]"', - ], - "bulk_create": [ - 'has incompatible type "List[Country]"; expected "Iterable[TwoFields]"', - 'List item 1 has incompatible type "Country"; expected "ProxyCountry"', - ], - "check_framework": [ - 'base class "Model" defined the type as "Callable', - 'Value of type "Collection[str]" is not indexable', - "Unsupported target for indexed assignment", - ], - "constraints": ['Argument "condition" to "UniqueConstraint" has incompatible type "str"; expected "Optional[Q]"'], - "contenttypes_tests": [ - '"FooWithBrokenAbsoluteUrl" has no attribute "unknown_field"', - "contenttypes_tests.models.Site", - 'Argument 1 to "set" of "RelatedManager" has incompatible type "SiteManager[Site]"', - ], - "custom_lookups": [ - 'in base class "SQLFuncMixin"', - 'has no attribute "name"', - ], - "custom_columns": [ - "Cannot resolve keyword 'firstname' into field", - ], - "custom_pk": [ - '"Employee" has no attribute "id"', - ], - "custom_managers": [ - 'Incompatible types in assignment (expression has type "CharField', - 'Item "Book" of "Optional[Book]" has no attribute "favorite_avg"', - ], - "csrf_tests": [ - 'expression has type "property", base class "HttpRequest" defined the type as "QueryDict"', - 'expression has type "Dict[, ]", variable has type "SessionBase"', - ], - "dates": [ - 'Too few arguments for "dates" of', - ], - "dbshell": [ - 'Incompatible types in assignment (expression has type "None"', - ], - "defer": ['Too many arguments for "refresh_from_db" of "Model"'], - "delete": [ - 'Incompatible type for lookup \'pk\': (got "Optional[int]", expected "Union[str, int]")', - ], - "dispatch": ['Item "str" of "Union[ValueError, str]" has no attribute "args"'], - "deprecation": ['"Manager" has no attribute "old"', '"Manager" has no attribute "new"'], - "db_functions": [ - '"FloatModel" has no attribute', - 'Incompatible types in assignment (expression has type "Optional[Any]", variable has type "FloatModel")', - ], - "decorators": [ - '"Type[object]" has no attribute "method"', - 'Value of type variable "_T" of function cannot be "descriptor_wrapper"', - ], - "expressions_window": ['has incompatible type "str"'], - "file_uploads": [ - 'has no attribute "content_type"', - ], - "file_storage": [ - 'Incompatible types in assignment (expression has type "None", variable has type "str")', - 'Property "base_url" defined in "FileSystemStorage" is read-only', - ], - "files": [ - 'Incompatible types in assignment (expression has type "IOBase", variable has type "File")', - 'Argument 1 to "TextIOWrapper" has incompatible type "File"; expected "BinaryIO"', - 'Incompatible types in assignment (expression has type "BinaryIO", variable has type "File")', - ], - "filtered_relation": [ - 'has no attribute "name"', - ], - "fixtures": [ - 'Incompatible types in assignment (expression has type "int", target has type "Iterable[str]")', - 'Incompatible types in assignment (expression has type "SpyManager[Spy]"', - ], - "fixtures_regress": [ - 'Unsupported left operand type for + ("None")', - ], - "from_db_value": [ - '"Cash" has no attribute', - '"__str__" of "Decimal"', - ], - "get_object_or_404": [ - 'Argument 1 to "get_object_or_404" has incompatible type "str"; ' - + 'expected "Union[Type[], QuerySet[]]"', - 'Argument 1 to "get_list_or_404" has incompatible type "List[Type[Article]]"; ' - + 'expected "Union[Type[], QuerySet[]]"', - "CustomClass", - ], - "generic_relations": [ - "Cannot resolve keyword 'vegetable' into field", - ], - "generic_relations_regress": [ - '"Link" has no attribute', - ], - "httpwrappers": [ - 'Argument 2 to "appendlist" of "QueryDict"', - 'Incompatible types in assignment (expression has type "int", target has type "Union[str, List[str]]")', - 'Argument 1 to "fromkeys" of "QueryDict" has incompatible type "int"', - ], - "humanize_tests": [ - 'Argument 1 to "append" of "list" has incompatible type "None"; expected "str"', - ], - "lookup": [ - 'Unexpected keyword argument "headline__startswith" for "in_bulk" of', - "is called with more than one field", - "Cannot resolve keyword 'pub_date_year' into field", - "Cannot resolve keyword 'blahblah' into field", - ], - "logging_tests": [ - re.compile(r'Argument [0-9] to "makeRecord" of "Logger"'), - '"LogRecord" has no attribute "request"', - ], - "m2m_regress": [ - "Cannot resolve keyword 'porcupine' into field", - 'Argument 1 to "set" of "RelatedManager" has incompatible type "int"', - ], - "mail": [ - 'List item 1 has incompatible type "None"; expected "str"', - "Incompatible types in assignment " - + '(expression has type "bool", variable has type "Union[SMTP_SSL, SMTP, None]")', - ], - "messages_tests": [ - 'List item 0 has incompatible type "Dict[str, Message]"; expected "Message"', - "Too many arguments", - "CustomRequest", - ], - "middleware": [ - re.compile(r'"(HttpRequest|WSGIRequest)" has no attribute'), - 'Incompatible types in assignment (expression has type "HttpResponseBase", variable has type "HttpResponse")', - ], - "many_to_many": [ - '(expression has type "List[Article]", variable has type "Publication_Article_RelatedManager1', - '"add" of "RelatedManager" has incompatible type "Article"; expected "Union[Publication, int]"', - ], - "many_to_one": [ - 'Incompatible type for "parent" of "Child" (got "None", expected "Union[Parent, Combinable]")', - 'Incompatible type for "parent" of "Child" (got "Child", expected "Union[Parent, Combinable]")', - 'expression has type "List[]", variable has type "RelatedManager[Article]"', - '"Reporter" has no attribute "cached_query"', - 'to "add" of "RelatedManager" has incompatible type "Reporter"; expected "Union[Article, int]"', - ], - "middleware_exceptions": [ - 'Argument 1 to "append" of "list" has incompatible type "Tuple[Any, Any]"; expected "str"' - ], - "migrate_signals": [ - 'Value of type "Optional[Any]" is not indexable', - 'Argument 1 to "set" has incompatible type "Optional[Any]"; expected "Iterable[Any]"', - ], - "migrations": [ - "FakeMigration", - "FakeLoader", - '"Manager[Any]" has no attribute "args"', - 'Dict entry 0 has incompatible type "Any"', - 'Argument 1 to "append" of "list" has incompatible type', - 'base class "Model" defined the type as "BaseManager[Any]"', - 'Argument 1 to "RunPython" has incompatible type "str"', - ], - "model_fields": [ - 'Item "Field[Any, Any]" of "Union[Field[Any, Any], ForeignObjectRel]" has no attribute', - 'Incompatible types in assignment (expression has type "Type[Person', - 'Incompatible types in assignment (expression has type "FloatModel", variable has type', - '"ImageFile" has no attribute "was_opened"', - 'Incompatible type for "size" of "FloatModel" (got "object", expected "Union[float, int, str, Combinable]")', - 'Incompatible type for "value" of "IntegerModel" (got "object", expected', - '"Child" has no attribute "get_foo_display"', - ], - "model_forms": [ - '"render" of "Widget"', - "Module 'django.core.validators' has no attribute 'ValidationError'", - "Incompatible types in assignment", - "NewForm", - '"type" has no attribute "base_fields"', - 'Argument "instance" to "InvalidModelForm" has incompatible type "Type[Category]"', - ], - "model_indexes": ['Argument "condition" to "Index" has incompatible type "str"; expected "Optional[Q]"'], - "model_inheritance": [ - 'base class "AbstractBase" defined', - 'base class "AbstractModel" defined', - 'Definition of "name" in base class "ConcreteParent"', - ' Definition of "name" in base class "AbstractParent"', - "referent_references", - "Cannot resolve keyword 'attached_comment_set' into field", - ], - "model_meta": ['List item 0 has incompatible type "str"; expected "Union[Field[Any, Any], ForeignObjectRel]"'], - "model_regress": [ - 'Incompatible type for "department" of "Worker"', - '"PickledModel" has no attribute', - '"Department" has no attribute "evaluate"', - "Unsupported target for indexed assignment", - ], - "model_formsets_regress": [ - 'Incompatible types in assignment (expression has type "int", target has type "str")', - ], - "model_options": [ - 'expression has type "Dict[str, Type[Model]]", target has type "OrderedDict', - ], - "model_enums": [ - "'bool' is not a valid base class", - ], - "null_queries": ["Cannot resolve keyword 'foo' into field"], - "order_with_respect_to": [ - '"Dimension" has no attribute "set_component_order"', - ], - "one_to_one": [ - 'expression has type "None", variable has type "UndergroundBar"', - 'Item "OneToOneField[Union[Place, Combinable], Place]" ' - + 'of "Union[OneToOneField[Union[Place, Combinable], Place], Any]"', - ], - "pagination": [ - '"int" not callable', - ], - "postgres_tests": [ - "DummyArrayField", - "DummyJSONField", - 'Incompatible types in assignment (expression has type "Type[Field[Any, Any]]', - 'Argument "encoder" to "JSONField" has incompatible type "DjangoJSONEncoder";', - '("None" and "SearchQuery")', - ], - "properties": [re.compile('Unexpected attribute "(full_name|full_name_2)" for model "Person"')], - "prefetch_related": [ - '"Person" has no attribute "houses_lst"', - '"Book" has no attribute "first_authors"', - '"Book" has no attribute "the_authors"', - 'Incompatible types in assignment (expression has type "List[Room]", variable has type "Manager[Room]")', - 'Item "Room" of "Optional[Room]" has no attribute "house_attr"', - 'Item "Room" of "Optional[Room]" has no attribute "main_room_of_attr"', - 'Argument 2 to "Prefetch" has incompatible type "ValuesQuerySet', - ], - "proxy_models": ["Incompatible types in assignment", 'in base class "User"'], - "queries": [ - 'Incompatible types in assignment (expression has type "None", variable has type "str")', - 'Invalid index type "Optional[str]" for "Dict[str, int]"; expected type "str"', - 'Unsupported operand types for & ("Manager[Author]" and "Manager[Tag]")', - 'Unsupported operand types for | ("Manager[Author]" and "Manager[Tag]")', - "ObjectA", - "'flat' and 'named' can't be used together", - '"Collection[Any]" has no attribute "explain"', - "Cannot resolve keyword 'unknown_field' into field", - 'Incompatible type for lookup \'tag\': (got "str", expected "Union[Tag, int, None]")', - 'No overload variant of "__getitem__" of "QuerySet" matches argument type "str"', - ], - "requests": [ - 'Incompatible types in assignment (expression has type "Dict[str, str]", variable has type "QueryDict")' - ], - "responses": [ - 'Argument 1 to "TextIOWrapper" has incompatible type "HttpResponse"; expected "IO[bytes]"', - '"FileLike" has no attribute "closed"', - 'Argument 1 to "TextIOWrapper" has incompatible type "HttpResponse"; expected "BinaryIO"', - ], - "reverse_lookup": ["Cannot resolve keyword 'choice' into field"], - "settings_tests": ['Argument 1 to "Settings" has incompatible type "Optional[str]"; expected "str"'], - "shortcuts": [ - 'error: "Context" has no attribute "request"', - ], - "signals": ['Argument 1 to "append" of "list" has incompatible type "Tuple[Any, Any, Optional[Any], Any]";'], - "sites_framework": [ - 'expression has type "CurrentSiteManager[CustomArticle]", base class "AbstractArticle"', - "Name 'Optional' is not defined", - ], - "sites_tests": [ - '"RequestSite" of "Union[Site, RequestSite]" has no attribute "id"', - ], - "syndication_tests": [ - 'Argument 1 to "add_domain" has incompatible type "*Tuple[object, ...]"', - ], - "sessions_tests": [ - 'Incompatible types in assignment (expression has type "None", variable has type "int")', - '"AbstractBaseSession" has no attribute', - '"None" not callable', - ], - "select_for_update": ['"Thread" has no attribute "isAlive"'], - "select_related": [ - 'Item "ForeignKey[Union[Genus, Combinable], Genus]" ' - + 'of "Union[ForeignKey[Union[Genus, Combinable], Genus], Any]"' - ], - "select_related_onetoone": [ - 'Incompatible types in assignment (expression has type "Parent2", variable has type "Parent1")', - '"Parent1" has no attribute', - ], - "servers": [ - re.compile('Argument [0-9] to "WSGIRequestHandler"'), - '"HTTPResponse" has no attribute', - '"type" has no attribute', - '"WSGIRequest" has no attribute "makefile"', - "LiveServerAddress", - '"Stub" has no attribute "makefile"', - ], - "serializers": [ - '"Model" has no attribute "data"', - '"Iterable[Any]" has no attribute "content"', - re.compile(r'Argument 1 to "(serialize|deserialize)" has incompatible type "None"; expected "str"'), - ], - "string_lookup": [ - '"Bar" has no attribute "place"', - ], - "test_utils": [ - '"PossessedCar" has no attribute "color"', - 'expression has type "None", variable has type "List[str]"', - ], - "test_client": ['(expression has type "HttpResponse", variable has type "StreamingHttpResponse")'], - "test_client_regress": [ - '(expression has type "Dict[, ]", variable has type "SessionBase")', - 'Unsupported left operand type for + ("None")', - 'Argument 1 to "len" has incompatible type "Context"; expected "Sized"', - ], - "transactions": [ - 'Incompatible types in assignment (expression has type "Thread", variable has type "Callable[[], Any]")' - ], - "urlpatterns": [ - '"object" not callable', - '"None" not callable', - 'Argument 2 to "path" has incompatible type "Callable[[Any], None]"', - 'Incompatible return value type (got "None", expected "HttpResponseBase")', - ], - "urlpatterns_reverse": [ - 'No overload variant of "path" matches argument types "str", "None"', - 'No overload variant of "zip" matches argument types "Any", "object"', - 'Argument 1 to "get_callable" has incompatible type "int"', - ], - "utils_tests": [ - 'Argument 1 to "activate" has incompatible type "None"; expected "Union[tzinfo, str]"', - 'Argument 1 to "activate" has incompatible type "Optional[str]"; expected "str"', - 'Incompatible types in assignment (expression has type "None", base class "object" defined the type as', - "Class", - 'has no attribute "cp"', - 'Argument "name" to "cached_property" has incompatible type "int"; expected "Optional[str]"', - 'has no attribute "sort"', - "Unsupported target for indexed assignment", - 'defined the type as "None"', - 'Argument 1 to "Path" has incompatible type "Optional[str]"', - '"None" not callable', - '"WSGIRequest" has no attribute "process_response_content"', - 'No overload variant of "join" matches argument types "str", "None"', - 'Argument 1 to "Archive" has incompatible type "None"; expected "str"', - 'Argument 1 to "to_path" has incompatible type "int"; expected "Union[Path, str]"', - 'Cannot infer type argument 1 of "cached_property"', - ], - "view_tests": [ - "Module 'django.views.debug' has no attribute 'Path'", - 'Value of type "Optional[List[str]]" is not indexable', - "ExceptionUser", - "view_tests.tests.test_debug.User", - "Exception must be derived from BaseException", - "No binding for nonlocal 'tb_frames' found", - ], - "validation": [ - 'has no attribute "name"', - ], - "wsgi": [ - '"HttpResponse" has no attribute "block_size"', - ], - # test_runner_apps/tagged/tests_syntax_error.py - "test_runner_apps": [ - "invalid syntax", - "invalid decimal literal", - ], -} - - -def check_if_custom_ignores_are_covered_by_common() -> None: - from scripts.typecheck_tests import does_pattern_fit - - common_ignore_patterns = IGNORED_ERRORS["__common__"] - for module_name, patterns in IGNORED_ERRORS.items(): - if module_name == "__common__": - continue - for pattern in patterns: - for common_pattern in common_ignore_patterns: - if isinstance(pattern, str) and does_pattern_fit(common_pattern, pattern): - print(f'pattern "{module_name}: {pattern!r}" is covered by pattern {common_pattern!r}') - - -check_if_custom_ignores_are_covered_by_common() diff --git a/scripts/git_helpers.py b/scripts/git_helpers.py deleted file mode 100644 index cc7a0f91d..000000000 --- a/scripts/git_helpers.py +++ /dev/null @@ -1,34 +0,0 @@ -import shutil -from typing import Optional, Union - -from git.remote import RemoteProgress -from git.repo import Repo - -from scripts.paths import DJANGO_SOURCE_DIRECTORY - - -class ProgressPrinter(RemoteProgress): - def line_dropped(self, line: str) -> None: - print(line) - - def update( - self, op_code: int, cur_count: Union[str, float], max_count: Union[str, float, None] = None, message: str = "" - ) -> None: - print(self._cur_line) - - -def checkout_django_branch(django_version: str, commit_sha: Optional[str]) -> None: - branch = f"stable/{django_version}.x" - if DJANGO_SOURCE_DIRECTORY.exists(): - shutil.rmtree(DJANGO_SOURCE_DIRECTORY) - DJANGO_SOURCE_DIRECTORY.mkdir(exist_ok=True, parents=False) - repo = Repo.clone_from( - "https://github.com/django/django.git", - DJANGO_SOURCE_DIRECTORY, - progress=ProgressPrinter(), # type: ignore - branch=branch, - depth=100, - ) - if commit_sha and repo.head.commit.hexsha != commit_sha: - repo.remote("origin").fetch(branch, progress=ProgressPrinter(), depth=100) - repo.git.checkout(branch) diff --git a/scripts/paths.py b/scripts/paths.py deleted file mode 100644 index 3e98cb8ac..000000000 --- a/scripts/paths.py +++ /dev/null @@ -1,4 +0,0 @@ -from pathlib import Path - -PROJECT_DIRECTORY = Path(__file__).parent.parent -DJANGO_SOURCE_DIRECTORY = PROJECT_DIRECTORY / "django-source" # type: Path diff --git a/scripts/stubgen-django.py b/scripts/stubgen-django.py deleted file mode 100644 index 226cc230c..000000000 --- a/scripts/stubgen-django.py +++ /dev/null @@ -1,15 +0,0 @@ -from argparse import ArgumentParser - -from mypy.stubgen import generate_stubs, parse_options - -from scripts.git_helpers import checkout_django_branch -from scripts.paths import DJANGO_SOURCE_DIRECTORY - -if __name__ == "__main__": - parser = ArgumentParser() - parser.add_argument("--django_version", required=True) - parser.add_argument("--commit_sha", required=False) - args = parser.parse_args() - checkout_django_branch(args.django_version, args.commit_sha) - stubgen_options = parse_options([f"{DJANGO_SOURCE_DIRECTORY}", "-o=stubgen"]) - generate_stubs(stubgen_options) diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py deleted file mode 100755 index 4c24a6686..000000000 --- a/scripts/typecheck_tests.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env 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 = { - "3.2": "007e46d815063d598e0d3db78bfb371100e5c61c", - "4.1": "491dccec1aa10e829539e4e4fcd8cca606a57ebc", - "4.2": "879e5d587b84e6fc961829611999431778eb9f6a", -} -DEFAULT_DJANGO_VERSION = "4.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] - 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