Displaying a temporary html file with webbrowser in Python - python

Really simple, I want to create a temporary html page that I display with the usual webbrowser.
Why does the following code produce an empty page?
import tempfile
import webbrowser
import time
with tempfile.NamedTemporaryFile('r+', suffix = '.html') as f:
f.write('<html><body><h1>Test</h1></body></html>')
webbrowser.open('file://' + f.name)
time.sleep(1) # to prevent the file from dying before displayed

Because your file doesn't exist on the disk and sits entirely in memory. That's why the browser starts but opens nothing since no code has been provided.
Try this:
#!/usr/bin/python
import tempfile
import webbrowser
tmp=tempfile.NamedTemporaryFile(delete=False)
path=tmp.name+'.html'
f=open(path, 'w')
f.write("<html><body><h1>Test</h1></body></html>")
f.close()
webbrowser.open('file://' + path)

Tested on Python 3.4.
import subprocess
import webbrowser
from http.server import BaseHTTPRequestHandler, HTTPServer
PORT = 7000
HOST = '127.0.0.1'
SERVER_ADDRESS = '{host}:{port}'.format(host=HOST, port=PORT)
FULL_SERVER_ADDRESS = 'http://' + SERVER_ADDRESS
def TemproraryHttpServer(page_content_type, raw_data):
"""
A simpe, temprorary http web server on the pure Python 3.
It has features for processing pages with a XML or HTML content.
"""
class HTTPServerRequestHandler(BaseHTTPRequestHandler):
"""
An handler of request for the server, hosting XML-pages.
"""
def do_GET(self):
"""Handle GET requests"""
# response from page
self.send_response(200)
# set up headers for pages
content_type = 'text/{0}'.format(page_content_type)
self.send_header('Content-type', content_type)
self.end_headers()
# writing data on a page
self.wfile.write(bytes(raw_data, encoding='utf'))
return
if page_content_type not in ['html', 'xml']:
raise ValueError('This server can serve only HTML or XML pages.')
page_content_type = page_content_type
# kill a process, hosted on a localhost:PORT
subprocess.call(['fuser', '-k', '{0}/tcp'.format(PORT)])
# Started creating a temprorary http server.
httpd = HTTPServer((HOST, PORT), HTTPServerRequestHandler)
# run a temprorary http server
httpd.serve_forever()
if __name__ == '__main__':
def run_xml_server():
xml_data = """
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
"""
# open in a browser URL and see a result
webbrowser.open(FULL_SERVER_ADDRESS)
# run server
TemproraryHttpServer('xml', xml_data)
def run_html_server():
html_data = """
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>This is a Heading</h1>
<p>This is a paragraph.</p>
</body>
</html>
"""
# open in a browser URL and see a result
webbrowser.open(FULL_SERVER_ADDRESS)
# run server
TemproraryHttpServer('html', html_data)
# choice needed server:
# run_xml_server()
# run_html_server()

Just change the file's current position.
import tempfile
import webbrowser
import time
with tempfile.NamedTemporaryFile('r+', suffix = '.html') as f:
f.write('<html><body><h1>Test</h1></body></html>')
webbrowser.open('file://' + f.name)
f.seek(0)
time.sleep(1) # to prevent the file from dying before displayed

This piece of code is an edition to the previews one and continuation of the discussion with the OP. It shows time.sleep() after webbrowser.open(). I don't think it's actually needed because the /tmp directory is emptied automatically on a regular bases by the OS but the OP commented that if he deletes the temp file via Python it is deleted before it gets fully loaded by the browser. Most likely it happens because the "browser" process is detached from this scrip which is its parent and Python doesn't wait for the process completion before executing the next statement. I though it would be clear for everyone without explanation but obviously you, guys, don't read comments.
import os, time
# ...
webbrowser.open('file://' + path)
time.sleep(1)
if os.path.exists(path):
os.remove(path)

Related

Import with multiple arguments: running python script in flask

