add tests for the django test suite

This commit is contained in:
Maxim Kurnikov
2019-01-26 17:17:35 +03:00
parent 38e841c4c7
commit 1afa079b0b
18 changed files with 232 additions and 57 deletions

View File

@@ -7,21 +7,21 @@ sudo: required
jobs:
include:
- name: "Run plugin test suite with python 3.7"
python: 3.7
script: |
set -e
pytest
- name: "Typecheck Django test suite"
python: 3.7
script: |
xonsh ./scripts/typecheck_django_tests.xsh
- name: "Lint with black"
python: 3.7
script: |
black --check --line-length=120 django-stubs/
- name: "Run plugin test suite with python 3.7"
python: 3.7
script: |
set -e
pytest
# - name: "Typecheck Django test suite"
# python: 3.7
# script: |
# xonsh ./scripts/typecheck_django_tests.xsh
- name: "Lint with black"
python: 3.7
script: |
black --check --line-length=120 django-stubs/
before_install: |
# Upgrade pip, setuptools, and wheel

View File

@@ -1,4 +1,5 @@
from typing import Any
from django.utils.version import get_version as get_version
VERSION: Any

View File

@@ -1,7 +1,7 @@
# Stubs for django.conf.urls (Python 3.5)
from typing import Any, Callable, Dict, List, Optional, overload, Tuple, Union
from django.http.response import HttpResponse
from django.http.response import HttpResponse, HttpResponseBase
from django.urls import URLResolver, URLPattern
@@ -14,7 +14,9 @@ IncludedURLConf = Tuple[List[URLResolver], Optional[str], Optional[str]]
def include(arg: Any, namespace: str = ..., app_name: str = ...) -> IncludedURLConf: ...
@overload
def url(regex: str, view: Callable[..., HttpResponse], kwargs: Dict[str, Any] = ..., name: str = ...) -> URLPattern: ...
def url(
regex: str, view: Callable[..., HttpResponseBase], kwargs: Dict[str, Any] = ..., name: str = ...
) -> URLPattern: ...
@overload
def url(regex: str, view: IncludedURLConf, kwargs: Dict[str, Any] = ..., name: str = ...) -> URLResolver: ...
@overload

View File

@@ -0,0 +1 @@
from .messages import Warning as Warning, Info as Info, Debug as Debug, Error as Error, Critical as Critical

View File

@@ -1,4 +1,4 @@
from typing import Any, Optional, Union
from typing import Any, Optional
DEBUG: int
INFO: int

View File

@@ -1,4 +1,4 @@
from typing import Any, List, Optional
from typing import Any, List
from django.core.checks.messages import Warning

View File

@@ -31,10 +31,15 @@ class FileSystemStorage(Storage):
file_permissions_mode: Optional[int] = ...,
directory_permissions_mode: Optional[int] = ...,
) -> None: ...
@property
def base_location(self) -> str: ...
@property
def location(self) -> str: ...
@property
def base_url(self) -> str: ...
@property
def file_permissions_mode(self) -> Optional[int]: ...
@property
def directory_permissions_mode(self) -> Optional[int]: ...
class DefaultStorage(LazyObject): ...

View File

@@ -1,6 +1,6 @@
from typing import Any, Dict, List, Optional, Tuple, Union
from django.core.management.base import BaseCommand as BaseCommand
from django.core.management.base import BaseCommand as BaseCommand, CommandError as CommandError
def find_commands(management_dir: str) -> List[str]: ...
def load_command_class(app_name: str, name: str) -> BaseCommand: ...

View File

