When setting up a Flask server, we can try to receive the file user uploaded by
imagefile = flask.request.files['imagefile']
filename_ = str(datetime.datetime.now()).replace(' ', '_') + \
werkzeug.secure_filename(imagefile.filename)
filename = os.path.join(UPLOAD_FOLDER, filename_)
imagefile.save(filename)
logging.info('Saving to %s.', filename)
image = exifutil.open_oriented_im(filename)
When I am looking at the Klein documentation, I've seen http://klein.readthedocs.io/en/latest/examples/staticfiles.html, however this seems like providing file from the webservice instead of receiving a file that's been uploaded to the web service. If I want to let my Klein server able to receive an abc.jpg and save it in the file system, is there any documentation that can guide me towards that objective?
As Liam Kelly commented, the snippets from this post should work. Using cgi.FieldStorage makes it possible to easily send file metadata without explicitly sending it. A Klein/Twisted approach would look something like this:
from cgi import FieldStorage
from klein import Klein
from werkzeug import secure_filename
app = Klein()
#app.route('/')
def formpage(request):
return '''
<form action="/images" enctype="multipart/form-data" method="post">
<p>
Please specify a file, or a set of files:<br>
<input type="file" name="datafile" size="40">
</p>
<div>
<input type="submit" value="Send">
</div>
</form>
'''
#app.route('/images', methods=['POST'])
def processImages(request):
method = request.method.decode('utf-8').upper()
content_type = request.getHeader('content-type')
img = FieldStorage(
fp = request.content,
headers = request.getAllHeaders(),
environ = {'REQUEST_METHOD': method, 'CONTENT_TYPE': content_type})
name = secure_filename(img[b'datafile'].filename)
with open(name, 'wb') as fileOutput:
# fileOutput.write(img['datafile'].value)
fileOutput.write(request.args[b'datafile'][0])
app.run('localhost', 8000)
For whatever reason, my Python 3.4 (Ubuntu 14.04) version of cgi.FieldStorage doesn't return the correct results. I tested this on Python 2.7.11 and it works fine. With that being said, you could also collect the filename and other metadata on the frontend and send them in an ajax call to klein. This way you won't have to do too much processing on the backend (which is usually a good thing). Alternatively, you could figure out how to use the utilities provided by werkzeug. The functions werkzeug.secure_filename and request.files (ie. FileStorage) aren't particularly difficult to implement or recreate.
Related
I am developing a micro services architecture locally on my laptop, where a flask app communicates with a Google cloud function (using functions-framework library).
In it,the following happens:
The user uploads a file to a form. Upon submit, the file is sent to Flask
Flask will then extract the file from the request and then send the file to the cloud function, running on port 8080
When the file is sent though the cloud function is returning a 400 status code (bad request).
What am I doing wrong?
===form.html===
<html>
<body>
<h1>Report</h1>
<form action = "http://localhost:3000**/process**" method = "post" enctype = "multipart/form-data">
<input type = "file" name = "file" />
<input type = "hidden" name = "report" />
<p><input type = "submit" value = "submit" /></p>
</form>
</body>
</html>
===Flask===
...
#app.route('/process',methods = ['POST'])
def process():
f = request.files['file']
files = {'document': f.read()}
headers = {'Content-type': 'multipart/form-data'}
url='http://127.0.0.1:8080'
r = requests.post(url,files=files,headers=headers)
if r:
return redirect(url_for('success',tool=r.text))
#app.route('/form')
def form():
return render_template('form.html')
if __name__ == '__main__':
app.run(port=3000)
===functions-framework===
def func2(request):
file=request.files['document']
return str(type(file))
In the documentation for Functions Framework, there are more links to learn more about this, particularly on how to use the Functions Framework for Python runtime. Here you can find a quickstart about error handling.
In this answer from another question, you could check how to implement an error handler for a given code error and get the description of the error in order to debug your code and know why you're getting the 400 status code error.
I have form tags like this
<form name="input_form" action="/test.py" method="get">
Set Frequency: <input type="number" name="set_freq" id="set_freq"> <br>
<input type="submit" value="Submit" />
<input id="reset" type="reset" value="Reset" /><br>
</form>
I need to have it where, the user enter 1500 or whatever value, and then once submit is hit, that number is passed to the python program, test.py for right now.
There is more than one way to do that, you can use CGI (a webserver that calls your python script and serves the output) or a WSGI framework like Django or Flask, or others. Of course, these also need to be served, either from a "typical" webserver like apache or Nginx or something like Gunicorn.
my recommendation is to use a framework like Flask to accomplish that task.
install it by running, preferably in a virtual env:
pip install flask
then you could write something simple as
from flask import Flask, request, render_template
# Flask constructor
app = Flask(__name__)
# A decorator used to tell the application
# which URL is associated function
#app.route('/test.py', methods =["GET", "POST"])
def get_freq():
if request.method == "POST":
# getting input with freq = set_freq in HTML form
freq = request.form.get("set_freq") # <--- do whatever you want with that value
return "Your freq value is " + freq
return render_template("form.html")
if __name__=='__main__':
app.run()
then you will need to provide your form.html template to be served, and put it in the ./templates folder.
<form action="{{ url_for("get_freq") }}" method="post">
<label for="set_freq">Set Frequency:</label>
<input type="number" id="set_freq" name="set_freq" >
<button type="submit">submit</button>
now run the script and open http://127.0.0.1:5000/test.py
you will be served with the form and by submitting it you will send the freq value straight to the backend where you can interpret it.
for learning purposes:
for learning purposes, you can use the HTTP server in the python standard library without using a framework. this not intended for production and even could take more effort than using web frameworks (this is the point of using such frameworks).
#!/usr/bin/env python3
"""
Usage::
./server.py [<port>]
"""
from http.server import BaseHTTPRequestHandler, HTTPServer
import logging
from urllib.parse import urlparse, parse_qs
class S(BaseHTTPRequestHandler):
def _set_response(self, code):
self.send_response(code)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
logging.info("GET request,\nPath: %s\nHeaders:\n%s\n", str(self.path), str(self.headers))
query_components = parse_qs(urlparse(self.path).query)
if query_components.get('set_freq'):
freq = query_components.get('set_freq') # <--- do whatever you want with that value
print(freq)
self._set_response(200)
self.wfile.write("Python HTTP server received your GET request".encode("utf-8"))
def run(server_class=HTTPServer, handler_class=S, port=8080):
logging.basicConfig(level=logging.INFO)
server_address = ('', port)
httpd = server_class(server_address, handler_class)
logging.info('Starting httpd...\n')
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
logging.info('Stopping httpd...\n')
if __name__ == '__main__':
from sys import argv
if len(argv) == 2:
run(port=int(argv[1]))
else:
run()
run the web server and as it starts to listen to incoming requests you can now open your form page and submit your data. you'll need to edit the path where your form will send the data, here is the final snippet.
<!DOCTYPE html>
<html>
<body>
<h2>HTML Forms</h2>
<form name="input_form" action="http://localhost:8080">
Set Frequency: <input type="number" name="set_freq" id="set_freq"> <br>
<input type="submit" value="Submit" />
<input id="reset" type="reset" value="Reset" /><br>
</form>
<p>If you click the "Submit" button, the form data will be sent to your local Python 3 HTTP server.</p>
</body>
</html>
again this is nowhere a complete or optimized or production code.
use it just in case you want to get something up and running to play with and learn.
code Explanation:
BaseHTTPRequestHandler class is used to handle the HTTP requests that arrive at the server. By itself, it cannot respond to any actual HTTP requests; it must be subclassed to handle each request method (e.g. GET or POST). so we extend it in S class by adding the do_GET method that will be called on GET requests.
from Python official doc:
The handler will parse the request and the headers, then call a method
specific to the request type. The method name is constructed from the
request. For example, for the request method SPAM, the do_SPAM()
method will be called with no arguments. All of the relevant
information is stored in instance variables of the handler. Subclasses
should not need to override or extend the init() method.
read more from here:
https://docs.python.org/3/library/http.server.html#http.server.HTTPServer
I am trying to write a small Tornado server that lets users upload files using a HTML form, then give the link to someone else who then will simultaneously download the file while it is being uploaded.
For now the idea was that data would be some sort of Iterator that is created by the upload and then consumed by the download, however currently the entire file is being written into data.
I found a few people talking about chunked file uploads with Tornado, however couldn't find any reference pages for it.
import os
import tornado.web
import tornado.ioloop
settings = {'debug': True}
data = None
# assumes an <input type="file" name="file" />
class ShareHandler(tornado.web.RequestHandler):
def post(self, uri):
data = self.request.files['file'][0]['body']
class FetchHandler(tornado.web.RequestHandler):
def get(self, uri):
for line in data:
self.write(line)
handlers = [
(r'/share/(.*)', ShareHandler),
(r'/fetch/(.*)', FetchHandler),
]
application = tornado.web.Application(handlers, **settings)
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
Tornado doesn't support streaming uploads. This is one of the most commonly asked questions about it. =) The maintainer is actively implementing the feature, watch here:
https://github.com/facebook/tornado/pull/1021
I have a simple web server based on BaseHTTPServer which processes GET requests (I reuse a previous example below). I would like, for a particular GET parameter (x in the example below), to open a web page with a simple form and a submit button.
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from urlparse import urlparse, parse_qs
class GetHandler(BaseHTTPRequestHandler):
def do_GET(self):
url = urlparse(self.path)
d = parse_qs(url[4])
if 'x' in d:
self.handle_input_form() # this is the part I want to write
else:
if 'c' in d:
print d['c'][0]
self.send_response(200)
self.end_headers()
return
def handle_input_form(self):
# here a form is displayed, user can input something, submit and
# the content this is handled back to the script for processing
# the next three lines are just a place holder
pass
self.send_response(200)
self.end_headers()
server = HTTPServer(('localhost', 8080), GetHandler)
server.serve_forever()
In other words, this is a self-contained web server (no cgi pages) which I want to keep as simple as possible. I saw a great example of how to use CGI together with the documentation pages, but all assume that there will be a classical cgi-bin structure.
Is what I am trying to achieve easy in Python (I am sure it is possible :))?
I would appreciate very much a general answer on best practices ("do it like that" or "don't do it like that" - please keep in mind this is an internal, private server which will not run anything important) as well as the overall flow of handle_input_form().
EDIT: Following up on Jon Clements' suggestion I used Bottle and adapted the example in the tutorial:
import bottle
#bottle.get('/note') # or #route('/note')
def note():
return '''
<form action="/note" method="post">
<textarea cols="40" rows="5" name="note">
Some initial text, if needed
</textarea>
<input value="submit" type="submit" />
</form>
'''
#bottle.post('/note') # or #route('/note', method='POST')
def note_update():
note = bottle.request.forms.get('note')
# processing the content of the text frame here
For something this simple that's also scalable you're better off using a micro-framework such as flask or bottle.
I need to implement a rather simple web form on Google App Engine (GAE-Python) that accepts some form input (name, email, telephone) and a resume (typically TXT, PDF or DOC/DOCX) file. Once the form is submitted, I want to contents of the form to be emailed and if a file is submitted in the form, for it to be included as an attachment in the same email to a designated email address.
I don't need the file to exist after it is emailed/attached. Sort of like a temp file, or stored in a temp blob store.
With HTML5 and jQuery, there are lot of fancy user interfaces to implement file uploads. Is there any recommended approach to use one of these that work nicely with GAE, as well as being able to degrade gracefully if the browser does not support the modern methods (namely IE)?
I am using jinja2 framework, if that is relevant. (I am a Python novice by the way)
Thanks in advance!
For upload a file as a blob in GAE you need the blobstore_handlers from built-in framework called webapp.
The docs have a complete sample for upload files and I do not think there are other ways to upload to the blobstore.
When you have the blob see the first sample of this page from docs for attach the blob to the email.
Now, for a "temp file solution" you can try a different way: write the upload file to the ram with StringIO python module. Something like that:
<form action="/test/" method="POST" enctype="multipart/form-data">
<input type="file" name="file"><br>
<input type="submit"name="submit" value="Submit">
</form>
def post(self):
output = StringIO.StringIO()
upload = self.request.get('file')
output.write(upload)
self.response.write(output.getvalue())