Javascript for Python programmers

Unless you're just writing a simple HTTP API server, any amount of web programming in Python will likely require at least a little bit of Javascript. Like it or not (and I will try to argue in this post that you should like it for what it's good at), Javascript is really the only game in town when it comes to client-side scripting on a web page. Sure, there are a number of Python-to-Javascript transpilers out there, but using these just tends to limit the ability to use new Javascript features as they are rolled out to browsers and may limit the ability to use third-party Javascript libraries. At the very least, using one these transpilers introduces added complexity to deploying a web app1.

In this post, I will describe some things I've learned about Javascript from the perspective of someone who prefers to use Python as much as possible. This guide is mainly aimed at scientists and others who are not primarily programmers but who may find it useful to make a web app for their main work. It is assumed that the reader is at least moderately familiar with Javascript (Mozilla has a nice tutorial to get you up to speed if not).

Namespaces, encapsulation, modularization, and bundling

Modules in Python make it very easy to encapsulate components without polluting the global namespace. In contrast, Javascript in the browser will make everything a global if you are not careful2. The good news is ...

more ...

Flask and server-sent events

I recently discovered the existence of the HTML5 server-sent events standard. Although it lacks the bidirectional communications of a websocket, SSE is perfect for the publish-subscribe networking pattern. This pattern just so happens to fit in conveniently with writing software to remotely monitor hardware that many people might want to check in on at the same time.

In order to try SSE out within a Flask framework, I put together a simple demo app using gevent. The core of the demo on the Python side looks like this:

app = Flask(__name__)

def event():
    while True:
        yield 'data: ' + json.dumps(random.rand(1000).tolist()) + '\n\n'

def index():
    return render_template('index.html')

@app.route('/stream/', methods=['GET', 'POST'])
def stream():
    return Response(event(), mimetype="text/event-stream")

This can be run either using gevent's WSGI server or gunicorn using gevent workers.

Update 2016-04-21: There is now a very nice Flask extension called Flask-SSE which handles all of this for you. It additionally supports the concept of channels in order to fine tune what notifications a given client receives.

more ...

Using websockets with Flask via Tornado

I've been working on some projects for the lab that involve remotely controlling hardware to perform various tasks. Since the hardware in question is shared between different experiments, some sort of asynchronous solution is needed, and a web-based client coupled with websockets seemed to be the best bet (this also leaves the option open in the future to write a standalone client that is not browser-based if desired).

There is no shortage of web frameworks for Python. Some of the more popular ones are Django, Flask, Tornado, and Pyramid. Of these, I greatly prefer Flask for a number of reasons:

  • Very thorough and easy to read documentation, including "snippets" with helpful tips and a very helpful community.
  • Extreme ease of use for both small and large projects.
  • Great use of decorators to further ease development.
  • A large number of extensions to build up a complex project without requiring overhead for simple projects.

This is not to say that the other options are bad, but having looked at all of them, Flask suits me best. The one problem: only Tornado directly supports websockets since it is both an HTTP server and a web framework in one, whereas the others utilize WSGI for deployment.

Luckily, it is possible to leverage both the excellent asynchronous features of Tornado and the power and ease of use of Flask through Tornado's ability to serve WSGI apps with tornado.wsgi.WSGIContainer. The Flask documentation shows a very simple example on how to do just ...

more ...