@@ -60,7 +60,7 @@ class BaseCommand:
def add_arguments(self, parser: CommandParser) -> None: ...
def print_help(self, prog_name: str, subcommand: str) -> None: ...
def run_from_argv(self, argv: List[str]) -> None: ...
def execute(self, *args: Any, **options: Any) -> Optional[Union[Tuple, str]]: ...
def execute(self, *args: Any, **options: Any) -> Any: ...
def check(
self,
app_configs: Optional[List[AppConfig]] = ...,

View File

@@ -11,6 +11,7 @@ from .utils import (
NotSupportedError as NotSupportedError,
InternalError as InternalError,
InterfaceError as InterfaceError,
ConnectionHandler as ConnectionHandler,
)
from . import migrations

View File

@@ -1,9 +1,35 @@
from typing import Any, Optional
from typing import Any, Optional, Tuple, Iterable, Callable, Dict, Union
from django.db.models.query_utils import RegisterLookupMixin
_Choice = Tuple[Any, str]
_ChoiceNamedGroup = Tuple[str, Iterable[_Choice]]
_FieldChoices = Iterable[Union[_Choice, _ChoiceNamedGroup]]
_ValidatorCallable = Callable[[...], None]
_ErrorMessagesToOverride = Dict[str, Any]
class Field(RegisterLookupMixin):
def __init__(self, **kwargs: Any): ...
def __init__(
self,
verbose_name: Optional[str] = ...,
name: Optional[str] = ...,
primary_key: bool = ...,
unique: bool = ...,
blank: bool = ...,
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
choices: Optional[_FieldChoices] = ...,
help_text: str = ...,
db_column: Optional[str] = ...,
db_tablespace: Optional[str] = ...,
validators: Iterable[_ValidatorCallable] = ...,
error_messages: Optional[_ErrorMessagesToOverride] = ...,
): ...
def __get__(self, instance, owner) -> Any: ...
class IntegerField(Field):
@@ -19,24 +45,83 @@ class BigIntegerField(IntegerField): ...
class FloatField(Field): ...
class DecimalField(IntegerField):
def __init__(self, *, max_digits: Optional[int] = ..., decimal_places: Optional[int] = ..., **kwargs): ...
def __init__(
self,
verbose_name: Optional[str] = ...,
name: Optional[str] = ...,
max_digits: Optional[int] = ...,
decimal_places: Optional[int] = ...,
primary_key: bool = ...,
unique: bool = ...,
blank: bool = ...,
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
choices: Optional[_FieldChoices] = ...,
help_text: str = ...,
db_column: Optional[str] = ...,
db_tablespace: Optional[str] = ...,
validators: Iterable[_ValidatorCallable] = ...,
error_messages: Optional[_ErrorMessagesToOverride] = ...,
): ...
class AutoField(Field):
def __get__(self, instance, owner) -> int: ...
class CharField(Field):
def __init__(self, max_length: int = ..., **kwargs: Any): ...
def __init__(
self,
verbose_name: Optional[str] = ...,
name: Optional[str] = ...,
primary_key: bool = ...,
max_length: Optional[int] = ...,
unique: bool = ...,
blank: bool = ...,
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
choices: Optional[_FieldChoices] = ...,
help_text: str = ...,
db_column: Optional[str] = ...,
db_tablespace: Optional[str] = ...,
validators: Iterable[_ValidatorCallable] = ...,
error_messages: Optional[_ErrorMessagesToOverride] = ...,
): ...
def __set__(self, instance, value: str) -> None: ...
def __get__(self, instance, owner) -> str: ...
class SlugField(CharField):
def __init__(self, max_length: int = ..., **kwargs: Any): ...
def __init__(
self,
verbose_name: Optional[str] = ...,
name: Optional[str] = ...,
primary_key: bool = ...,
max_length: Optional[int] = ...,
allow_unicode: bool = ...,
unique: bool = ...,
blank: bool = ...,
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
choices: Optional[_FieldChoices] = ...,
help_text: str = ...,
db_column: Optional[str] = ...,
db_tablespace: Optional[str] = ...,
validators: Iterable[_ValidatorCallable] = ...,
error_messages: Optional[_ErrorMessagesToOverride] = ...,
): ...
class EmailField(CharField):
def __init__(self, max_length: int = ..., **kwargs: Any): ...
class URLField(CharField):
def __init__(self, max_length: int = ..., **kwargs: Any): ...
class EmailField(CharField): ...
class URLField(CharField): ...
class TextField(Field):
def __set__(self, instance, value: str) -> None: ...
@@ -63,7 +148,21 @@ class GenericIPAddressField(Field):
name: Optional[Any] = ...,
protocol: str = ...,
unpack_ipv4: bool = ...,
**kwargs: Any
primary_key: bool = ...,
unique: bool = ...,
blank: bool = ...,
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
choices: Optional[_FieldChoices] = ...,
help_text: str = ...,
db_column: Optional[str] = ...,
db_tablespace: Optional[str] = ...,
validators: Iterable[_ValidatorCallable] = ...,
error_messages: Optional[_ErrorMessagesToOverride] = ...,
) -> None: ...
class DateTimeCheckMixin: ...
@@ -75,7 +174,21 @@ class DateField(DateTimeCheckMixin, Field):
name: Optional[str] = ...,
auto_now: bool = ...,
auto_now_add: bool = ...,
**kwargs
primary_key: bool = ...,
unique: bool = ...,
blank: bool = ...,
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
choices: Optional[_FieldChoices] = ...,
help_text: str = ...,
db_column: Optional[str] = ...,
db_tablespace: Optional[str] = ...,
validators: Iterable[_ValidatorCallable] = ...,
error_messages: Optional[_ErrorMessagesToOverride] = ...,
): ...
class TimeField(DateTimeCheckMixin, Field): ...
@@ -92,10 +205,22 @@ class FilePathField(Field):
recursive: bool = ...,
allow_files: bool = ...,
allow_folders: bool = ...,
**kwargs
primary_key: bool = ...,
unique: bool = ...,
blank: bool = ...,
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
choices: Optional[_FieldChoices] = ...,
help_text: str = ...,
db_column: Optional[str] = ...,
db_tablespace: Optional[str] = ...,
validators: Iterable[_ValidatorCallable] = ...,
error_messages: Optional[_ErrorMessagesToOverride] = ...,
): ...
class BinaryField(Field):
def __init__(self, editable: bool = ..., **kwargs: Any): ...
class BinaryField(Field): ...
class DurationField(Field): ...

