mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-10 14:01:56 +08:00
updated package setup (#485)
* updated package setup * updated to use python 3.9 * fixed test runner * fixed typecheck tests * fixed discrepencies * added override to runner * updated travis * updated pre-commit hooks * updated dep
This commit is contained in:
committed by
GitHub
parent
a3624dec36
commit
44151c485d
@@ -1,28 +0,0 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
STUBS_ROOT = Path(__file__).parent.parent / 'django-stubs'
|
||||
|
||||
|
||||
def build_package_name(path: str) -> str:
|
||||
return '.'.join(['django'] + list(Path(path).relative_to(STUBS_ROOT).with_suffix('').parts))
|
||||
|
||||
|
||||
packages: List[str] = []
|
||||
for dirpath, dirnames, filenames in os.walk(STUBS_ROOT):
|
||||
if not dirnames:
|
||||
package = build_package_name(dirpath)
|
||||
packages.append(package)
|
||||
|
||||
for filename in filenames:
|
||||
if filename != '__init__.pyi':
|
||||
package = build_package_name(os.path.join(dirpath, filename))
|
||||
packages.append(package)
|
||||
|
||||
test_lines: List[str] = []
|
||||
for package in packages:
|
||||
test_lines.append('import ' + package)
|
||||
|
||||
test_contents = '\n'.join(sorted(test_lines))
|
||||
print(test_contents)
|
||||
@@ -1,88 +0,0 @@
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
import libcst
|
||||
from libcst import Annotation, BaseExpression, FunctionDef, Name, Subscript
|
||||
from libcst.metadata import SyntacticPositionProvider
|
||||
|
||||
BASE_DIR = 'django-stubs'
|
||||
|
||||
fpath = os.path.join(BASE_DIR, 'core', 'checks', 'model_checks.pyi')
|
||||
with open(fpath, 'r') as f:
|
||||
contents = f.read()
|
||||
|
||||
|
||||
tree = libcst.parse_module(contents)
|
||||
|
||||
|
||||
class TypeAnnotationsAnalyzer(libcst.CSTVisitor):
|
||||
METADATA_DEPENDENCIES = (SyntacticPositionProvider,)
|
||||
|
||||
def __init__(self, fpath: str):
|
||||
super().__init__()
|
||||
self.fpath = fpath
|
||||
|
||||
def get_node_location(self, node: FunctionDef) -> str:
|
||||
start_line = self.get_metadata(SyntacticPositionProvider, node).start.line
|
||||
return f'{self.fpath}:{start_line}'
|
||||
|
||||
def show_error_for_node(self, node: FunctionDef, error_message: str):
|
||||
print(self.get_node_location(node), error_message)
|
||||
|
||||
def check_subscripted_annotation(self, annotation: BaseExpression) -> Optional[str]:
|
||||
if isinstance(annotation, Subscript):
|
||||
if isinstance(annotation.value, Name):
|
||||
error_message = self.check_concrete_class_usage(annotation.value)
|
||||
if error_message:
|
||||
return error_message
|
||||
|
||||
if annotation.value.value == 'Union':
|
||||
for slice_param in annotation.slice:
|
||||
if isinstance(slice_param.slice.value, Name):
|
||||
error_message = self.check_concrete_class_usage(annotation.value)
|
||||
if error_message:
|
||||
return error_message
|
||||
|
||||
def check_concrete_class_usage(self, name_node: Name) -> Optional[str]:
|
||||
if name_node.value == 'List':
|
||||
return (f'Concrete class {name_node.value!r} used for an iterable annotation. '
|
||||
f'Use abstract collection (Iterable, Collection, Sequence) instead')
|
||||
|
||||
def visit_FunctionDef(self, node: FunctionDef) -> Optional[bool]:
|
||||
params_node = node.params
|
||||
for param_node in [*params_node.params, *params_node.default_params]:
|
||||
param_name = param_node.name.value
|
||||
annotation_node = param_node.annotation # type: Annotation
|
||||
if annotation_node is not None:
|
||||
annotation = annotation_node.annotation
|
||||
if annotation.value == 'None':
|
||||
self.show_error_for_node(node, f'"None" type annotation used for parameter {param_name!r}')
|
||||
continue
|
||||
|
||||
error_message = self.check_subscripted_annotation(annotation)
|
||||
if error_message is not None:
|
||||
self.show_error_for_node(node, error_message)
|
||||
continue
|
||||
|
||||
if node.returns is not None:
|
||||
return_annotation = node.returns.annotation
|
||||
if isinstance(return_annotation, Subscript) and return_annotation.value.value == 'Union':
|
||||
self.show_error_for_node(node, 'Union is return type annotation')
|
||||
|
||||
return False
|
||||
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(BASE_DIR):
|
||||
for filename in filenames:
|
||||
fpath = os.path.join(dirpath, filename)
|
||||
# skip all other checks for now, low priority
|
||||
if not fpath.startswith(('django-stubs/db', 'django-stubs/views', 'django-stubs/apps',
|
||||
'django-stubs/http', 'django-stubs/contrib/postgres')):
|
||||
continue
|
||||
|
||||
with open(fpath, 'r') as f:
|
||||
contents = f.read()
|
||||
|
||||
tree = libcst.MetadataWrapper(libcst.parse_module(contents))
|
||||
analyzer = TypeAnnotationsAnalyzer(fpath)
|
||||
tree.visit(analyzer)
|
||||
@@ -1,233 +1,237 @@
|
||||
import os
|
||||
|
||||
import django
|
||||
|
||||
SECRET_KEY = '1'
|
||||
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',
|
||||
"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',
|
||||
"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']
|
||||
test_modules += ["choices"]
|
||||
|
||||
invalid_apps = {
|
||||
'import_error_package',
|
||||
"import_error_package",
|
||||
}
|
||||
|
||||
for app in invalid_apps:
|
||||
test_modules.remove(app)
|
||||
|
||||
INSTALLED_APPS += test_modules
|
||||
|
||||
if os.environ.get("TYPECHECK_TESTS"):
|
||||
INSTALLED_APPS += test_modules
|
||||
|
||||
@@ -2,27 +2,69 @@
|
||||
# using this constant.
|
||||
import re
|
||||
|
||||
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'}
|
||||
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']
|
||||
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 = {
|
||||
'__common__': [
|
||||
"__common__": [
|
||||
*MOCK_OBJECTS,
|
||||
*EXTERNAL_MODULES,
|
||||
'Need type annotation for',
|
||||
"Need type annotation for",
|
||||
'has no attribute "getvalue"',
|
||||
'Cannot assign to a method',
|
||||
'already defined',
|
||||
'Cannot assign to a type',
|
||||
"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'),
|
||||
@@ -30,259 +72,245 @@ IGNORED_ERRORS = {
|
||||
# private members
|
||||
re.compile(r'has no attribute ("|\')_[a-zA-Z_]+("|\')'),
|
||||
"'Settings' object has no attribute",
|
||||
'**Dict',
|
||||
"**Dict",
|
||||
'has incompatible type "object"',
|
||||
'undefined in superclass',
|
||||
'Argument after ** must be a mapping',
|
||||
'note:',
|
||||
"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',
|
||||
"does not return a value",
|
||||
'has no attribute "alternatives"',
|
||||
'gets multiple values for keyword argument',
|
||||
"gets multiple values for keyword argument",
|
||||
'"Handler" has no attribute',
|
||||
'Module has no attribute',
|
||||
'namedtuple',
|
||||
"Module has no attribute",
|
||||
"namedtuple",
|
||||
# TODO: see test in managers/test_managers.yml
|
||||
"Cannot determine type of",
|
||||
'cache_clear',
|
||||
'cache_info',
|
||||
"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)"'),
|
||||
"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',
|
||||
"ptr",
|
||||
'Incompatible types in assignment (expression has type "Callable[',
|
||||
'SimpleLazyObject',
|
||||
'Test',
|
||||
"SimpleLazyObject",
|
||||
"Test",
|
||||
'Mixin" has no attribute',
|
||||
'Incompatible types in string interpolation',
|
||||
"Incompatible types in string interpolation",
|
||||
'"None" has no attribute',
|
||||
'has no attribute "assert',
|
||||
'Unsupported dynamic base class',
|
||||
"Unsupported dynamic base class",
|
||||
'error: "HttpResponse" has no attribute "streaming_content"',
|
||||
'error: "HttpResponse" has no attribute "context_data"',
|
||||
],
|
||||
'admin_checks': [
|
||||
'Argument 1 to "append" of "list" has incompatible type "str"; expected "CheckMessage"'
|
||||
],
|
||||
'admin_inlines': [
|
||||
"admin_checks": ['Argument 1 to "append" of "list" has incompatible type "str"; expected "CheckMessage"'],
|
||||
"admin_inlines": [
|
||||
'error: "HttpResponse" has no attribute "rendered_content"',
|
||||
],
|
||||
'admin_utils': [
|
||||
"admin_utils": [
|
||||
'"Article" has no attribute "non_field"',
|
||||
],
|
||||
'aggregation': [
|
||||
"aggregation": [
|
||||
re.compile(r'got "Optional\[(Author|Publisher)\]", expected "Union\[(Author|Publisher), Combinable\]"'),
|
||||
'Argument 2 for "super" not an instance of argument 1',
|
||||
],
|
||||
'annotations': [
|
||||
"annotations": [
|
||||
'Incompatible type for "store" of "Employee" (got "Optional[Store]", expected "Union[Store, Combinable]")'
|
||||
],
|
||||
'apps': [
|
||||
"apps": [
|
||||
'Incompatible types in assignment (expression has type "str", target has type "type")',
|
||||
],
|
||||
'auth_tests': [
|
||||
"auth_tests": [
|
||||
'"PasswordValidator" has no attribute "min_length"',
|
||||
'AbstractBaseUser',
|
||||
"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',
|
||||
"mock_getpass",
|
||||
'Unsupported left operand type for + ("Sequence[str]")',
|
||||
'AuthenticationFormWithInactiveUsersOkay',
|
||||
"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': [
|
||||
"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': [
|
||||
"backends": ['"DatabaseError" has no attribute "pgcode"'],
|
||||
"builtin_server": [
|
||||
'"ServerHandler" has no attribute',
|
||||
'Incompatible types in assignment (expression has type "Tuple[BytesIO, BytesIO]"',
|
||||
],
|
||||
'bulk_create': [
|
||||
"bulk_create": [
|
||||
'has incompatible type "List[Country]"; expected "Iterable[TwoFields]"',
|
||||
'List item 1 has incompatible type "Country"; expected "ProxyCountry"',
|
||||
],
|
||||
'check_framework': [
|
||||
"check_framework": [
|
||||
'base class "Model" defined the type as "Callable',
|
||||
'Value of type "Collection[str]" is not indexable',
|
||||
'Unsupported target for indexed assignment',
|
||||
"Unsupported target for indexed assignment",
|
||||
],
|
||||
'constraints': [
|
||||
'Argument "condition" to "UniqueConstraint" has incompatible type "str"; expected "Optional[Q]"'
|
||||
],
|
||||
'contenttypes_tests': [
|
||||
"constraints": ['Argument "condition" to "UniqueConstraint" has incompatible type "str"; expected "Optional[Q]"'],
|
||||
"contenttypes_tests": [
|
||||
'"FooWithBrokenAbsoluteUrl" has no attribute "unknown_field"',
|
||||
'contenttypes_tests.models.Site',
|
||||
"contenttypes_tests.models.Site",
|
||||
'Argument 1 to "set" of "RelatedManager" has incompatible type "SiteManager[Site]"',
|
||||
],
|
||||
'custom_lookups': [
|
||||
"custom_lookups": [
|
||||
'in base class "SQLFuncMixin"',
|
||||
'has no attribute "name"',
|
||||
],
|
||||
'custom_columns': [
|
||||
"custom_columns": [
|
||||
"Cannot resolve keyword 'firstname' into field",
|
||||
],
|
||||
'custom_pk': [
|
||||
"custom_pk": [
|
||||
'"Employee" has no attribute "id"',
|
||||
],
|
||||
'custom_managers': [
|
||||
"custom_managers": [
|
||||
'Incompatible types in assignment (expression has type "CharField',
|
||||
'Item "Book" of "Optional[Book]" has no attribute "favorite_avg"',
|
||||
],
|
||||
'csrf_tests': [
|
||||
"csrf_tests": [
|
||||
'expression has type "property", base class "HttpRequest" defined the type as "QueryDict"',
|
||||
'expression has type "Dict[<nothing>, <nothing>]", variable has type "SessionBase"',
|
||||
],
|
||||
'dates': [
|
||||
"dates": [
|
||||
'Too few arguments for "dates" of',
|
||||
],
|
||||
'dbshell': [
|
||||
"dbshell": [
|
||||
'Incompatible types in assignment (expression has type "None"',
|
||||
],
|
||||
'defer': [
|
||||
'Too many arguments for "refresh_from_db" of "Model"'
|
||||
],
|
||||
'delete': [
|
||||
"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': [
|
||||
"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")'
|
||||
'Incompatible types in assignment (expression has type "Optional[Any]", variable has type "FloatModel")',
|
||||
],
|
||||
'decorators': [
|
||||
"decorators": [
|
||||
'"Type[object]" has no attribute "method"',
|
||||
'Value of type variable "_T" of function cannot be "descriptor_wrapper"'
|
||||
'Value of type variable "_T" of function cannot be "descriptor_wrapper"',
|
||||
],
|
||||
'expressions_window': [
|
||||
'has incompatible type "str"'
|
||||
],
|
||||
'file_uploads': [
|
||||
"expressions_window": ['has incompatible type "str"'],
|
||||
"file_uploads": [
|
||||
'has no attribute "content_type"',
|
||||
],
|
||||
'file_storage': [
|
||||
"file_storage": [
|
||||
'Incompatible types in assignment (expression has type "None", variable has type "str")',
|
||||
'Property "base_url" defined in "FileSystemStorage" is read-only',
|
||||
],
|
||||
'files': [
|
||||
"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': [
|
||||
"filtered_relation": [
|
||||
'has no attribute "name"',
|
||||
],
|
||||
'fixtures': [
|
||||
"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': [
|
||||
"fixtures_regress": [
|
||||
'Unsupported left operand type for + ("None")',
|
||||
],
|
||||
'from_db_value': [
|
||||
"from_db_value": [
|
||||
'"Cash" has no attribute',
|
||||
'"__str__" of "Decimal"',
|
||||
],
|
||||
'get_object_or_404': [
|
||||
"get_object_or_404": [
|
||||
'Argument 1 to "get_object_or_404" has incompatible type "str"; '
|
||||
+ 'expected "Union[Type[<nothing>], QuerySet[<nothing>]]"',
|
||||
'Argument 1 to "get_list_or_404" has incompatible type "List[Type[Article]]"; '
|
||||
+ 'expected "Union[Type[<nothing>], QuerySet[<nothing>]]"',
|
||||
'CustomClass',
|
||||
"CustomClass",
|
||||
],
|
||||
'generic_relations': [
|
||||
"generic_relations": [
|
||||
"Cannot resolve keyword 'vegetable' into field",
|
||||
],
|
||||
'generic_relations_regress': [
|
||||
"generic_relations_regress": [
|
||||
'"Link" has no attribute',
|
||||
],
|
||||
'httpwrappers': [
|
||||
"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': [
|
||||
"humanize_tests": [
|
||||
'Argument 1 to "append" of "list" has incompatible type "None"; expected "str"',
|
||||
],
|
||||
'lookup': [
|
||||
"lookup": [
|
||||
'Unexpected keyword argument "headline__startswith" for "in_bulk" of',
|
||||
'is called with more than one field',
|
||||
"is called with more than one field",
|
||||
"Cannot resolve keyword 'pub_date_year' into field",
|
||||
"Cannot resolve keyword 'blahblah' into field",
|
||||
],
|
||||
'logging_tests': [
|
||||
"logging_tests": [
|
||||
re.compile(r'Argument [0-9] to "makeRecord" of "Logger"'),
|
||||
'"LogRecord" has no attribute "request"',
|
||||
],
|
||||
'm2m_regress': [
|
||||
"m2m_regress": [
|
||||
"Cannot resolve keyword 'porcupine' into field",
|
||||
'Argument 1 to "set" of "RelatedManager" has incompatible type "int"',
|
||||
],
|
||||
'mail': [
|
||||
"mail": [
|
||||
'List item 1 has incompatible type "None"; expected "str"',
|
||||
'Incompatible types in assignment '
|
||||
"Incompatible types in assignment "
|
||||
+ '(expression has type "bool", variable has type "Union[SMTP_SSL, SMTP, None]")',
|
||||
],
|
||||
'messages_tests': [
|
||||
"messages_tests": [
|
||||
'List item 0 has incompatible type "Dict[str, Message]"; expected "Message"',
|
||||
'Too many arguments',
|
||||
'CustomRequest',
|
||||
"Too many arguments",
|
||||
"CustomRequest",
|
||||
],
|
||||
'middleware': [
|
||||
"middleware": [
|
||||
re.compile(r'"(HttpRequest|WSGIRequest)" has no attribute'),
|
||||
'Incompatible types in assignment (expression has type "HttpResponseBase", variable has type "HttpResponse")',
|
||||
],
|
||||
'many_to_many': [
|
||||
"many_to_many": [
|
||||
'(expression has type "List[Article]", variable has type "Article_RelatedManager2',
|
||||
'"add" of "RelatedManager" has incompatible type "Article"; expected "Union[Publication, int]"',
|
||||
],
|
||||
'many_to_one': [
|
||||
"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[<nothing>]", 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': [
|
||||
"middleware_exceptions": [
|
||||
'Argument 1 to "append" of "list" has incompatible type "Tuple[Any, Any]"; expected "str"'
|
||||
],
|
||||
'migrate_signals': [
|
||||
"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',
|
||||
"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': [
|
||||
"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',
|
||||
@@ -291,186 +319,168 @@ IGNORED_ERRORS = {
|
||||
'Incompatible type for "value" of "IntegerModel" (got "object", expected',
|
||||
'"Child" has no attribute "get_foo_display"',
|
||||
],
|
||||
'model_forms': [
|
||||
"model_forms": [
|
||||
'"render" of "Widget"',
|
||||
"Module 'django.core.validators' has no attribute 'ValidationError'",
|
||||
'Incompatible types in assignment',
|
||||
'NewForm',
|
||||
"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': [
|
||||
"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"
|
||||
"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': [
|
||||
"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',
|
||||
"Unsupported target for indexed assignment",
|
||||
],
|
||||
'model_formsets_regress': [
|
||||
"model_formsets_regress": [
|
||||
'Incompatible types in assignment (expression has type "int", target has type "str")',
|
||||
],
|
||||
'model_options': [
|
||||
"model_options": [
|
||||
'expression has type "Dict[str, Type[Model]]", target has type "OrderedDict',
|
||||
],
|
||||
'model_enums': [
|
||||
"model_enums": [
|
||||
"'bool' is not a valid base class",
|
||||
],
|
||||
'null_queries': [
|
||||
"Cannot resolve keyword 'foo' into field"
|
||||
],
|
||||
'order_with_respect_to': [
|
||||
"null_queries": ["Cannot resolve keyword 'foo' into field"],
|
||||
"order_with_respect_to": [
|
||||
'"Dimension" has no attribute "set_component_order"',
|
||||
],
|
||||
'one_to_one': [
|
||||
"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': [
|
||||
"pagination": [
|
||||
'"int" not callable',
|
||||
],
|
||||
'postgres_tests': [
|
||||
'DummyArrayField',
|
||||
'DummyJSONField',
|
||||
"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': [
|
||||
"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'
|
||||
'Argument 2 to "Prefetch" has incompatible type "ValuesQuerySet',
|
||||
],
|
||||
'proxy_models': [
|
||||
'Incompatible types in assignment',
|
||||
'in base class "User"'
|
||||
],
|
||||
'queries': [
|
||||
"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',
|
||||
"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': [
|
||||
"requests": [
|
||||
'Incompatible types in assignment (expression has type "Dict[str, str]", variable has type "QueryDict")'
|
||||
],
|
||||
'responses': [
|
||||
"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': [
|
||||
"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': [
|
||||
"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': [
|
||||
"sites_tests": [
|
||||
'"RequestSite" of "Union[Site, RequestSite]" has no attribute "id"',
|
||||
],
|
||||
'syndication_tests': [
|
||||
"syndication_tests": [
|
||||
'Argument 1 to "add_domain" has incompatible type "*Tuple[object, ...]"',
|
||||
],
|
||||
'sessions_tests': [
|
||||
"sessions_tests": [
|
||||
'Incompatible types in assignment (expression has type "None", variable has type "int")',
|
||||
'"AbstractBaseSession" has no attribute',
|
||||
'"None" not callable',
|
||||
],
|
||||
'select_related': [
|
||||
"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': [
|
||||
"select_related_onetoone": [
|
||||
'Incompatible types in assignment (expression has type "Parent2", variable has type "Parent1")',
|
||||
'"Parent1" has no attribute'
|
||||
'"Parent1" has no attribute',
|
||||
],
|
||||
'servers': [
|
||||
"servers": [
|
||||
re.compile('Argument [0-9] to "WSGIRequestHandler"'),
|
||||
'"HTTPResponse" has no attribute',
|
||||
'"type" has no attribute',
|
||||
'"WSGIRequest" has no attribute "makefile"',
|
||||
'LiveServerAddress',
|
||||
"LiveServerAddress",
|
||||
'"Stub" has no attribute "makefile"',
|
||||
],
|
||||
'serializers': [
|
||||
"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"')
|
||||
re.compile(r'Argument 1 to "(serialize|deserialize)" has incompatible type "None"; expected "str"'),
|
||||
],
|
||||
'string_lookup': [
|
||||
"string_lookup": [
|
||||
'"Bar" has no attribute "place"',
|
||||
],
|
||||
'test_utils': [
|
||||
"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': [
|
||||
"test_client": ['(expression has type "HttpResponse", variable has type "StreamingHttpResponse")'],
|
||||
"test_client_regress": [
|
||||
'(expression has type "Dict[<nothing>, <nothing>]", variable has type "SessionBase")',
|
||||
'Unsupported left operand type for + ("None")',
|
||||
'Argument 1 to "len" has incompatible type "Context"; expected "Sized"',
|
||||
],
|
||||
'transactions': [
|
||||
"transactions": [
|
||||
'Incompatible types in assignment (expression has type "Thread", variable has type "Callable[[], Any]")'
|
||||
],
|
||||
'urlpatterns': [
|
||||
"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': [
|
||||
"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"'
|
||||
'Argument 1 to "get_callable" has incompatible type "int"',
|
||||
],
|
||||
'utils_tests': [
|
||||
"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',
|
||||
"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',
|
||||
"Unsupported target for indexed assignment",
|
||||
'defined the type as "None"',
|
||||
'Argument 1 to "Path" has incompatible type "Optional[str]"',
|
||||
'"None" not callable',
|
||||
@@ -480,18 +490,18 @@ IGNORED_ERRORS = {
|
||||
'Argument 1 to "to_path" has incompatible type "int"; expected "Union[Path, str]"',
|
||||
'Cannot infer type argument 1 of "cached_property"',
|
||||
],
|
||||
'view_tests': [
|
||||
"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',
|
||||
"ExceptionUser",
|
||||
"view_tests.tests.test_debug.User",
|
||||
"Exception must be derived from BaseException",
|
||||
"No binding for nonlocal 'tb_frames' found",
|
||||
],
|
||||
'validation': [
|
||||
"validation": [
|
||||
'has no attribute "name"',
|
||||
],
|
||||
'wsgi': [
|
||||
"wsgi": [
|
||||
'"HttpResponse" has no attribute "block_size"',
|
||||
],
|
||||
}
|
||||
@@ -500,9 +510,9 @@ IGNORED_ERRORS = {
|
||||
def check_if_custom_ignores_are_covered_by_common() -> None:
|
||||
from scripts.typecheck_tests import is_pattern_fits
|
||||
|
||||
common_ignore_patterns = IGNORED_ERRORS['__common__']
|
||||
common_ignore_patterns = IGNORED_ERRORS["__common__"]
|
||||
for module_name, patterns in IGNORED_ERRORS.items():
|
||||
if module_name == '__common__':
|
||||
if module_name == "__common__":
|
||||
continue
|
||||
for pattern in patterns:
|
||||
for common_pattern in common_ignore_patterns:
|
||||
|
||||
31
scripts/git_helpers.py
Normal file
31
scripts/git_helpers.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import shutil
|
||||
from typing import Optional
|
||||
|
||||
from git import RemoteProgress, 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, cur_count, max_count=None, message=""):
|
||||
print(self._cur_line)
|
||||
|
||||
|
||||
def checkout_django_branch(django_version: str, commit_sha: Optional[str]) -> Repo:
|
||||
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(),
|
||||
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(commit_sha)
|
||||
@@ -1,14 +0,0 @@
|
||||
[mypy]
|
||||
strict_optional = True
|
||||
ignore_missing_imports = True
|
||||
check_untyped_defs = True
|
||||
warn_no_return = False
|
||||
show_traceback = True
|
||||
allow_redefinition = True
|
||||
incremental = True
|
||||
|
||||
plugins =
|
||||
mypy_django_plugin.main
|
||||
|
||||
[mypy.plugins.django-stubs]
|
||||
django_settings_module = 'scripts.django_tests_settings'
|
||||
4
scripts/paths.py
Normal file
4
scripts/paths.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from pathlib import Path
|
||||
|
||||
PROJECT_DIRECTORY = Path(__file__).parent.parent
|
||||
DJANGO_SOURCE_DIRECTORY = PROJECT_DIRECTORY / "django-source" # type: Path
|
||||
15
scripts/stubgen-django.py
Normal file
15
scripts/stubgen-django.py
Normal file
@@ -0,0 +1,15 @@
|
||||
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)
|
||||
@@ -3,28 +3,27 @@ from pytest_mypy_plugins.item import YamlTestItem
|
||||
|
||||
|
||||
def django_plugin_hook(test_item: YamlTestItem) -> None:
|
||||
custom_settings = test_item.parsed_test_data.get('custom_settings', '')
|
||||
installed_apps = test_item.parsed_test_data.get('installed_apps', None)
|
||||
custom_settings = test_item.parsed_test_data.get("custom_settings", "")
|
||||
installed_apps = test_item.parsed_test_data.get("installed_apps", None)
|
||||
|
||||
if installed_apps and custom_settings:
|
||||
raise ValueError('"installed_apps" and "custom_settings" are not compatible, please use one or the other')
|
||||
|
||||
if installed_apps is not None:
|
||||
# custom_settings is empty, add INSTALLED_APPS
|
||||
installed_apps += ['django.contrib.contenttypes']
|
||||
installed_apps_as_str = '(' + ','.join([repr(app) for app in installed_apps]) + ',)'
|
||||
custom_settings += 'INSTALLED_APPS = ' + installed_apps_as_str
|
||||
installed_apps += ["django.contrib.contenttypes"]
|
||||
installed_apps_as_str = "(" + ",".join([repr(app) for app in installed_apps]) + ",)"
|
||||
custom_settings += "INSTALLED_APPS = " + installed_apps_as_str
|
||||
|
||||
if 'SECRET_KEY' not in custom_settings:
|
||||
if "SECRET_KEY" not in custom_settings:
|
||||
custom_settings = 'SECRET_KEY = "1"\n' + custom_settings
|
||||
|
||||
django_settings_section = "\n[mypy.plugins.django-stubs]\n" \
|
||||
"django_settings_module = mysettings"
|
||||
django_settings_section = "\n[mypy.plugins.django-stubs]\n" "django_settings_module = mysettings"
|
||||
if not test_item.additional_mypy_config:
|
||||
test_item.additional_mypy_config = django_settings_section
|
||||
else:
|
||||
if '[mypy.plugins.django-stubs]' not in test_item.additional_mypy_config:
|
||||
if "[mypy.plugins.django-stubs]" not in test_item.additional_mypy_config:
|
||||
test_item.additional_mypy_config += django_settings_section
|
||||
|
||||
mysettings_file = File(path='mysettings.py', content=custom_settings)
|
||||
mysettings_file = File(path="mysettings.py", content=custom_settings)
|
||||
test_item.files.append(mysettings_file)
|
||||
|
||||
@@ -4,30 +4,27 @@ import subprocess
|
||||
import sys
|
||||
from argparse import ArgumentParser
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Pattern, Tuple, Union
|
||||
from distutils import spawn
|
||||
from typing import Dict, List, Pattern, Union
|
||||
|
||||
from git import RemoteProgress, Repo
|
||||
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
|
||||
|
||||
from scripts.enabled_test_modules import (
|
||||
EXTERNAL_MODULES, IGNORED_ERRORS, IGNORED_MODULES, MOCK_OBJECTS,
|
||||
)
|
||||
|
||||
DJANGO_COMMIT_REFS: Dict[str, Tuple[str, str]] = {
|
||||
'2.2': ('stable/2.2.x', '8093aaa8ff9dd7386a069c6eb49fcc1c5980c033'),
|
||||
'3.0': ('stable/3.0.x', '44da7abda848f05caaed74f6a749038c87dedfda')
|
||||
DJANGO_COMMIT_REFS: Dict[str, str] = {
|
||||
"2.2": "8093aaa8ff9dd7386a069c6eb49fcc1c5980c033",
|
||||
"3.0": "44da7abda848f05caaed74f6a749038c87dedfda",
|
||||
}
|
||||
PROJECT_DIRECTORY = Path(__file__).parent.parent
|
||||
DJANGO_SOURCE_DIRECTORY = PROJECT_DIRECTORY / 'django-sources' # type: Path
|
||||
|
||||
|
||||
def get_unused_ignores(ignored_message_freq: Dict[str, Dict[Union[str, Pattern], int]]) -> 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}')
|
||||
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
|
||||
|
||||
|
||||
@@ -42,7 +39,7 @@ def is_pattern_fits(pattern: Union[Pattern, str], line: str):
|
||||
|
||||
|
||||
def is_ignored(line: str, test_folder_name: str, *, ignored_message_freqs: Dict[str, Dict[str, int]]) -> bool:
|
||||
if 'runtests' in line:
|
||||
if "runtests" in line:
|
||||
return True
|
||||
|
||||
if test_folder_name in IGNORED_MODULES:
|
||||
@@ -53,83 +50,42 @@ def is_ignored(line: str, test_folder_name: str, *, ignored_message_freqs: Dict[
|
||||
ignored_message_freqs[test_folder_name][pattern] += 1
|
||||
return True
|
||||
|
||||
for pattern in IGNORED_ERRORS['__common__']:
|
||||
for pattern in IGNORED_ERRORS["__common__"]:
|
||||
if is_pattern_fits(pattern, line):
|
||||
ignored_message_freqs['__common__'][pattern] += 1
|
||||
ignored_message_freqs["__common__"][pattern] += 1
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def replace_with_clickable_location(error: str, abs_test_folder: Path) -> str:
|
||||
raw_path, _, error_line = error.partition(': ')
|
||||
fname, _, line_number = raw_path.partition(':')
|
||||
|
||||
try:
|
||||
path = abs_test_folder.joinpath(fname).relative_to(PROJECT_DIRECTORY)
|
||||
except ValueError:
|
||||
# fail on travis, just show an error
|
||||
return error
|
||||
|
||||
clickable_location = f'./{path}:{line_number or 1}'
|
||||
return error.replace(raw_path, clickable_location)
|
||||
|
||||
|
||||
class ProgressPrinter(RemoteProgress):
|
||||
def line_dropped(self, line: str) -> None:
|
||||
print(line)
|
||||
|
||||
def update(self, op_code, cur_count, max_count=None, message=''):
|
||||
print(self._cur_line)
|
||||
|
||||
|
||||
def get_django_repo_object(branch: str) -> Repo:
|
||||
if not DJANGO_SOURCE_DIRECTORY.exists():
|
||||
DJANGO_SOURCE_DIRECTORY.mkdir(exist_ok=True, parents=False)
|
||||
return Repo.clone_from('https://github.com/django/django.git', DJANGO_SOURCE_DIRECTORY,
|
||||
progress=ProgressPrinter(),
|
||||
branch=branch,
|
||||
depth=100)
|
||||
else:
|
||||
repo = Repo(DJANGO_SOURCE_DIRECTORY)
|
||||
return repo
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('--django_version', choices=['2.2', '3.0'], required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
# install proper Django version
|
||||
subprocess.check_call([sys.executable, '-m', 'pip', 'install', f'Django=={args.django_version}.*'])
|
||||
|
||||
branch, commit_sha = DJANGO_COMMIT_REFS[args.django_version]
|
||||
repo = get_django_repo_object(branch)
|
||||
if repo.head.commit.hexsha != commit_sha:
|
||||
repo.remote('origin').fetch(branch, progress=ProgressPrinter(), depth=100)
|
||||
repo.git.checkout(commit_sha)
|
||||
|
||||
mypy_config_file = (PROJECT_DIRECTORY / 'scripts' / 'mypy.ini').absolute()
|
||||
mypy_cache_dir = Path(__file__).parent / '.mypy_cache'
|
||||
tests_root = DJANGO_SOURCE_DIRECTORY / 'tests'
|
||||
parser.add_argument("--django_version", default="3.0")
|
||||
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_config_file.parent / '.mypy_cache'),
|
||||
'--config-file', str(mypy_config_file),
|
||||
'--show-traceback',
|
||||
'--no-error-summary',
|
||||
'--hide-error-context'
|
||||
]
|
||||
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)]
|
||||
|
||||
import distutils.spawn
|
||||
|
||||
mypy_executable = distutils.spawn.find_executable('mypy')
|
||||
mypy_executable = spawn.find_executable("mypy")
|
||||
mypy_argv = [mypy_executable, *mypy_options]
|
||||
completed = subprocess.run(
|
||||
mypy_argv,
|
||||
env={'PYTHONPATH': str(tests_root)},
|
||||
env={"PYTHONPATH": str(tests_root), "TYPECHECK_TESTS": "1"},
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
@@ -140,20 +96,19 @@ if __name__ == '__main__':
|
||||
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]
|
||||
path_to_error = line.split(":")[0]
|
||||
test_folder_name = path_to_error.split("/")[2]
|
||||
except IndexError:
|
||||
test_folder_name = 'unknown'
|
||||
test_folder_name = "unknown"
|
||||
|
||||
if not is_ignored(line, test_folder_name,
|
||||
ignored_message_freqs=ignored_message_freqs):
|
||||
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))
|
||||
print("UNUSED IGNORES ------------------------------------------------")
|
||||
print("\n".join(unused_ignores))
|
||||
|
||||
sys.exit(global_rc)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user