How to remove all files from Linode S3 boto using python? - python-3.x

I successfully create files in bucket of object storage in Linode. But while deleting all files in that storage it prompts an error.
import boto3
cfg = {
"aws_access_key_id":"XXXXXXXXXXXXXXXXXX",
"aws_secret_access_key": "XXXXXXXXXXXXXXXXXXXXXXXX",
"endpoint_url": "*********************",
}
S3_BUCKET = "test"
# empty existing bucket
def empty_s3_bucket():
client = boto3.client(
's3',
**cfg,
)
response = client.list_objects_v2(Bucket=S3_BUCKET)
if 'Contents' in response:
for item in response['Contents']:
print('deleting file', item['Key'])
client.delete_object(Bucket=S3_BUCKET, Key=item['Key'])
while response['KeyCount'] == 1000:
response = client.list_objects_v2(
Bucket=S3_BUCKET,
StartAfter=response['Contents'][0]['Key'],
)
for item in response['Contents']:
print('deleting file', item['Key'])
client.delete_object(Bucket=S3_BUCKET, Key=item['Key'])
empty_s3_bucket()
Above code cannot delete all files in that object storage however can delete single file by using different logic. Following error generates on above code:
Traceback (most recent call last):
File "c:/********/linode_empty.py", line 30, in <module>
empty_s3_bucket()
File "c:/*********/linode_empty.py", line 16, in empty_s3_bucket
response = client.list_objects_v2(Bucket=S3_BUCKET)
File "C:\********\venv\lib\site-packages\botocore\client.py", line 357, in _api_call
return self._make_api_call(operation_name, kwargs)
File "C:\*******\venv\lib\site-packages\botocore\client.py", line 676, in _make_api_call
raise error_class(parsed_response, operation_name)
botocore.errorfactory.NoSuchKey: An error occurred (NoSuchKey) when calling the ListObjectsV2 operation: Unknown
I tried for different codes suggested in old post about this on stackoverflow Amazon S3 boto - how to delete folder? but got same error.

try this:
it'll collect all the keys and batch delete 1000 at a time
import math
s3sr = boto3.resource('s3')
s3sc = boto3.client('s3')
def get_list_of_keys_from_prefix(bucket, prefix):
"""gets list of keys for given bucket and prefix"""
keys_list = []
paginator = s3sr.meta.client.get_paginator('list_objects_v2')
# use Delimiter to limit search to that level of hierarchy
for page in paginator.paginate(Bucket=bucket, Prefix=prefix, Delimiter='/'):
keys = [content['Key'] for content in page.get('Contents')]
# print('keys in page: ', len(keys))
keys_list.extend(keys)
# print(keys_list)
print('total keys in bucket: ', len(keys_list))
return keys_list
bucket = 'test'
prefix = '' #if you have 'subfolders' enter the prefix, otherwise use ''
keys_list = get_list_of_keys_from_prefix(bucket, prefix)
# print(keys_list)
total_keys = len(keys_list)
chunk_size = 1000
num_batches = math.ceil(total_keys / chunk_size)
for b in range(0, num_batches):
batch_to_delete = []
for k in keys_list[chunk_size*b:chunk_size*b+chunk_size]:
batch_to_delete.append({'Key': k})
# print({'Key': k})
# print(batch_to_delete)
s3sc.delete_objects(Bucket=bucket, Delete={'Objects': batch_to_delete,},'Quiet': True)

I'm using the previous code for less than 1000 objects
import boto3
linode_obj_config = {
"aws_access_key_id": "",
"aws_secret_access_key": "",
"endpoint_url": "",
}
client = boto3.client("s3", **linode_obj_config)
def get_list_of_keys_from_prefix(bucket, prefix):
keys_list = []
response = client.list_objects(Bucket=bucket, Prefix=prefix)
for obj in response['Contents']:
keys_list.append(obj["Key"])
# print(keys_list)
# print('total keys in bucket: ', len(keys_list))
# print("list keys: ", keys_list)
return keys_list
bucket = ''
prefix = ''
keys_list = get_list_of_keys_from_prefix(bucket, prefix)
for b in keys_list:
client.delete_object(Bucket=bucket, Key=b)

Related

How do you a change guild icon from a list of randomly selected local image's?