I have a python script main.py that takes in two arguments (2 text files)
I'm using MAC OS X
Python 2.7
This runs easily on terminal with:
python main.py train.txt sample.txt
I have now developed a small front-end using Flask with very minor HTML as follows:
#front.py FLASK
from flask import Flask, render_template, request, redirect
app = Flask(__name__)
#app.route('/')
def hello_world():
return render_template('index.html')
#app.route('/signup', methods = ['POST'])
def signup():
email = request.form['email']
email1 = request.form['email1']
# command below is just for testing, I wish to implement the same as this would if this would be typed in terminal.
print("main.py " + email + " " + email1)
return redirect('/')
if __name__ == "__main__":
app.run()
and the HTML
<!DOCTYPE html>
<html>
<head>
<title>T</title>
</head>
<body>
<form action="/signup" method="post">
<input type="text" name="email"></input>
<input type="text" name="email1"></input>
<input type="submit" value="Signup"></input>
</form>
</body>
</html>
This HTML code is simply using a form to take in the 2 arguments ( I find this easier than JS as I have no experience with that).
I have just written the
print("main.py " + email + " " + email1)
command above to test, it's not of any utility for now.
Usage of the parameters:
#main.py
from filter import Filter
import sys
# Get arguments from user
train = sys.argv[1]
messages = sys.argv[2]
# Open files for reading and writing
train_file = open(train, "rb")
messages_file = open(messages, "rb")
predictions_file = open("predictions.txt", "w")
# Create new filter and train it using the train-file
f = Filter()
f.train(train_file)
#filter the messages in messages_file, write results to predictions_file
f.filter(messages_file, predictions_file)
# Close all the files
train_file.close()
messages_file.close()
predictions_file.close()
I wish to now run my script which is main.py via this flask application itself, and want to know how this is possible.
I was using import main with another app decorator say /exec and manually changing the URL to go from 127.0.0.2000 to 127.0.0.2000/exec but this was giving errors as main requires the arguments to be passed.
Sorry if I'm unclear in explaining the problem, please let me know if I can explain anything in a better way to help understand the problem.
Thank you
You need to rework this script slightly. You should put all the code that deals with input inside a name == '__main__' block as you do in the Flask app, and the rest inside a function that you call from that block:
def do_stuff(train, messages):
# Open files for reading and writing
train_file = open(train, "rb")
...
predictions_file.close()
if __name__ == '__main__':
# Get arguments from user
train = sys.argv[1]
messages = sys.argv[2]
do_stuff(train, messages)
Now your Flask app can call main.do_stuff(email, email1).

Python Twisted web server audio file

I am trying to create a simple web server with twisted in python. I am having trouble serving an m4a audio file though.
In the current program, when I load http://localhost:8880/mp3.html, it works fine. It shows the audio player and the mp3 plays. In addition, the program prints both "/mp3.html" and "/test.mp3".
However, when I load http://localhost:8880/m4a.html, it doesn't work. It shows the audio player, but the m4a doesn't play. In addition, the program prints only "/m4a.html" and not "/test.m4a".
My current code is below.
import urlparse
import os
from twisted.internet import reactor
from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.web.static import File
import time
import subprocess
import mimetypes
class playM4A(Resource):
isLeaf = True
def render_GET(self, request):
this=urlparse.urlparse(request.path)#scheme,netloc,path,query
root,ext=os.path.splitext(this.path)
filename=os.path.basename(request.path)
fileFolder=request.path.replace(filename,"")
self.serverRoot=os.getcwd()
print request.path
if ext==".m4a":
thisFile=File(self.serverRoot+request.path)
return File.render_GET(thisFile,request)
elif ext==".mp3":
thisFile=File(self.serverRoot+request.path)
return File.render_GET(thisFile,request)
elif filename=="m4a.html":
return """
<html>
<audio controls>
<source src="http://localhost:8880/test.m4a" type="audio/mp4a-latm">
Your browser does not support the audio element.
</audio>
not m4a </html>"""
elif filename=="mp3.html":
return """
<html>
<audio controls>
<source src="http://localhost:8880/test.mp3" type="audio/mp3">
Your browser does not support the audio element.
</audio>
not m4a </html>"""
resource = playM4A()
factory = Site(resource)
reactor.listenTCP(8880, factory)
reactor.run()
The code works if you change audio/mp4a-latm to audio/mp4

How to send a pygame image over websockets?

