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:
Na'aman Hirschfeld
2020-10-29 09:59:48 +01:00
committed by GitHub
parent a3624dec36
commit 44151c485d
74 changed files with 1141 additions and 1446 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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
View 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)

View File

@@ -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
View 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
View 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)

View File

@@ -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)

View 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)