Skip to content

Commit

Permalink
Add local version for GS
Browse files Browse the repository at this point in the history
  • Loading branch information
jayqi committed Jan 24, 2021
1 parent 759f6cd commit ed6980a
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 22 deletions.
10 changes: 10 additions & 0 deletions cloudpathlib/local/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,25 @@
local_azure_blob_implementation,
LocalAzureBlobClient,
LocalAzureBlobPath,
local_gs_implementation,
LocalGSClient,
LocalGSPath,
local_s3_implementation,
LocalS3Client,
LocalS3Path,
)
from .localclient import LocalClient
from .localpath import LocalPath

__all__ = [
"local_azure_blob_implementation",
"LocalAzureBlobClient",
"LocalAzureBlobPath",
"LocalClient",
"local_gs_implementation",
"LocalGSClient",
"LocalGSPath",
"LocalPath",
"local_s3_implementation",
"LocalS3Client",
"LocalS3Path",
Expand Down
15 changes: 15 additions & 0 deletions cloudpathlib/local/implementations/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from .azure import local_azure_blob_implementation, LocalAzureBlobClient, LocalAzureBlobPath
from .gs import local_gs_implementation, LocalGSClient, LocalGSPath
from .s3 import local_s3_implementation, LocalS3Client, LocalS3Path

__all__ = [
"local_azure_blob_implementation",
"LocalAzureBlobClient",
"LocalAzureBlobPath",
"local_gs_implementation",
"LocalGSClient",
"LocalGSPath",
"local_s3_implementation",
"LocalS3Client",
"LocalS3Path",
]
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from ..cloudpath import CloudImplementation
from .localclient import LocalClient
from .localpath import LocalPath
from ...cloudpath import CloudImplementation
from ..localclient import LocalClient
from ..localpath import LocalPath


local_azure_blob_implementation = CloudImplementation()
Expand Down Expand Up @@ -64,47 +64,47 @@ def md5(self) -> str:
local_azure_blob_implementation._path_class = LocalAzureBlobPath


local_s3_implementation = CloudImplementation()
"""Replacement for "s3" CloudImplementation meta object in cloudpathlib.implementation_registry"""
local_azure_blob_implementation = CloudImplementation()
"""Replacement for "azure" CloudImplementation meta object in
cloudpathlib.implementation_registry"""


class LocalS3Client(LocalClient):
"""Replacement for S3Client that uses the local file system. Intended as a monkeypatch
class LocalAzureBlobClient(LocalClient):
"""Replacement for AzureBlobClient that uses the local file system. Intended as a monkeypatch
substitute when writing tests.
"""

_cloud_meta = local_s3_implementation
_cloud_meta = local_azure_blob_implementation


LocalS3Client.S3Path = LocalS3Client.CloudPath # type: ignore
LocalAzureBlobClient.AzureBlobPath = LocalAzureBlobClient.CloudPath # type: ignore


class LocalS3Path(LocalPath):
"""Replacement for S3Path that uses the local file system. Intended as a monkeypatch substitute
when writing tests.
class LocalAzureBlobPath(LocalPath):
"""Replacement for AzureBlobPath that uses the local file system. Intended as a monkeypatch
substitute when writing tests.
"""

cloud_prefix: str = "s3://"
_cloud_meta = local_s3_implementation
cloud_prefix: str = "az://"
_cloud_meta = local_azure_blob_implementation

@property
def drive(self) -> str:
return self.bucket
return self.container

def mkdir(self, parents=False, exist_ok=False):
# not possible to make empty directory on s3
# not possible to make empty directory on blob storage
pass

@property
def bucket(self) -> str:
def container(self) -> str:
return self._no_prefix.split("/", 1)[0]

@property
def key(self) -> str:
def blob(self) -> str:
key = self._no_prefix_no_drive

# key should never have starting slash for
# use with boto, etc.
if key.startswith("/"):
key = key[1:]

Expand All @@ -114,8 +114,12 @@ def key(self) -> str:
def etag(self):
return self.client._md5(self)

@property
def md5(self) -> str:
return self.client._md5(self)


LocalS3Path.__name__ = "S3Path"
LocalAzureBlobPath.__name__ = "AzureBlobPath"

local_s3_implementation._client_class = LocalS3Client
local_s3_implementation._path_class = LocalS3Path
local_azure_blob_implementation._client_class = LocalAzureBlobClient
local_azure_blob_implementation._path_class = LocalAzureBlobPath
60 changes: 60 additions & 0 deletions cloudpathlib/local/implementations/gs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from ...cloudpath import CloudImplementation
from ..localclient import LocalClient
from ..localpath import LocalPath


local_gs_implementation = CloudImplementation()
"""Replacement for "gs" CloudImplementation meta object in cloudpathlib.implementation_registry"""


class LocalGSClient(LocalClient):
"""Replacement for GSClient that uses the local file system. Intended as a monkeypatch
substitute when writing tests.
"""

_cloud_meta = local_gs_implementation


LocalGSClient.GSPath = LocalGSClient.CloudPath # type: ignore


class LocalGSPath(LocalPath):
"""Replacement for GSPath that uses the local file system. Intended as a monkeypatch substitute
when writing tests.
"""

cloud_prefix: str = "gs://"
_cloud_meta = local_gs_implementation

@property
def drive(self) -> str:
return self.bucket

def mkdir(self, parents=False, exist_ok=False):
# not possible to make empty directory on gs
pass

@property
def bucket(self) -> str:
return self._no_prefix.split("/", 1)[0]

@property
def blob(self) -> str:
key = self._no_prefix_no_drive

# key should never have starting slash for
# use with boto, etc.
if key.startswith("/"):
key = key[1:]

return key

@property
def etag(self):
return self.client._md5(self)


LocalGSPath.__name__ = "GSPath"

local_gs_implementation._client_class = LocalGSClient
local_gs_implementation._path_class = LocalGSPath
60 changes: 60 additions & 0 deletions cloudpathlib/local/implementations/s3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from ...cloudpath import CloudImplementation
from ..localclient import LocalClient
from ..localpath import LocalPath


local_s3_implementation = CloudImplementation()
"""Replacement for "s3" CloudImplementation meta object in cloudpathlib.implementation_registry"""


class LocalS3Client(LocalClient):
"""Replacement for S3Client that uses the local file system. Intended as a monkeypatch
substitute when writing tests.
"""

_cloud_meta = local_s3_implementation


LocalS3Client.S3Path = LocalS3Client.CloudPath # type: ignore


class LocalS3Path(LocalPath):
"""Replacement for S3Path that uses the local file system. Intended as a monkeypatch substitute
when writing tests.
"""

cloud_prefix: str = "s3://"
_cloud_meta = local_s3_implementation

@property
def drive(self) -> str:
return self.bucket

def mkdir(self, parents=False, exist_ok=False):
# not possible to make empty directory on s3
pass

@property
def bucket(self) -> str:
return self._no_prefix.split("/", 1)[0]

@property
def key(self) -> str:
key = self._no_prefix_no_drive

# key should never have starting slash for
# use with boto, etc.
if key.startswith("/"):
key = key[1:]

return key

@property
def etag(self):
return self.client._md5(self)


LocalS3Path.__name__ = "S3Path"

local_s3_implementation._client_class = LocalS3Client
local_s3_implementation._path_class = LocalS3Path
29 changes: 29 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
local_azure_blob_implementation,
LocalAzureBlobClient,
LocalAzureBlobPath,
local_gs_implementation,
LocalGSClient,
LocalGSPath,
local_s3_implementation,
LocalS3Client,
LocalS3Path,
Expand Down Expand Up @@ -232,6 +235,31 @@ def local_azure_rig(request, monkeypatch, assets_dir):
rig.client_class.reset_default_storage_dir() # reset local storage directory


@fixture()
def local_gs_rig(request, monkeypatch, assets_dir):
drive = os.getenv("LIVE_GS_BUCKET", "bucket")
test_dir = create_test_dir_name(request)

# copy test assets
shutil.copytree(assets_dir, LocalGSClient.get_default_storage_dir() / drive / test_dir)

monkeypatch.setitem(implementation_registry, "gs", local_gs_implementation)

rig = CloudProviderTestRig(
path_class=LocalGSPath,
client_class=LocalGSClient,
drive=drive,
test_dir=test_dir,
)

rig.client_class().set_as_default_client() # set default client

yield rig

rig.client_class._default_client = None # reset default client
rig.client_class.reset_default_storage_dir() # reset local storage directory


@fixture()
def local_s3_rig(request, monkeypatch, assets_dir):
drive = os.getenv("LIVE_S3_BUCKET", "bucket")
Expand Down Expand Up @@ -265,5 +293,6 @@ def local_s3_rig(request, monkeypatch, assets_dir):
s3_rig,
local_azure_rig,
local_s3_rig,
local_gs_rig,
],
)

0 comments on commit ed6980a

Please sign in to comment.