I'm currently trying to code something that will let websites view my webcam. I'm roughly following the tutorial linked on this website, except using Python and pygame instead of Processing.
At the moment, my code is grabbing a pygame image (which was originally a SimpleCV image), attempting to convert it into jpg format, and send it over websockets to the client where it will display it inside an img tag. However, I can't seem to figure out how to convert a pygame image into jpg and get it to display properly on the web browser.
This is my code for the server, which uses Flask and gevent:
#!/usr/bin/env python
import base64
import cStringIO
import time
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from flask import Flask, request, render_template
import pygame
pygame.init()
import SimpleCV as scv
app = Flask(__name__)
cam = scv.Camera(0)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/camera')
def camera():
if request.environ.get('wsgi.websocket'):
ws = request.environ['wsgi.websocket']
while True:
image = cam.getImage().flipHorizontal().getPGSurface()
data = cStringIO.StringIO()
pygame.image.save(image, data)
ws.send(base64.b64encode(data.getvalue()))
time.sleep(0.5)
if __name__ == '__main__':
http_server = WSGIServer(('',5000), app, handler_class=WebSocketHandler)
http_server.serve_forever()
This is my HTML file:
<!DOCTYPE HTML>
<html>
<head>
<title>Flask/Gevent WebSocket Test</title>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
if ("WebSocket" in window) {
cam = new WebSocket("ws://" + document.domain + ":5000/camera");
cam.onmessage = function (msg) {
$("#cam").attr('src', 'data:image/jpg;base64,' + msg.data);
};
cam.onerror = function(e) {
console.log(e);
}
} else {
alert("WebSocket not supported");
}
});
</script>
</head>
<body>
<img id="cam" src="" width="640" height="480" />
</body>
</html>
These are the specific lines that I think I'm having trouble with:
while True:
image = cam.getImage().flipHorizontal().getPGSurface()
data = cStringIO.StringIO()
pygame.image.save(image, data)
ws.send(base64.b64encode(data.getvalue()))
time.sleep(0.5)
Currently, if I try and run my code, going to localhost:5000 will display an invalid jpg image. It also becomes really laggy if I try running it on Firefox, but that may be an unrelated issue that I can debug later.
I've checked and made sure that the pygame image is a valid one, since I'm converting it from another library, and also checked that I was using websockets correctly by sending text data back and forth.
I've also tried calling pygame.image.to_string to try and convert the pygame surface into RGB format, but that also doesn't work.
What am I doing wrong?
Using the underlying PIL image, we can write to a file-like object, read back and base-64 encode it:
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from flask import Flask, request
from time import sleep
from cStringIO import StringIO
import pygame
pygame.init()
import SimpleCV as scv
app = Flask(__name__)
cam = scv.Camera(0)
#app.route('/camera')
def camera():
if request.environ.get('wsgi.websocket'):
ws = request.environ['wsgi.websocket']
while True:
fp = StringIO()
image = cam.getImage().flipHorizontal().getPIL()
image.save(fp, 'JPEG')
ws.send(fp.getvalue().encode("base64"))
#fp.close() << benchmark and memory tests needed
sleep(0.5)
if __name__ == '__main__':
http_server = WSGIServer(('',5000), app, handler_class=WebSocketHandler)
http_server.serve_forever()
I'm fighting with the same issue and the problem is a double codification. In the Python file, you have to remove the line "ws.send(base64.b64encode(data.getvalue()))" and send the image without encoded. Then in the js file, your script will make the codification and that all.

Python / CGI - Upload file attempt returns an empty page