View File

@@ -1,3 +1,5 @@
from django.core.exceptions import ValidationError as ValidationError
from .forms import Form as Form, BaseForm as BaseForm
from .models import ModelForm as ModelForm

View File

@@ -1,6 +1,6 @@
from typing import Any, Dict, Iterator, Optional, List
from django.template.base import Template
from django.template.base import Template as Template
from django.template.exceptions import TemplateDoesNotExist
from django.template.engine import Engine

View File

@@ -1,6 +1,6 @@
from typing import Callable, Dict, List, Optional, Tuple, Any
from django.template.base import Template
from django.template.base import Template as Template
from django.template.exceptions import TemplateSyntaxError
from .base import BaseEngine

View File

@@ -51,5 +51,5 @@ class Engine:
) -> Tuple[Template, Origin]: ...
def from_string(self, template_code: str) -> Template: ...
def get_template(self, template_name: str) -> Template: ...
def render_to_string(self, template_name: str, context: Any = ...) -> SafeText: ...
def render_to_string(self, template_name: str, context: Optional[Dict[str, Any]] = ...) -> SafeText: ...
def select_template(self, template_name_list: List[str]) -> Template: ...

View File

@@ -1,19 +1,12 @@
from typing import Dict, List, Optional, Union
from typing import Dict, List, Optional, Union, Any
from django.core.handlers.wsgi import WSGIRequest
from django.template.backends.django import Template as DjangoTemplate
from django.template.backends.dummy import Template as DummyTemplate
from django.template.backends.jinja2 import Template as Jinja2Template
def get_template(
template_name: str, using: Optional[str] = ...
) -> Union[DjangoTemplate, DummyTemplate, Jinja2Template]: ...
def select_template(
template_name_list: Union[List[str], str], using: Optional[str] = ...
) -> Union[DjangoTemplate, DummyTemplate, Jinja2Template]: ...
def get_template(template_name: str, using: Optional[str] = ...) -> Any: ...
def select_template(template_name_list: Union[List[str], str], using: Optional[str] = ...) -> Any: ...
def render_to_string(
template_name: Union[List[str], str],
context: Optional[Union[Dict[str, bool], Dict[str, str]]] = ...,
context: Optional[Dict[str, Any]] = ...,
request: Optional[WSGIRequest] = ...,
using: Optional[str] = ...,
) -> str: ...

View File

@@ -5,6 +5,6 @@ from .testcases import (
LiveServerTestCase as LiveServerTestCase,
)
from .utils import override_settings as override_settings
from .utils import override_settings as override_settings, modify_settings as modify_settings
from .client import Client as Client

View File

@@ -2,10 +2,55 @@ import os
if not os.path.exists('./django-sources'):
git clone -b stable/2.1.x https://github.com/django/django.git django-sources
ignored_error_patterns = ["Need type annotation for", "already defined on", "Cannot assign to a"]
for line in $(mypy --config-file ./scripts/mypy.ini ./django-sources/tests).split('\n'):
for pattern in ignored_error_patterns:
if pattern in line:
break
else:
print(line)
IGNORED_ERROR_PATTERNS = [
'Need type annotation for',
'already defined on',
'Cannot assign to a',
'cannot perform relative import',
'broken_app',
'LazySettings',
'Cannot infer type of lambda',
'Incompatible types in assignment (expression has type "Callable[',
'"Callable[[Any], Any]" has no attribute',
'Invalid value for a to= parameter'
]
TESTS_DIRS = [
'absolute_url_overrides',
'admin_*',
'aggregation*',
'annotations'
]
def check_file_in_the_current_directory(directory, fname):
cd @(directory)
with ${...}.swap(FNAME=fname):
for line in $(mypy --config-file ../../../scripts/mypy.ini $FNAME).split('\n'):
for pattern in IGNORED_ERROR_PATTERNS:
if pattern in line:
break
else:
if line:
print(line)
cd -
def parse_ls_output_into_fnames(output):
fnames = []
for line in output.splitlines()[1:]:
fnames.append(line.split()[-1])
return fnames
all_tests_dirs = []
for test_dir in TESTS_DIRS:
with ${...}.swap(TEST_DIR=test_dir):
dirs = g`django-sources/tests/$TEST_DIR`
all_tests_dirs.extend(dirs)
for tests_dir in all_tests_dirs:
print('Checking ' + tests_dir)
abs_dir = os.path.join(os.getcwd(), tests_dir)
with ${...}.swap(ABS_DIR=abs_dir):
ls_output = $(ls $ABS_DIR)
for fname in parse_ls_output_into_fnames(ls_output):
path_to_check = os.path.join(abs_dir, fname)
check_file_in_the_current_directory(abs_dir, fname)