
## Installation

To use Rabata.io with Python, you'll need to install the boto3 library, which is the Amazon Web Services (AWS) SDK for Python.

### Install boto3

```bash
$ pip install boto3
```

It's recommended to use a virtual environment:

```bash
$ python -m venv venv
$ source venv/bin/activate  # On Windows: venv\Scripts\activate
$ pip install boto3
```

## Configuration

There are several ways to configure boto3 to work with Rabata.io.

### Method 1: Using AWS Credentials File

If you've already configured the AWS CLI as shown in the [AWS CLI Quickstart](/docs/quickstart/aws-cli/), boto3 will automatically use those credentials.

### Method 2: Explicit Configuration in Code

You can explicitly configure the S3 client in your code:

```python
import boto3

# Create an S3 client with Rabata.io endpoint
s3_client = boto3.client(
    's3',
    endpoint_url='https://s3.us-east-1.rabata.io',
    aws_access_key_id='YOUR_ACCESS_KEY',
    aws_secret_access_key='YOUR_SECRET_KEY',
    region_name='us-east-1'
)

# Create an S3 resource with Rabata.io endpoint
s3_resource = boto3.resource(
    's3',
    endpoint_url='https://s3.us-east-1.rabata.io',
    aws_access_key_id='YOUR_ACCESS_KEY',
    aws_secret_access_key='YOUR_SECRET_KEY',
    region_name='us-east-1'
)
```

### Method 3: Using Environment Variables

You can set environment variables to configure boto3:

```bash
# Set these environment variables before running your Python script
export AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY
export AWS_SECRET_ACCESS_KEY=YOUR_SECRET_KEY
export AWS_DEFAULT_REGION=us-east-1
```

Then in your code:

```python
import boto3
import os

# Create an S3 client with Rabata.io endpoint
s3_client = boto3.client(
    's3',
    endpoint_url='https://s3.us-east-1.rabata.io'
)
```

> **Security Note**: Never hardcode your credentials in your source code, especially if it's stored in a version control system. Use environment variables, AWS credentials file, or a secure secrets management system.

### Note on Older Python Libraries

If you're using older Python S3 libraries like **boto v2** (the predecessor to boto3), you may need to explicitly configure signature version 4, as these libraries default to the older v2 signatures which Rabata.io doesn't support:

```python
# For boto v2 (not recommended - consider upgrading to boto3)
from boto.s3.connection import S3Connection
conn = S3Connection(
    aws_access_key_id='YOUR_ACCESS_KEY',
    aws_secret_access_key='YOUR_SECRET_KEY',
    host='s3.us-east-1.rabata.io',
    calling_format='boto.s3.connection.OrdinaryCallingFormat',
    signature_version='s3v4'  # Explicit v4 required for boto v2
)
```

Modern libraries like boto3 automatically use signature v4 for custom S3-compatible endpoints, so explicit configuration is not necessary.

## Basic Operations

Here are some common operations you can perform with boto3 and Rabata.io.

### Bucket Operations

#### List All Buckets

```python
import boto3

s3_client = boto3.client(
    's3',
    endpoint_url='https://s3.us-east-1.rabata.io',
    aws_access_key_id='YOUR_ACCESS_KEY',
    aws_secret_access_key='YOUR_SECRET_KEY'
)

response = s3_client.list_buckets()
for bucket in response['Buckets']:
    print(f"Bucket Name: {bucket['Name']}")
```

#### Create a Bucket

```python
s3_client.create_bucket(Bucket='my-bucket-name')
```

#### Delete a Bucket

```python
s3_client.delete_bucket(Bucket='my-bucket-name')
```

Note: The bucket must be empty before it can be deleted.

### Object Operations

#### List Objects in a Bucket

```python
response = s3_client.list_objects_v2(Bucket='my-bucket-name')
if 'Contents' in response:
    for obj in response['Contents']:
        print(f"Object Key: {obj['Key']}, Size: {obj['Size']} bytes")
```

#### Upload a File

```python
# Method 1: Using upload_file
s3_client.upload_file(
    'local-file.txt',
    'my-bucket-name',
    'remote-file.txt'
)

# Method 2: Using put_object
with open('local-file.txt', 'rb') as file:
    s3_client.put_object(
        Bucket='my-bucket-name',
        Key='remote-file.txt',
        Body=file.read()
    )
```

#### Download a File

```python
# Method 1: Using download_file
s3_client.download_file(
    'my-bucket-name',
    'remote-file.txt',
    'local-file.txt'
)

# Method 2: Using get_object
response = s3_client.get_object(
    Bucket='my-bucket-name',
    Key='remote-file.txt'
)
content = response['Body'].read()
with open('local-file.txt', 'wb') as file:
    file.write(content)
```

#### Delete a File

```python
s3_client.delete_object(
    Bucket='my-bucket-name',
    Key='file-to-delete.txt'
)
```

#### Delete Multiple Files

