4949from upath .types import WritablePath
5050from upath .types import WritablePathLike
5151
52+ if sys .version_info >= (3 , 13 ):
53+ from pathlib import UnsupportedOperation
54+ else :
55+ UnsupportedOperation = NotImplementedError
56+ """Raised when an unsupported operation is called on a path object."""
57+
5258if TYPE_CHECKING :
5359 import upath .implementations as _uimpl
5460
6369 _MT = TypeVar ("_MT" )
6470 _WT = TypeVar ("_WT" , bound = "WritablePath" )
6571
66- __all__ = ["UPath" ]
72+ __all__ = [
73+ "UPath" ,
74+ "UnsupportedOperation" ,
75+ ]
6776
6877_FSSPEC_HAS_WORKING_GLOB = None
6978
@@ -103,7 +112,7 @@ def _buffering2blocksize(mode: str, buffering: int) -> int | None:
103112
104113
105114def _raise_unsupported (cls_name : str , method : str ) -> NoReturn :
106- raise NotImplementedError (f"{ cls_name } .{ method } () is unsupported" )
115+ raise UnsupportedOperation (f"{ cls_name } .{ method } () is unsupported" )
107116
108117
109118class _UPathMeta (ABCMeta ):
@@ -311,7 +320,7 @@ def path(self) -> str:
311320 # For relative paths, we need to resolve to absolute path
312321 current_dir = self .cwd () # type: ignore[attr-defined]
313322 except NotImplementedError :
314- raise NotImplementedError (
323+ raise UnsupportedOperation (
315324 f"fsspec paths can not be relative and"
316325 f" { type (self ).__name__ } .cwd() is unsupported"
317326 ) from None
@@ -1513,20 +1522,20 @@ def glob(
15131522 self ,
15141523 pattern : str ,
15151524 * ,
1516- case_sensitive : bool = UNSET_DEFAULT ,
1517- recurse_symlinks : bool = UNSET_DEFAULT ,
1525+ case_sensitive : bool | None = None ,
1526+ recurse_symlinks : bool = False ,
15181527 ) -> Iterator [Self ]:
15191528 """Iterate over this subtree and yield all existing files (of any
15201529 kind, including directories) matching the given relative pattern."""
1521- if case_sensitive is not UNSET_DEFAULT :
1530+ if case_sensitive is not None :
15221531 warnings .warn (
15231532 "UPath.glob(): case_sensitive is currently ignored." ,
15241533 UserWarning ,
15251534 stacklevel = 2 ,
15261535 )
1527- if recurse_symlinks is not UNSET_DEFAULT :
1536+ if recurse_symlinks :
15281537 warnings .warn (
1529- "UPath.glob(): recurse_symlinks is currently ignored." ,
1538+ "UPath.glob(): recurse_symlinks=True is currently ignored." ,
15301539 UserWarning ,
15311540 stacklevel = 2 ,
15321541 )
@@ -1543,22 +1552,22 @@ def rglob(
15431552 self ,
15441553 pattern : str ,
15451554 * ,
1546- case_sensitive : bool = UNSET_DEFAULT ,
1547- recurse_symlinks : bool = UNSET_DEFAULT ,
1555+ case_sensitive : bool | None = None ,
1556+ recurse_symlinks : bool = False ,
15481557 ) -> Iterator [Self ]:
15491558 """Recursively yield all existing files (of any kind, including
15501559 directories) matching the given relative pattern, anywhere in
15511560 this subtree.
15521561 """
1553- if case_sensitive is not UNSET_DEFAULT :
1562+ if case_sensitive is not None :
15541563 warnings .warn (
15551564 "UPath.glob(): case_sensitive is currently ignored." ,
15561565 UserWarning ,
15571566 stacklevel = 2 ,
15581567 )
1559- if recurse_symlinks is not UNSET_DEFAULT :
1568+ if recurse_symlinks :
15601569 warnings .warn (
1561- "UPath.glob(): recurse_symlinks is currently ignored." ,
1570+ "UPath.glob(): recurse_symlinks=True is currently ignored." ,
15621571 UserWarning ,
15631572 stacklevel = 2 ,
15641573 )
@@ -1971,13 +1980,39 @@ def is_relative_to(
19711980 return self == other or other in self .parents
19721981
19731982 def hardlink_to (self , target : ReadablePathLike ) -> None :
1974- raise NotImplementedError
1983+ _raise_unsupported (type (self ).__name__ , "hardlink_to" )
1984+
1985+ def full_match (
1986+ self ,
1987+ pattern : str | SupportsPathLike ,
1988+ * ,
1989+ case_sensitive : bool | None = None ,
1990+ ) -> bool :
1991+ """Match this path against the provided glob-style pattern.
1992+ Return True if matching is successful, False otherwise.
1993+ """
1994+ if case_sensitive is not None :
1995+ warnings .warn (
1996+ f"{ type (self ).__name__ } .full_match(): case_sensitive"
1997+ " is currently ignored." ,
1998+ UserWarning ,
1999+ stacklevel = 2 ,
2000+ )
2001+ return super ().full_match (str (pattern ))
19752002
1976- def match (self , pattern : str ) -> bool :
1977- # fixme: hacky emulation of match. needs tests...
1978- if not pattern :
2003+ def match (
2004+ self ,
2005+ path_pattern : str | SupportsPathLike ,
2006+ * ,
2007+ case_sensitive : bool | None = None ,
2008+ ) -> bool :
2009+ """Match this path against the provided non-recursive glob-style pattern.
2010+ Return True if matching is successful, False otherwise.
2011+ """
2012+ path_pattern = str (path_pattern )
2013+ if not path_pattern :
19792014 raise ValueError ("pattern cannot be empty" )
1980- return self .full_match (pattern .replace ("**" , "*" ))
2015+ return self .full_match (path_pattern .replace ("**" , "*" ))
19812016
19822017 @classmethod
19832018 def __get_pydantic_core_schema__ (
0 commit comments