From 2ec7eb10d59b3fc6ec31c68ddde684500a9407d6 Mon Sep 17 00:00:00 2001 From: fkuehnlenz Date: Wed, 22 May 2024 13:16:56 +0200 Subject: [PATCH 1/7] implement SMBPath and tests --- setup.cfg | 1 + upath/_flavour_sources.py | 371 ++++++++++++------------ upath/implementations/smb.py | 32 ++ upath/registry.py | 1 + upath/tests/conftest.py | 55 ++++ upath/tests/implementations/test_smb.py | 11 + 6 files changed, 287 insertions(+), 184 deletions(-) create mode 100644 upath/implementations/smb.py create mode 100644 upath/tests/implementations/test_smb.py diff --git a/setup.cfg b/setup.cfg index bf310953..f3a3cfe4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,6 +50,7 @@ dev = # pyarrow pydantic pydantic-settings + smbprotocol [options.package_data] upath = diff --git a/upath/_flavour_sources.py b/upath/_flavour_sources.py index ab22e010..f9af2b72 100644 --- a/upath/_flavour_sources.py +++ b/upath/_flavour_sources.py @@ -17,6 +17,7 @@ without a direct dependency on the underlying filesystem package. """ + # # skipping protocols: # - blockcache @@ -66,10 +67,10 @@ def __init_subclass__(cls: Any, **kwargs): class AbstractFileSystemFlavour(FileSystemFlavourBase): - __orig_class__ = 'fsspec.spec.AbstractFileSystem' - __orig_version__ = '2024.2.0' - protocol = 'abstract' - root_marker = '' + __orig_class__ = "fsspec.spec.AbstractFileSystem" + __orig_version__ = "2024.2.0" + protocol = "abstract" + root_marker = "" @classmethod def _strip_protocol(cls, path): @@ -114,11 +115,11 @@ def _parent(cls, path): class AsyncLocalFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'morefs.asyn_local.AsyncLocalFileSystem' - __orig_version__ = '0.2.0' + __orig_class__ = "morefs.asyn_local.AsyncLocalFileSystem" + __orig_version__ = "0.2.0" protocol = () - root_marker = '/' - sep = '/' + root_marker = "/" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -143,11 +144,11 @@ def _parent(cls, path): class AzureBlobFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'adlfs.spec.AzureBlobFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('abfs', 'az', 'abfss') - root_marker = '' - sep = '/' + __orig_class__ = "adlfs.spec.AzureBlobFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("abfs", "az", "abfss") + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path: str): @@ -216,11 +217,11 @@ def _get_kwargs_from_urls(urlpath): class AzureDatalakeFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'adlfs.gen1.AzureDatalakeFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('adl',) - root_marker = '' - sep = '/' + __orig_class__ = "adlfs.gen1.AzureDatalakeFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("adl",) + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -238,11 +239,11 @@ def _get_kwargs_from_urls(paths): class BoxFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'boxfs.boxfs.BoxFileSystem' - __orig_version__ = '0.2.1' - protocol = ('box',) - root_marker = '' - sep = '/' + __orig_class__ = "boxfs.boxfs.BoxFileSystem" + __orig_version__ = "0.2.1" + protocol = ("box",) + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path) -> str: @@ -252,11 +253,11 @@ def _strip_protocol(cls, path) -> str: class DaskWorkerFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.dask.DaskWorkerFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('dask',) - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.dask.DaskWorkerFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("dask",) + root_marker = "" + sep = "/" @staticmethod def _get_kwargs_from_urls(path): @@ -268,27 +269,27 @@ def _get_kwargs_from_urls(path): class DataFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.data.DataFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('data',) - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.data.DataFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("data",) + root_marker = "" + sep = "/" class DatabricksFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.dbfs.DatabricksFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('dbfs',) - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.dbfs.DatabricksFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("dbfs",) + root_marker = "" + sep = "/" class DictFSFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'morefs.dict.DictFS' - __orig_version__ = '0.2.0' - protocol = ('dictfs',) - root_marker = '' - sep = '/' + __orig_class__ = "morefs.dict.DictFS" + __orig_version__ = "0.2.0" + protocol = ("dictfs",) + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path: str) -> str: @@ -301,19 +302,19 @@ def _strip_protocol(cls, path: str) -> str: class DropboxDriveFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'dropboxdrivefs.core.DropboxDriveFileSystem' - __orig_version__ = '1.3.1' - protocol = ('dropbox',) - root_marker = '' - sep = '/' + __orig_class__ = "dropboxdrivefs.core.DropboxDriveFileSystem" + __orig_version__ = "1.3.1" + protocol = ("dropbox",) + root_marker = "" + sep = "/" class FTPFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.ftp.FTPFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('ftp',) - root_marker = '/' - sep = '/' + __orig_class__ = "fsspec.implementations.ftp.FTPFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("ftp",) + root_marker = "/" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -328,11 +329,11 @@ def _get_kwargs_from_urls(urlpath): class GCSFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'gcsfs.core.GCSFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('gcs', 'gs') - root_marker = '' - sep = '/' + __orig_class__ = "gcsfs.core.GCSFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("gcs", "gs") + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -405,11 +406,11 @@ def _split_path(cls, path, version_aware=False): class GitFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.git.GitFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('git',) - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.git.GitFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("git",) + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -433,11 +434,11 @@ def _get_kwargs_from_urls(path): class GithubFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.github.GithubFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('github',) - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.github.GithubFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("github",) + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -458,11 +459,11 @@ def _get_kwargs_from_urls(path): class HTTPFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.http.HTTPFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('http', 'https') - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.http.HTTPFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("http", "https") + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -479,11 +480,11 @@ def _parent(cls, path): class HadoopFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.arrow.HadoopFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('hdfs', 'arrow_hdfs') - root_marker = '/' - sep = '/' + __orig_class__ = "fsspec.implementations.arrow.HadoopFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("hdfs", "arrow_hdfs") + root_marker = "/" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -512,27 +513,27 @@ def _get_kwargs_from_urls(path): class HfFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'huggingface_hub.hf_file_system.HfFileSystem' - __orig_version__ = '0.20.3' - protocol = ('hf',) - root_marker = '' - sep = '/' + __orig_class__ = "huggingface_hub.hf_file_system.HfFileSystem" + __orig_version__ = "0.20.3" + protocol = ("hf",) + root_marker = "" + sep = "/" class JupyterFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.jupyter.JupyterFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('jupyter', 'jlab') - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.jupyter.JupyterFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("jupyter", "jlab") + root_marker = "" + sep = "/" class LakeFSFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'lakefs_spec.spec.LakeFSFileSystem' - __orig_version__ = '0.7.0' - protocol = ('lakefs',) - root_marker = '' - sep = '/' + __orig_class__ = "lakefs_spec.spec.LakeFSFileSystem" + __orig_version__ = "0.7.0" + protocol = ("lakefs",) + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -546,11 +547,11 @@ def _strip_protocol(cls, path): class LibArchiveFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.libarchive.LibArchiveFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('libarchive',) - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.libarchive.LibArchiveFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("libarchive",) + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -559,11 +560,11 @@ def _strip_protocol(cls, path): class LocalFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.local.LocalFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('file', 'local') - root_marker = '/' - sep = '/' + __orig_class__ = "fsspec.implementations.local.LocalFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("file", "local") + root_marker = "/" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -588,25 +589,27 @@ def _parent(cls, path): class MemFSFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'morefs.memory.MemFS' - __orig_version__ = '0.2.0' - protocol = ('memfs',) - root_marker = '' - sep = '/' + __orig_class__ = "morefs.memory.MemFS" + __orig_version__ = "0.2.0" + protocol = ("memfs",) + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): if path.startswith("memfs://"): path = path[len("memfs://") :] - return MemoryFileSystemFlavour._strip_protocol(path) # pylint: disable=protected-access + return MemoryFileSystemFlavour._strip_protocol( + path + ) # pylint: disable=protected-access class MemoryFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.memory.MemoryFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('memory',) - root_marker = '/' - sep = '/' + __orig_class__ = "fsspec.implementations.memory.MemoryFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("memory",) + root_marker = "/" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -619,11 +622,11 @@ def _strip_protocol(cls, path): class OCIFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'ocifs.core.OCIFileSystem' - __orig_version__ = '1.3.1' - protocol = ('oci', 'ocilake') - root_marker = '' - sep = '/' + __orig_class__ = "ocifs.core.OCIFileSystem" + __orig_version__ = "1.3.1" + protocol = ("oci", "ocilake") + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -647,11 +650,11 @@ def _parent(cls, path): class OSSFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'ossfs.core.OSSFileSystem' - __orig_version__ = '2023.12.0' - protocol = ('oss',) - root_marker = '' - sep = '/' + __orig_class__ = "ossfs.core.OSSFileSystem" + __orig_version__ = "2023.12.0" + protocol = ("oss",) + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -687,27 +690,27 @@ def _strip_protocol(cls, path): class OverlayFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'morefs.overlay.OverlayFileSystem' - __orig_version__ = '0.2.0' - protocol = ('overlayfs',) - root_marker = '' - sep = '/' + __orig_class__ = "morefs.overlay.OverlayFileSystem" + __orig_version__ = "0.2.0" + protocol = ("overlayfs",) + root_marker = "" + sep = "/" class ReferenceFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.reference.ReferenceFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('reference',) - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.reference.ReferenceFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("reference",) + root_marker = "" + sep = "/" class S3FileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 's3fs.core.S3FileSystem' - __orig_version__ = '2024.2.0' - protocol = ('s3', 's3a') - root_marker = '' - sep = '/' + __orig_class__ = "s3fs.core.S3FileSystem" + __orig_version__ = "2024.2.0" + protocol = ("s3", "s3a") + root_marker = "" + sep = "/" @staticmethod def _get_kwargs_from_urls(urlpath): @@ -730,11 +733,11 @@ def _get_kwargs_from_urls(urlpath): class SFTPFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.sftp.SFTPFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('sftp', 'ssh') - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.sftp.SFTPFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("sftp", "ssh") + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -749,11 +752,11 @@ def _get_kwargs_from_urls(urlpath): class SMBFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.smb.SMBFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('smb',) - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.smb.SMBFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("smb",) + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -769,27 +772,27 @@ def _get_kwargs_from_urls(path): class TarFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.tar.TarFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('tar',) - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.tar.TarFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("tar",) + root_marker = "" + sep = "/" class WandbFSFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'wandbfs._wandbfs.WandbFS' - __orig_version__ = '0.0.2' - protocol = ('wandb',) - root_marker = '' - sep = '/' + __orig_class__ = "wandbfs._wandbfs.WandbFS" + __orig_version__ = "0.0.2" + protocol = ("wandb",) + root_marker = "" + sep = "/" class WebHDFSFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.webhdfs.WebHDFS' - __orig_version__ = '2024.2.0' - protocol = ('webhdfs', 'webHDFS') - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.webhdfs.WebHDFS" + __orig_version__ = "2024.2.0" + protocol = ("webhdfs", "webHDFS") + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -806,11 +809,11 @@ def _get_kwargs_from_urls(urlpath): class WebdavFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'webdav4.fsspec.WebdavFileSystem' - __orig_version__ = '0.9.8' - protocol = ('webdav', 'dav') - root_marker = '' - sep = '/' + __orig_class__ = "webdav4.fsspec.WebdavFileSystem" + __orig_version__ = "0.9.8" + protocol = ("webdav", "dav") + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path: str) -> str: @@ -820,11 +823,11 @@ def _strip_protocol(cls, path: str) -> str: class XRootDFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec_xrootd.xrootd.XRootDFileSystem' - __orig_version__ = '0.2.4' - protocol = ('root',) - root_marker = '/' - sep = '/' + __orig_class__ = "fsspec_xrootd.xrootd.XRootDFileSystem" + __orig_version__ = "0.2.4" + protocol = ("root",) + root_marker = "/" + sep = "/" @classmethod def _strip_protocol(cls, path: str | list[str]) -> Any: @@ -846,11 +849,11 @@ def _get_kwargs_from_urls(u: str) -> dict[Any, Any]: class ZipFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'fsspec.implementations.zip.ZipFileSystem' - __orig_version__ = '2024.2.0' - protocol = ('zip',) - root_marker = '' - sep = '/' + __orig_class__ = "fsspec.implementations.zip.ZipFileSystem" + __orig_version__ = "2024.2.0" + protocol = ("zip",) + root_marker = "" + sep = "/" @classmethod def _strip_protocol(cls, path): @@ -859,8 +862,8 @@ def _strip_protocol(cls, path): class _DVCFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = 'dvc.fs.dvc._DVCFileSystem' - __orig_version__ = '3.47.0' - protocol = ('dvc',) - root_marker = '/' - sep = '/' + __orig_class__ = "dvc.fs.dvc._DVCFileSystem" + __orig_version__ = "3.47.0" + protocol = ("dvc",) + root_marker = "/" + sep = "/" diff --git a/upath/implementations/smb.py b/upath/implementations/smb.py new file mode 100644 index 00000000..9bab14be --- /dev/null +++ b/upath/implementations/smb.py @@ -0,0 +1,32 @@ +import smbprotocol.exceptions + +from upath import UPath + + +class SMBPath(UPath): + __slots__ = () + + @property + def path(self): + return "/" + super().path + + def mkdir(self, mode=0o777, parents=False, exist_ok=False): + # smbclient does not support setting mode externally + if parents and not exist_ok and self.exists(): + raise FileExistsError(str(self)) + try: + self.fs.mkdir( + self.path, + create_parents=parents, + ) + except smbprotocol.exceptions.SMBOSError: + if not exist_ok: + raise FileExistsError(str(self)) + if not self.is_dir(): + raise FileExistsError(str(self)) + + def iterdir(self): + if not self.is_dir(): + raise NotADirectoryError(str(self)) + else: + return super().iterdir() diff --git a/upath/registry.py b/upath/registry.py index 7a54b7f3..c886e39c 100644 --- a/upath/registry.py +++ b/upath/registry.py @@ -80,6 +80,7 @@ class _Registry(MutableMapping[str, "type[upath.UPath]"]): "webdav+http": "upath.implementations.webdav.WebdavPath", "webdav+https": "upath.implementations.webdav.WebdavPath", "github": "upath.implementations.github.GitHubPath", + "smb": "upath.implementations.smb.SMBPath", } if TYPE_CHECKING: diff --git a/upath/tests/conftest.py b/upath/tests/conftest.py index a2f85b0f..976623e5 100644 --- a/upath/tests/conftest.py +++ b/upath/tests/conftest.py @@ -12,6 +12,7 @@ import pytest from fsspec.implementations.local import LocalFileSystem from fsspec.implementations.local import make_path_posix +from fsspec.implementations.smb import SMBFileSystem from fsspec.registry import _registry from fsspec.registry import register_implementation from fsspec.utils import stringify_path @@ -409,3 +410,57 @@ def azure_fixture(azurite_credentials, azure_container): finally: for blob in client.list_blobs(): client.delete_blob(blob["name"]) + + +@pytest.fixture(scope="module") +def smb_container(): + try: + pchk = ["docker", "run", "--name", "fsspec_test_smb", "hello-world"] + subprocess.check_call(pchk) + stop_docker("fsspec_test_smb") + except (subprocess.CalledProcessError, FileNotFoundError): + pytest.skip("docker run not available") + + # requires docker + container = "fsspec_smb" + stop_docker(container) + cfg = "-p -u 'testuser;testpass' -s 'home;/share;no;no;no;testuser'" + port = 445 + img = f"docker run --name {container} --detach -p 139:139 -p {port}:445 dperson/samba" # noqa: E231 E501 + cmd = f"{img} {cfg}" + try: + subprocess.check_output(shlex.split(cmd)).strip().decode() + time.sleep(2) + yield { + "host": "localhost", + "port": port, + "username": "testuser", + "password": "testpass", + "register_session_retries": 100, # max ~= 10 seconds + } + finally: + import smbclient # pylint: disable=import-outside-toplevel + + smbclient.reset_connection_cache() + stop_docker(container) + + +@pytest.fixture +def smb_url(smb_container): + smb_url = "smb://{username}:{password}@{host}/home/" + smb_url = smb_url.format(**smb_container) + return smb_url + + +@pytest.fixture +def smb_fixture(local_testdir, smb_url, smb_container): + smb = SMBFileSystem( + host=smb_container["host"], + port=smb_container["port"], + username=smb_container["username"], + password=smb_container["password"], + ) + url = smb_url + "testdir/" + smb.put(local_testdir, "/home/testdir", recursive=True) + yield url + smb.delete("/home/testdir", recursive=True) diff --git a/upath/tests/implementations/test_smb.py b/upath/tests/implementations/test_smb.py new file mode 100644 index 00000000..e9d1fb92 --- /dev/null +++ b/upath/tests/implementations/test_smb.py @@ -0,0 +1,11 @@ +import pytest + +from upath import UPath +from upath.tests.cases import BaseTests + + +class TestUPathSMB(BaseTests): + + @pytest.fixture(autouse=True) + def path(self, smb_fixture): + self.path = UPath(smb_fixture) From d5c59b8a4aec5b6f15966dd50c53b53a9b1e6ce8 Mon Sep 17 00:00:00 2001 From: Andreas Poehlmann Date: Fri, 14 Jun 2024 23:32:29 +0200 Subject: [PATCH 2/7] upath._flavour_sources: revert formatting changes --- upath/_flavour_sources.py | 371 +++++++++++++++++++------------------- 1 file changed, 184 insertions(+), 187 deletions(-) diff --git a/upath/_flavour_sources.py b/upath/_flavour_sources.py index f9af2b72..ab22e010 100644 --- a/upath/_flavour_sources.py +++ b/upath/_flavour_sources.py @@ -17,7 +17,6 @@ without a direct dependency on the underlying filesystem package. """ - # # skipping protocols: # - blockcache @@ -67,10 +66,10 @@ def __init_subclass__(cls: Any, **kwargs): class AbstractFileSystemFlavour(FileSystemFlavourBase): - __orig_class__ = "fsspec.spec.AbstractFileSystem" - __orig_version__ = "2024.2.0" - protocol = "abstract" - root_marker = "" + __orig_class__ = 'fsspec.spec.AbstractFileSystem' + __orig_version__ = '2024.2.0' + protocol = 'abstract' + root_marker = '' @classmethod def _strip_protocol(cls, path): @@ -115,11 +114,11 @@ def _parent(cls, path): class AsyncLocalFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "morefs.asyn_local.AsyncLocalFileSystem" - __orig_version__ = "0.2.0" + __orig_class__ = 'morefs.asyn_local.AsyncLocalFileSystem' + __orig_version__ = '0.2.0' protocol = () - root_marker = "/" - sep = "/" + root_marker = '/' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -144,11 +143,11 @@ def _parent(cls, path): class AzureBlobFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "adlfs.spec.AzureBlobFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("abfs", "az", "abfss") - root_marker = "" - sep = "/" + __orig_class__ = 'adlfs.spec.AzureBlobFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('abfs', 'az', 'abfss') + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path: str): @@ -217,11 +216,11 @@ def _get_kwargs_from_urls(urlpath): class AzureDatalakeFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "adlfs.gen1.AzureDatalakeFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("adl",) - root_marker = "" - sep = "/" + __orig_class__ = 'adlfs.gen1.AzureDatalakeFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('adl',) + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -239,11 +238,11 @@ def _get_kwargs_from_urls(paths): class BoxFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "boxfs.boxfs.BoxFileSystem" - __orig_version__ = "0.2.1" - protocol = ("box",) - root_marker = "" - sep = "/" + __orig_class__ = 'boxfs.boxfs.BoxFileSystem' + __orig_version__ = '0.2.1' + protocol = ('box',) + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path) -> str: @@ -253,11 +252,11 @@ def _strip_protocol(cls, path) -> str: class DaskWorkerFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.dask.DaskWorkerFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("dask",) - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.dask.DaskWorkerFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('dask',) + root_marker = '' + sep = '/' @staticmethod def _get_kwargs_from_urls(path): @@ -269,27 +268,27 @@ def _get_kwargs_from_urls(path): class DataFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.data.DataFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("data",) - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.data.DataFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('data',) + root_marker = '' + sep = '/' class DatabricksFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.dbfs.DatabricksFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("dbfs",) - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.dbfs.DatabricksFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('dbfs',) + root_marker = '' + sep = '/' class DictFSFlavour(AbstractFileSystemFlavour): - __orig_class__ = "morefs.dict.DictFS" - __orig_version__ = "0.2.0" - protocol = ("dictfs",) - root_marker = "" - sep = "/" + __orig_class__ = 'morefs.dict.DictFS' + __orig_version__ = '0.2.0' + protocol = ('dictfs',) + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path: str) -> str: @@ -302,19 +301,19 @@ def _strip_protocol(cls, path: str) -> str: class DropboxDriveFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "dropboxdrivefs.core.DropboxDriveFileSystem" - __orig_version__ = "1.3.1" - protocol = ("dropbox",) - root_marker = "" - sep = "/" + __orig_class__ = 'dropboxdrivefs.core.DropboxDriveFileSystem' + __orig_version__ = '1.3.1' + protocol = ('dropbox',) + root_marker = '' + sep = '/' class FTPFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.ftp.FTPFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("ftp",) - root_marker = "/" - sep = "/" + __orig_class__ = 'fsspec.implementations.ftp.FTPFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('ftp',) + root_marker = '/' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -329,11 +328,11 @@ def _get_kwargs_from_urls(urlpath): class GCSFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "gcsfs.core.GCSFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("gcs", "gs") - root_marker = "" - sep = "/" + __orig_class__ = 'gcsfs.core.GCSFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('gcs', 'gs') + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -406,11 +405,11 @@ def _split_path(cls, path, version_aware=False): class GitFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.git.GitFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("git",) - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.git.GitFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('git',) + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -434,11 +433,11 @@ def _get_kwargs_from_urls(path): class GithubFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.github.GithubFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("github",) - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.github.GithubFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('github',) + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -459,11 +458,11 @@ def _get_kwargs_from_urls(path): class HTTPFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.http.HTTPFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("http", "https") - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.http.HTTPFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('http', 'https') + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -480,11 +479,11 @@ def _parent(cls, path): class HadoopFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.arrow.HadoopFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("hdfs", "arrow_hdfs") - root_marker = "/" - sep = "/" + __orig_class__ = 'fsspec.implementations.arrow.HadoopFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('hdfs', 'arrow_hdfs') + root_marker = '/' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -513,27 +512,27 @@ def _get_kwargs_from_urls(path): class HfFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "huggingface_hub.hf_file_system.HfFileSystem" - __orig_version__ = "0.20.3" - protocol = ("hf",) - root_marker = "" - sep = "/" + __orig_class__ = 'huggingface_hub.hf_file_system.HfFileSystem' + __orig_version__ = '0.20.3' + protocol = ('hf',) + root_marker = '' + sep = '/' class JupyterFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.jupyter.JupyterFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("jupyter", "jlab") - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.jupyter.JupyterFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('jupyter', 'jlab') + root_marker = '' + sep = '/' class LakeFSFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "lakefs_spec.spec.LakeFSFileSystem" - __orig_version__ = "0.7.0" - protocol = ("lakefs",) - root_marker = "" - sep = "/" + __orig_class__ = 'lakefs_spec.spec.LakeFSFileSystem' + __orig_version__ = '0.7.0' + protocol = ('lakefs',) + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -547,11 +546,11 @@ def _strip_protocol(cls, path): class LibArchiveFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.libarchive.LibArchiveFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("libarchive",) - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.libarchive.LibArchiveFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('libarchive',) + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -560,11 +559,11 @@ def _strip_protocol(cls, path): class LocalFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.local.LocalFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("file", "local") - root_marker = "/" - sep = "/" + __orig_class__ = 'fsspec.implementations.local.LocalFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('file', 'local') + root_marker = '/' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -589,27 +588,25 @@ def _parent(cls, path): class MemFSFlavour(AbstractFileSystemFlavour): - __orig_class__ = "morefs.memory.MemFS" - __orig_version__ = "0.2.0" - protocol = ("memfs",) - root_marker = "" - sep = "/" + __orig_class__ = 'morefs.memory.MemFS' + __orig_version__ = '0.2.0' + protocol = ('memfs',) + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): if path.startswith("memfs://"): path = path[len("memfs://") :] - return MemoryFileSystemFlavour._strip_protocol( - path - ) # pylint: disable=protected-access + return MemoryFileSystemFlavour._strip_protocol(path) # pylint: disable=protected-access class MemoryFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.memory.MemoryFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("memory",) - root_marker = "/" - sep = "/" + __orig_class__ = 'fsspec.implementations.memory.MemoryFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('memory',) + root_marker = '/' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -622,11 +619,11 @@ def _strip_protocol(cls, path): class OCIFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "ocifs.core.OCIFileSystem" - __orig_version__ = "1.3.1" - protocol = ("oci", "ocilake") - root_marker = "" - sep = "/" + __orig_class__ = 'ocifs.core.OCIFileSystem' + __orig_version__ = '1.3.1' + protocol = ('oci', 'ocilake') + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -650,11 +647,11 @@ def _parent(cls, path): class OSSFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "ossfs.core.OSSFileSystem" - __orig_version__ = "2023.12.0" - protocol = ("oss",) - root_marker = "" - sep = "/" + __orig_class__ = 'ossfs.core.OSSFileSystem' + __orig_version__ = '2023.12.0' + protocol = ('oss',) + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -690,27 +687,27 @@ def _strip_protocol(cls, path): class OverlayFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "morefs.overlay.OverlayFileSystem" - __orig_version__ = "0.2.0" - protocol = ("overlayfs",) - root_marker = "" - sep = "/" + __orig_class__ = 'morefs.overlay.OverlayFileSystem' + __orig_version__ = '0.2.0' + protocol = ('overlayfs',) + root_marker = '' + sep = '/' class ReferenceFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.reference.ReferenceFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("reference",) - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.reference.ReferenceFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('reference',) + root_marker = '' + sep = '/' class S3FileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "s3fs.core.S3FileSystem" - __orig_version__ = "2024.2.0" - protocol = ("s3", "s3a") - root_marker = "" - sep = "/" + __orig_class__ = 's3fs.core.S3FileSystem' + __orig_version__ = '2024.2.0' + protocol = ('s3', 's3a') + root_marker = '' + sep = '/' @staticmethod def _get_kwargs_from_urls(urlpath): @@ -733,11 +730,11 @@ def _get_kwargs_from_urls(urlpath): class SFTPFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.sftp.SFTPFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("sftp", "ssh") - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.sftp.SFTPFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('sftp', 'ssh') + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -752,11 +749,11 @@ def _get_kwargs_from_urls(urlpath): class SMBFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.smb.SMBFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("smb",) - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.smb.SMBFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('smb',) + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -772,27 +769,27 @@ def _get_kwargs_from_urls(path): class TarFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.tar.TarFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("tar",) - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.tar.TarFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('tar',) + root_marker = '' + sep = '/' class WandbFSFlavour(AbstractFileSystemFlavour): - __orig_class__ = "wandbfs._wandbfs.WandbFS" - __orig_version__ = "0.0.2" - protocol = ("wandb",) - root_marker = "" - sep = "/" + __orig_class__ = 'wandbfs._wandbfs.WandbFS' + __orig_version__ = '0.0.2' + protocol = ('wandb',) + root_marker = '' + sep = '/' class WebHDFSFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.webhdfs.WebHDFS" - __orig_version__ = "2024.2.0" - protocol = ("webhdfs", "webHDFS") - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.webhdfs.WebHDFS' + __orig_version__ = '2024.2.0' + protocol = ('webhdfs', 'webHDFS') + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -809,11 +806,11 @@ def _get_kwargs_from_urls(urlpath): class WebdavFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "webdav4.fsspec.WebdavFileSystem" - __orig_version__ = "0.9.8" - protocol = ("webdav", "dav") - root_marker = "" - sep = "/" + __orig_class__ = 'webdav4.fsspec.WebdavFileSystem' + __orig_version__ = '0.9.8' + protocol = ('webdav', 'dav') + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path: str) -> str: @@ -823,11 +820,11 @@ def _strip_protocol(cls, path: str) -> str: class XRootDFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec_xrootd.xrootd.XRootDFileSystem" - __orig_version__ = "0.2.4" - protocol = ("root",) - root_marker = "/" - sep = "/" + __orig_class__ = 'fsspec_xrootd.xrootd.XRootDFileSystem' + __orig_version__ = '0.2.4' + protocol = ('root',) + root_marker = '/' + sep = '/' @classmethod def _strip_protocol(cls, path: str | list[str]) -> Any: @@ -849,11 +846,11 @@ def _get_kwargs_from_urls(u: str) -> dict[Any, Any]: class ZipFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "fsspec.implementations.zip.ZipFileSystem" - __orig_version__ = "2024.2.0" - protocol = ("zip",) - root_marker = "" - sep = "/" + __orig_class__ = 'fsspec.implementations.zip.ZipFileSystem' + __orig_version__ = '2024.2.0' + protocol = ('zip',) + root_marker = '' + sep = '/' @classmethod def _strip_protocol(cls, path): @@ -862,8 +859,8 @@ def _strip_protocol(cls, path): class _DVCFileSystemFlavour(AbstractFileSystemFlavour): - __orig_class__ = "dvc.fs.dvc._DVCFileSystem" - __orig_version__ = "3.47.0" - protocol = ("dvc",) - root_marker = "/" - sep = "/" + __orig_class__ = 'dvc.fs.dvc._DVCFileSystem' + __orig_version__ = '3.47.0' + protocol = ('dvc',) + root_marker = '/' + sep = '/' From 64dfa0d003f28dde94dc2ebeeb6e3dd4694dd298 Mon Sep 17 00:00:00 2001 From: Andreas Poehlmann Date: Fri, 14 Jun 2024 23:37:57 +0200 Subject: [PATCH 3/7] tests: add smb protocol to registry tests --- upath/tests/test_registry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/upath/tests/test_registry.py b/upath/tests/test_registry.py index 1c54357f..e7fa1621 100644 --- a/upath/tests/test_registry.py +++ b/upath/tests/test_registry.py @@ -22,6 +22,7 @@ "memory", "s3", "s3a", + "smb", "webdav", "webdav+http", "webdav+https", From bdcfefdd5ec9e37e46362ad10a7ff81935204528 Mon Sep 17 00:00:00 2001 From: Andreas Poehlmann Date: Sat, 15 Jun 2024 00:47:13 +0200 Subject: [PATCH 4/7] tests: update smb glob test (mark '*' as xfail for now) --- upath/tests/implementations/test_smb.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/upath/tests/implementations/test_smb.py b/upath/tests/implementations/test_smb.py index e9d1fb92..f95bba1f 100644 --- a/upath/tests/implementations/test_smb.py +++ b/upath/tests/implementations/test_smb.py @@ -1,4 +1,6 @@ import pytest +from fsspec import __version__ as fsspec_version +from packaging.version import Version from upath import UPath from upath.tests.cases import BaseTests @@ -9,3 +11,26 @@ class TestUPathSMB(BaseTests): @pytest.fixture(autouse=True) def path(self, smb_fixture): self.path = UPath(smb_fixture) + + @pytest.mark.parametrize( + "pattern", + ( + "*.txt", + pytest.param( + "*", + marks=pytest.mark.xfail( + reason="SMBFileSystem.info appends '/' to dirs" + ), + ), + pytest.param( + "**/*.txt", + marks=( + pytest.mark.xfail(reason="requires fsspec>=2023.9.0") + if Version(fsspec_version) < Version("2023.9.0") + else () + ), + ), + ), + ) + def test_glob(self, pathlib_base, pattern): + super().test_glob(pathlib_base, pattern) From 526c21ac255fddf779b0eb0a4ed54ad74a5a1f61 Mon Sep 17 00:00:00 2001 From: Andreas Poehlmann Date: Sat, 15 Jun 2024 00:47:56 +0200 Subject: [PATCH 5/7] upath.implementations.smb: configure flavour to correctly handle path parsing --- upath/_flavour.py | 1 + upath/implementations/smb.py | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/upath/_flavour.py b/upath/_flavour.py index 6bbabf0f..54899600 100644 --- a/upath/_flavour.py +++ b/upath/_flavour.py @@ -108,6 +108,7 @@ class WrappedFileSystemFlavour: # (pathlib_abc.FlavourBase) "https", "s3", "s3a", + "smb", "gs", "gcs", "az", diff --git a/upath/implementations/smb.py b/upath/implementations/smb.py index 9bab14be..61513df0 100644 --- a/upath/implementations/smb.py +++ b/upath/implementations/smb.py @@ -6,10 +6,6 @@ class SMBPath(UPath): __slots__ = () - @property - def path(self): - return "/" + super().path - def mkdir(self, mode=0o777, parents=False, exist_ok=False): # smbclient does not support setting mode externally if parents and not exist_ok and self.exists(): From 19b54f799e677b3ebcf3fe04855660288f062ecb Mon Sep 17 00:00:00 2001 From: Andreas Poehlmann Date: Sat, 15 Jun 2024 00:55:39 +0200 Subject: [PATCH 6/7] tests: skip smb test on windows --- upath/tests/implementations/test_smb.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/upath/tests/implementations/test_smb.py b/upath/tests/implementations/test_smb.py index f95bba1f..f4046137 100644 --- a/upath/tests/implementations/test_smb.py +++ b/upath/tests/implementations/test_smb.py @@ -4,8 +4,10 @@ from upath import UPath from upath.tests.cases import BaseTests +from upath.tests.utils import skip_on_windows +@skip_on_windows class TestUPathSMB(BaseTests): @pytest.fixture(autouse=True) From 1bf7ac5b2246e3ef7916e25613158d903eba60f5 Mon Sep 17 00:00:00 2001 From: Andreas Poehlmann Date: Sat, 15 Jun 2024 01:10:28 +0200 Subject: [PATCH 7/7] upath.implementations.smb: make rename work with older fsspec --- upath/implementations/smb.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/upath/implementations/smb.py b/upath/implementations/smb.py index 61513df0..c072165c 100644 --- a/upath/implementations/smb.py +++ b/upath/implementations/smb.py @@ -1,3 +1,5 @@ +import warnings + import smbprotocol.exceptions from upath import UPath @@ -26,3 +28,25 @@ def iterdir(self): raise NotADirectoryError(str(self)) else: return super().iterdir() + + def rename(self, target, **kwargs): + if "recursive" in kwargs: + warnings.warn( + "SMBPath.rename(): recursive is currently ignored.", + UserWarning, + stacklevel=2, + ) + if "maxdepth" in kwargs: + warnings.warn( + "SMBPath.rename(): maxdepth is currently ignored.", + UserWarning, + stacklevel=2, + ) + if not isinstance(target, UPath): + target = self.parent.joinpath(target).resolve() + self.fs.mv( + self.path, + target.path, + **kwargs, + ) + return target