I have been trying to make a Slash command to change the Guild's icon. The icon it changes it to is picked from a list of icons at random but I'm getting this error and have no idea what it means:
Ignoring exception in command icon_change: Traceback (most recent call last): File "C:\Users\Leo\AppData\Local\Programs\Python\Python310\lib\site-packages\nextcord\application_command.py", line 1053, in _call_with_hooks
await callback(*args) File "C:\Users\Leo\AppData\Local\Programs\Python\Python310\lib\site-packages\nextcord\application_command.py", line 1135, in call_invoke_slash
await self.invoke_slash(interaction, **kwargs) File "C:\Users\Leo\AppData\Local\Programs\Python\Python310\lib\site-packages\nextcord\application_command.py", line 1228, in invoke_slash
await self.callback(interaction, **kwargs) File "C:\PC Code\Python\Nextcord - Bots\utilities 2.6 - NextCord.py", line 255, in icon_change
await interaction.guild.edit(icon=ficon) File "C:\Users\Leo\AppData\Local\Programs\Python\Python310\lib\site-packages\nextcord\guild.py", line 1570, in edit
fields['icon'] = utils._bytes_to_base64_data(icon) File "C:\Users\Leo\AppData\Local\Programs\Python\Python310\lib\site-packages\nextcord\utils.py", line 495, in _bytes_to_base64_data
mime = _get_mime_type_for_image(data) File "C:\Users\Leo\AppData\Local\Programs\Python\Python310\lib\site-packages\nextcord\utils.py", line 481, in _get_mime_type_for_image
if data.startswith(b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A'): TypeError: startswith first arg must be str or a tuple of str, not bytes
The above exception was the direct cause of the following exception:
nextcord.errors.ApplicationInvokeError: Command raised an exception: TypeError: startswith first arg must be str or a tuple of str, not bytes
Here is the code I currently have:
#bot.slash_command(description="Change server icon")
#application_checks.is_owner()
async def icon_change(interaction : Interaction):
with open('C:\Server_Icons\Logoaa.png', 'rb') as Iconaa:
icona = Iconaa.read()
with open('C:\Server_Icons\Logocc.png', 'rb') as Iconcc:
iconc = Iconcc.read()
with open('C:\Server_Icons\Logodd.png', 'rb') as Icondd:
icond = Icondd.read()
with open('C:\Server_Icons\Logoff.png', 'rb') as Iconff:
iconf = Iconff.read()
with open('C:\Server_Icons\Logohh.png', 'rb') as Iconhh:
iconh = Iconhh.read()
iconch = ['icona', 'iconc', 'icond', 'iconf', 'iconh']
ficon = random.choice(iconch)
await interaction.guild.edit(icon=ficon)
Any help would be appreciated.
This can be fixed by converting the image to a byte array using 'bytearray()'
Example:
with open('C:\Images\Image.png', 'rb') as Image:
a = Image.read()
imageA = bytearray(a)
Fixed code:
#bot.slash_command(description="Change server icon")
#application_checks.is_owner()
async def icon_change(interaction : Interaction):
with open('C:\Server_Icons\Logoaa.png', 'rb') as Iconaa:
iconaaa = Iconaa.read()
icona = bytearray(iconaaa)
with open('C:\Server_Icons\Logocc.png', 'rb') as Iconcc:
iconccc = Iconcc.read()
iconc = bytearray(iconccc)
with open('C:\Server_Icons\Logodd.png', 'rb') as Icondd:
iconddd = Icondd.read()
icond = bytearray(iconddd)
with open('C:\Server_Icons\Logoff.png', 'rb') as Iconff:
iconfff = Iconff.read()
iconf = bytearray(iconfff)
with open('C:\Server_Icons\Logohh.png', 'rb') as Iconhh:
iconhhh = Iconhh.read()
iconh = bytearray(iconhhh)
iconch = [icona, iconc, icond, iconf, iconh]
ficon = random.choice(iconch)
await interaction.send(f"Icon changed!")
await interaction.guild.edit(icon=ficon)

How can I delete via python all the s3 "delete marker" placeholder filtered by "LastModified " (for ex. just from yesterday)?

I modified some scripts to delete all the "delete marker" placeholders from some bucket in s3 but I never found/developed something where I can delete the "delete marker" filtered by datetime.
My scope is to create a script to run after a "delete_object_job" failure, so I can run a new script where set the datatime of the failure and delete all the "delete-marker" just from that datetime.
Actually from this code I can delete all the "data marker" from some buckets but without a datetime filter:
#!/usr/bin/env python
import json
from datetime import datetime
from boto3 import Session
BUCKET_NAME = "germano"
prefix = ''
session = Session(region_name='eu-south-1', profile_name='default')
bucket = session.client('s3')
MAX_KEYS = 10000
def get_bucket_versions(version_id, key):
return bucket.list_object_versions(Bucket=BUCKET_NAME,
MaxKeys=MAX_KEYS,
Prefix=prefix,
VersionIdMarker=version_id,
KeyMarker=key)
class DateTimeEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime):
return o.isoformat()
return json.JSONEncoder.default(self, o)
#ottengo gli attributes della classe creata DateTimeEncoder
#DateTimeEncoder = DateTimeEncoder()
#attributes_of_DateTimeEncoder = dir(DateTimeEncoder)
#print(attributes_of_DateTimeEncoder)
def objects_to_restore(versions):
return [
{
'VersionId': marker['VersionId'],
'Key': marker['Key']
} for marker in versions.get('DeleteMarkers') if marker['IsLatest']
]
def restore_s3_objects(version_markers, count):
markers_to_delete = objects_to_restore(version_markers)
print(f"Will restore {len(markers_to_delete)} items during request number: {count}")
if not markers_to_delete:
return 0
bucket.delete_objects(Bucket=BUCKET_NAME, Delete={'Objects': markers_to_delete})
return len(markers_to_delete)
obj_list = bucket.list_object_versions(Bucket=BUCKET_NAME,
MaxKeys=MAX_KEYS,
Prefix=prefix)
_next_version_id = obj_list.get('NextVersionIdMarker')
_next_key_marker = obj_list.get('NextKeyMarker')
counter = 1
total_restored = restore_s3_objects(obj_list, counter)
while _next_version_id and _next_key_marker:
counter += 1
another_list_of_versions = get_bucket_versions(_next_version_id, _next_key_marker)
_next_version_id = another_list_of_versions.get('NextVersionIdMarker')
_next_key_marker = another_list_of_versions.get('NextKeyMarker')
total_restored += restore_s3_objects(another_list_of_versions, counter)
print(f"Total Restored: {total_restored}")
i solved just modifing a bit the function "objects_to_restore":
def objects_to_restore(versions, last_modified_timestamp="2022-04-28 09:19:56.986445+00:00"):
print (versions.get('DeleteMarkers'))
#print (versions.get('Versions'))
return [
{
'VersionId': marker['VersionId'],
'Key': marker['Key'],
} for marker in versions.get('DeleteMarkers')
if marker['IsLatest']
if str(marker["LastModified"]) >= str(last_modified_timestamp)

Boto3 get list of all ec2 instances with ebs volume id, size to an excel

Export AWS EC2 details to xlsx/csv using boto3 and python - This works but to gather EBS volumes, type and size attached to each ec2 instance and append to the same line in the excel is challenging for me. Below one, just appends the volume info in the next line. If I have a separate function and call it in "result.append", I could fetch only the first volume. If I return multiple values in the function like volume id, volume size, volume type - I could add all 3 of these values to the same cell in the excel, instead of a separate column for each. Please help. I'm obviously in learning phase.
volume_iterator = ec3.volumes.all()
for v in volume_iterator:
for a in v.attachments:
if a['InstanceId'] == each['InstanceId']:
result.append({
'volume.id': v.id,
'volume.size': v.size,
'volume.state': v.volume_type
})
Final output in CSV looks like below. All the volume related values are in the same column "volume.id". Volume info should be separated.
ImageId InstanceType InstanceId InstanceName volume.id volume.type volume.size
ami-042e828f5df03 t3.large i-07db6118eb51e <server_name> [{8, 'vol-0085fdebc7', 'gp3'}, {'vol-0d417698824e', 'gp3', 128}]
This works.
import boto3
import csv
import datetime
import logging
from os import environ
import collections
import time
import sys
### ENABLE The profilename below, while testing from local. Disable this and session line in 63, enable line 64 session before pushing to Lambda#######
profilename='<>'
aws_Acct='<>.csv'
volume_id_list=[]
result = []
regions = ['us-east-1', 'us-east-2', 'us-west-1', 'us-west-2']
#regions = ['us-east-1']
#Name Tag
def get_tag(each, tag_name):
if 'Tags' in each:
for tag in each['Tags']:
if tag['Key'] == tag_name:
return tag['Value']
return ''
#Volumes
def get_vol(each, ec2):
resultVol = {
"vol_id": "",
"vol_size": "",
"vol_type": ""
}
resp = ec2.describe_volumes(
Filters=[{'Name':'attachment.instance-id','Values':[each['InstanceId']]}]
)
for volume in (resp["Volumes"]):
resultVol['vol_id'] += (str(volume["VolumeId"]) + "\n")
resultVol['vol_size'] += (str(volume["Size"]) + "\n")
resultVol['vol_type'] += (str(volume["VolumeType"]) + "\n")
return resultVol
#Security Groups
def sec_gp(each, ec2):
resultSG = {
"sg_id": "",
"sg_name": ""
}
for sg in each['SecurityGroups']:
resultSG['sg_id'] += (str(sg["GroupId"]) + "\n")
resultSG['sg_name'] += (str(sg["GroupName"]) + "\n")
return resultSG
def lambda_handler(event, context):
try:
logging.basicConfig(level=logging.INFO)
logging.info('EC2 Inventory details')
for region in regions:
session = boto3.Session(profile_name=profilename, region_name=region)
#session = boto3.Session(region_name=region)
ec2 = session.client('ec2')
response = ec2.describe_instances()
for item in response["Reservations"]:
for each in item['Instances']:
volsss = get_vol(each, ec2)
sgss = sec_gp(each, ec2)
#print(sgss)
result.append({
'ImageId': each.get('ImageId', ''),
'InstanceType': each.get('InstanceType', ''),
'PublicIp': each.get('PublicIpAddress', ''),
'PrivateIp': each.get('PrivateIpAddress', ''),
'InstanceId': each.get('InstanceId', ''),
'SubnetId': each.get('SubnetId', ''),
'VpcId': each.get('VpcId', ''),
'InstanceName': get_tag(each, 'Name'),
'volume.size': volsss['vol_size'],
'volume.id': volsss['vol_id'],
'volume.type': volsss['vol_type'],
'DeleteOnTermination': each.get('DeleteOnTermination', ''),
'SGGroupName': sgss['sg_name'],
'SGGroupID': sgss['sg_id'],
'State': each['State']['Name'],
'Region': each['Placement']['AvailabilityZone']
})
# Write to csv file.
header = ['ImageId', 'InstanceType', 'InstanceId', 'InstanceName', 'PublicIp', 'PrivateIp', 'Region', 'State', 'volume.id', 'volume.size', 'volume.type', 'SubnetId', 'VpcId', 'SGGroupName', 'SGGroupID', 'DeleteOnTermination']
with open(aws_Acct, 'w') as file:
writer = csv.DictWriter(file, fieldnames=header)
writer.writeheader()
writer.writerows(result)
except Exception as e:
logging.error(
'EC2 inventory with uncaught exception: {}'.format(e)
)
if __name__ == '__main__':
lambda_handler(None, None)
Final output looks like:

IMAP4LIB When using the store command I get the error "BAD [b'Could not parse command']"

I am new to all of this so I'm sorry if I mess this up or have already made a mess. I have two classes a GUI and my MailSorter class in the GUI class I have method which logins, then one that fetches all the EmailIds then finally fetches all the From emails and stores it in a dict. which stores the From email and amount of times it appears and an array with the From email and the ID.
def fetchFrom(self,emailIDs):
EmailAmount = dict()
Email = []
count = 0
for emailId in emailIDs:
#Converts email into string
result2,email_data = self.mail.fetch(emailId,'(RFC822)')
try:
raw_email = email_data[0][1].decode("utf-8")
email_message = email.message_from_string(raw_email)
#Fetches email address sent from
From = email_message["From"]
Email.append((From,emailId))
#print(From)
if From in EmailAmount:
EmailAmount[From] = EmailAmount[From] + 1
else:
EmailAmount[From] = 1
count += 1
if count > 10:
break
except Exception as e:
self.log.append((emailId,e))
def mainScreenInterface(self):
#Process
print("Loading program")
EmailIds = self.Mail.fetchEmailId()
EmailDict, self.EmailArray = self.Mail.fetchFrom(EmailIds)
self.master.geometry("750x600")
self.master.title("Main Screen")
self.destoryWidget()
#New Frame
self.mainScreen = tk.Frame(self.master)
self.mainScreen.pack()
#Labels
mainText = tk.Label(self.mainScreen,text = "All Emails")
mainText.config(font=("Courier","25"))
#Buttons
delete = tk.Button(self.mainScreen,text="Delete", command = self.Delete)
deleteAll = tk.Button(self.mainScreen,text="Delete All", command = self.DeleteAll)
Help = tk.Button(self.mainScreen,text="Help", command = self.Help_)
#Scrollbar
scrollbar = tk.Scrollbar(root)
scrollbar.pack(side="right",fill="y")
#Listbox
self.listbox = tk.Listbox(root,width = root.winfo_screenwidth(), height = 25)
#Attach a scrool wheel to the listbox
self.listbox.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=self.listbox.yview)
#Add items to the list box
count = 1
for x,y in EmailDict.items():
self.listbox.insert(count,(x,y))
count += 1
#Placement
paddingValue = 40
mainText.pack(side="top")
self.listbox.pack(side="top")
delete.pack(side="left",padx=paddingValue)
deleteAll.pack(side="left",padx=paddingValue)
Help.pack(side="left",padx=paddingValue)
def Delete(self):
emailName = self.listbox.get(tk.ANCHOR)[0]
self.Mail.deleteEmail(emailName,self.EmailArray)
So the fetchFrom is from the mailSorter class and the other two are the GUI class, when I call the deleteEmail I get the error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:\Users\******\Desktop\Email Sorter v3.py", line 197, in Delete
self.Mail.deleteEmail(emailName,self.EmailArray)
File "C:\Users\******\Desktop\Email Sorter v3.py", line 66, in deleteEmail
self.mail.store(Id[1].strip(), '+X-GM-tk.LabelS', '\\Trash')
File "C:\Python\lib\imaplib.py", line 840, in store
typ, dat = self._simple_command('STORE', message_set, command, flags)
File "C:\Python\lib\imaplib.py", line 1196, in _simple_command
return self._command_complete(name, self._command(name, *args))
File "C:\Python\lib\imaplib.py", line 1027, in _command_complete
raise self.error('%s command error: %s %s' % (name, typ, data))
imaplib.IMAP4.error: STORE command error: BAD [b'Could not parse command']
but when I run it as a text base with no GUI and use an example email it all works fine:
test = MailSorter("hamadnassor5#gmail.com","snerfulbubble1.")
test.login()
EmailIds = test.fetchEmailId()
EmailDict, EmailArray = test.fetchFrom(EmailIds)
test.displayEmails(EmailDict)
test.deleteEmail("Xbox <Xbox#outlook.com>",EmailArray)
test.closeCon()
DeleteMail code
def deleteEmail(self, emailName, EmailArray):
for Id in EmailArray:
if Id[0] == emailName:
print(Id[0])
print(emailName)
print(Id[1])
self.mail.store(Id[1].strip(), '+X-GM-tk.LabelS', '\\Trash')

