63
63
GetObjectOutput ,
64
64
GetObjectRequest ,
65
65
GetObjectRetentionOutput ,
66
- GetObjectTaggingOutput ,
67
- GetObjectTaggingRequest ,
68
66
HeadObjectOutput ,
69
67
HeadObjectRequest ,
70
68
InputSerialization ,
@@ -215,8 +213,10 @@ class S3Provider(S3Api, ServiceLifecycleHook):
215
213
def get_store (account_id : Optional [str ] = None , region : Optional [str ] = None ) -> S3Store :
216
214
return s3_stores [account_id or DEFAULT_AWS_ACCOUNT_ID ][region or AWS_REGION_US_EAST_1 ]
217
215
218
- def _clear_bucket_from_store (self , context : RequestContext , bucket : BucketName ):
219
- store = self .get_store (context .account_id , context .region )
216
+ def _clear_bucket_from_store (
217
+ self , bucket_account_id : str , bucket_region : str , bucket : BucketName
218
+ ):
219
+ store = self .get_store (bucket_account_id , bucket_region )
220
220
store .bucket_lifecycle_configuration .pop (bucket , None )
221
221
store .bucket_versioning_status .pop (bucket , None )
222
222
store .bucket_cors .pop (bucket , None )
@@ -330,8 +330,14 @@ def create_bucket(
330
330
def delete_bucket (
331
331
self , context : RequestContext , bucket : BucketName , expected_bucket_owner : AccountId = None
332
332
) -> None :
333
+ moto_backend = get_moto_s3_backend (context )
334
+ moto_bucket = get_bucket_from_moto (moto_backend , bucket = bucket )
333
335
call_moto (context )
334
- self ._clear_bucket_from_store (context , bucket )
336
+ self ._clear_bucket_from_store (
337
+ bucket_account_id = moto_bucket .account_id ,
338
+ bucket_region = moto_bucket .region_name ,
339
+ bucket = bucket ,
340
+ )
335
341
self ._cors_handler .invalidate_cache ()
336
342
337
343
def get_bucket_location (
@@ -645,20 +651,18 @@ def delete_object(
645
651
request : DeleteObjectRequest ,
646
652
) -> DeleteObjectOutput :
647
653
# TODO: implement DeleteMarker response
654
+ bucket_name = request ["Bucket" ]
655
+ moto_backend = get_moto_s3_backend (context )
656
+ moto_bucket = get_bucket_from_moto (moto_backend , bucket = bucket_name )
648
657
if request .get ("BypassGovernanceRetention" ) is not None :
649
- bucket_name = request ["Bucket" ]
650
- moto_backend = get_moto_s3_backend (context )
651
- bucket = get_bucket_from_moto (moto_backend , bucket = bucket_name )
652
- if not bucket .object_lock_enabled :
658
+ if not moto_bucket .object_lock_enabled :
653
659
raise InvalidArgument (
654
660
"x-amz-bypass-governance-retention is only applicable to Object Lock enabled buckets." ,
655
661
ArgumentName = "x-amz-bypass-governance-retention" ,
656
662
)
657
663
658
- if (
659
- request ["Bucket" ]
660
- not in self .get_store (context .account_id , context .region ).bucket_notification_configs
661
- ):
664
+ store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
665
+ if request ["Bucket" ] not in store .bucket_notification_configs :
662
666
return call_moto (context )
663
667
664
668
# TODO: we do not differentiate between deleting a key and creating a DeleteMarker in a versioned bucket
@@ -759,8 +763,7 @@ def complete_multipart_upload(
759
763
)
760
764
761
765
bucket_name = request ["Bucket" ]
762
- moto_backend = get_moto_s3_backend (context )
763
- moto_bucket = get_bucket_from_moto (moto_backend , bucket_name )
766
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket_name )
764
767
if not (upload_id := request .get ("UploadId" )) in moto_bucket .multiparts :
765
768
raise NoSuchUpload (
766
769
"The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed." ,
@@ -778,7 +781,7 @@ def complete_multipart_upload(
778
781
def upload_part (self , context : RequestContext , request : UploadPartRequest ) -> UploadPartOutput :
779
782
bucket_name = request ["Bucket" ]
780
783
moto_backend = get_moto_s3_backend (context )
781
- moto_bucket = get_bucket_from_moto (moto_backend , bucket_name )
784
+ moto_bucket = get_bucket_from_moto (moto_backend , bucket = bucket_name )
782
785
if not (upload_id := request .get ("UploadId" )) in moto_bucket .multiparts :
783
786
raise NoSuchUpload (
784
787
"The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed." ,
@@ -873,22 +876,6 @@ def list_multipart_uploads(
873
876
874
877
return response
875
878
876
- @handler ("GetObjectTagging" , expand = False )
877
- def get_object_tagging (
878
- self , context : RequestContext , request : GetObjectTaggingRequest
879
- ) -> GetObjectTaggingOutput :
880
- response : GetObjectTaggingOutput = call_moto (context )
881
- # FIXME: because of an issue with the serializer, we cannot return the VersionId for now
882
- # the specs give a GetObjectTaggingOutput but the real return tag is `Tagging` which already exists as a shape
883
- # we can't add the VersionId for now
884
- if (
885
- "VersionId" in response
886
- and request ["Bucket" ]
887
- not in self .get_store (context .account_id , context .region ).bucket_versioning_status
888
- ):
889
- response .pop ("VersionId" )
890
- return response
891
-
892
879
@handler ("PutObjectTagging" , expand = False )
893
880
def put_object_tagging (
894
881
self , context : RequestContext , request : PutObjectTaggingRequest
@@ -1312,27 +1299,26 @@ def put_bucket_notification_configuration(
1312
1299
self ._verify_notification_configuration (
1313
1300
notification_configuration , skip_destination_validation , context , bucket
1314
1301
)
1315
- self .get_store (context .account_id , context .region ).bucket_notification_configs [
1316
- bucket
1317
- ] = notification_configuration
1302
+ moto_backend = get_moto_s3_backend (context )
1303
+ moto_bucket = get_bucket_from_moto (moto_backend , bucket = bucket )
1304
+ store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1305
+ store .bucket_notification_configs [bucket ] = notification_configuration
1318
1306
1319
1307
def get_bucket_notification_configuration (
1320
1308
self , context : RequestContext , bucket : BucketName , expected_bucket_owner : AccountId = None
1321
1309
) -> NotificationConfiguration :
1322
1310
# TODO how to verify expected_bucket_owner
1323
1311
# check if the bucket exists
1324
- get_bucket_from_moto (get_moto_s3_backend (context ), bucket = bucket )
1325
- return self .get_store (context .account_id , context .region ).bucket_notification_configs .get (
1326
- bucket , NotificationConfiguration ()
1327
- )
1312
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket = bucket )
1313
+ store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1314
+ return store .bucket_notification_configs .get (bucket , NotificationConfiguration ())
1328
1315
1329
1316
def get_bucket_website (
1330
1317
self , context : RequestContext , bucket : BucketName , expected_bucket_owner : AccountId = None
1331
1318
) -> GetBucketWebsiteOutput :
1332
1319
# to check if the bucket exists
1333
1320
# TODO: simplify this when we don't use moto
1334
- moto_backend = get_moto_s3_backend (context )
1335
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1321
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket = bucket )
1336
1322
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1337
1323
if not (website_configuration := store .bucket_website_configuration .get (bucket )):
1338
1324
ex = NoSuchWebsiteConfiguration (
@@ -1354,8 +1340,7 @@ def put_bucket_website(
1354
1340
) -> None :
1355
1341
# to check if the bucket exists
1356
1342
# TODO: simplify this when we don't use moto
1357
- moto_backend = get_moto_s3_backend (context )
1358
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1343
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1359
1344
1360
1345
validate_website_configuration (website_configuration )
1361
1346
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
@@ -1366,12 +1351,10 @@ def delete_bucket_website(
1366
1351
) -> None :
1367
1352
# to check if the bucket exists
1368
1353
# TODO: simplify this when we don't use moto
1369
- moto_backend = get_moto_s3_backend (context )
1370
- get_bucket_from_moto ( moto_backend , bucket )
1354
+ moto_bucket = get_bucket_from_moto ( get_moto_s3_backend (context ), bucket = bucket )
1355
+ store = self . get_store ( moto_bucket . account_id , moto_bucket . region_name )
1371
1356
# does not raise error if the bucket did not have a config, will simply return
1372
- self .get_store (context .account_id , context .region ).bucket_website_configuration .pop (
1373
- bucket , None
1374
- )
1357
+ store .bucket_website_configuration .pop (bucket , None )
1375
1358
1376
1359
def post_object (
1377
1360
self , context : RequestContext , bucket : BucketName , body : IO [Body ] = None
@@ -1397,11 +1380,9 @@ def post_object(
1397
E377
code>
1380
if "${filename}" in key_name :
1398
1381
key_name = key_name .replace ("${filename}" , context .request .files ["file" ].filename )
1399
1382
1400
- moto_backend = get_moto_s3_backend (context )
1401
1383
# TODO: add concept of VersionId
1402
- key = get_key_from_moto_bucket (
1403
- get_bucket_from_moto (moto_backend , bucket = bucket ), key = key_name
1404
- )
1384
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket = bucket )
1385
+ key = get_key_from_moto_bucket (moto_bucket , key = key_name )
1405
1386
# hacky way to set the etag in the headers as well: two locations for one value
1406
1387
response ["ETagHeader" ] = key .etag
1407
1388
@@ -1423,7 +1404,8 @@ def post_object(
1423
1404
"LocationHeader" , f"{ get_full_default_bucket_location (bucket )} { key_name } "
1424
1405
)
1425
1406
1426
- if bucket in self .get_store (context .account_id , context .region ).bucket_versioning_status :
1407
+ store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1408
+ if bucket in store .bucket_versioning_status :
1427
1409
response ["VersionId" ] = key .version_id
1428
1410
1429
1411
self ._notify (context , key_name = key_name )
@@ -1444,11 +1426,10 @@ def get_object_attributes(
1444
1426
request : GetObjectAttributesRequest ,
1445
1427
) -> GetObjectAttributesOutput :
1446
1428
bucket_name = request ["Bucket" ]
1447
- moto_backend = get_moto_s3_backend (context )
1448
- bucket = get_bucket_from_moto (moto_backend , bucket_name )
1429
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket_name )
1449
1430
# TODO: rework the delete marker handling
1450
1431
key = get_key_from_moto_bucket (
1451
- moto_bucket = bucket ,
1432
+ moto_bucket = moto_bucket ,
1452
1433
key = request ["Key" ],
1453
1434
version_id = request .get ("VersionId" ),
1454
1435
raise_if_delete_marker_method = "GET" ,
@@ -1470,10 +1451,8 @@ def get_object_attributes(
1470
1451
1471
1452
response ["LastModified" ] = key .last_modified
1472
1453
1473
- if (
1474
- bucket_name
1475
- in self .get_store (context .account_id , context .region ).bucket_versioning_status
1476
- ):
1454
+ store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1455
+ if bucket_name in store .bucket_versioning_status :
1477
1456
response ["VersionId" ] = key .version_id
1478
1457
1479
1458
if key .multipart :
@@ -1491,8 +1470,7 @@ def put_bucket_analytics_configuration(
1491
1470
analytics_configuration : AnalyticsConfiguration ,
1492
1471
expected_bucket_owner : AccountId = None ,
1493
1472
) -> None :
1494
- moto_backend = get_moto_s3_backend (context )
1495
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1473
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1496
1474
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1497
1475
1498
1476
validate_bucket_analytics_configuration (
@@ -1511,8 +1489,7 @@ def get_bucket_analytics_configuration(
1511
1489
id : AnalyticsId ,
1512
1490
expected_bucket_owner : AccountId = None ,
1513
1491
) -> GetBucketAnalyticsConfigurationOutput :
1514
- moto_backend = get_moto_s3_backend (context )
1515
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1492
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1516
1493
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1517
1494
1518
1495
analytics_configuration : AnalyticsConfiguration = store .bucket_analytics_configuration .get (
@@ -1529,8 +1506,7 @@ def list_bucket_analytics_configurations(
1529
1506
continuation_token : Token = None ,
1530
1507
expected_bucket_owner : AccountId = None ,
1531
1508
) -> ListBucketAnalyticsConfigurationsOutput :
1532
- moto_backend = get_moto_s3_backend (context )
1533
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1509
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1534
1510
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1535
1511
1536
1512
analytics_configurations : Dict [
@@ -1550,8 +1526,7 @@ def delete_bucket_analytics_configuration(
1550
1526
id : AnalyticsId ,
1551
1527
expected_bucket_owner : AccountId = None ,
1552
1528
) -> None :
1553
- moto_backend = get_moto_s3_backend (context )
1554
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1529
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1555
1530
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1556
1531
1557
1532
analytics_configurations = store .bucket_analytics_configuration .get (bucket , {})
@@ -1565,8 +1540,7 @@ def put_bucket_intelligent_tiering_configuration(
1565
1540
id : IntelligentTieringId ,
1566
1541
intelligent_tiering_configuration : IntelligentTieringConfiguration ,
1567
1542
) -> None :
1568
- moto_backend = get_moto_s3_backend (context )
1569
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1543
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1570
1544
1571
1545
validate_bucket_intelligent_tiering_configuration (id , intelligent_tiering_configuration )
1572
1546
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
@@ -1578,8 +1552,7 @@ def put_bucket_intelligent_tiering_configuration(
1578
1552
def get_bucket_intelligent_tiering_configuration (
1579
1553
self , context : RequestContext , bucket : BucketName , id : IntelligentTieringId
1580
1554
) -> GetBucketIntelligentTieringConfigurationOutput :
1581
- moto_backend = get_moto_s3_backend (context )
1582
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1555
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1583
1556
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1584
1557
1585
1558
intelligent_tiering_configuration : IntelligentTieringConfiguration = (
@@ -1594,8 +1567,7 @@ def get_bucket_intelligent_tiering_configuration(
1594
1567
def delete_bucket_intelligent_tiering_configuration (
1595
1568
self , context : RequestContext , bucket : BucketName , id : IntelligentTieringId
1596
1569
) -> None :
1597
- moto_backend = get_moto_s3_backend (context )
1598
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1570
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1599
1571
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1600
1572
1601
1573
bucket_intelligent_tiering_configurations = (
@@ -1607,8 +1579,7 @@ def delete_bucket_intelligent_tiering_configuration(
1607
1579
def list_bucket_intelligent_tiering_configurations (
1608
1580
self , context : RequestContext , bucket : BucketName , continuation_token : Token = None
1609
1581
) -> ListBucketIntelligentTieringConfigurationsOutput :
1610
- moto_backend = get_moto_s3_backend (context )
1611
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1582
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1612
1583
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1613
1584
1614
1585
bucket_intelligent_tiering_configurations : Dict [
@@ -1633,7 +1604,7 @@ def put_bucket_logging(
1633
1604
expected_bucket_owner : AccountId = None ,
1634
1605
) -> None :
1635
1606
moto_backend = get_moto_s3_backend (context )
1636
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1607
+ moto_bucket = get_bucket_from_moto (moto_backend , bucket = bucket )
1637
1608
1638
1609
if not (logging_config := bucket_logging_status .get ("LoggingEnabled" )):
1639
1610
moto_bucket .logging = {}
@@ -1665,8 +1636,7 @@ def put_bucket_logging(
1665
1636
def get_bucket_logging (
1666
1637
self , context : RequestContext , bucket : BucketName , expected_bucket_owner : AccountId = None
1667
1638
) -> GetBucketLoggingOutput :
1668
- moto_backend = get_moto_s3_backend (context )
1669
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1639
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1670
1640
if not moto_bucket .logging :
1671
1641
return GetBucketLoggingOutput ()
1672
1642
@@ -1721,8 +1691,7 @@ def put_bucket_inventory_configuration(
1721
1691
inventory_configuration : InventoryConfiguration ,
1722
1692
expected_bucket_owner : AccountId = None ,
1723
1693
) -> None :
1724
- moto_backend = get_moto_s3_backend (context )
1725
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1694
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1726
1695
1727
1696
validate_inventory_configuration (
1728
1697
config_id = id , inventory_configuration = inventory_configuration
@@ -1739,8 +1708,7 @@ def get_bucket_inventory_configuration(
1739
1708
id : InventoryId ,
1740
1709
expected_bucket_owner : AccountId = None ,
1741
1710
) -> GetBucketInventoryConfigurationOutput :
1742
- moto_backend = get_moto_s3_backend (context )
1743
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1711
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1744
1712
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1745
1713
1746
1714
inventory_configuration = store .bucket_inventory_configurations .get (bucket , {}).get (id )
@@ -1755,8 +1723,7 @@ def list_bucket_inventory_configurations(
1755
1723
continuation_token : Token = None ,
1756
1724
expected_bucket_owner : AccountId = None ,
1757
1725
) -> ListBucketInventoryConfigurationsOutput :
1758
- moto_backend = get_moto_s3_backend (context )
1759
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1726
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1760
1727
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1761
1728
1762
1729
bucket_inventory_configurations = store .bucket_inventory_configurations .get (bucket , {})
@@ -1775,8 +1742,7 @@ def delete_bucket_inventory_configuration(
1775
1742
id : InventoryId ,
1776
1743
expected_bucket_owner : AccountId = None ,
1777
1744
) -> None :
1778
- moto_backend = get_moto_s3_backend (context )
1779
- moto_bucket = get_bucket_from_moto (moto_backend , bucket )
1745
+ moto_bucket = get_bucket_from_moto (get_moto_s3_backend (context ), bucket )
1780
1746
store = self .get_store (moto_bucket .account_id , moto_bucket .region_name )
1781
1747
1782
1748
bucket_inventory_configurations = store .bucket_inventory_configurations .get (bucket , {})
0 commit comments