Validate and save a ZIP file in Flask - python-3.x

I'm writing an app using Flask and one of the things I want in it is the ability to upload a ZIP that conforms to a specific form; as such I have a small function that takes a FileStorage object from the form and first unzips it, checks the contents, and then tries to save. There's a problem, however - apparently unzipping it "breaks" the FileStorage object, as the following function:
def upload_modfile(modfile):
if not modfile.filename.endswith('.zip'):
raise ModError('Incorrect filename')
mod_path = join(get_mods_path(), secure_filename(modfile.filename))
if isfile(mod_path):
raise ModError('File ' + modfile.filename + ' already exists')
modzip = ZipFile(modfile)
base_filename = modfile.filename[:-4]
modzip_contents = modzip.namelist()
if join(base_filename, 'info.json') not in modzip_contents:
raise ModError('Could not validate file')
modfile.save(mod_path)
return True
saves modfile as a text file saying Archive: <filename>.zip. If I comment out the entire ZipFile bit (i.e. everything involving modzip), the file is saved just fine.
I'm pretty much brand new to Python and am a little confused as to what to do in this case, save for saving the file in /tmp. Should I somehow clone modfile by way of some stream? Is there a way of "rewinding" the stream pointer within FileStorage that I'm missing?

Related

Why Reading Upload file and Reading Local file producing different results?

I am posting file to python flask and then read its content using following code:
def post(self):
if 'file' not in request.files:
return {'error': 'no file'}
try:
f=open("text2.txt")
local_content=f.read()
content=request.files['file'].read().decode('utf-8')
if hash(content) != hash(local_content) :
return {'error': 'content changed','local':hash(local_content),'uploaded':hash(content)}
else:
return {'error': 'same','local':hash(local_content),'uploaded':hash(content)}
I also put same file text2.txt on server and read it locally using
local_content=f.read()
but both results are different.I tried comparing two string using following
if content != local_content
above conditions is always returning true.
but when I print both strings they are exactly same.
I am doing some processing on those strings and trying and both content and local_content produces different results.
So can anyone tell me why uploaded content is behaving differently than local content
Even I face this issue while uploading images using flask. The binary streams were different as compared to reading local file.
I solve this issue with file.seek(0)
files = request.files.getlist('files[]')
for file in files:
file.seek(0)
fileBytes = file.read()
image_stringRead = base64.b64encode(fileBytes)

Create and use WAV file as an object Python

I am creating a personal assistant in Python. I am using Snowboy to record audio, and it works very well. Snowboy has a saveMessage() method that creates and writes a wav file to the disk. This wav file is later read and used as an AudioFile object by Speech_Recognition. I find it very inefficient that the program has to write and read wav files to the disk. I would much rather have the wav file be passed around as an object without EVER saving it to the disk.
Here is the snowboy saveMessage() module that I would like to reweite.
def saveMessage(self):
"""
Save the message stored in self.recordedData to a timestamped file.
"""
filename = 'output' + str(int(time.time())) + '.wav'
data = b''.join(self.recordedData)
#use wave to save data
wf = wave.open(filename, 'wb')
wf.setnchannels(1)
wf.setsampwidth(self.audio.get_sample_size(
self.audio.get_format_from_width(
self.detector.BitsPerSample() / 8)))
wf.setframerate(self.detector.SampleRate())
wf.writeframes(data)
wf.close()
logger.debug("finished saving: " + filename)
return filename #INSTEAD OF RETURNING filename I WANT THIS TO RETURN THE wav file object
Please note that the AudioFile class requires that the path for the wave file OR a "file-like" object must be passed into it. I am not sure what a "file-like" object is, so I will provide the AudioFile assert statement for the wav file argument:
assert isinstance(filename_or_fileobject, (type(""), type(u""))) or hasattr(filename_or_fileobject, "read"), "Given audio file must be a filename string or a file-like object"
I have tried to use an instance of BytesIO to save the wav data, BytesIO is apparently not a file-like object. Here was what I tried:
def saveMessage(self):
filename = 'output' + str(int(time.time())) + '.wav'
data = b''.join(self.recordedData)
#use wave to save data
with io.BytesIO() as wav_file:
wav_writer = wave.open(wav_file, "wb")
try:
wav_writer.setnchannels(1)
wav_writer.setsampwidth(self.audio.get_sample_size(
self.audio.get_format_from_width(
self.detector.BitsPerSample() / 8)))
wav_writer.setframerate(self.detector.SampleRate())
wav_writer.writeframes(data)
wav_data = wav_file.getvalue()
finally:
wav_writer.close()
logger.debug("finished saving: " + filename)
return wav_data
The error I got was: AssertionError: Given audio file must be a filename string or a file-like object
I am using python 3.7 on a Raspberry PI 3B+ running Raspbian Buster Lite kernel version 4.19.36.
If I can provide any additional information or clarify anything, please ask.
Thanks so much!
Something like this should work:
from speech_recognition import AudioData
def saveMessage(self):
filename = 'output' + str(int(time.time())) + '.wav'
data = b''.join(self.recordedData)
ad = AudioData(data, 16000, 2)
result = recognizer.recognize_google(ad)
Note that speech_recognition.listen can invoke snowboy internally, so you probably don't have to use external snowboy, you can just use listen with parameter snowboy_configuration.

