chub-dev 0.1.0 → 0.1.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +55 -0
  2. package/bin/chub-mcp +2 -0
  3. package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
  4. package/dist/airtable/docs/database/python/DOC.md +1735 -0
  5. package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
  6. package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
  7. package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
  8. package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
  9. package/dist/asana/docs/tasks/DOC.md +1396 -0
  10. package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
  11. package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
  12. package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
  13. package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
  14. package/dist/auth0/docs/identity/python/DOC.md +1199 -0
  15. package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
  16. package/dist/aws/docs/s3/python/DOC.md +1807 -0
  17. package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
  18. package/dist/binance/docs/trading/python/DOC.md +1454 -0
  19. package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
  20. package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
  21. package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
  22. package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
  23. package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
  24. package/dist/clerk/docs/auth/python/DOC.md +274 -0
  25. package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
  26. package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
  27. package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
  28. package/dist/cohere/docs/llm/DOC.md +1335 -0
  29. package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
  30. package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
  31. package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
  32. package/dist/deepgram/docs/speech/python/DOC.md +685 -0
  33. package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
  34. package/dist/deepl/docs/translation/python/DOC.md +944 -0
  35. package/dist/deepseek/docs/llm/DOC.md +1220 -0
  36. package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
  37. package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
  38. package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
  39. package/dist/discord/docs/bot/python/DOC.md +1130 -0
  40. package/dist/elasticsearch/docs/search/DOC.md +1634 -0
  41. package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
  42. package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
  43. package/dist/firebase/docs/auth/DOC.md +1015 -0
  44. package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
  45. package/dist/gemini/docs/genai/python/DOC.md +555 -0
  46. package/dist/github/docs/octokit/DOC.md +1560 -0
  47. package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
  48. package/dist/google/docs/bigquery/python/DOC.md +1503 -0
  49. package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
  50. package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
  51. package/dist/huggingface/docs/transformers/DOC.md +948 -0
  52. package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
  53. package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
  54. package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
  55. package/dist/jira/docs/issues/python/DOC.md +1492 -0
  56. package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
  57. package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
  58. package/dist/landingai-ade/docs/api/DOC.md +620 -0
  59. package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
  60. package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
  61. package/dist/landingai-ade/skills/SKILL.md +489 -0
  62. package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
  63. package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
  64. package/dist/linear/docs/tracker/DOC.md +1554 -0
  65. package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
  66. package/dist/livekit/docs/realtime/python/DOC.md +163 -0
  67. package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
  68. package/dist/meilisearch/docs/search/DOC.md +1241 -0
  69. package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
  70. package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
  71. package/dist/mongodb/docs/atlas/DOC.md +2041 -0
  72. package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
  73. package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
  74. package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
  75. package/dist/okta/docs/identity/python/DOC.md +1401 -0
  76. package/dist/openai/docs/chat/javascript/DOC.md +407 -0
  77. package/dist/openai/docs/chat/python/DOC.md +568 -0
  78. package/dist/paypal/docs/checkout/DOC.md +278 -0
  79. package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
  80. package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
  81. package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
  82. package/dist/plaid/docs/banking/python/DOC.md +1203 -0
  83. package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
  84. package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
  85. package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
  86. package/dist/prisma/docs/orm/python/DOC.md +1317 -0
  87. package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
  88. package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
  89. package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
  90. package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
  91. package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
  92. package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
  93. package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
  94. package/dist/redis/docs/key-value/python/DOC.md +2054 -0
  95. package/dist/registry.json +2817 -0
  96. package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
  97. package/dist/resend/docs/email/DOC.md +1271 -0
  98. package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
  99. package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
  100. package/dist/search-index.json +1 -0
  101. package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
  102. package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
  103. package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
  104. package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
  105. package/dist/shopify/docs/storefront/DOC.md +457 -0
  106. package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
  107. package/dist/slack/docs/workspace/python/DOC.md +271 -0
  108. package/dist/square/docs/payments/javascript/DOC.md +1855 -0
  109. package/dist/square/docs/payments/python/DOC.md +1728 -0
  110. package/dist/stripe/docs/api/DOC.md +1727 -0
  111. package/dist/stripe/docs/payments/DOC.md +1726 -0
  112. package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
  113. package/dist/stytch/docs/auth/python/DOC.md +1962 -0
  114. package/dist/supabase/docs/client/DOC.md +1606 -0
  115. package/dist/twilio/docs/messaging/python/DOC.md +469 -0
  116. package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
  117. package/dist/vercel/docs/platform/DOC.md +1940 -0
  118. package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
  119. package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
  120. package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
  121. package/dist/zendesk/docs/support/python/DOC.md +2297 -0
  122. package/package.json +22 -6
  123. package/skills/get-api-docs/SKILL.md +84 -0
  124. package/src/commands/annotate.js +83 -0
  125. package/src/commands/build.js +12 -1
  126. package/src/commands/feedback.js +150 -0
  127. package/src/commands/get.js +83 -42
  128. package/src/commands/search.js +7 -0
  129. package/src/index.js +43 -17
  130. package/src/lib/analytics.js +90 -0
  131. package/src/lib/annotations.js +57 -0
  132. package/src/lib/bm25.js +170 -0
  133. package/src/lib/cache.js +69 -6
  134. package/src/lib/config.js +8 -3
  135. package/src/lib/identity.js +99 -0
  136. package/src/lib/registry.js +103 -20
  137. package/src/lib/telemetry.js +86 -0
  138. package/src/mcp/server.js +177 -0
  139. package/src/mcp/tools.js +251 -0
