A small Python CLI application that uploads local files to Amazon S3.
The project is structured around clear separation of concerns:
| Module | File | Responsibility |
|---|---|---|
transfer_models |
transfer_models.py |
Immutable request/result data classes |
local_file_helper |
local_file_helper.py |
Local file validation, metadata extraction, and S3 key resolution |
s3_gateway |
s3_gateway.py |
All AWS S3 interaction via boto3 |
transfer_service |
transfer_service.py |
Orchestrates validation, key resolution, and upload |
cli_app |
cli_app.py |
Command-line entrypoint; wires dependencies and invokes the service |
Because FileTransferService accepts its dependencies via constructor injection, the uploader can be reused from scripts or other interfaces without touching the CLI layer.
- Python 3.11+
- AWS credentials configured (environment variables,
~/.aws/credentials, or an IAM role)
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txtdocker build -t s3-uploader .python -m cli_app --source ./example.txt --bucket my-bucket --key uploads/example.txtusage: cli_app [-h] --source SOURCE --bucket BUCKET
[--key KEY] [--key-prefix KEY_PREFIX]
[--region REGION] [--profile PROFILE]
[--content-type CONTENT_TYPE]
Upload a local file to Amazon S3.
required arguments:
--source SOURCE Path to the local file to upload
--bucket BUCKET Destination S3 bucket name
optional arguments:
--key KEY Explicit S3 object key (overrides --key-prefix)
--key-prefix KEY_PREFIX Prefix prepended to the file name to form the key
--region REGION AWS region (e.g. us-east-1)
--profile PROFILE AWS named profile from ~/.aws/credentials
--content-type CONTENT_TYPE
MIME type for the uploaded object
# Upload with an explicit key
python -m cli_app --source ./report.pdf --bucket my-bucket --key docs/report.pdf
# Upload using a key prefix (key becomes "uploads/report.pdf")
python -m cli_app --source ./report.pdf --bucket my-bucket --key-prefix uploads/
# Upload using a specific AWS profile and region
python -m cli_app --source ./data.csv --bucket my-bucket \
--key-prefix data/ --profile staging --region eu-west-1docker run --rm \
-e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
-e AWS_DEFAULT_REGION=us-east-1 \
-v "$(pwd)/example.txt:/data/example.txt" \
s3-uploader \
--source /data/example.txt --bucket my-bucket --key uploads/example.txtfrom transfer_models import UploadRequest
from local_file_helper import LocalFileInspector
from s3_gateway import S3Uploader
from transfer_service import FileTransferService
request = UploadRequest(
source_path="./example.txt",
bucket="my-bucket",
key="uploads/example.txt",
key_prefix=None,
region=None,
profile=None,
content_type=None,
)
service = FileTransferService(
file_inspector=LocalFileInspector(),
s3_uploader=S3Uploader(),
)
result = service.transfer(request)
print(result.object_url)Credentials are resolved by boto3 in the following order:
- Environment variables (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_SESSION_TOKEN) - AWS named profile (
--profileflag orAWS_PROFILEenv var) ~/.aws/credentialsdefault profile- IAM instance / task role (EC2, ECS, Lambda)
| Code | Meaning |
|---|---|
0 |
Upload succeeded |
1 |
Upload failed (error message printed to stderr) |