Fix overloads and remove PathLike in finders (#1063)

* Fix overloads in finders

Signed-off-by: Anders Kaseorg <andersk@mit.edu>

* 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 <andersk@mit.edu>
This commit is contained in:
Anders Kaseorg
2022-07-22 00:35:24 -07:00
committed by GitHub
parent 563e947402
commit 3d8d900487
2 changed files with 27 additions and 30 deletions

View File

@@ -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.checks.messages import CheckMessage
from django.core.files.storage import FileSystemStorage, Storage from django.core.files.storage import FileSystemStorage, Storage
from django.utils._os import _PathCompatible
if sys.version_info < (3, 8): if sys.version_info < (3, 8):
from typing_extensions import Literal from typing_extensions import Literal
@@ -15,44 +14,42 @@ searched_locations: Any
class BaseFinder: class BaseFinder:
def check(self, **kwargs: Any) -> List[CheckMessage]: ... def check(self, **kwargs: Any) -> List[CheckMessage]: ...
@overload @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 @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]: ... def list(self, ignore_patterns: Optional[Iterable[str]]) -> Iterable[Any]: ...
class FileSystemFinder(BaseFinder): class FileSystemFinder(BaseFinder):
locations: List[Tuple[str, _PathCompatible]] = ... locations: List[Tuple[str, str]] = ...
storages: Dict[_PathCompatible, Any] = ... storages: Dict[str, Any] = ...
def __init__(self, app_names: Sequence[str] = ..., *args: Any, **kwargs: Any) -> None: ... def __init__(self, app_names: Sequence[str] = ..., *args: Any, **kwargs: Any) -> None: ...
def find_location( def find_location(self, root: str, path: str, prefix: Optional[str] = ...) -> Optional[str]: ...
self, root: _PathCompatible, path: str, prefix: Optional[str] = ...
) -> Optional[_PathCompatible]: ...
@overload @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 @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]: ... def list(self, ignore_patterns: Optional[Iterable[str]]) -> Iterable[Any]: ...
class AppDirectoriesFinder(BaseFinder): class AppDirectoriesFinder(BaseFinder):
storage_class: Type[FileSystemStorage] = ... storage_class: Type[FileSystemStorage] = ...
source_dir: str = ... source_dir: str = ...
apps: List[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 __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 @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 @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]: ... def list(self, ignore_patterns: Optional[Iterable[str]]) -> Iterable[Any]: ...
class BaseStorageFinder(BaseFinder): class BaseStorageFinder(BaseFinder):
storage: Storage = ... storage: Storage = ...
def __init__(self, storage: Optional[Storage] = ..., *args: Any, **kwargs: Any) -> None: ... def __init__(self, storage: Optional[Storage] = ..., *args: Any, **kwargs: Any) -> None: ...
@overload @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 @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]: ... def list(self, ignore_patterns: Optional[Iterable[str]]) -> Iterable[Any]: ...
class DefaultStorageFinder(BaseStorageFinder): class DefaultStorageFinder(BaseStorageFinder):
@@ -60,9 +57,9 @@ class DefaultStorageFinder(BaseStorageFinder):
def __init__(self, *args: Any, **kwargs: Any) -> None: ... def __init__(self, *args: Any, **kwargs: Any) -> None: ...
@overload @overload
def find(path: _PathCompatible, all: Literal[False] = False) -> Optional[_PathCompatible]: ... # type: ignore def find(path: str, all: Literal[False] = ...) -> Optional[str]: ...
@overload @overload
def find(path: _PathCompatible, all: Literal[True] = ...) -> List[_PathCompatible]: ... def find(path: str, all: Literal[True]) -> List[str]: ...
def get_finders() -> Iterator[BaseFinder]: ... def get_finders() -> Iterator[BaseFinder]: ...
@overload @overload
def get_finder( def get_finder(

View File

@@ -2,38 +2,38 @@
main: | main: |
from django.contrib.staticfiles import finders 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(): 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.FileSystemFinder().find("filepath")) # N: Revealed type is "Union[builtins.str, None]"
reveal_type(finders.AppDirectoriesFinder().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, None]"
reveal_type(finders.DefaultStorageFinder().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, None]"
- case: test_find_all - case: test_find_all
main: | main: |
from django.contrib.staticfiles import finders 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(): 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.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[Union[builtins.str, os.PathLike[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[Union[builtins.str, os.PathLike[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 - case: test_file_system_finder # test methods *only* on FileSystemFinder
main: | main: |
from django.contrib.staticfiles.finders import FileSystemFinder from django.contrib.staticfiles.finders import FileSystemFinder
finder = 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 - case: test_app_directories_finder # test methods *only* on AppDirectoriesFinder
main: | main: |
from django.contrib.staticfiles.finders import AppDirectoriesFinder from django.contrib.staticfiles.finders import AppDirectoriesFinder
finder = 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]"