From 3d8d9004874bc09308cce0f1e0fd5507782c9bb8 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Fri, 22 Jul 2022 00:35:24 -0700 Subject: [PATCH] Fix overloads and remove `PathLike` in `finders` (#1063) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix overloads in finders Signed-off-by: Anders Kaseorg * Remove PathLike from finders Django really requires these paths to be str. For example, in FileSystemFinder, .find(path) calls .find_location(…, path, …) which evaluates path.startswith(prefix) and path[len(prefix) :]; these don’t work on arbitrary PathLike objects. Signed-off-by: Anders Kaseorg --- django-stubs/contrib/staticfiles/finders.pyi | 33 +++++++++---------- .../contrib/staticfiles/test_finders.yml | 24 +++++++------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/django-stubs/contrib/staticfiles/finders.pyi b/django-stubs/contrib/staticfiles/finders.pyi index 5a9d505b5..02691bda2 100644 --- a/django-stubs/contrib/staticfiles/finders.pyi +++ b/django-stubs/contrib/staticfiles/finders.pyi @@ -3,7 +3,6 @@ from typing import Any, Dict, Iterable, Iterator, List, Optional, Sequence, Tupl from django.core.checks.messages import CheckMessage from django.core.files.storage import FileSystemStorage, Storage -from django.utils._os import _PathCompatible if sys.version_info < (3, 8): from typing_extensions import Literal @@ -15,44 +14,42 @@ searched_locations: Any class BaseFinder: def check(self, **kwargs: Any) -> List[CheckMessage]: ... @overload - def find(self, path: _PathCompatible, all: Literal[False] = False) -> Optional[_PathCompatible]: ... # type: ignore + def find(self, path: str, all: Literal[False] = ...) -> Optional[str]: ... @overload - def find(self, path: _PathCompatible, all: Literal[True] = ...) -> List[_PathCompatible]: ... + def find(self, path: str, all: Literal[True]) -> List[str]: ... def list(self, ignore_patterns: Optional[Iterable[str]]) -> Iterable[Any]: ... class FileSystemFinder(BaseFinder): - locations: List[Tuple[str, _PathCompatible]] = ... - storages: Dict[_PathCompatible, Any] = ... + locations: List[Tuple[str, str]] = ... + storages: Dict[str, Any] = ... def __init__(self, app_names: Sequence[str] = ..., *args: Any, **kwargs: Any) -> None: ... - def find_location( - self, root: _PathCompatible, path: str, prefix: Optional[str] = ... - ) -> Optional[_PathCompatible]: ... + def find_location(self, root: str, path: str, prefix: Optional[str] = ...) -> Optional[str]: ... @overload - def find(self, path: _PathCompatible, all: Literal[False] = False) -> Optional[_PathCompatible]: ... # type: ignore + def find(self, path: str, all: Literal[False] = ...) -> Optional[str]: ... @overload - def find(self, path: _PathCompatible, all: Literal[True] = ...) -> List[_PathCompatible]: ... + def find(self, path: str, all: Literal[True]) -> List[str]: ... def list(self, ignore_patterns: Optional[Iterable[str]]) -> Iterable[Any]: ... class AppDirectoriesFinder(BaseFinder): storage_class: Type[FileSystemStorage] = ... source_dir: str = ... apps: List[str] = ... - storages: Dict[_PathCompatible, FileSystemStorage] = ... + storages: Dict[str, FileSystemStorage] = ... def __init__(self, app_names: Optional[Iterable[str]] = ..., *args: Any, **kwargs: Any) -> None: ... - def find_in_app(self, app: str, path: _PathCompatible) -> Optional[_PathCompatible]: ... + def find_in_app(self, app: str, path: str) -> Optional[str]: ... @overload - def find(self, path: _PathCompatible, all: Literal[False] = False) -> Optional[_PathCompatible]: ... # type: ignore + def find(self, path: str, all: Literal[False] = ...) -> Optional[str]: ... @overload - def find(self, path: _PathCompatible, all: Literal[True] = ...) -> List[_PathCompatible]: ... + def find(self, path: str, all: Literal[True]) -> List[str]: ... def list(self, ignore_patterns: Optional[Iterable[str]]) -> Iterable[Any]: ... class BaseStorageFinder(BaseFinder): storage: Storage = ... def __init__(self, storage: Optional[Storage] = ..., *args: Any, **kwargs: Any) -> None: ... @overload - def find(self, path: _PathCompatible, all: Literal[False] = False) -> Optional[_PathCompatible]: ... # type: ignore + def find(self, path: str, all: Literal[False] = ...) -> Optional[str]: ... @overload - def find(self, path: _PathCompatible, all: Literal[True] = ...) -> List[_PathCompatible]: ... + def find(self, path: str, all: Literal[True]) -> List[str]: ... def list(self, ignore_patterns: Optional[Iterable[str]]) -> Iterable[Any]: ... class DefaultStorageFinder(BaseStorageFinder): @@ -60,9 +57,9 @@ class DefaultStorageFinder(BaseStorageFinder): def __init__(self, *args: Any, **kwargs: Any) -> None: ... @overload -def find(path: _PathCompatible, all: Literal[False] = False) -> Optional[_PathCompatible]: ... # type: ignore +def find(path: str, all: Literal[False] = ...) -> Optional[str]: ... @overload -def find(path: _PathCompatible, all: Literal[True] = ...) -> List[_PathCompatible]: ... +def find(path: str, all: Literal[True]) -> List[str]: ... def get_finders() -> Iterator[BaseFinder]: ... @overload def get_finder( diff --git a/tests/typecheck/contrib/staticfiles/test_finders.yml b/tests/typecheck/contrib/staticfiles/test_finders.yml index 04dc5a48c..dc9bae135 100644 --- a/tests/typecheck/contrib/staticfiles/test_finders.yml +++ b/tests/typecheck/contrib/staticfiles/test_finders.yml @@ -2,38 +2,38 @@ main: | from django.contrib.staticfiles import finders - reveal_type(finders.find("filepath")) # N: Revealed type is "Union[builtins.str, os.PathLike[builtins.str], None]" + reveal_type(finders.find("filepath")) # N: Revealed type is "Union[builtins.str, None]" for finder in finders.get_finders(): - reveal_type(finder.find("filepath")) # N: Revealed type is "Union[builtins.str, os.PathLike[builtins.str], None]" + reveal_type(finder.find("filepath")) # N: Revealed type is "Union[builtins.str, None]" - reveal_type(finders.FileSystemFinder().find("filepath")) # N: Revealed type is "Union[builtins.str, os.PathLike[builtins.str], None]" - reveal_type(finders.AppDirectoriesFinder().find("filepath")) # N: Revealed type is "Union[builtins.str, os.PathLike[builtins.str], None]" - reveal_type(finders.DefaultStorageFinder().find("filepath")) # N: Revealed type is "Union[builtins.str, os.PathLike[builtins.str], None]" + reveal_type(finders.FileSystemFinder().find("filepath")) # N: Revealed type is "Union[builtins.str, None]" + reveal_type(finders.AppDirectoriesFinder().find("filepath")) # N: Revealed type is "Union[builtins.str, None]" + reveal_type(finders.DefaultStorageFinder().find("filepath")) # N: Revealed type is "Union[builtins.str, None]" - case: test_find_all main: | from django.contrib.staticfiles import finders - reveal_type(finders.find("filepath", all=True)) # N: Revealed type is "builtins.list[Union[builtins.str, os.PathLike[builtins.str]]]" + reveal_type(finders.find("filepath", all=True)) # N: Revealed type is "builtins.list[builtins.str]" for finder in finders.get_finders(): - reveal_type(finder.find("filepath", all=True)) # N: Revealed type is "builtins.list[Union[builtins.str, os.PathLike[builtins.str]]]" + reveal_type(finder.find("filepath", all=True)) # N: Revealed type is "builtins.list[builtins.str]" - reveal_type(finders.FileSystemFinder().find("filepath", all=True)) # N: Revealed type is "builtins.list[Union[builtins.str, os.PathLike[builtins.str]]]" - reveal_type(finders.AppDirectoriesFinder().find("filepath", all=True)) # N: Revealed type is "builtins.list[Union[builtins.str, os.PathLike[builtins.str]]]" - reveal_type(finders.DefaultStorageFinder().find("filepath", all=True)) # N: Revealed type is "builtins.list[Union[builtins.str, os.PathLike[builtins.str]]]" + reveal_type(finders.FileSystemFinder().find("filepath", all=True)) # N: Revealed type is "builtins.list[builtins.str]" + reveal_type(finders.AppDirectoriesFinder().find("filepath", all=True)) # N: Revealed type is "builtins.list[builtins.str]" + reveal_type(finders.DefaultStorageFinder().find("filepath", all=True)) # N: Revealed type is "builtins.list[builtins.str]" - case: test_file_system_finder # test methods *only* on FileSystemFinder main: | from django.contrib.staticfiles.finders import FileSystemFinder finder = FileSystemFinder() - reveal_type(finder.find_location(".", "filepath")) # N: Revealed type is "Union[builtins.str, os.PathLike[builtins.str], None]" + reveal_type(finder.find_location(".", "filepath")) # N: Revealed type is "Union[builtins.str, None]" - case: test_app_directories_finder # test methods *only* on AppDirectoriesFinder main: | from django.contrib.staticfiles.finders import AppDirectoriesFinder finder = AppDirectoriesFinder() - reveal_type(finder.find_in_app("app", "filepath")) # N: Revealed type is "Union[builtins.str, os.PathLike[builtins.str], None]" + reveal_type(finder.find_in_app("app", "filepath")) # N: Revealed type is "Union[builtins.str, None]"