Package: aioaws
aioawsAsyncio compatible SDK for aws services.This library does not depend on boto, boto3 or any of the other bloated, opaque and mind thumbing AWS SDKs. Instead, it
is written from scratch to provide clean, secure and easily debuggable access to AWS services I want to use.The library is formatted with black and includes complete type hints (mypy passes in strict-mode).It currently supports:S3- list, delete, recursive delete, generating signed upload URLs, generating signed download URLsSES- sending emails including with attachments and multipartSNS- enough to get notifications about mail delivery from SESAWS Signature Version 4authentication for any AWS service (this is the only clean & modern implementation of AWS4 I know of in python, seecore.py)The only dependencies ofaioaws, are:aiofiles- for asynchronous reading of filescryptography- for verifying SNS signatureshttpx- for HTTP requestspydantic- for validating responsesInstallpipinstallaioawsS3 Usageimportasyncio# requires `pip install aioaws`fromaioaws.s3importS3Client,S3ConfigfromhttpximportAsyncClient# requires `pip install devtools`fromdevtoolsimportdebugasyncdefs3_demo(client:AsyncClient):s3=S3Client(client,S3Config('<access key>','<secret key>','<region>','my_bucket_name.com'))# upload a file:awaits3.upload('path/to/upload-to.txt',b'this the content')# list all files in a bucketfiles=[fasyncforfins3.list()]debug(files)"""[S3File(key='path/to/upload-to.txt',last_modified=datetime.datetime(...),size=16,e_tag='...',storage_class='STANDARD',),]"""# list all files with a given prefix in a bucketfiles=[fasyncforfins3.list('path/to/')]debug(files)# # delete a file# await s3.delete('path/to/file.txt')# # delete two files# await s3.delete('path/to/file1.txt', 'path/to/file2.txt')# delete recursively based on a prefixawaits3.delete_recursive('path/to/')# generate an upload link suitable for sending to a borwser to enabled# secure direct file upload (see below)upload_data=s3.signed_upload_url(path='path/to/',filename='demo.png',content_type='image/png',size=123,)debug(upload_data)"""{'url': 'https://my_bucket_name.com/','fields': {'Key': 'path/to/demo.png','Content-Type': 'image/png','AWSAccessKeyId': '<access key>','Content-Disposition': 'attachment; filename="demo.png"','Policy': '...','Signature': '...',},}"""# generate a temporary link to allow yourself or a client to download a filedownload_url=s3.signed_download_url('path/to/demo.png',max_age=60)print(download_url)#> https://my_bucket_name.com/path/to/demo.png?....asyncdefmain():asyncwithAsyncClient(timeout=30)asclient:awaits3_demo(client)asyncio.run(main())upload_datashown in the above example can be used in JS with something like this:constformData=newFormData()for(let[name,value]ofObject.entries(upload_data.fields)){formData.append(name,value)}constfileField=document.querySelector('input[type="file"]')formData.append('file',fileField.files[0])constresponse=awaitfetch(upload_data.url,{method:'POST',body:formData})(in the request to getupload_datayou would need to provide the file size and content-type in order
for them for the upload shown here to succeed)SESTo send an email with SES:frompathlibimportPathfromhttpximportAsyncClientfromaioaws.sesimportSesConfig,SesClient,SesRecipient,SesAttachmentasyncdefses_demo(client:AsyncClient):ses_client=SesClient(client,SesConfig('<access key>','<secret key>','<region>'))message_id=awaitses_client.send_email(SesRecipient('sende@example.com','Sender','Name'),'This is the subject',[SesRecipient('recipient@eample.com','John','Doe')],'this is the plain text body',html_body='<b>This is the HTML body.<b>',bcc=[SesRecipient(...)],attachments=[SesAttachment(b'this is content','attachment-name.txt','text/plain'),SesAttachment(Path('foobar.png')),],unsubscribe_link='https:://example.com/unsubscribe',configuration_set='SES configuration set',message_tags={'ses':'tags','go':'here'},)print('SES message ID:',message_id)asyncdefmain():asyncwithAsyncClient()asclient:awaitses_demo(client)asyncio.run(main())SNSReceiving data about SES webhooks from SNS (assuming you're using FastAPI)fromaioaws.sesimportSesWebhookInfofromaioaws.snsimportSnsWebhookErrorfromfastapiimportRequestfromhttpximportAsyncClientasync_client=AsyncClient...@app.post('/ses-webhook/',include_in_schema=False)asyncdefses_webhook(request:Request):request_body=awaitrequest.body()try:webhook_info=awaitSesWebhookInfo.build(request_body,async_client)exceptSnsWebhookErrorase:debug(message=e.message,details=e.details,headers=e.headers)raise...debug(webhook_info)...Seeherefor more information about what's provided in aSesWebhookInfo.