I really searched about 50 related pages but never seen a problem similar to my problem. When I press the submit button, it calls the script but the script returns an empty page and I see no file was uploaded. There is no typing error in my codes, I checked it several times and I really need this code running for my project. What might be the problem? I am running apache under ubuntu and my codes are:
html code:
<html><body>
<form enctype="multipart/form-data" action="save_file.py" method="post">
<p>File: <input type="file" name="file"></p>
<p><input type="submit" value="Upload"></p>
</form>
</body></html>
python code:
#!/usr/bin/env python
import cgi, os
import cgitb; cgitb.enable()
try: #windows needs stdio set for binary mode
import msvcrt
msvcrt.setmode (0, os.O_BINARY)
msvcrt.setmode (1, os.O_BINARY)
except ImportError:
pass
form = cgi.FieldStorage()
#nested FieldStorage instance holds the file
fileitem = form['file']
#if file is uploaded
if fileitem.filename:
#strip leading path from filename to avoid directory based attacks
fn = os.path.basename(fileitem.filename)
open('/files' + fn, 'wb').write(fileitem.file.read())
message = 'The file "' + fn + '" was uploaded successfully'
else:
message = 'No file was uploaded'
print """\
Content-Type: text/html\n
<html><body>
<p>%s</p>
</body></html>
""" % (message,)
I just tested your script, with a few small corrections to the paths to make it work for me locally. With the paths set correctly, and permissions set properly, this code does work fine.
Here are the things to make sure of:
In your html file's form properties, make sure you are pointing to the python script that lives in a cgi-bin: action="/cgi-bin/save_file.py". For me, I have a cgi-bin at the root of my web server, and I placed the python script there. It will not work if you are running the script from a standard document location on the web server
Make sure your save_file.py has executable permissions: chmod 755 save_file.py
In your save_file.py, ensure that you are building a valid path to open the file for saving. I made mine absolute just for testing purposes, but something like this: open(os.path.join('/path/to/upload/files', fn)
With those points set correctly, you should not have any problems.

Is it possible to use Python, AJAX & CGI together

I want to have a web page where you click a button, by using AJAX I get a string from a python script, then display that string in a paragraph HTML element.
I know I can do this by using Python, WSGI & AJAX (theoretically I can do it this way) but its waaaay too difficult. I am experienced with CGI & python.
So can I do the above using CGI?
If I can how do the python script work, exactly the same as when serving a page using CGI?
This doesn't work:
import cgitb; cgitb.enable()
import cgi
import os
print "Content-Type: text/html\n"
input_data = cgi.FieldStorage()
print "hello"
When I click my button in my page, nothing happens & my CGI server (which works fine for cgi page requests) gives me a http 501 error.
My html & javascript:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript">
<!--
function onTest( dest, params )
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById( "bb" ).innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("POST",dest,true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send( params );
}
-->
</script>
</head>
<body>
<p id="bb"> abcdef </p>
Click it
</body>
</html>
Here are 3 files [my.html, myCGI.py, myPyServer.py]. In windows XP I put them all in the same directory and double-click on myPyServer.py and things work very well.
my.html is the same as your html except:
yours: Click it
mine: Click it
myCGI.py is pretty close to yours
import cgitb; cgitb.enable()
import cgi
import os
input_data = cgi.FieldStorage()
if input_data:
print "Content-Type: text/html\n"
print "hello"
else:
f = open('my.html', 'r'); s = f.read(); f.close()
print "Content-Type: text/html\n"
print s
myPyServer.py
import CGIHTTPServer
import BaseHTTPServer
import sys
class Handler(CGIHTTPServer.CGIHTTPRequestHandler):
cgi_directories = ["/"] #make sure this is where you want it. [was "/cgi"]
PORT = 8000
httpd = BaseHTTPServer.HTTPServer(("", PORT), Handler)
# see effbot http://effbot.org/librarybook/thread.htm
def runserver():
print "serving at port", PORT
httpd.serve_forever()
import thread
thread.start_new_thread(runserver, ())
print "opening browser"
import webbrowser
url = 'http://127.0.0.1:8000/myCGI.py'
webbrowser.open_new(url)
quit = 'n'
while not(quit=='quit'):
quit = raw_input('\n ***Type "quit" and hit return to exit myPyServer.*** \n\n')
print "myPyServer will now exit."
sys.exit(0)
Of course you can use plain old CGI if you want. Your code works fine for me. (The "abcdef" turns into "hello" when the link is clicked.)
You must have some simple error in your setup. I'd check file permissions on your test scripts (a+rx), which might have been overlooked. Also I assume you've got a "#!/usr/bin/env python" (or equivalent) at the top of your cgi script (it is omitted in your example above).
Check out sajax:
http://www.modernmethod.com/sajax/
There's a python library and example in the download. You can have one CGI script that can handle your view and implement any AJAX call.
Here is one simple example using Python CGI and ajax.
http://www.ssiddique.info/writing-your-first-python-cgi-ajax-script.html

Categories