Read a CSV from Google Cloud Storage using Google Cloud Functions in Python script

I'm new in GCP and I'm trying to do a simple API with Cloud Functions. This API needs to read a CSV from Google Cloud Storage bucket and return a JSON. To do this, in my local I can run normally, open a file.
But in Cloud Functions, I received a blob from bucket, and don know how manipulate this, I'm receiving error
I try convert blob to Bytes and to string but i don't know exactly how do it
Code working in my local env:
data1 = '2019-08-20'
data1 = datetime.datetime.strptime(data1, '%Y-%m-%d')
data2 = '2019-11-21'
data2 = datetime.datetime.strptime(data2, '%Y-%m-%d')
with open("/home/thiago/mycsvexample.csv", "r") as fin:
#create a CSV dictionary reader object
print(type(fin))
csv_dreader = csv.DictReader(fin)
#iterate over all rows in CSV dict reader
for row in csv_dreader:
#check for invalid Date values
#convert date string to a date object
date = datetime.datetime.strptime(row['date'], '%Y-%m-%d')
#check if date falls within requested range
if date >= data1 and date <= data2:
total = total + float(row['total'])
print(total)
Code in Google Cloud Functions:
import csv, datetime
from google.cloud import storage
from io import BytesIO
def get_orders(request):
"""Responds to any HTTP request.
Args:
request (flask.Request): HTTP request object.
Returns:
The response text or any set of values that can be turned into a
Response object using
`make_response <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>`.
"""
request_json = request.get_json()
if request.args and 'token' in request.args:
if request.args['token'] == 'mytoken888888':
client = storage.Client()
bucket = client.get_bucket('mybucketgoogle.appspot.com')
blob = bucket.get_blob('mycsvfile.csv')
byte_stream = BytesIO()
blob.download_to_file(byte_stream)
byte_stream.seek(0)
file = byte_stream
#with open(BytesIO(blob), "r") as fin:
#create a CSV dictionary reader object
csv_dreader = csv.DictReader(file)
#iterate over all rows in CSV dict reader
for row in csv_dreader:
#check for invalid Date values
date = datetime.datetime.strptime(row['date'], '%Y-%m-%d')
#check if date falls within requested range
if date >= datetime.datetime.strptime(request.args['start_date']) and date <= datetime.datetime.strptime(request.args['end_date']):
total = total + float(row['total'])
dict = {'total_faturado' : total}
return dict
else:
return f'Passe parametros corretos'
else:
return f'Passe parametros corretos'
Error in Google Cloud Functions:
Traceback (most recent call last): File "/env/local/lib/python3.7/site-packages/google/cloud/functions/worker.py", line 346, in run_http_function result = _function_handler.invoke_user_function(flask.request) File "/env/local/lib/python3.7/site-packages/google/cloud/functions/worker.py", line 217, in invoke_user_function return call_user_function(request_or_event) File "/env/local/lib/python3.7/site-packages/google/cloud/functions/worker.py", line 210, in call_user_function return self._user_function(request_or_event) File "/user_code/main.py", line 31, in get_orders_tramontina for row in csv_dreader: File "/opt/python3.7/lib/python3.7/csv.py", line 111, in __next__ self.fieldnames File "/opt/python3.7/lib/python3.7/csv.py", line 98, in fieldnames self._fieldnames = next(self.reader) _csv.Error: iterator should return strings, not bytes (did you open the file in text mode?)
I try do some other things but no sucess...
Someone can help me with this blob, to convert this or manipulate with the right way?
Thank you all
This is the code that worked for me:
from google.cloud import storage
import csv
client = storage.Client()
bucket = client.get_bucket('source')
blob = bucket.blob('file')
dest_file = '/tmp/file.csv'
blob.download_to_filename(dest_file)
dict = {}
total = 0
with open(dest_file) as fh:
# assuming your csv is del by comma
rd = csv.DictReader(fh, delimiter=',')
for row in rd:
date = datetime.datetime.strptime(row['date'], '%Y-%m-%d')
#check if date falls within requested range
if date >= datetime.datetime.strptime(request.args['start_date']) and date <= datetime.datetime.strptime(request.args['end_date']):
total = total + float(row['total'])
dict['total_faturado'] = total
I'm able to do this too using a library gcsfs
https://gcsfs.readthedocs.io/en/latest/
def get_orders_tramontina(request):
"""Responds to any HTTP request.
Args:
request (flask.Request): HTTP request object.
Returns:
The response text or any set of values that can be turned into a
Response object using
`make_response <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>`.
"""
request_json = request.get_json()
if request.args and 'token' in request.args:
if request.args['token'] == 'mytoken':
fs = gcsfs.GCSFileSystem(project='myproject')
total = 0
with fs.open('mybucket.appspot.com/mycsv.csv', "r") as fin:
csv_dreader = csv.DictReader(fin)
#iterate over all rows in CSV dict reader
for row in csv_dreader:
#check for invalid Date values
date = datetime.datetime.strptime(row['date'], '%Y-%m-%d')
#check if date falls within requested range
if date >= datetime.datetime.strptime(request.args['start_date'], '%Y-%m-%d') and date <= datetime.datetime.strptime(request.args['end_date'], '%Y-%m-%d'):
total = total + float(row['total'])
dict = {'total_faturado' : total}
return json.dumps(dict)```
Try to download file as string, that way you can check for invalid data values, and eventually write that to a file.
change blob.download_to_file(byte_stream) to my_blob_str = blob.download_as_string()
I think your actual problem is byte_stream = BytesIO() since your output reads iterator should return strings, not bytes (did you open the file in text mode?)
It is expecting a string, but gets bytes. What is the purpose of byte_stream? If random, just remove it.

Resources