"""Utils for AWS S3 operations.""" import re import boto3 from botocore.exceptions import ClientError _S3_HTTP_PATH = r"^https://(?P.+)\.s3\.amazonaws\.com/(?P.+)$" _S3_PROTOCOL_PATH = r"^s3://(?P[^/]+)/(?P.+)$" def extract_bucket_path(url): """Extract bucket name and object key from url. Args: url (str): S3 URL like 'https://bucket-name.s3.amazonaws.com/path/to/file.txt'. Return: tuple: bucket name and bucket path. """ match = re.search(_S3_HTTP_PATH, url) if not match: match = re.search(_S3_PROTOCOL_PATH, url) if not match: raise Exception("The S3 url '{url}' is not valid.".format(url=url)) return match.group("bucket"), match.group("key") def get_presigned_url(bucket, key, expiration_time=3600): """Get presigned url. Args: bucket (str): s3 bucket name. key (str): s3 key. expiration_time (int): seconds after which link will be expired. Returns: str: presigned url. """ s3 = boto3.client("s3") return s3.generate_presigned_url( ClientMethod="get_object", Params={"Bucket": bucket, "Key": key}, ExpiresIn=expiration_time, ) def object_exists(bucket, key): """Check if s3 object exists. Args: bucket (str): Bucket name. For example, myBucket key (str): full path to s3 object. For example, archives/file_part1.gz Returns: bool: True if exists, False otherwise. """ try: client = boto3.client("s3") client.head_object(Bucket=bucket, Key=key) return True except ClientError as error: if error.response["Error"]["Code"] == "404": return False raise def delete_object(bucket: str, key: str): """Delete object from bucket. Args: bucket (str): Bucket name. For example, myBucket key (str): full path to s3 object. For example, archives/file_part1.gz """ client = boto3.client("s3") client.delete_object(Bucket=bucket, Key=key)