summarize_from_feedback/utils/blobs.py (57 lines of code) (raw):

import concurrent.futures import os import warnings from contextlib import contextmanager from urllib.parse import urlparse, unquote import blobfile as bf from filelock import FileLock warnings.filterwarnings("ignore", "Your application has authenticated using end user credentials") class NotBlobPathException(Exception): pass def parse_url(url): """ Given a GCS or Azure path, returns either: ('gs', bucket, path) or ('az', account, path) """ result = urlparse(url.rstrip("/")) if result.scheme == "gs": return 'gs', result.netloc, unquote(result.path.lstrip("/")) elif result.scheme == "https" and result.netloc == "storage.googleapis.com": bucket, rest = result.path.lstrip("/").split("/", 1) return 'gs', bucket, unquote(rest) elif result.scheme == "https" and result.netloc.endswith(".blob.core.windows.net"): account = result.netloc[:-len(".blob.core.windows.net")] return 'az', account, unquote(result.path.lstrip("/")) else: raise NotBlobPathException(f"Could not parse {url} as blob storage url") def is_blob_url(url): try: parse_url(url) return True except NotBlobPathException: return False def parallel_copy_recursive(src_dir, dst_dir, max_workers=16, overwrite=False): """Similar to `gsutil -m cp -r $local_dir/'*' $remote_dir/`""" futures = [] # NOTE: if we use ProcessPoolExecutor, this can't be used within pytorch workers with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: for root, _, filenames in bf.walk(src_dir): assert root.startswith(src_dir) for filename in filenames: src_file = bf.join(root, filename) dst_file = bf.join(dst_dir, root[len(src_dir) + 1 :], filename) print("copying", src_file, dst_file) future = executor.submit(bf.copy, src_file, dst_file, overwrite=overwrite) futures.append(future) for future in futures: future.result() def download_directory_cached(url): """ Given a blob storage path, caches the contents locally. WARNING: only use this function if contents under the path won't change! """ cache_dir = "/tmp/bf-dir-cache" scheme, bucket_or_account, path = parse_url(url) local_path = os.path.join(cache_dir, scheme, bucket_or_account, path) os.makedirs(local_path, exist_ok=True) with FileLock(os.path.join(local_path, ".LOCKFILE")): downloaded_marker = os.path.join(local_path, ".DOWNLOADED") if not os.path.exists(downloaded_marker): parallel_copy_recursive(url, local_path) with open(downloaded_marker, "w"): pass return local_path @contextmanager def open_file_cached(path, mode="r"): """ Given a GCS path url, caches the contents locally. WARNING: only use this function if contents under the path won't change! """ with bf.BlobFile(path, mode=mode, cache_dir="/tmp/bf-file-cache", streaming=False) as f: yield f