Skip to content
10 changes: 10 additions & 0 deletions dev/fsspec_inspector/generate_flavours.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ def _fix_azure_blob_file_system(x: str) -> str:
return x


def _fix_data_file_system(x: str) -> str:
return re.sub(
"sep = '/'",
"sep = '' # type: ignore[assignment]\n "
"altsep = ' ' # type: ignore[assignment]",
x,
)


def _fix_memfs_file_system(x: str) -> str:
return re.sub(
"_MemFS",
Expand Down Expand Up @@ -184,6 +193,7 @@ def _fix_xrootd_file_system(x: str) -> str:
FIX_SOURCE = {
"AbstractFileSystem": _fix_abstract_file_system,
"AzureBlobFileSystem": _fix_azure_blob_file_system,
"DataFileSystem": _fix_data_file_system,
"MemFS": _fix_memfs_file_system,
"MemoryFileSystem": _fix_memory_file_system,
"OSSFileSystem": _fix_oss_file_system,
Expand Down
2 changes: 1 addition & 1 deletion upath/_flavour.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ def sep(self) -> str: # type: ignore[override]

@property
def altsep(self) -> str | None: # type: ignore[override]
return None
return getattr(self._spec, "altsep", None)

def isabs(self, path: JoinablePathLike) -> bool:
path = self.strip_protocol(path)
Expand Down
3 changes: 2 additions & 1 deletion upath/_flavour_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,8 @@ class DataFileSystemFlavour(AbstractFileSystemFlavour):
__orig_version__ = '2025.10.0'
protocol = ('data',)
root_marker = ''
sep = '/'
sep = "" # type: ignore[assignment]
altsep = " " # type: ignore[assignment]


class DatabricksFileSystemFlavour(AbstractFileSystemFlavour):
Expand Down
9 changes: 7 additions & 2 deletions upath/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ class UPath(_UPathMixin, WritablePath, ReadablePath):
if TYPE_CHECKING: # noqa: C901
_chain: Chain
_chain_parser: FSSpecChainParser
_fs_cached: bool
_fs_cached: AbstractFileSystem
_raw_urlpaths: Sequence[JoinablePathLike]
_relative_base: str | None

Expand Down Expand Up @@ -965,6 +965,8 @@ def with_segments(self, *pathsegments: JoinablePathLike) -> Self:
protocol=self._protocol,
**self._storage_options,
)
if hasattr(self, "_fs_cached"):
new_instance._fs_cached = self._fs_cached

if is_relative:
new_instance._relative_base = self._relative_base
Expand Down Expand Up @@ -1755,7 +1757,10 @@ def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
if exists and not exist_ok:
raise FileExistsError(str(self))
if not exists:
self.fs.touch(self.path, truncate=True)
try:
self.fs.touch(self.path, truncate=True)
except NotImplementedError:
_raise_unsupported(type(self).__name__, "touch")
else:
try:
self.fs.touch(self.path, truncate=False)
Expand Down
36 changes: 36 additions & 0 deletions upath/implementations/cloud.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from __future__ import annotations

import sys
from collections.abc import Iterator
from typing import TYPE_CHECKING
from typing import Any

from upath import UnsupportedOperation
from upath._chain import DEFAULT_CHAIN_PARSER
from upath._flavour import upath_strip_protocol
from upath.core import UPath
Expand All @@ -13,8 +15,10 @@
from typing import Literal

if sys.version_info >= (3, 11):
from typing import Self
from typing import Unpack
else:
from typing_extensions import Self
from typing_extensions import Unpack

from upath._chain import FSSpecChainParser
Expand Down Expand Up @@ -166,3 +170,35 @@ def __init__(
super().__init__(
*args, protocol=protocol, chain_parser=chain_parser, **storage_options
)

def iterdir(self) -> Iterator[Self]:
try:
yield from super().iterdir()
except NotImplementedError:
raise UnsupportedOperation

def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
raise UnsupportedOperation

def mkdir(
self,
mode: int = 0o777,
parents: bool = False,
exist_ok: bool = False,
) -> None:
raise UnsupportedOperation

def unlink(self, missing_ok: bool = False) -> None:
raise UnsupportedOperation

def write_bytes(self, data: bytes) -> int:
raise UnsupportedOperation("DataPath does not support writing")

def write_text(
self,
data: str,
encoding: str | None = None,
errors: str | None = None,
newline: str | None = None,
) -> int:
raise UnsupportedOperation("DataPath does not support writing")
62 changes: 60 additions & 2 deletions upath/implementations/data.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from __future__ import annotations

import sys
from collections.abc import Iterator
from collections.abc import Sequence
from typing import TYPE_CHECKING
from urllib.parse import quote_plus

from upath._protocol import get_upath_protocol
from upath.core import UnsupportedOperation
from upath.core import UPath
from upath.types import JoinablePathLike
Expand Down Expand Up @@ -45,10 +48,49 @@ def __str__(self) -> str:
return self.parser.join(*self._raw_urlpaths)

def with_segments(self, *pathsegments: JoinablePathLike) -> Self:
raise UnsupportedOperation("path operation not supported by DataPath")
try:
(segment,) = pathsegments
except ValueError:
raise UnsupportedOperation("join not supported by DataPath")
if get_upath_protocol(segment) != "data":
raise ValueError(f"requires a data URI, got: {segment!r}")
return type(self)(segment, protocol="data", **self.storage_options)

@property
def name(self) -> str:
return quote_plus(self.path)

@property
def stem(self) -> str:
return quote_plus(self.path)

@property
def suffix(self) -> str:
return ""

@property
def suffixes(self) -> list[str]:
return []

def with_name(self, name: str) -> Self:
raise UnsupportedOperation("with_name not supported by DataPath")

def with_suffix(self, suffix: str) -> Self:
raise UnsupportedOperation("path operation not supported by DataPath")
raise UnsupportedOperation("with_suffix not supported by DataPath")

def with_stem(self, stem: str) -> Self:
raise UnsupportedOperation("with_stem not supported by DataPath")

@property
def parent(self) -> Self:
return self

@property
def parents(self) -> Sequence[Self]:
return []

def full_match(self, pattern, *, case_sensitive: bool | None = None) -> bool:
return super().full_match(pattern, case_sensitive=case_sensitive)

def mkdir(
self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False
Expand All @@ -66,3 +108,19 @@ def write_text(
newline: str | None = None,
) -> int:
raise UnsupportedOperation("DataPath does not support writing")

def iterdir(self) -> Iterator[Self]:
raise NotADirectoryError

def glob(
self, pattern, *, case_sensitive=None, recurse_symlinks=False
) -> Iterator[Self]:
return iter([])

def rglob(
self, pattern, *, case_sensitive=None, recurse_symlinks=False
) -> Iterator[Self]:
return iter([])

def unlink(self, missing_ok: bool = False) -> None:
raise UnsupportedOperation
27 changes: 27 additions & 0 deletions upath/implementations/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from collections.abc import Sequence
from typing import TYPE_CHECKING

from upath.core import UnsupportedOperation
from upath.core import UPath
from upath.types import JoinablePathLike

Expand Down Expand Up @@ -56,3 +57,29 @@ def parts(self) -> Sequence[str]:
return parts[1:]
else:
return parts

def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
raise UnsupportedOperation

def mkdir(
self,
mode: int = 0o777,
parents: bool = False,
exist_ok: bool = False,
) -> None:
raise UnsupportedOperation

def unlink(self, missing_ok: bool = False) -> None:
raise UnsupportedOperation

def write_bytes(self, data: bytes) -> int:
raise UnsupportedOperation

def write_text(
self,
data: str,
encoding: str | None = None,
errors: str | None = None,
newline: str | None = None,
) -> int:
raise UnsupportedOperation("GitHubPath does not support writing")
27 changes: 27 additions & 0 deletions upath/implementations/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from fsspec.asyn import sync

from upath import UnsupportedOperation
from upath._stat import UPathStatResult
from upath.core import UPath
from upath.types import JoinablePathLike
Expand Down Expand Up @@ -124,3 +125,29 @@ def resolve(
break

return resolved_path

def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
raise UnsupportedOperation

def mkdir(
self,
mode: int = 0o777,
parents: bool = False,
exist_ok: bool = False,
) -> None:
raise UnsupportedOperation

def unlink(self, missing_ok: bool = False) -> None:
raise UnsupportedOperation

def write_bytes(self, data: bytes) -> int:
raise UnsupportedOperation("DataPath does not support writing")

def write_text(
self,
data: str,
encoding: str | None = None,
errors: str | None = None,
newline: str | None = None,
) -> int:
raise UnsupportedOperation("DataPath does not support writing")
27 changes: 27 additions & 0 deletions upath/implementations/tar.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import TYPE_CHECKING

from upath._stat import UPathStatResult
from upath.core import UnsupportedOperation
from upath.core import UPath
from upath.types import JoinablePathLike
from upath.types import StatResultType
Expand Down Expand Up @@ -41,6 +42,32 @@ def __init__(
**storage_options: Unpack[TarStorageOptions],
) -> None: ...

def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
raise UnsupportedOperation

def mkdir(
self,
mode: int = 0o777,
parents: bool = False,
exist_ok: bool = False,
) -> None:
raise UnsupportedOperation

def unlink(self, missing_ok: bool = False) -> None:
raise UnsupportedOperation

def write_bytes(self, data: bytes) -> int:
raise UnsupportedOperation("DataPath does not support writing")

def write_text(
self,
data: str,
encoding: str | None = None,
errors: str | None = None,
newline: str | None = None,
) -> int:
raise UnsupportedOperation("DataPath does not support writing")

def stat(
self,
*,
Expand Down
Loading