""" Google Cloud Storage. """ import io from typing import Optional, Tuple from google.api_core.exceptions import NotFound from google.auth.exceptions import DefaultCredentialsError from google.cloud import storage from google.cloud.storage.blob import Blob from google.cloud.storage.retry import DEFAULT_RETRY from ..common import _split_cloud_path from .scheme_client import SchemeClient class GsClient(SchemeClient): scheme = "gs" def __init__(self, resource: str) -> None: super().__init__(resource) self.blob = GsClient.get_gcs_blob(resource) self._loaded = False def load(self): if not self._loaded: try: self.blob.reload() self._loaded = True except NotFound: raise FileNotFoundError(self.resource) def get_etag(self) -> Optional[str]: self.load() return self.blob.etag or self.blob.md5_hash def get_size(self) -> Optional[int]: self.load() return self.blob.size def get_resource(self, temp_file: io.BufferedWriter) -> None: self.load() self.blob.download_to_file(temp_file, checksum="md5", retry=DEFAULT_RETRY) def get_bytes_range(self, index: int, length: int) -> bytes: self.load() return self.blob.download_as_bytes(start=index, end=index + length - 1) @staticmethod def split_gcs_path(resource: str) -> Tuple[str, str]: return _split_cloud_path(resource, "gs") @staticmethod def get_gcs_blob(resource: str) -> Blob: try: gcs_resource = storage.Client() except DefaultCredentialsError: gcs_resource = storage.Client.create_anonymous_client() bucket_name, gcs_path = GsClient.split_gcs_path(resource) bucket = gcs_resource.bucket(bucket_name) blob = bucket.blob(gcs_path) return blob