```python
s3_client.delete_objects(
    Bucket='my-bucket-name',
    Delete={
        'Objects': [
            {'Key': 'file1.txt'},
            {'Key': 'file2.txt'},
            {'Key': 'file3.txt'}
        ]
    }
)
```

## Advanced Operations

Here are some more advanced operations you can perform with boto3 and Rabata.io.

### Working with Object Metadata

```python
s3_client.put_object(
    Bucket='my-bucket-name',
    Key='file-with-metadata.txt',
    Body=b'Hello, World!',
    Metadata={
        'custom-key': 'custom-value',
        'content-type': 'text/plain'
    }
)
```
<!--
### Setting Object ACLs

```python
s3_client.put_object(
    Bucket='my-bucket-name',
    Key='public-file.txt',
    Body=b'This is a public file',
    ACL='public-read'
)
``` -->

### Multipart Uploads

For large files, you can use multipart uploads:

```python
import os
import math
import threading

def upload_large_file(file_path, bucket, key, part_size=5*1024*1024):
    """Upload a large file using multipart upload."""
    # Initiate the multipart upload
    mpu = s3_client.create_multipart_upload(Bucket=bucket, Key=key)
    upload_id = mpu['UploadId']

    try:
        # Get file size
        file_size = os.path.getsize(file_path)

        # Calculate the number of parts
        part_count = math.ceil(file_size / part_size)

        # Prepare the parts list
        parts = []

        # Upload each part
        with open(file_path, 'rb') as file:
            for i in range(part_count):
                # Read the part data
                file.seek(i * part_size)
                data = file.read(min(part_size, file_size - i * part_size))

                # Upload the part
                part = s3_client.upload_part(
                    Bucket=bucket,
                    Key=key,
                    UploadId=upload_id,
                    PartNumber=i+1,
                    Body=data
                )

                # Add the part to the parts list
                parts.append({
                    'PartNumber': i+1,
                    'ETag': part['ETag']
                })

        # Complete the multipart upload
        s3_client.complete_multipart_upload(
            Bucket=bucket,
            Key=key,
            UploadId=upload_id,
            MultipartUpload={'Parts': parts}
        )

        print(f"Successfully uploaded {file_path} to {bucket}/{key}")

    except Exception as e:
        # Abort the multipart upload if something goes wrong
        s3_client.abort_multipart_upload(
            Bucket=bucket,
            Key=key,
            UploadId=upload_id
        )
        print(f"Error uploading {file_path}: {e}")
        raise

# Example usage
upload_large_file('large-file.iso', 'my-bucket-name', 'large-file.iso')
```

### Using Presigned URLs

Generate a presigned URL to allow temporary access to an object:

```python
presigned_url = s3_client.generate_presigned_url(
    'get_object',
    Params={
        'Bucket': 'my-bucket-name',
        'Key': 'private-file.txt'
    },
    ExpiresIn=3600  # URL expires in 1 hour
)

print(f"Presigned URL: {presigned_url}")
```

### Using S3 Resource Instead of Client

The boto3 S3 resource provides a higher-level, object-oriented API:

```python
import boto3

s3 = boto3.resource(
    's3',
    endpoint_url='https://s3.us-east-1.rabata.io',
    aws_access_key_id='YOUR_ACCESS_KEY',
    aws_secret_access_key='YOUR_SECRET_KEY'
)

# List all buckets
for bucket in s3.buckets.all():
    print(bucket.name)

# Get a bucket
bucket = s3.Bucket('my-bucket-name')

# List all objects in a bucket
for obj in bucket.objects.all():
    print(obj.key)

# Upload a file
bucket.upload_file('local-file.txt', 'remote-file.txt')

# Download a file
bucket.download_file('remote-file.txt', 'local-file.txt')

# Delete an object
obj = s3.Object('my-bucket-name', 'file-to-delete.txt')
obj.delete()
```

## Error Handling

It's important to handle errors properly when working with S3:

```python
import boto3
from botocore.exceptions import ClientError

s3_client = boto3.client(
    's3',
    endpoint_url='https://s3.us-east-1.rabata.io',
    aws_access_key_id='YOUR_ACCESS_KEY',
    aws_secret_access_key='YOUR_SECRET_KEY'
)

try:
    response = s3_client.get_object(
        Bucket='my-bucket-name',
        Key='non-existent-file.txt'
    )
except ClientError as e:
    error_code = e.response['Error']['Code']
    if error_code == 'NoSuchKey':
        print("The object does not exist.")
    elif error_code == 'NoSuchBucket':
        print("The bucket does not exist.")
    else:
        print(f"An error occurred: {e}")
```

---

<div class="docs-article__actions">
  <a href="/docs/quickstart/django/" class="btn btn--secondary">Django Integration</a>
  <a href="/docs/quickstart/flask/" class="btn btn--secondary">Flask Integration</a>
  <a href="/docs/quickstart/fastapi/" class="btn btn--secondary">FastAPI Integration</a>
</div>
