This question already has an answer here:
Remove file after Flask serves it
(1 answer)
Closed 1 year ago.
I want my server to send a file to the user, and then delete the file.
The problem is that in order to return the file to the user, i am using this:
return send_file(pathAndFilename, as_attachment=True, attachment_filename = requestedFile)
Since this returns, how can i delete the file from the os with os.remove(pathAndFilename)?
I also tried this:
send_file(pathAndFilename, as_attachment=True, attachment_filename = requestedFile)
os.remove(pathAndFilename)
return 0
But i got this error:
TypeError: The view function did not return a valid response. The return type must be a string, dict, tuple, Response instance, or WSGI callable, but it was a int.
Since send_file already returns the response from the endpoint, it is no longer possible to execute code afterwards.
However, it is possible to write the file to a stream before the file is deleted and then to send the stream in response.
from flask import send_file
import io, os, shutil
#app.route('/download/<path:filename>')
def download(filename):
path = os.path.join(
app.static_folder,
filename
)
cache = io.BytesIO()
with open(path, 'rb') as fp:
shutil.copyfileobj(fp, cache)
cache.flush()
cache.seek(0)
os.remove(path)
return send_file(cache, as_attachment=True, attachment_filename=filename)
In order to achieve better use of the memory for larger files, I think a temporary file is more suitable as a buffer.
from flask import send_file
import os, shutil, tempfile
#app.route('/download/<path:filename>')
def download(filename):
path = os.path.join(
app.static_folder,
filename
)
cache = tempfile.NamedTemporaryFile()
with open(path, 'rb') as fp:
shutil.copyfileobj(fp, cache)
cache.flush()
cache.seek(0)
os.remove(path)
return send_file(cache, as_attachment=True, attachment_filename=filename)
I hope your conditions are met.
Have fun implementing your project.
Related
I wanted to compare the content of two files compressed from the same file with the gzip.open() method from the python3 standard library. Above the code code creating two compressed files:
import shutil
import gzip
with open('file1.txt', 'rb') as f_in:
with gzip.open('output1.gz',"wb") as f_out:
shutil.copyfileobj(f_in, f_out)
with open('file1.txt', 'rb') as f_in:
with gzip.open('output2.gz',"wb") as f_out:
shutil.copyfileobj(f_in, f_out)
Then I compared the gzipped-files with the filecmp module from the standard library:
import filecmp
print(filecmp.cmp("output1.gz", "output2.gz", shallow=False))
That return False due to different timestamps and filename in the headers of the files as pointed by Kris in this thread.
So according to the RFC 1952 the filename section of the headers that comes after the timestamp section is terminated with a null byte. So I created a function to look for this byte and start hashing the rest of the bytes with the md5() method from the hashlib module from the standard library. And then compare the hashes of the files.
import hashlib
def compareContent(filename):
md5 = hashlib.md5()
with open(filename, 'rb') as f_in:
while True:
text = f_in.read(1)
if text == b'\x00':
break
while True:
data = f_in.read(8192)
if not data:
break
md5.update(data)
return md5.hexdigest()`
hash_one = compareContent("output1.gz")
hash_two = compareContent("output2.gz")
print(hash_one == hash_two)
This finally returns True and seems to work well.
I'm just a little bit surprised that I could not find an already existing function to do this work.
As a beginner, my questions are:
Am I missing something? Does such a function already exist?
If not, Is there any better way to achieve this or to improve my code?
Here is the code available in a Colab notebook: compare gzipped-files
I am using below code where I am using PUT api from POSTMAN to send a file to a machine hosting the api using python script
#app.route('/uploadFIle', methods=['PUT'])
def uploadFile():
chunk_size = 4096
with open("/Users/xyz/Documents/filename", 'wb') as f:
while True:
chunk = request.stream.read(chunk_size)
if len(chunk) == 0:
break
f.write(chunk)
return jsonify({"success":"File transfer initiated"})
Is there a way to get the original filename so that I can use the same while saving the file ?
Can do as below by passing name from PUT api itself, but is it the best solution ?
#app.route('/uploadFIle/<string:filename>', methods=['PUT'])
def uploadFile(filename):
Below is how I achieved it using flask -
Choose form-data under body in POSTMAN
You can give any key, i used 'file' as key, then choose option 'file' from drop down arrow in key column
Attach file under 'value' column and use below code to get the file name -
from flask import request
file = request.files['file']
file_name = file.filename
I create a API by fastAPI like the following:
#app.post('/uploadFile/')
async def uploadFile(file:UploadFile = File(...)):
file_name,extension_file_name = os.path.splitext(file.filename)
base_path = os.path.join(os.getcwd(),'static')
path_cheked_exists = os.path.join(base_path,extension_file_name[1:])
if not os.path.exists(path_cheked_exists):
os.makedirs(path_cheked_exists)
try:
shutil.copy(file,path_cheked_exists)
except Exception as exp:
print("can not copy that file")
return {'file':'okay'}
API returned the result but didn't save file .
Thanks for any help with shutil module
Instead of using shutil module, you can use a simple context manager
with open('filename.ext', 'wb+') as file_obj:
file_obj.write(file.file.read())
Also your problem could be that you only wrote file.
Try shutil.copy(file.file,path_cheked_exists)
I am trying to send a XML file to RabbitMQ from python but I am getting the below error
Error
File "<ipython-input-134-8a1b7f8b2e41>", line 3
channel.basic_publish(exchange='',queue='abc',''.join(lines))
^
SyntaxError: positional argument follows keyword argument
My Code
import ssl
!pip install pika
import pika
ssl_options = pika.SSLOptions(ssl._create_unverified_context())
credentials = pika.PlainCredentials(username='abcc', password='abcc')
connection = pika.BlockingConnection(pika.ConnectionParameters(
host='xxxx', port=5671, virtual_host ='xxx', credentials=credentials,
ssl_options=ssl_options))
channel = connection.channel()
result = channel.queue_declare(queue='abc')
with open('20200205280673.xml', 'r') as fp:
lines = fp.readlines()
channel.basic_publish(exchange='',queue='abc',''.join(lines))
Whats wrong in the above code?
As #ymz suggested, you are missing the body key in the basic.publish method. Also, the basic_publish method has no argument called queue. Please have a look at its implementation docs
Edit #1: I have already answered this question elsewhere How to send a XML file to RabbitMQ using Python?
Edit #2: Automating publishing of XML files. Assuming all the files are present in a directory called xml_files
import os
DIR = '/path/to/xml_files'
for filename in os.listdir(DIR):
filepath = f"{DIR}/{filename}"
with open(filepath) as fp:
lines = fp.readlines()
channel.basic_publish(exchange='exchange', routing_key='queue', body=''.join(lines))
Code here.
from twisted.web.static import File
from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.internet import ssl, reactor
from twisted.python.modules import getModule
import secure_aes
import urllib.parse
import cgi
import json
import os
import hashlib
import coserver
import base64
import sim
if not os.path.exists(os.path.join(os.getcwd(),'images')):
os.mkdir(os.path.join(os.getcwd(),'images'))
with open ('form.html','r') as f:
fillout_form = f.read()
with open ('image.html','r') as f:
image_output = f.read()
port = 80#int(os.environ.get('PORT', 17995))
class FormPage(Resource):
#isLeaf = True
def getChild(self, name, request):
print('GC')
if name == '':
return self
return Resource.getChild(self, name, request)
def render_GET(self, request):
print(request)
#do stuff and return stuff
root = FormPage()
root.putChild('rcs', File("./images"))
#factory = Site(FormPage())
factory = Site(root)
reactor.listenTCP(port, factory)
reactor.run()
As you can see, I did root.putChild towards the end of things, expecting that when I got to http://site/rcs I get given a directory listing of the contents of ./images but of course that doesn't happen. What am I missing? I've tried many things suggested from here. Also this one doesn't work because that's just serving static files anyways. It goes to getChild all the time regardless of whether if have specified putChild or not.
On Python 3, a bare string literal like "rcs" is a unicode string (which Python 3 calls "str" but which I will call "unicode" to avoid ambiguity).
However, twisted.web.resource.Resource.putChild requires a byte string as its first argument. It misbehaves rather poorly when given unicode, instead. Make your path segments into byte strings (eg b"rcs") and the server will behave better on Python 3.