diff --git a/django-stubs/core/files/base.pyi b/django-stubs/core/files/base.pyi index e0a5179..445a70c 100644 --- a/django-stubs/core/files/base.pyi +++ b/django-stubs/core/files/base.pyi @@ -1,12 +1,13 @@ from io import StringIO -from typing import Any, Iterator, Optional, Union +from typing import Any, Iterator, Optional, Union, IO, Type +from types import TracebackType from django.core.files.utils import FileProxyMixin -class File(FileProxyMixin): +class File(FileProxyMixin, IO[Any]): DEFAULT_CHUNK_SIZE: Any = ... file: StringIO = ... - name: Optional[str] = ... + name: str = ... mode: str = ... def __init__(self, file: Any, name: Optional[str] = ...) -> None: ... def __bool__(self) -> bool: ... @@ -15,8 +16,11 @@ class File(FileProxyMixin): def chunks(self, chunk_size: Optional[int] = ...) -> Iterator[Union[bytes, bytearray]]: ... def multiple_chunks(self, chunk_size: Optional[Any] = ...): ... def __iter__(self) -> Iterator[Union[bytes, str]]: ... + def __next__(self) -> Union[bytes, str]: ... def __enter__(self) -> File: ... - def __exit__(self, exc_type: None, exc_value: None, tb: None) -> None: ... + def __exit__( + self, exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], tb: Optional[TracebackType] + ) -> bool: ... def open(self, mode: Optional[str] = ...) -> File: ... def close(self) -> None: ... diff --git a/django-stubs/core/files/images.pyi b/django-stubs/core/files/images.pyi index 5112b6a..3195698 100644 --- a/django-stubs/core/files/images.pyi +++ b/django-stubs/core/files/images.pyi @@ -1,5 +1,4 @@ -from io import BytesIO -from typing import Any, Union +from typing import Any, IO, Union from django.core.files import File @@ -11,4 +10,4 @@ class ImageFile(File): @property def height(self) -> int: ... -def get_image_dimensions(file_or_path: Union[BytesIO, str], close: bool = ...) -> Any: ... +def get_image_dimensions(file_or_path: Union[str, IO[bytes]], close: bool = ...) -> Any: ... diff --git a/django-stubs/core/files/storage.pyi b/django-stubs/core/files/storage.pyi index b4b0242..2fa6627 100644 --- a/django-stubs/core/files/storage.pyi +++ b/django-stubs/core/files/storage.pyi @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Any, IO, List, Optional, Tuple +from typing import Any, List, Optional, Tuple, IO from django.core.files.base import File from django.utils.functional import LazyObject diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py index 1b5c33b..e2d0404 100644 --- a/scripts/typecheck_tests.py +++ b/scripts/typecheck_tests.py @@ -61,6 +61,8 @@ IGNORED_ERRORS = { + 'expected "Union[str, bytes, bytearray]"', 'Incompatible types in assignment (expression has type "None", variable has type Module)', 'note:', + 'undefined in superclass', + '**Dict' ], 'admin_scripts': [ 'Incompatible types in assignment (expression has type "Callable[' @@ -76,7 +78,6 @@ IGNORED_ERRORS = { '"object" not callable', ], 'aggregation': [ - '"as_sql" undefined in superclass', 'Incompatible type for "contact" of "Book" (got "Optional[Author]", expected "Union[Author, Combinable]")', 'Incompatible type for "publisher" of "Book" (got "Optional[Publisher]", ' + 'expected "Union[Publisher, Combinable]")' @@ -114,16 +115,18 @@ IGNORED_ERRORS = { 'dispatch': [ 'Argument 1 to "connect" of "Signal" has incompatible type "object"; expected "Callable[..., Any]"' ], - 'deprecation': [ - re.compile('"(old|new)" undefined in superclass') - ], 'db_functions': [ 'for **', 'expected "float"', 'Incompatible types in assignment (expression has type "Optional[FloatModel]", variable has type "FloatModel")' ], - 'file_uploads': [ - '"handle_uncaught_exception" undefined in superclass' + 'file_storage': [ + 'Incompatible types in assignment (expression has type "Callable[[], Any]"' + ], + 'files': [ + '"file_move_safe" does not return a value', + 'Argument 1 to "unlink" has incompatible type "Optional[str]"; expected "Union[bytes, str, _PathLike[Any]]"', + 'Incompatible types in assignment (expression has type "IOBase", variable has type "File")' ], 'fixtures': [ 'Incompatible types in assignment (expression has type "int", target has type "Iterable[str]")' @@ -132,7 +135,6 @@ IGNORED_ERRORS = { 'List item 0 has incompatible type "Jinja2"; expected "DjangoTemplates"', 'Not enough arguments for format string', 'Argument after ** must be a mapping, not "object"', - '"media" undefined in superclass', 'expression has type "None", base class "TestFormParent"', 'variable has type "SongForm"', '"full_clean" of "BaseForm" does not return a value', @@ -158,16 +160,9 @@ IGNORED_ERRORS = { + 'expected "Union[Type[], QuerySet[, ]]"', 'CustomClass' ], - 'get_or_create': [ - 'Argument 1 to "update_or_create" of "QuerySet" has incompatible type "**Dict[str, object]"; ' - + 'expected "Optional[MutableMapping[str, Any]]"' - ], 'humanize_tests': [ 'Argument 1 to "append" of "list" has incompatible type "None"; expected "str"' ], - 'logging_tests': [ - re.compile('"(setUpClass|tearDownClass)" undefined in superclass') - ], 'lookup': [ 'Unexpected keyword argument "headline__startswith" for "in_bulk" of "QuerySet"', ], @@ -385,9 +380,9 @@ TESTS_DIRS = [ 'field_deconstruction', 'field_defaults', 'field_subclassing', - # TODO: 'file_storage', + 'file_storage', 'file_uploads', - # TODO: 'files', + 'files', 'filtered_relation', 'fixtures', 'fixtures_model_package',