Source code for poseinterface.s3
"""S3 utilities for poseinterface."""
import json
import logging
import boto3
from botocore.exceptions import ClientError
[docs]
def parse_s3_uri(s3_uri: str) -> tuple[str, str]:
"""Parse an S3 URI into bucket and key components.
Parameters
----------
s3_uri
S3 URI in the format ``s3://bucket-name/path/to/file``.
Returns
-------
tuple[str, str]
Tuple of (bucket_name, key).
Raises
------
ValueError
If the S3 URI format is invalid.
"""
if not s3_uri.startswith("s3://"):
raise ValueError(
f"Invalid S3 URI format. Expected 's3://bucket/key', got {s3_uri}"
)
uri_parts = s3_uri[5:].split("/", 1)
if len(uri_parts) != 2:
raise ValueError(
f"Invalid S3 URI format. Expected 's3://bucket/key', got {s3_uri}"
)
return uri_parts[0], uri_parts[1]
[docs]
def download_json_from_s3(
bucket_name: str, key: str, aws_profile: str | None = None
) -> dict:
"""Download and parse a JSON file from S3.
Parameters
----------
bucket_name
Name of the S3 bucket.
key
S3 object key (path within the bucket).
aws_profile
Optional AWS profile name to use for authentication.
Returns
-------
dict
Parsed JSON content.
Raises
------
FileNotFoundError
If the file does not exist on S3.
ClientError
If there are other S3 access issues.
"""
session = boto3.Session(profile_name=aws_profile)
s3_client = session.client("s3")
try:
logging.info(f"Downloading s3://{bucket_name}/{key}")
response = s3_client.get_object(Bucket=bucket_name, Key=key)
return json.loads(response["Body"].read().decode("utf-8"))
except ClientError as e:
error_code = e.response.get("Error", {}).get("Code", "Unknown")
if error_code == "NoSuchKey":
raise FileNotFoundError(
f"File not found on S3: s3://{bucket_name}/{key}"
) from e
logging.error(
"Failed to download from s3://%s/%s (S3 error: %s)",
bucket_name,
key,
error_code,
)
raise
[docs]
def upload_json_to_s3(
data: dict,
bucket_name: str,
key: str,
aws_profile: str | None = None,
) -> None:
"""Upload a JSON object to S3.
Parameters
----------
data
Dictionary to serialize and upload.
bucket_name
Name of the S3 bucket.
key
S3 object key (path within the bucket).
aws_profile
Optional AWS profile name to use for authentication.
Raises
------
ClientError
If there are S3 access issues.
"""
session = boto3.Session(profile_name=aws_profile)
s3_client = session.client("s3")
logging.info(f"Uploading to s3://{bucket_name}/{key}")
s3_client.put_object(
Bucket=bucket_name,
Key=key,
Body=json.dumps(data),
ContentType="application/json",
)