How to save files to a directory and append those files to a list in Python?

Scenario:
I want to check whether if a directory contains a certain '.png' image file. If so, this image file along with all the other files (with png extension only) gets stored in a different directory. (The solution I am looking for should work in all OS platforms i.e Windows, Unix, etc.) and in a remote server i.e (FTP etc.)
I have tried the following code below:
import os, sys
import shutil
import pathlib
import glob
def search():
image_file = 'picture.png'
try:
arr = [] #List will be used to append all the files in a particular directory.
directory = pathlib.Path("collection") #checks if the collection directory exists.
files = []
#need to convert the PosixPath (directory) to a string.
[files.extend(glob.glob(str(directory) + "/**/*.png", recursive = True))]
res = [img for img in files if(img in image_file)] #checks if the image is within the list of files i.e 'picture.png' == 'collection\\picture.png'
if str(bool(res)): #If True...proceed
print("Image is available in image upload storage directory")
for file in files:
transfer_file = str(file)
shutil.copy(file, 'PNG_files/') #send all the files to a different directory i.e 'PNG_files' by using the shutil module.
arr.append(transfer_file)
return arr
else:
print("image not found in directory")
except OSError as e:
return e.errno
result = search() #result should return the 'arr' list. This list should contain png images only.
However, during execution, the For loop is not getting executed. Which means:
The image files are not stored in the 'PNG_files' directory.
The images are not getting appended in the 'arr' list.
The code above the For loop worked as expected. Can anyone explain to me what went wrong?
There are several issues:
In this line
res = [img for img in files if(img in image_file)] #checks if the image is within the list of files i.e 'picture.png' == 'collection\\picture.png'
you should check the other way around (as written in the comment): image_file in img, e.g. picture.png in collection/picture.png.
str(directory) + "/**/*.png" is not OS independent. If you need this to work on Windows, too, you should use os.path.join(str(directory), '**', '*.png') instead!
This check is incorrect: if str(bool(res)):. It's actually always true, because bool(res) is either True or False, str(bool(res)) is either "True" or "False", but both are actually True, as neither is an empty string. Correctly: if res:.
And finally, you're missing the creation of the PNG_files directory. You need to either manually create it before running the script, or call os.mkdir().

Getting the absolute filename of file uploaded through Python Flask App

I am trying to create a flask app that can be used to upload any user selected file to my azure storage. For some reason, the mime-type of the uploaded file is always set to 'application/octet-stream'. If I directly upload the file to azure using its UI, then the mime-type is correct. To solve this problem, I am trying to manually calculate the mimetype of the file and pass it as metadata.
The issue I am having is that I am not able to figure out a way to get the absolute filepath of the user selected file to be uploaded.
What I am looking for is the absolute path: path/to/file/doctest2.txt
Here is how the flask app looks like:
#app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
file = request.files['file']
filename = secure_filename(file.filename)
fileextension = filename.rsplit('.',1)[1]
Randomfilename = id_generator()
filename = Randomfilename + '.' + fileextension
try:
blob_service.create_blob_from_stream(container, filename, file)
except Exception:
print 'Exception=' + Exception
pass
ref = 'http://'+ account + '.blob.core.windows.net/' + container + '/' + filename
seems like we can get the filename using f.filename, but I am not sure how to get the full path here.
Complete code can be found here:
https://github.com/codesagar/Azure-Blobs/blob/master/blob.py
The ultimate goal is to calculate the mimetype of the file to be uploaded.
I do have the file-blob(variable f). IS there a better way to get the mime from blob rather than hunting for the absolute file-path?
I solved my problem by using the following line of code:
mime_type = f.content_type
This gives me the mimetype of the file and eliminates the need for getting the file's absolute path.

Openpxl does not add new entries to File

I tried to add a new item to an already existing spreadsheet but it doesn't seem to work. However, the file's property matches my timestamp of last recent call in python 3. Because this is a rather larger project, some background information may be necessary for trouble shooting.
I am using Openpyxl 2.5.3
As for now, both files (*.py and *.xlsx) are in the same directory
furthermore, they're currently stored in a OneDrive folder which synchronizes automatically
When trying to run
def add_value(self, to_position: Coordinate, new_value: str or int) -> bool:
try:
string = get_column_letter(to_position[0]) if isinstance(to_position[0], int) else to_position[0]
self.Sheet[f"{string}{to_position[1]}"].value = str(new_value)
workbook.save(self.Fullfilename)
return True
except (FileNotFoundError, IOError) as e:
print(f"{e}\n{filename} couldn't be found in current working directory\n[{os.listdir()}].")
return False
the function evaluates to True but no changes to the files have been made.
Ok, I am really stupid. My __init__ constructor comes with an attribute called self.Workbook. But I misspellt it self.Worbook, which in turn affected self.Sheet = self.WorBook.active. Note that I wrote workbook.save(self.Fullfilename), but I have to save the changes to self.Workbook.save(Fullfilename). As a final note, the *.xlsx's timestamp update in file properties was displayed next to 更新日時 (date of modification) which initially lead to my confusion whether my script accessed or edited the spreadsheet for real.

Resources