1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
|
from __future__ import annotations
import fnmatch
import ntpath
from typing import TYPE_CHECKING, Any, Callable, overload
if TYPE_CHECKING:
from typing_extensions import Literal
@overload
def load(param: None) -> Null: ...
@overload
def load(param: str) -> Pattern: ...
@overload
def load(param: Any) -> Any: ...
def load(param):
"""
If the supplied parameter is a string, assume it's a simple
pattern.
"""
return (
Pattern(param)
if isinstance(param, str)
else param
if param is not None
else Null()
)
class Base:
pass
class Null(Base):
def __call__(self, path: str) -> Literal[True]:
return True
class Pattern(Base):
pattern: str
_pattern: str
def __init__(self, pattern: str):
self.pattern = pattern
def get_pattern(self, normcase: Callable[[str], str]) -> str:
try:
return self._pattern
except AttributeError:
pass
self._pattern = normcase(self.pattern)
return self._pattern
# NOTE: 'path' should be annotated with Path, but cannot due to circular imports.
def __call__(self, path) -> bool:
normcase = getattr(self, 'normcase', path.module.normcase)
pattern = self.get_pattern(normcase)
return fnmatch.fnmatchcase(normcase(path.name), pattern)
class CaseInsensitive(Pattern):
"""
A Pattern with a ``'normcase'`` property, suitable for passing to
:meth:`iterdir`, :meth:`dirs`, :meth:`files`, :meth:`walk`,
:meth:`walkdirs`, or :meth:`walkfiles` to match case-insensitive.
For example, to get all files ending in .py, .Py, .pY, or .PY in the
current directory::
from path import Path, matchers
Path('.').files(matchers.CaseInsensitive('*.py'))
"""
normcase = staticmethod(ntpath.normcase)
|