# SDK – Python (boto3)

Use `boto3` to interact with Aurora’s S3-compatible endpoint.

> Available S3 endpoint: `a-s3.aur.lu` (France, Albi).

## Install

```bash
pip install boto3
```

## Configure client

```python
import boto3

session = boto3.session.Session(
    aws_access_key_id="<YOUR_ACCESS_KEY>",
    aws_secret_access_key="<YOUR_SECRET_KEY>",
    region_name="us-east-1",
)

s3 = session.client(
    "s3",
    endpoint_url="https://a-s3.aur.lu",
)

# List buckets
for b in s3.list_buckets()["Buckets"]:
    print(b["Name"])
```

## Upload and download

```python
# Upload
s3.upload_file("./file.txt", "my-bucket", "file.txt")

# Download
s3.download_file("my-bucket", "file.txt", "./file.txt")
```

## Multipart upload

```python
import math
from concurrent.futures import ThreadPoolExecutor

MB = 1024 * 1024
part_size = 16 * MB

bucket = "my-bucket"
key = "bigfile.bin"
path = "./bigfile.bin"

mpu = s3.create_multipart_upload(Bucket=bucket, Key=key)
upload_id = mpu["UploadId"]

parts = []
with open(path, "rb") as f:
    size = f.seek(0, 2) or f.tell()
    f.seek(0)
    total_parts = math.ceil(size / part_size)

    def upload_part(i: int):
        f.seek(i * part_size)
        body = f.read(part_size)
        resp = s3.upload_part(
            Bucket=bucket,
            Key=key,
            PartNumber=i + 1,
            UploadId=upload_id,
            Body=body,
        )
        return {"ETag": resp["ETag"], "PartNumber": i + 1}

    with ThreadPoolExecutor(max_workers=8) as pool:
        parts = list(pool.map(upload_part, range(total_parts)))

s3.complete_multipart_upload(
    Bucket=bucket,
    Key=key,
    UploadId=upload_id,
    MultipartUpload={"Parts": parts},
)
```