@@ -0,0 +1,1807 @@
1
+ ---
2
+ name: s3
3
+ description: "AWS S3 SDK for Python (boto3) - Complete guide for S3 operations in Python projects"
4
+ metadata:
5
+ languages: "python"
6
+ versions: "1.40.59"
7
+ updated-on: "2026-03-02"
8
+ source: maintainer
9
+ tags: "aws,s3,storage,cloud,bucket"
10
+ ---
11
+
12
+ # AWS S3 SDK for Python (boto3) - Complete Guide
13
+
14
+ ## Golden Rule
15
+
16
+ **ALWAYS use `boto3` for AWS S3 operations in Python projects.**
17
+
18
+ ```bash
19
+ pip install boto3
20
+ ```
21
+
22
+ **DO NOT use:**
23
+ - `boto` (legacy library, deprecated)
24
+ - Any unofficial S3 libraries
25
+
26
+ `boto3` is the official AWS SDK for Python. It provides low-level client access and high-level object-oriented resource access to AWS services.
27
+
28
+ **Python Version Requirements:**
29
+ - Python 3.9 or later (support for Python 3.8 ended on 2025-04-22)
30
+
31
+ ---
32
+
33
+ ## Installation
34
+
35
+ ### Basic Installation
36
+
37
+ ```bash
38
+ pip install boto3
39
+ ```
40
+
41
+ ### With pip (specific version)
42
+
43
+ ```bash
44
+ pip install boto3==1.40.59
45
+ ```
46
+
47
+ ### With Poetry
48
+
49
+ ```bash
50
+ poetry add boto3
51
+ ```
52
+
53
+ ### With uv
54
+
55
+ ```bash
56
+ uv add boto3
57
+ ```
58
+
59
+ ### Environment Variables
60
+
61
+ Create a `.env` file:
62
+
63
+ ```env
64
+ AWS_ACCESS_KEY_ID=your_access_key_id
65
+ AWS_SECRET_ACCESS_KEY=your_secret_access_key
66
+ AWS_DEFAULT_REGION=us-east-1
67
+ AWS_S3_BUCKET=your-bucket-name
68
+ ```
69
+
70
+ Load environment variables in your code:
71
+
72
+ ```python
73
+ import os
74
+ from dotenv import load_dotenv
75
+
76
+ load_dotenv()
77
+
78
+ REGION = os.getenv("AWS_DEFAULT_REGION")
79
+ BUCKET = os.getenv("AWS_S3_BUCKET")
80
+ ```
81
+
82
+ ### AWS Credentials Configuration
83
+
84
+ Boto3 looks for credentials in this order:
85
+
86
+ 1. Environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`)
87
+ 2. Shared credentials file (`~/.aws/credentials`)
88
+ 3. AWS config file (`~/.aws/config`)
89
+ 4. IAM role (when running on EC2)
90
+
91
+ Configure credentials using AWS CLI:
92
+
93
+ ```bash
94
+ aws configure
95
+ ```
96
+
97
+ ---
98
+
99
+ ## Initialization
100
+
101
+ ### Client vs Resource
102
+
103
+ boto3 provides two interfaces:
104
+
105
+ - **Client**: Low-level service access (1-to-1 mapping with AWS APIs)
106
+ - **Resource**: Higher-level object-oriented interface
107
+
108
+ ```python
109
+ import boto3
110
+
111
+ # Client (low-level)
112
+ s3_client = boto3.client("s3")
113
+
114
+ # Resource (high-level)
115
+ s3_resource = boto3.resource("s3")
116
+ ```
117
+
118
+ ### Basic Client Setup
119
+
120
+ ```python
121
+ import boto3
122
+
123
+ # Default credentials from environment or AWS config
124
+ s3 = boto3.client("s3")
125
+ ```
126
+
127
+ ### Client with Region
128
+
129
+ ```python
130
+ import boto3
131
+
132
+ s3 = boto3.client("s3", region_name="us-east-1")
133
+ ```
134
+
135
+ ### Client with Explicit Credentials
136
+
137
+ ```python
138
+ import boto3
139
+
140
+ s3 = boto3.client(
141
+ "s3",
142
+ aws_access_key_id="YOUR_ACCESS_KEY",
143
+ aws_secret_access_key="YOUR_SECRET_KEY",
144
+ region_name="us-east-1"
145
+ )
146
+ ```
147
+
148
+ ### Client with Session
149
+
150
+ ```python
151
+ import boto3
152
+
153
+ session = boto3.Session(
154
+ aws_access_key_id="YOUR_ACCESS_KEY",
155
+ aws_secret_access_key="YOUR_SECRET_KEY",
156
+ region_name="us-east-1"
157
+ )
158
+
159
+ s3 = session.client("s3")
160
+ ```
161
+
162
+ ### Resource Setup
163
+
164
+ ```python
165
+ import boto3
166
+
167
+ s3 = boto3.resource("s3")
168
+
169
+ # With region
170
+ s3 = boto3.resource("s3", region_name="us-west-2")
171
+ ```
172
+
173
+ ### Client with Custom Endpoint (LocalStack, MinIO)
174
+
175
+ ```python
176
+ import boto3
177
+
178
+ s3 = boto3.client(
179
+ "s3",
180
+ endpoint_url="http://localhost:4566",
181
+ aws_access_key_id="test",
182
+ aws_secret_access_key="test",
183
+ region_name="us-east-1"
184
+ )
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Bucket Operations
190
+
191
+ ### List All Buckets
192
+
193
+ ```python
194
+ import boto3
195
+
196
+ s3 = boto3.client("s3")
197
+
198
+ def list_buckets():
199
+ try:
200
+ response = s3.list_buckets()
201
+
202
+ print("Buckets:")
203
+ for bucket in response["Buckets"]:
204
+ print(f" • {bucket['Name']} (Created: {bucket['CreationDate']})")
205
+ except Exception as e:
206
+ print(f"Error listing buckets: {e}")
207
+
208
+ # Using resource
209
+ s3 = boto3.resource("s3")
210
+
211
+ def list_buckets_resource():
212
+ for bucket in s3.buckets.all():
213
+ print(f" • {bucket.name}")
214
+ ```
215
+
216
+ ### Create Bucket
217
+
218
+ ```python
219
+ import boto3
220
+
221
+ s3 = boto3.client("s3")
222
+
223
+ def create_bucket(bucket_name):
224
+ try:
225
+ s3.create_bucket(Bucket=bucket_name)
226
+ print(f"Bucket created: {bucket_name}")
227
+ except Exception as e:
228
+ print(f"Error creating bucket: {e}")
229
+
230
+ # Using resource
231
+ s3 = boto3.resource("s3")
232
+
233
+ def create_bucket_resource(bucket_name):
234
+ try:
235
+ s3.create_bucket(Bucket=bucket_name)
236
+ print(f"Bucket created: {bucket_name}")
237
+ except Exception as e:
238
+ print(f"Error: {e}")
239
+ ```
240
+
241
+ ### Create Bucket in Specific Region
242
+
243
+ ```python
244
+ import boto3
245
+
246
+ s3 = boto3.client("s3", region_name="us-west-2")
247
+
248
+ def create_bucket_in_region(bucket_name, region):
249
+ try:
250
+ if region == "us-east-1":
251
+ s3.create_bucket(Bucket=bucket_name)
252
+ else:
253
+ s3.create_bucket(
254
+ Bucket=bucket_name,
255
+ CreateBucketConfiguration={"LocationConstraint": region}
256
+ )
257
+
258
+ print(f"Bucket created in {region}")
259
+ except Exception as e:
260
+ print(f"Error creating bucket: {e}")
261
+ ```
262
+
263
+ ### Delete Bucket
264
+
265
+ ```python
266
+ import boto3
267
+
268
+ s3 = boto3.client("s3")
269
+
270
+ def delete_bucket(bucket_name):
271
+ try:
272
+ s3.delete_bucket(Bucket=bucket_name)
273
+ print(f"Bucket deleted: {bucket_name}")
274
+ except Exception as e:
275
+ print(f"Error deleting bucket: {e}")
276
+
277
+ # Using resource
278
+ s3 = boto3.resource("s3")
279
+
280
+ def delete_bucket_resource(bucket_name):
281
+ try:
282
+ bucket = s3.Bucket(bucket_name)
283
+ bucket.delete()
284
+ print(f"Bucket deleted: {bucket_name}")
285
+ except Exception as e:
286
+ print(f"Error: {e}")
287
+ ```
288
+
289
+ ### Check if Bucket Exists
290
+
291
+ ```python
292
+ import boto3
293
+ from botocore.exceptions import ClientError
294
+
295
+ s3 = boto3.client("s3")
296
+
297
+ def bucket_exists(bucket_name):
298
+ try:
299
+ s3.head_bucket(Bucket=bucket_name)
300
+ return True
301
+ except ClientError as e:
302
+ if e.response["Error"]["Code"] == "404":
303
+ return False
304
+ raise
305
+ ```
306
+
307
+ ### Get Bucket Location
308
+
309
+ ```python
310
+ import boto3
311
+
312
+ s3 = boto3.client("s3")
313
+
314
+ def get_bucket_location(bucket_name):
315
+ try:
316
+ response = s3.get_bucket_location(Bucket=bucket_name)
317
+ location = response["LocationConstraint"]
318
+
319
+ # us-east-1 returns None
320
+ if location is None:
321
+ location = "us-east-1"
322
+
323
+ print(f"Bucket location: {location}")
324
+ return location
325
+ except Exception as e:
326
+ print(f"Error: {e}")
327
+ ```
328
+
329
+ ---
330
+
331
+ ## Object Upload Operations
332
+
333
+ ### Upload File from Disk
334
+
335
+ ```python
336
+ import boto3
337
+
338
+ s3 = boto3.client("s3")
339
+
340
+ def upload_file(file_path, bucket_name, object_key):
341
+ try:
342
+ s3.upload_file(file_path, bucket_name, object_key)
343
+ print(f"Uploaded {file_path} to {bucket_name}/{object_key}")
344
+ except Exception as e:
345
+ print(f"Upload error: {e}")
346
+
347
+ # Using resource
348
+ s3 = boto3.resource("s3")
349
+
350
+ def upload_file_resource(file_path, bucket_name, object_key):
351
+ try:
352
+ bucket = s3.Bucket(bucket_name)
353
+ bucket.upload_file(file_path, object_key)
354
+ print(f"Uploaded {file_path}")
355
+ except Exception as e:
356
+ print(f"Upload error: {e}")
357
+ ```
358
+
359
+ ### Upload with put_object
360
+
361
+ ```python
362
+ import boto3
363
+
364
+ s3 = boto3.client("s3")
365
+
366
+ def upload_object(bucket_name, key, data):
367
+ try:
368
+ s3.put_object(
369
+ Bucket=bucket_name,
370
+ Key=key,
371
+ Body=data
372
+ )
373
+ print(f"Uploaded to {key}")
374
+ except Exception as e:
375
+ print(f"Upload error: {e}")
376
+
377
+ # Upload string
378
+ upload_object("my-bucket", "file.txt", b"Hello, S3!")
379
+
380
+ # Upload JSON
381
+ import json
382
+ upload_object("my-bucket", "data.json", json.dumps({"key": "value"}))
383
+ ```
384
+
385
+ ### Upload with Content Type
386
+
387
+ ```python
388
+ import boto3
389
+
390
+ s3 = boto3.client("s3")
391
+
392
+ def upload_with_content_type(bucket_name, key, file_path, content_type):
393
+ try:
394
+ s3.upload_file(
395
+ file_path,
396
+ bucket_name,
397
+ key,
398
+ ExtraArgs={"ContentType": content_type}
399
+ )
400
+ print(f"Uploaded {key} as {content_type}")
401
+ except Exception as e:
402
+ print(f"Upload error: {e}")
403
+
404
+ # Usage
405
+ upload_with_content_type(
406
+ "my-bucket",
407
+ "image.jpg",
408
+ "./photo.jpg",
409
+ "image/jpeg"
410
+ )
411
+ ```
412
+
413
+ ### Upload with Metadata
414
+
415
+ ```python
416
+ import boto3
417
+
418
+ s3 = boto3.client("s3")
419
+
420
+ def upload_with_metadata(bucket_name, key, file_path):
421
+ try:
422
+ s3.upload_file(
423
+ file_path,
424
+ bucket_name,
425
+ key,
426
+ ExtraArgs={
427
+ "Metadata": {
428
+ "uploaded-by": "user123",
429
+ "original-name": "document.pdf",
430
+ "category": "reports"
431
+ }
432
+ }
433
+ )
434
+ print("Uploaded with metadata")
435
+ except Exception as e:
436
+ print(f"Upload error: {e}")
437
+ ```
438
+
439
+ ### Upload with Server-Side Encryption
440
+
441
+ ```python
442
+ import boto3
443
+
444
+ s3 = boto3.client("s3")
445
+
446
+ def upload_encrypted(bucket_name, key, file_path):
447
+ try:
448
+ s3.upload_file(
449
+ file_path,
450
+ bucket_name,
451
+ key,
452
+ ExtraArgs={"ServerSideEncryption": "AES256"}
453
+ )
454
+ print("Uploaded with encryption")
455
+ except Exception as e:
456
+ print(f"Upload error: {e}")
457
+ ```
458
+
459
+ ### Upload with ACL
460
+
461
+ ```python
462
+ import boto3
463
+
464
+ s3 = boto3.client("s3")
465
+
466
+ def upload_with_acl(bucket_name, key, file_path):
467
+ try:
468
+ s3.upload_file(
469
+ file_path,
470
+ bucket_name,
471
+ key,
472
+ ExtraArgs={"ACL": "public-read"}
473
+ )
474
+ print("Uploaded as public")
475
+ except Exception as e:
476
+ print(f"Upload error: {e}")
477
+ ```
478
+
479
+ ### Upload Binary Data
480
+
481
+ ```python
482
+ import boto3
483
+
484
+ s3 = boto3.client("s3")
485
+
486
+ def upload_binary(bucket_name, key, data):
487
+ try:
488
+ s3.put_object(
489
+ Bucket=bucket_name,
490
+ Key=key,
491
+ Body=data,
492
+ ContentType="application/octet-stream"
493
+ )
494
+ print(f"Uploaded binary data to {key}")
495
+ except Exception as e:
496
+ print(f"Upload error: {e}")
497
+
498
+ # Usage
499
+ with open("image.png", "rb") as f:
500
+ upload_binary("my-bucket", "uploads/image.png", f.read())
501
+ ```
502
+
503
+ ### Batch Upload Multiple Files
504
+
505
+ ```python
506
+ import boto3
507
+ import os
508
+
509
+ s3 = boto3.client("s3")
510
+
511
+ def upload_directory(directory_path, bucket_name, s3_prefix=""):
512
+ try:
513
+ for root, dirs, files in os.walk(directory_path):
514
+ for file in files:
515
+ local_path = os.path.join(root, file)
516
+ relative_path = os.path.relpath(local_path, directory_path)
517
+ s3_key = os.path.join(s3_prefix, relative_path).replace("\\", "/")
518
+
519
+ s3.upload_file(local_path, bucket_name, s3_key)
520
+ print(f"Uploaded: {s3_key}")
521
+
522
+ print(f"Uploaded directory: {directory_path}")
523
+ except Exception as e:
524
+ print(f"Batch upload error: {e}")
525
+ ```
526
+
527
+ ---
528
+
529
+ ## Object Download Operations
530
+
531
+ ### Download File to Disk
532
+
533
+ ```python
534
+ import boto3
535
+
536
+ s3 = boto3.client("s3")
537
+
538
+ def download_file(bucket_name, key, file_path):
539
+ try:
540
+ s3.download_file(bucket_name, key, file_path)
541
+ print(f"Downloaded to {file_path}")
542
+ except Exception as e:
543
+ print(f"Download error: {e}")
544
+
545
+ # Using resource
546
+ s3 = boto3.resource("s3")
547
+
548
+ def download_file_resource(bucket_name, key, file_path):
549
+ try:
550
+ bucket = s3.Bucket(bucket_name)
551
+ bucket.download_file(key, file_path)
552
+ print(f"Downloaded to {file_path}")
553
+ except Exception as e:
554
+ print(f"Download error: {e}")
555
+ ```
556
+
557
+ ### Download as Bytes
558
+
559
+ ```python
560
+ import boto3
561
+
562
+ s3 = boto3.client("s3")
563
+
564
+ def download_as_bytes(bucket_name, key):
565
+ try:
566
+ response = s3.get_object(Bucket=bucket_name, Key=key)
567
+ data = response["Body"].read()
568
+ return data
569
+ except Exception as e:
570
+ print(f"Download error: {e}")
571
+ return None
572
+
573
+ # Usage
574
+ data = download_as_bytes("my-bucket", "file.txt")
575
+ ```
576
+
577
+ ### Download as String
578
+
579
+ ```python
580
+ import boto3
581
+
582
+ s3 = boto3.client("s3")
583
+
584
+ def download_as_string(bucket_name, key, encoding="utf-8"):
585
+ try:
586
+ response = s3.get_object(Bucket=bucket_name, Key=key)
587
+ content = response["Body"].read().decode(encoding)
588
+ return content
589
+ except Exception as e:
590
+ print(f"Download error: {e}")
591
+ return None
592
+
593
+ # Download JSON
594
+ import json
595
+
596
+ def download_json(bucket_name, key):
597
+ content = download_as_string(bucket_name, key)
598
+ if content:
599
+ return json.loads(content)
600
+ return None
601
+ ```
602
+
603
+ ### Download with Error Handling
604
+
605
+ ```python
606
+ import boto3
607
+ from botocore.exceptions import ClientError
608
+
609
+ s3 = boto3.client("s3")
610
+
611
+ def download_safe(bucket_name, key, file_path):
612
+ try:
613
+ s3.download_file(bucket_name, key, file_path)
614
+ print(f"Downloaded to {file_path}")
615
+ return True
616
+ except ClientError as e:
617
+ if e.response["Error"]["Code"] == "404":
618
+ print(f"Object not found: {key}")
619
+ else:
620
+ print(f"Error: {e}")
621
+ return False
622
+ ```
623
+
624
+ ### Download with Version
625
+
626
+ ```python
627
+ import boto3
628
+
629
+ s3 = boto3.client("s3")
630
+
631
+ def download_version(bucket_name, key, file_path, version_id):
632
+ try:
633
+ s3.download_file(
634
+ bucket_name,
635
+ key,
636
+ file_path,
637
+ ExtraArgs={"VersionId": version_id}
638
+ )
639
+ print(f"Downloaded version {version_id}")
640
+ except Exception as e:
641
+ print(f"Download error: {e}")
642
+ ```
643
+
644
+ ### Download Byte Range
645
+
646
+ ```python
647
+ import boto3
648
+
649
+ s3 = boto3.client("s3")
650
+
651
+ def download_range(bucket_name, key, start, end):
652
+ try:
653
+ response = s3.get_object(
654
+ Bucket=bucket_name,
655
+ Key=key,
656
+ Range=f"bytes={start}-{end}"
657
+ )
658
+ data = response["Body"].read()
659
+ return data
660
+ except Exception as e:
661
+ print(f"Download error: {e}")
662
+ return None
663
+ ```
664
+
665
+ ### Get Object Metadata Only
666
+
667
+ ```python
668
+ import boto3
669
+
670
+ s3 = boto3.client("s3")
671
+
672
+ def get_object_metadata(bucket_name, key):
673
+ try:
674
+ response = s3.head_object(Bucket=bucket_name, Key=key)
675
+
676
+ print("Metadata:")
677
+ print(f" Content-Type: {response.get('ContentType')}")
678
+ print(f" Content-Length: {response.get('ContentLength')} bytes")
679
+ print(f" Last Modified: {response.get('LastModified')}")
680
+ print(f" ETag: {response.get('ETag')}")
681
+ print(f" Metadata: {response.get('Metadata')}")
682
+
683
+ return response
684
+ except Exception as e:
685
+ print(f"Error: {e}")
686
+ ```
687
+
688
+ ---
689
+
690
+ ## List Objects
691
+
692
+ ### List All Objects
693
+
694
+ ```python
695
+ import boto3
696
+
697
+ s3 = boto3.client("s3")
698
+
699
+ def list_objects(bucket_name):
700
+ try:
701
+ response = s3.list_objects_v2(Bucket=bucket_name)
702
+
703
+ if "Contents" in response:
704
+ print("Objects:")
705
+ for obj in response["Contents"]:
706
+ print(f" • {obj['Key']} ({obj['Size']} bytes)")
707
+ else:
708
+ print("Bucket is empty")
709
+ except Exception as e:
710
+ print(f"List error: {e}")
711
+
712
+ # Using resource
713
+ s3 = boto3.resource("s3")
714
+
715
+ def list_objects_resource(bucket_name):
716
+ try:
717
+ bucket = s3.Bucket(bucket_name)
718
+
719
+ for obj in bucket.objects.all():
720
+ print(f" • {obj.key} ({obj.size} bytes)")
721
+ except Exception as e:
722
+ print(f"List error: {e}")
723
+ ```
724
+
725
+ ### List Objects with Prefix
726
+
727
+ ```python
728
+ import boto3
729
+
730
+ s3 = boto3.client("s3")
731
+
732
+ def list_objects_with_prefix(bucket_name, prefix):
733
+ try:
734
+ response = s3.list_objects_v2(Bucket=bucket_name, Prefix=prefix)
735
+
736
+ if "Contents" in response:
737
+ print(f"Objects with prefix '{prefix}':")
738
+ for obj in response["Contents"]:
739
+ print(f" • {obj['Key']}")
740
+ else:
741
+ print(f"No objects with prefix '{prefix}'")
742
+ except Exception as e:
743
+ print(f"List error: {e}")
744
+
745
+ # Using resource
746
+ s3 = boto3.resource("s3")
747
+
748
+ def list_objects_with_prefix_resource(bucket_name, prefix):
749
+ bucket = s3.Bucket(bucket_name)
750
+
751
+ for obj in bucket.objects.filter(Prefix=prefix):
752
+ print(f" • {obj.key}")
753
+ ```
754
+
755
+ ### List Objects with Pagination
756
+
757
+ ```python
758
+ import boto3
759
+
760
+ s3 = boto3.client("s3")
761
+
762
+ def list_objects_paginated(bucket_name):
763
+ try:
764
+ paginator = s3.get_paginator("list_objects_v2")
765
+ page_iterator = paginator.paginate(Bucket=bucket_name)
766
+
767
+ total_objects = 0
768
+
769
+ for page in page_iterator:
770
+ if "Contents" in page:
771
+ for obj in page["Contents"]:
772
+ print(f" • {obj['Key']}")
773
+ total_objects += 1
774
+
775
+ print(f"\nTotal objects: {total_objects}")
776
+ except Exception as e:
777
+ print(f"List error: {e}")
778
+ ```
779
+
780
+ ### List Objects with Max Keys
781
+
782
+ ```python
783
+ import boto3
784
+
785
+ s3 = boto3.client("s3")
786
+
787
+ def list_objects_limited(bucket_name, max_keys=10):
788
+ try:
789
+ response = s3.list_objects_v2(Bucket=bucket_name, MaxKeys=max_keys)
790
+
791
+ if "Contents" in response:
792
+ for obj in response["Contents"]:
793
+ print(f" • {obj['Key']}")
794
+
795
+ print(f"\nShowing {len(response['Contents'])} objects")
796
+ print(f"More available: {response.get('IsTruncated', False)}")
797
+ except Exception as e:
798
+ print(f"List error: {e}")
799
+ ```
800
+
801
+ ### List Objects in Folder Structure
802
+
803
+ ```python
804
+ import boto3
805
+
806
+ s3 = boto3.client("s3")
807
+
808
+ def list_folder(bucket_name, prefix=""):
809
+ try:
810
+ response = s3.list_objects_v2(
811
+ Bucket=bucket_name,
812
+ Prefix=prefix,
813
+ Delimiter="/"
814
+ )
815
+
816
+ # List folders (common prefixes)
817
+ if "CommonPrefixes" in response:
818
+ print("Folders:")
819
+ for cp in response["CommonPrefixes"]:
820
+ print(f" 📁 {cp['Prefix']}")
821
+
822
+ # List files
823
+ if "Contents" in response:
824
+ print("\nFiles:")
825
+ for obj in response["Contents"]:
826
+ print(f" 📄 {obj['Key']}")
827
+ except Exception as e:
828
+ print(f"List error: {e}")
829
+ ```
830
+
831
+ ### List with Filter
832
+
833
+ ```python
834
+ import boto3
835
+
836
+ s3 = boto3.resource("s3")
837
+
838
+ def list_objects_filtered(bucket_name, extension):
839
+ try:
840
+ bucket = s3.Bucket(bucket_name)
841
+
842
+ for obj in bucket.objects.all():
843
+ if obj.key.endswith(extension):
844
+ print(f" • {obj.key}")
845
+ except Exception as e:
846
+ print(f"List error: {e}")
847
+
848
+ # Usage
849
+ list_objects_filtered("my-bucket", ".jpg")
850
+ ```
851
+
852
+ ---
853
+
854
+ ## Delete Operations
855
+
856
+ ### Delete Single Object
857
+
858
+ ```python
859
+ import boto3
860
+
861
+ s3 = boto3.client("s3")
862
+
863
+ def delete_object(bucket_name, key):
864
+ try:
865
+ s3.delete_object(Bucket=bucket_name, Key=key)
866
+ print(f"Deleted: {key}")
867
+ except Exception as e:
868
+ print(f"Delete error: {e}")
869
+
870
+ # Using resource
871
+ s3 = boto3.resource("s3")
872
+
873
+ def delete_object_resource(bucket_name, key):
874
+ try:
875
+ obj = s3.Object(bucket_name, key)
876
+ obj.delete()
877
+ print(f"Deleted: {key}")
878
+ except Exception as e:
879
+ print(f"Delete error: {e}")
880
+ ```
881
+
882
+ ### Delete Multiple Objects (Batch)
883
+
884
+ ```python
885
+ import boto3
886
+
887
+ s3 = boto3.client("s3")
888
+
889
+ def delete_multiple_objects(bucket_name, keys):
890
+ try:
891
+ response = s3.delete_objects(
892
+ Bucket=bucket_name,
893
+ Delete={
894
+ "Objects": [{"Key": key} for key in keys]
895
+ }
896
+ )
897
+
898
+ if "Deleted" in response:
899
+ print(f"Deleted {len(response['Deleted'])} objects:")
900
+ for obj in response["Deleted"]:
901
+ print(f" • {obj['Key']}")
902
+
903
+ if "Errors" in response:
904
+ print("Errors:")
905
+ for error in response["Errors"]:
906
+ print(f" • {error['Key']}: {error['Message']}")
907
+ except Exception as e:
908
+ print(f"Batch delete error: {e}")
909
+
910
+ # Usage
911
+ delete_multiple_objects("my-bucket", ["file1.txt", "file2.txt", "file3.txt"])
912
+ ```
913
+
914
+ ### Delete All Objects with Prefix
915
+
916
+ ```python
917
+ import boto3
918
+
919
+ s3 = boto3.client("s3")
920
+
921
+ def delete_objects_with_prefix(bucket_name, prefix):
922
+ try:
923
+ response = s3.list_objects_v2(Bucket=bucket_name, Prefix=prefix)
924
+
925
+ if "Contents" not in response:
926
+ print("No objects to delete")
927
+ return
928
+
929
+ keys = [obj["Key"] for obj in response["Contents"]]
930
+
931
+ s3.delete_objects(
932
+ Bucket=bucket_name,
933
+ Delete={"Objects": [{"Key": key} for key in keys]}
934
+ )
935
+
936
+ print(f"Deleted {len(keys)} objects with prefix '{prefix}'")
937
+ except Exception as e:
938
+ print(f"Delete error: {e}")
939
+ ```
940
+
941
+ ### Delete All Objects in Bucket
942
+
943
+ ```python
944
+ import boto3
945
+
946
+ s3 = boto3.resource("s3")
947
+
948
+ def empty_bucket(bucket_name):
949
+ try:
950
+ bucket = s3.Bucket(bucket_name)
951
+ bucket.objects.all().delete()
952
+ print(f"Emptied bucket: {bucket_name}")
953
+ except Exception as e:
954
+ print(f"Empty error: {e}")
955
+ ```
956
+
957
+ ### Empty and Delete Bucket
958
+
959
+ ```python
960
+ import boto3
961
+
962
+ s3 = boto3.resource("s3")
963
+
964
+ def empty_and_delete_bucket(bucket_name):
965
+ try:
966
+ bucket = s3.Bucket(bucket_name)
967
+
968
+ # Delete all objects
969
+ bucket.objects.all().delete()
970
+ print(f"Deleted all objects")
971
+
972
+ # Delete all object versions (if versioning enabled)
973
+ bucket.object_versions.all().delete()
974
+ print(f"Deleted all object versions")
975
+
976
+ # Delete bucket
977
+ bucket.delete()
978
+ print(f"Deleted bucket: {bucket_name}")
979
+ except Exception as e:
980
+ print(f"Error: {e}")
981
+ ```
982
+
983
+ ---
984
+
985
+ ## Copy and Move Operations
986
+
987
+ ### Copy Object
988
+
989
+ ```python
990
+ import boto3
991
+
992
+ s3 = boto3.client("s3")
993
+
994
+ def copy_object(source_bucket, source_key, dest_bucket, dest_key):
995
+ try:
996
+ copy_source = {"Bucket": source_bucket, "Key": source_key}
997
+
998
+ s3.copy_object(
999
+ CopySource=copy_source,
1000
+ Bucket=dest_bucket,
1001
+ Key=dest_key
1002
+ )
1003
+
1004
+ print(f"Copied {source_key} to {dest_key}")
1005
+ except Exception as e:
1006
+ print(f"Copy error: {e}")
1007
+
1008
+ # Using resource
1009
+ s3 = boto3.resource("s3")
1010
+
1011
+ def copy_object_resource(source_bucket, source_key, dest_bucket, dest_key):
1012
+ try:
1013
+ copy_source = {"Bucket": source_bucket, "Key": source_key}
1014
+
1015
+ dest_obj = s3.Object(dest_bucket, dest_key)
1016
+ dest_obj.copy_from(CopySource=copy_source)
1017
+
1018
+ print(f"Copied {source_key} to {dest_key}")
1019
+ except Exception as e:
1020
+ print(f"Copy error: {e}")
1021
+ ```
1022
+
1023
+ ### Copy with Metadata
1024
+
1025
+ ```python
1026
+ import boto3
1027
+
1028
+ s3 = boto3.client("s3")
1029
+
1030
+ def copy_with_metadata(source_bucket, source_key, dest_bucket, dest_key):
1031
+ try:
1032
+ copy_source = {"Bucket": source_bucket, "Key": source_key}
1033
+
1034
+ s3.copy_object(
1035
+ CopySource=copy_source,
1036
+ Bucket=dest_bucket,
1037
+ Key=dest_key,
1038
+ Metadata={
1039
+ "copied-from": source_key,
1040
+ "copied-date": "2025-10-26"
1041
+ },
1042
+ MetadataDirective="REPLACE"
1043
+ )
1044
+
1045
+ print("Copied with new metadata")
1046
+ except Exception as e:
1047
+ print(f"Copy error: {e}")
1048
+ ```
1049
+
1050
+ ### Move Object (Copy + Delete)
1051
+
1052
+ ```python
1053
+ import boto3
1054
+
1055
+ s3 = boto3.client("s3")
1056
+
1057
+ def move_object(source_bucket, source_key, dest_bucket, dest_key):
1058
+ try:
1059
+ # Copy
1060
+ copy_source = {"Bucket": source_bucket, "Key": source_key}
1061
+ s3.copy_object(
1062
+ CopySource=copy_source,
1063
+ Bucket=dest_bucket,
1064
+ Key=dest_key
1065
+ )
1066
+
1067
+ # Delete source
1068
+ s3.delete_object(Bucket=source_bucket, Key=source_key)
1069
+
1070
+ print(f"Moved {source_key} to {dest_key}")
1071
+ except Exception as e:
1072
+ print(f"Move error: {e}")
1073
+ ```
1074
+
1075
+ ---
1076
+
1077
+ ## Presigned URLs
1078
+
1079
+ ### Presigned URL for Download (GET)
1080
+
1081
+ ```python
1082
+ import boto3
1083
+ from botocore.config import Config
1084
+
1085
+ s3 = boto3.client("s3", config=Config(signature_version="s3v4"))
1086
+
1087
+ def create_presigned_download_url(bucket_name, key, expiration=3600):
1088
+ try:
1089
+ url = s3.generate_presigned_url(
1090
+ ClientMethod="get_object",
1091
+ Params={"Bucket": bucket_name, "Key": key},
1092
+ ExpiresIn=expiration
1093
+ )
1094
+ return url
1095
+ except Exception as e:
1096
+ print(f"Presigned URL error: {e}")
1097
+ return None
1098
+
1099
+ # Usage
1100
+ url = create_presigned_download_url("my-bucket", "file.pdf", 3600)
1101
+ print(f"Download URL: {url}")
1102
+ ```
1103
+
1104
+ ### Presigned URL for Upload (PUT)
1105
+
1106
+ ```python
1107
+ import boto3
1108
+ from botocore.config import Config
1109
+
1110
+ s3 = boto3.client("s3", config=Config(signature_version="s3v4"))
1111
+
1112
+ def create_presigned_upload_url(bucket_name, key, expiration=3600):
1113
+ try:
1114
+ url = s3.generate_presigned_url(
1115
+ ClientMethod="put_object",
1116
+ Params={"Bucket": bucket_name, "Key": key},
1117
+ ExpiresIn=expiration
1118
+ )
1119
+ return url
1120
+ except Exception as e:
1121
+ print(f"Presigned URL error: {e}")
1122
+ return None
1123
+
1124
+ # Usage with requests
1125
+ import requests
1126
+
1127
+ upload_url = create_presigned_upload_url("my-bucket", "upload.txt")
1128
+
1129
+ with open("file.txt", "rb") as f:
1130
+ response = requests.put(upload_url, data=f)
1131
+ print(f"Upload status: {response.status_code}")
1132
+ ```
1133
+
1134
+ ### Presigned URL with Content Type
1135
+
1136
+ ```python
1137
+ import boto3
1138
+ from botocore.config import Config
1139
+
1140
+ s3 = boto3.client("s3", config=Config(signature_version="s3v4"))
1141
+
1142
+ def create_presigned_url_with_type(bucket_name, key, content_type, expiration=3600):
1143
+ try:
1144
+ url = s3.generate_presigned_url(
1145
+ ClientMethod="put_object",
1146
+ Params={
1147
+ "Bucket": bucket_name,
1148
+ "Key": key,
1149
+ "ContentType": content_type
1150
+ },
1151
+ ExpiresIn=expiration
1152
+ )
1153
+ return url
1154
+ except Exception as e:
1155
+ print(f"Presigned URL error: {e}")
1156
+ return None
1157
+ ```
1158
+
1159
+ ### Presigned POST for File Upload
1160
+
1161
+ ```python
1162
+ import boto3
1163
+
1164
+ s3 = boto3.client("s3")
1165
+
1166
+ def create_presigned_post(bucket_name, key, expiration=3600):
1167
+ try:
1168
+ response = s3.generate_presigned_post(
1169
+ Bucket=bucket_name,
1170
+ Key=key,
1171
+ ExpiresIn=expiration
1172
+ )
1173
+ return response
1174
+ except Exception as e:
1175
+ print(f"Presigned POST error: {e}")
1176
+ return None
1177
+
1178
+ # Usage
1179
+ presigned_post = create_presigned_post("my-bucket", "upload.txt")
1180
+
1181
+ # Client uploads using POST with the URL and fields
1182
+ import requests
1183
+
1184
+ with open("file.txt", "rb") as f:
1185
+ files = {"file": f}
1186
+ response = requests.post(
1187
+ presigned_post["url"],
1188
+ data=presigned_post["fields"],
1189
+ files=files
1190
+ )
1191
+ print(f"Upload status: {response.status_code}")
1192
+ ```
1193
+
1194
+ ### Presigned POST with Conditions
1195
+
1196
+ ```python
1197
+ import boto3
1198
+
1199
+ s3 = boto3.client("s3")
1200
+
1201
+ def create_presigned_post_with_conditions(bucket_name, key, max_size=10485760):
1202
+ try:
1203
+ response = s3.generate_presigned_post(
1204
+ Bucket=bucket_name,
1205
+ Key=key,
1206
+ Fields={"acl": "public-read"},
1207
+ Conditions=[
1208
+ {"acl": "public-read"},
1209
+ ["content-length-range", 0, max_size] # Max 10 MB
1210
+ ],
1211
+ ExpiresIn=3600
1212
+ )
1213
+ return response
1214
+ except Exception as e:
1215
+ print(f"Presigned POST error: {e}")
1216
+ return None
1217
+ ```
1218
+
1219
+ ---
1220
+
1221
+ ## Multipart Upload
1222
+
1223
+ ### Automatic Multipart Upload (Recommended)
1224
+
1225
+ ```python
1226
+ import boto3
1227
+ from boto3.s3.transfer import TransferConfig
1228
+
1229
+ s3 = boto3.client("s3")
1230
+
1231
+ def multipart_upload(file_path, bucket_name, key):
1232
+ try:
1233
+ # Configure multipart upload
1234
+ config = TransferConfig(
1235
+ multipart_threshold=1024 * 25, # 25 MB
1236
+ max_concurrency=10,
1237
+ multipart_chunksize=1024 * 25, # 25 MB
1238
+ use_threads=True
1239
+ )
1240
+
1241
+ s3.upload_file(
1242
+ file_path,
1243
+ bucket_name,
1244
+ key,
1245
+ Config=config
1246
+ )
1247
+
1248
+ print(f"Multipart upload complete: {key}")
1249
+ except Exception as e:
1250
+ print(f"Upload error: {e}")
1251
+ ```
1252
+
1253
+ ### Multipart Upload with Progress Callback
1254
+
1255
+ ```python
1256
+ import boto3
1257
+ import sys
1258
+
1259
+ s3 = boto3.client("s3")
1260
+
1261
+ class ProgressPercentage:
1262
+ def __init__(self, filename):
1263
+ self._filename = filename
1264
+ self._size = float(os.path.getsize(filename))
1265
+ self._seen_so_far = 0
1266
+
1267
+ def __call__(self, bytes_amount):
1268
+ self._seen_so_far += bytes_amount
1269
+ percentage = (self._seen_so_far / self._size) * 100
1270
+ sys.stdout.write(
1271
+ f"\r{self._filename}: {self._seen_so_far} / {self._size} ({percentage:.2f}%)"
1272
+ )
1273
+ sys.stdout.flush()
1274
+
1275
+ def multipart_upload_with_progress(file_path, bucket_name, key):
1276
+ try:
1277
+ s3.upload_file(
1278
+ file_path,
1279
+ bucket_name,
1280
+ key,
1281
+ Callback=ProgressPercentage(file_path)
1282
+ )
1283
+ print(f"\nUpload complete: {key}")
1284
+ except Exception as e:
1285
+ print(f"Upload error: {e}")
1286
+ ```
1287
+
1288
+ ### Manual Multipart Upload (Low-Level)
1289
+
1290
+ ```python
1291
+ import boto3
1292
+ import os
1293
+
1294
+ s3 = boto3.client("s3")
1295
+
1296
+ def manual_multipart_upload(file_path, bucket_name, key):
1297
+ try:
1298
+ # Step 1: Initiate multipart upload
1299
+ response = s3.create_multipart_upload(
1300
+ Bucket=bucket_name,
1301
+ Key=key
1302
+ )
1303
+ upload_id = response["UploadId"]
1304
+
1305
+ # Step 2: Upload parts
1306
+ parts = []
1307
+ chunk_size = 10 * 1024 * 1024 # 10 MB
1308
+ part_number = 1
1309
+
1310
+ with open(file_path, "rb") as f:
1311
+ while True:
1312
+ data = f.read(chunk_size)
1313
+ if not data:
1314
+ break
1315
+
1316
+ response = s3.upload_part(
1317
+ Bucket=bucket_name,
1318
+ Key=key,
1319
+ PartNumber=part_number,
1320
+ UploadId=upload_id,
1321
+ Body=data
1322
+ )
1323
+
1324
+ parts.append({
1325
+ "PartNumber": part_number,
1326
+ "ETag": response["ETag"]
1327
+ })
1328
+
1329
+ print(f"Uploaded part {part_number}")
1330
+ part_number += 1
1331
+
1332
+ # Step 3: Complete multipart upload
1333
+ s3.complete_multipart_upload(
1334
+ Bucket=bucket_name,
1335
+ Key=key,
1336
+ UploadId=upload_id,
1337
+ MultipartUpload={"Parts": parts}
1338
+ )
1339
+
1340
+ print(f"Multipart upload complete: {key}")
1341
+ except Exception as e:
1342
+ # Abort multipart upload on error
1343
+ s3.abort_multipart_upload(
1344
+ Bucket=bucket_name,
1345
+ Key=key,
1346
+ UploadId=upload_id
1347
+ )
1348
+ print(f"Upload error: {e}")
1349
+ ```
1350
+
1351
+ ### List In-Progress Multipart Uploads
1352
+
1353
+ ```python
1354
+ import boto3
1355
+
1356
+ s3 = boto3.client("s3")
1357
+
1358
+ def list_multipart_uploads(bucket_name):
1359
+ try:
1360
+ response = s3.list_multipart_uploads(Bucket=bucket_name)
1361
+
1362
+ if "Uploads" in response:
1363
+ print("In-progress uploads:")
1364
+ for upload in response["Uploads"]:
1365
+ print(f" • {upload['Key']} (ID: {upload['UploadId']})")
1366
+ else:
1367
+ print("No in-progress uploads")
1368
+ except Exception as e:
1369
+ print(f"List error: {e}")
1370
+ ```
1371
+
1372
+ ### Abort Multipart Upload
1373
+
1374
+ ```python
1375
+ import boto3
1376
+
1377
+ s3 = boto3.client("s3")
1378
+
1379
+ def abort_multipart_upload(bucket_name, key, upload_id):
1380
+ try:
1381
+ s3.abort_multipart_upload(
1382
+ Bucket=bucket_name,
1383
+ Key=key,
1384
+ UploadId=upload_id
1385
+ )
1386
+ print(f"Aborted upload: {key}")
1387
+ except Exception as e:
1388
+ print(f"Abort error: {e}")
1389
+ ```
1390
+
1391
+ ---
1392
+
1393
+ ## Object Tagging
1394
+
1395
+ ### Put Object Tags
1396
+
1397
+ ```python
1398
+ import boto3
1399
+
1400
+ s3 = boto3.client("s3")
1401
+
1402
+ def tag_object(bucket_name, key, tags):
1403
+ try:
1404
+ s3.put_object_tagging(
1405
+ Bucket=bucket_name,
1406
+ Key=key,
1407
+ Tagging={
1408
+ "TagSet": [
1409
+ {"Key": k, "Value": v} for k, v in tags.items()
1410
+ ]
1411
+ }
1412
+ )
1413
+ print(f"Tagged {key}")
1414
+ except Exception as e:
1415
+ print(f"Tagging error: {e}")
1416
+
1417
+ # Usage
1418
+ tag_object("my-bucket", "file.txt", {
1419
+ "Environment": "Production",
1420
+ "Department": "Engineering"
1421
+ })
1422
+ ```
1423
+
1424
+ ### Get Object Tags
1425
+
1426
+ ```python
1427
+ import boto3
1428
+
1429
+ s3 = boto3.client("s3")
1430
+
1431
+ def get_object_tags(bucket_name, key):
1432
+ try:
1433
+ response = s3.get_object_tagging(Bucket=bucket_name, Key=key)
1434
+
1435
+ print("Tags:")
1436
+ for tag in response["TagSet"]:
1437
+ print(f" {tag['Key']}: {tag['Value']}")
1438
+
1439
+ return response["TagSet"]
1440
+ except Exception as e:
1441
+ print(f"Get tags error: {e}")
1442
+ return None
1443
+ ```
1444
+
1445
+ ### Delete Object Tags
1446
+
1447
+ ```python
1448
+ import boto3
1449
+
1450
+ s3 = boto3.client("s3")
1451
+
1452
+ def delete_object_tags(bucket_name, key):
1453
+ try:
1454
+ s3.delete_object_tagging(Bucket=bucket_name, Key=key)
1455
+ print(f"Deleted tags from {key}")
1456
+ except Exception as e:
1457
+ print(f"Delete tags error: {e}")
1458
+ ```
1459
+
1460
+ ---
1461
+
1462
+ ## Bucket Configuration
1463
+
1464
+ ### Enable Versioning
1465
+
1466
+ ```python
1467
+ import boto3
1468
+
1469
+ s3 = boto3.client("s3")
1470
+
1471
+ def enable_versioning(bucket_name):
1472
+ try:
1473
+ s3.put_bucket_versioning(
1474
+ Bucket=bucket_name,
1475
+ VersioningConfiguration={"Status": "Enabled"}
1476
+ )
1477
+ print(f"Versioning enabled for {bucket_name}")
1478
+ except Exception as e:
1479
+ print(f"Versioning error: {e}")
1480
+ ```
1481
+
1482
+ ### Get Versioning Status
1483
+
1484
+ ```python
1485
+ import boto3
1486
+
1487
+ s3 = boto3.client("s3")
1488
+
1489
+ def get_versioning_status(bucket_name):
1490
+ try:
1491
+ response = s3.get_bucket_versioning(Bucket=bucket_name)
1492
+ status = response.get("Status", "Disabled")
1493
+ print(f"Versioning status: {status}")
1494
+ return status
1495
+ except Exception as e:
1496
+ print(f"Error: {e}")
1497
+ ```
1498
+
1499
+ ### Set Bucket CORS
1500
+
1501
+ ```python
1502
+ import boto3
1503
+
1504
+ s3 = boto3.client("s3")
1505
+
1506
+ def set_bucket_cors(bucket_name):
1507
+ try:
1508
+ cors_configuration = {
1509
+ "CORSRules": [
1510
+ {
1511
+ "AllowedHeaders": ["*"],
1512
+ "AllowedMethods": ["GET", "PUT", "POST", "DELETE"],
1513
+ "AllowedOrigins": ["*"],
1514
+ "ExposeHeaders": ["ETag"],
1515
+ "MaxAgeSeconds": 3000
1516
+ }
1517
+ ]
1518
+ }
1519
+
1520
+ s3.put_bucket_cors(
1521
+ Bucket=bucket_name,
1522
+ CORSConfiguration=cors_configuration
1523
+ )
1524
+
1525
+ print("CORS configured")
1526
+ except Exception as e:
1527
+ print(f"CORS error: {e}")
1528
+ ```
1529
+
1530
+ ### Get Bucket CORS
1531
+
1532
+ ```python
1533
+ import boto3
1534
+
1535
+ s3 = boto3.client("s3")
1536
+
1537
+ def get_bucket_cors(bucket_name):
1538
+ try:
1539
+ response = s3.get_bucket_cors(Bucket=bucket_name)
1540
+ print("CORS Rules:")
1541
+ print(response["CORSRules"])
1542
+ return response["CORSRules"]
1543
+ except Exception as e:
1544
+ print(f"Get CORS error: {e}")
1545
+ return None
1546
+ ```
1547
+
1548
+ ### Delete Bucket CORS
1549
+
1550
+ ```python
1551
+ import boto3
1552
+
1553
+ s3 = boto3.client("s3")
1554
+
1555
+ def delete_bucket_cors(bucket_name):
1556
+ try:
1557
+ s3.delete_bucket_cors(Bucket=bucket_name)
1558
+ print("CORS configuration deleted")
1559
+ except Exception as e:
1560
+ print(f"Delete CORS error: {e}")
1561
+ ```
1562
+
1563
+ ### Set Bucket Encryption
1564
+
1565
+ ```python
1566
+ import boto3
1567
+
1568
+ s3 = boto3.client("s3")
1569
+
1570
+ def set_bucket_encryption(bucket_name):
1571
+ try:
1572
+ s3.put_bucket_encryption(
1573
+ Bucket=bucket_name,
1574
+ ServerSideEncryptionConfiguration={
1575
+ "Rules": [
1576
+ {
1577
+ "ApplyServerSideEncryptionByDefault": {
1578
+ "SSEAlgorithm": "AES256"
1579
+ }
1580
+ }
1581
+ ]
1582
+ }
1583
+ )
1584
+ print("Encryption enabled")
1585
+ except Exception as e:
1586
+ print(f"Encryption error: {e}")
1587
+ ```
1588
+
1589
+ ### Set Bucket Lifecycle Policy
1590
+
1591
+ ```python
1592
+ import boto3
1593
+
1594
+ s3 = boto3.client("s3")
1595
+
1596
+ def set_lifecycle_policy(bucket_name):
1597
+ try:
1598
+ s3.put_bucket_lifecycle_configuration(
1599
+ Bucket=bucket_name,
1600
+ LifecycleConfiguration={
1601
+ "Rules": [
1602
+ {
1603
+ "Id": "DeleteOldObjects",
1604
+ "Status": "Enabled",
1605
+ "Expiration": {"Days": 90},
1606
+ "Filter": {"Prefix": "logs/"}
1607
+ }
1608
+ ]
1609
+ }
1610
+ )
1611
+ print("Lifecycle policy configured")
1612
+ except Exception as e:
1613
+ print(f"Lifecycle error: {e}")
1614
+ ```
1615
+
1616
+ ---
1617
+
1618
+ ## Waiters
1619
+
1620
+ ### Wait Until Object Exists
1621
+
1622
+ ```python
1623
+ import boto3
1624
+
1625
+ s3 = boto3.client("s3")
1626
+
1627
+ def wait_for_object(bucket_name, key):
1628
+ try:
1629
+ waiter = s3.get_waiter("object_exists")
1630
+ waiter.wait(Bucket=bucket_name, Key=key)
1631
+ print(f"Object exists: {key}")
1632
+ except Exception as e:
1633
+ print(f"Wait error: {e}")
1634
+ ```
1635
+
1636
+ ### Wait Until Object Not Exists
1637
+
1638
+ ```python
1639
+ import boto3
1640
+
1641
+ s3 = boto3.client("s3")
1642
+
1643
+ def wait_for_object_deletion(bucket_name, key):
1644
+ try:
1645
+ waiter = s3.get_waiter("object_not_exists")
1646
+ waiter.wait(Bucket=bucket_name, Key=key)
1647
+ print(f"Object deleted: {key}")
1648
+ except Exception as e:
1649
+ print(f"Wait error: {e}")
1650
+ ```
1651
+
1652
+ ### Wait Until Bucket Exists
1653
+
1654
+ ```python
1655
+ import boto3
1656
+
1657
+ s3 = boto3.client("s3")
1658
+
1659
+ def wait_for_bucket(bucket_name):
1660
+ try:
1661
+ waiter = s3.get_waiter("bucket_exists")
1662
+ waiter.wait(Bucket=bucket_name)
1663
+ print(f"Bucket exists: {bucket_name}")
1664
+ except Exception as e:
1665
+ print(f"Wait error: {e}")
1666
+ ```
1667
+
1668
+ ---
1669
+
1670
+ ## Error Handling
1671
+
1672
+ ### Common Error Types
1673
+
1674
+ ```python
1675
+ import boto3
1676
+ from botocore.exceptions import ClientError, NoCredentialsError
1677
+
1678
+ s3 = boto3.client("s3")
1679
+
1680
+ def handle_errors(bucket_name, key):
1681
+ try:
1682
+ response = s3.get_object(Bucket=bucket_name, Key=key)
1683
+ return response["Body"].read()
1684
+ except NoCredentialsError:
1685
+ print("No AWS credentials found")
1686
+ except ClientError as e:
1687
+ error_code = e.response["Error"]["Code"]
1688
+
1689
+ if error_code == "NoSuchKey":
1690
+ print("Object not found")
1691
+ elif error_code == "NoSuchBucket":
1692
+ print("Bucket not found")
1693
+ elif error_code == "AccessDenied":
1694
+ print("Access denied")
1695
+ elif error_code == "InvalidAccessKeyId":
1696
+ print("Invalid credentials")
1697
+ else:
1698
+ print(f"Error: {error_code}")
1699
+ except Exception as e:
1700
+ print(f"Unknown error: {e}")
1701
+ ```
1702
+
1703
+ ### Retry Logic with Backoff
1704
+
1705
+ ```python
1706
+ import boto3
1707
+ import time
1708
+ from botocore.exceptions import ClientError
1709
+
1710
+ s3 = boto3.client("s3")
1711
+
1712
+ def download_with_retry(bucket_name, key, max_retries=3):
1713
+ for attempt in range(max_retries):
1714
+ try:
1715
+ response = s3.get_object(Bucket=bucket_name, Key=key)
1716
+ return response["Body"].read()
1717
+ except ClientError as e:
1718
+ if attempt < max_retries - 1:
1719
+ wait_time = 2 ** attempt # Exponential backoff
1720
+ print(f"Attempt {attempt + 1} failed, retrying in {wait_time}s...")
1721
+ time.sleep(wait_time)
1722
+ else:
1723
+ raise
1724
+ ```
1725
+
1726
+ ### Custom Retry Configuration
1727
+
1728
+ ```python
1729
+ import boto3
1730
+ from botocore.config import Config
1731
+
1732
+ # Configure custom retry settings
1733
+ config = Config(
1734
+ retries={
1735
+ "max_attempts": 10,
1736
+ "mode": "adaptive"
1737
+ }
1738
+ )
1739
+
1740
+ s3 = boto3.client("s3", config=config)
1741
+ ```
1742
+
1743
+ ---
1744
+
1745
+ ## Complete Example: Full S3 Operations
1746
+
1747
+ ```python
1748
+ import boto3
1749
+ from botocore.exceptions import ClientError
1750
+ import json
1751
+
1752
+ def main():
1753
+ s3 = boto3.client("s3", region_name="us-east-1")
1754
+ bucket_name = f"my-test-bucket-{int(time.time())}"
1755
+
1756
+ try:
1757
+ # 1. Create bucket
1758
+ print("Creating bucket...")
1759
+ s3.create_bucket(Bucket=bucket_name)
1760
+
1761
+ # 2. Upload object
1762
+ print("Uploading object...")
1763
+ s3.put_object(
1764
+ Bucket=bucket_name,
1765
+ Key="test-file.txt",
1766
+ Body=b"Hello, S3!",
1767
+ ContentType="text/plain"
1768
+ )
1769
+
1770
+ # 3. Generate presigned URL
1771
+ print("Generating presigned URL...")
1772
+ url = s3.generate_presigned_url(
1773
+ ClientMethod="get_object",
1774
+ Params={"Bucket": bucket_name, "Key": "test-file.txt"},
1775
+ ExpiresIn=3600
1776
+ )
1777
+ print(f"Presigned URL: {url}")
1778
+
1779
+ # 4. Download object
1780
+ print("Downloading object...")
1781
+ response = s3.get_object(Bucket=bucket_name, Key="test-file.txt")
1782
+ content = response["Body"].read().decode("utf-8")
1783
+ print(f"Content: {content}")
1784
+
1785
+ # 5. List objects
1786
+ print("Listing objects...")
1787
+ response = s3.list_objects_v2(Bucket=bucket_name)
1788
+ for obj in response.get("Contents", []):
1789
+ print(f" • {obj['Key']}")
1790
+
1791
+ # 6. Delete object
1792
+ print("Deleting object...")
1793
+ s3.delete_object(Bucket=bucket_name, Key="test-file.txt")
1794
+
1795
+ # 7. Delete bucket
1796
+ print("Deleting bucket...")
1797
+ s3.delete_bucket(Bucket=bucket_name)
1798
+
1799
+ print("Complete!")
1800
+
1801
+ except ClientError as e:
1802
+ print(f"Error: {e}")
1803
+
1804
+ if __name__ == "__main__":
1805
+ import time
1806
+ main()
1807
+ ```