Pages tagged as ‘snippets’

convert a Request.write() into a WSGI yield

I tried that for a long time now using python generators with yield and send threads and much more. But I never got anything that looked easy to understand and worked at the same time. The problem basically occurs if you have an old python web application that has some sort of request object with a write method that directly writes to the output stream of the server interface (sys.stdout or some sort of fastcgi/mod_python output stream object) and you want to convert the application to WSGI. Take the following piece of code from an imaginary legacy application:

def old_application(request):
    from time import sleep
    request.header('Content-Type: text/html')
    for x in xrange(10):
        request.write(str(x) + ' ')
    request.flush()
    request.write('<br>And the next flush takes another second<br>')
    request.flush()
    sleep(1)
    request.write('And done!')

Say we want to convert that into a WSGI application with those semantics:

def wsgi_application(environ, start_response):
    from time import sleep
    start_response('200 OK', [('Content-Type', 'text/html'])
    yield ' '.join(str(x) for x in xrange(10)) + ' '
    yield '<br>And the next flush takes another second<br>'
    time.sleep(1)
    yield 'And Done!'

The main problem is the time.sleep and all those flush calls. That means we cannot just buffer the contents but convert the into a generator on the fly. What we need to get that done are either coroutines, greenlets or two threads that communicate with each other. The easiest and I guess also fastest approach are greenlets.

Here a function that converts an old legacy application like above into a WSGI application with the same semantics:

from py.magic import greenlet

class Request(object):

    def __init__(self, environ):
        self._parent = greenlet.getcurrent()
        self.environ = environ
        self.status = '200 OK'
        self.headers = []

    def header(self, item):
        self.headers.append(tuple(item.split(':', 1)))

    def write(self, text):
        self._parent.switch(('write', text))

    def flush(self):
        self._parent.switch(('flush', None))

def convert_app(application):
    def wsgi_app(environ, start_response):
        request = Request(environ)
        buffer = []
        headers_sent = []

        def flush():
            if not headers_sent:
                start_response(request.status, request.headers)
                headers_sent.append(True)
            data = ''.join(buffer)
            if data:
                yield data
            del buffer[:]

        def run():
            application(request)
            request.flush()

        g = greenlet(run, request._parent)
        while 1:
            rv = g.switch()
            if not rv:
                break
            signal, value = rv
            if signal == 'flush':
                for item in flush():
                    yield item
            elif signal == 'write':
                buffer.append(value)
    return wsgi_app

Now that’s a bunch of code. Let’s go step by step through it. The first thing we do is creating a request class. This class should resemble the old request object as much as possible. All methods can work like they did before, the only differences are the write and flush methods. Those switch back to the parent greenlet (which is the greenlet that generated the request object, usually the main greenlet) and send some data to it (namely the name of the method and the argument). Whenever python encounters this statement it stops the execution and goes back to the point that switched into this greenlet. This point is in our example in a loop that generates a generator for our WSGI application.

That leads us to the convert_app function that is passed and old legacy application and returns a new WSGI application. Inside this new WSGI application we create a new request object, pass it the WSGI environment and create some objects and functions we need so that we can process the data from the greenlets and convert it into a valid WSGI response: A buffer for unsent data, a list we use a sentinel for sent data, a flush method that returns a generator with the data from the buffer, starts the response and cleans the buffer, and a run method that invokes the old application and calls request.flush() after the application has finished so that we don’t have to do that in the application itself.

The mainloop after that basically switches between application greenlet and main greenlet until the return value of switch is None (that is the case if the application closed or someone switched into the main greenlet without arguments, which we don’t do). If that is the case we return, otherwise we check if it’s a flush or write call and handle that.

To launch the converted application with wsgiref all we have to do are those three lines of code:

from wsgiref.simple_server import make_server
srv = make_server('localhost', 5000, convert_app(old_application))
srv.serve_forever()

Basically greenlets would make it possible to host mod_python applications inside arbitrary WSGI servers. Maybe in the future someone writes a module that allows us to convert some of the mod_python applications into WSGI applications without touching existing application code.

Two Finger Scrolling on Ubuntu

One of the things I love about Macbook is that it has this nifty two finger scrolling enabled by default. But thanks to the awesome synaptics linux driver you can get that on any ubuntu system too as long as your touchpad isn’t too old. There are countless tutorials on that on the web, however there is one stupid pitfall.

If you enable two finger scrolling you will most likely hit a “feature” of Firefox. It will go forward and backward in history under some strange conditions. It may be useful if one can figure out how to trigger it, but the better way is to disable it like it’s on OS X. Set the following settings in your about:config:

mousewheel.horizscroll.withnokey.action = 0
mousewheel.horizscroll.withnokey.sysnumlines = true

Just for completeness here my xorg.conf settings:

Section "InputDevice"
        Identifier      "Synaptics Touchpad"
        Driver          "synaptics"
        Option          "SendCoreEvents"        "true"
        Option          "Device"                "/dev/psaux"
        Option          "Protocol"              "auto-dev"
        Option          "MaxTapTime"            "120"
        Option          "MaxTapMove"            "150"
        Option          "VertTwoFingerScroll"   "true"
        Option          "HorizTwoFingerScroll"  "true"
        Option          "VertEdgeScroll"        "false"
        Option          "HorizEdgeScroll"       "false"
        Option          "TapButton1"            "1"
        Option          "TapButton2"            "3"
        Option          "TapButton3"            "2"
        Option          "Emulate3Buttons"       "true"
        Option          "SHMConfig"             "true"
EndSection

CleverCSS

I was working on TextPress the last days, (I got motivated by the fact that WordPress has got security problems once more) and had to notice that CSS could need some variables. I wanted to write a simple preprocessor for css that inserts variables but ended up writing a small parser that accepts indented CSS code with inline expressions.

Basically what it does is converting this:

// Single Line Comment
foo = 4px
font_family = 'Verdana', sans-serif
base_size = 0.9em

/*
   this is a multiline comment
 */
body:
    padding: $foo * 4
    font ->
        family: $font_family
        size: $base_size + 0.2em

a.foo:
    background-image: url(foo.png)
    span:
        display: none

Into this:

body {
  padding: 16px;
  font-family: Verdana, sans-serif;
  font-size: 1.1em;
}

a.foo {
  background-image: url(foo.png);
}

a.foo span {
  display: none;
}

The advantage might not be visible in that small example but consider complex layouts etc. One thing I would love to add is some support for layout extending. Say you have a base layout and you can say @extends(’layout.ccss’) and would get all the layout informations from the layout file. But I don’t know how useful this is.

Right now the conversion process is quite slow, but I wouldn’t generate such stylesheets on request. It’s a much better idea to do generate them from a script. During development one could still generate them automatically.

The module is available in the sandbox hg repo: clevercss.py. Just call clevercss.convert and pass it the CleverCSS markup.

Things that don’t work yet are unit conversions. For example you cannot do “1cm + 11mm”.

Vim File Templates

All python modules I use have the same header. Usually I copy other modules but why not load a default template into a python file in vim?

Here a small snippet that does exactly that:

function! LoadFileTemplate()
  silent! 0r ~/.vim/templates/%:e.tmpl
  syn match vimTemplateMarker "<+.++>" containedin=ALL
  hi vimTemplateMarker guifg=#67a42c guibg=#112300 gui=bold
endfunction

function! JumpToNextPlaceholder()
  let old_query = getreg('/')
  echo search("<+.++>")
  exec "norm! c/+>/e<CR>"
  call setreg('/', old_query)
endfunction

autocmd BufNewFile * :call LoadFileTemplate()
nnoremap <C-J> :call JumpToNextPlaceholder()<CR>a
inoremap <C-J> <ESC>:call JumpToNextPlaceholder()<CR>a

What it does is looking for a template called “extension.tmpl” in ~/.vim/templates. If it finds one it loads it and highlights everything between “<+" and "+>” as placeholder. Hitting Ctrl+J jumps to the next placeholder.

An example template could look like this:

# -*- coding: utf-8 -*-
"""
<+ MODULE_NAME +>

<+ DESCRIPTION +>

Licensed under the <+ LICENSE +> license, see X for more details etc.
Copyright by …
"""

If you want to load a file without a template, just hit “u” right at the beginning and the inserted template will disappear.

Fun with Ruby Syntax

Smilies:

smilies = :-? /:-/ :-D

That’s nonsense code, smilies just gets /:-/ assigned. Fun nevertheless. Why that works? The first thing is a symbol literal, then there is a ternary operator, first result expression is a regular expression literal, the second is the negative version of the “D” constant. Because the symbol is true the second return expression is never evaluated and nobody complains about the missing constant D.

JavaScript Client Side Image Thumbnailing

First of all, the Quality of the thumbnail is quite bad, at least by now (just tested in firefox). Furthermore it’s a bad idea to do thumbnailing on the clientside but it works.

function makeThumb(src, canvas, width, height) {
  canvas.width = width;
  canvas.height = height;
  var ctx = canvas.getContext('2d');
  ctx.scale(
    width / src.width,
    height / src.height
  );
  ctx.drawImage(src, 0, 0);
}

src must be an Image, canvas a canvas element and width/height is the size of the resulting thumbnail. If you want to get the image data of the thumbnail for saving on the server or whatever, you can do canvas.toDataURL() which returns the data of the image as base64 version of a png.

Another Way to Capture Print in Python

When working with the Python ast module i found the pycodegen which generates bytecode from an ast. Basically what you can do with it is modifying the ast before compiling the code. So one use case is compiling code and patching all Print/Printnl nodes without a destination to buffer into a stream:

import compiler

def compile_with_stream(code, stream, filename='?'):
    print_nodes = [compiler.ast.Print, compiler.ast.Printnl]
    rv = compiler.parse(code)
    nodes = [rv]
    while nodes:
        node = nodes.pop()
        node.filename = filename
        if node.__class__ in print_nodes and node.dest is None:
            node.dest = compiler.ast.Const(stream, node.lineno)
        nodes.extend(node.getChildNodes())
    gen = compiler.pycodegen.ModuleCodeGenerator(rv)
    return gen.getCode()

Instead of using compiler.ast.Const you can also use compiler.ast.Name and point to a variable that contains the stream. This would allow caching the bytecode too. Now what it does is translating “print ‘Hello World’” to “print >> stream, ‘Hello World’” if there is no given destination. This can be useful for template engines (once again ^^).

Example usage:

from StringIO import StringIO
stream = StringIO()
exec compile_with_stream('print "Hello World"', stream)
print 'Captured: %r' % stream.getvalue()

any/all for Python2.4

Want to use any/all in Python2.4? Here the minimal implementation that break on the first not matching value like any and all in Python2.5 do:

def any(iterable):
    return False in (not x for x in iterable)

def all(iterable):
    return True not in (not x for x in iterable)

Credit for the idea goes to BlackJack from the German python forum

DBUS Introspection

Small snippet to get all the methods an DBus object supports:

from dbus import SessionBus, Interface
from dbus.introspect_parser import process_introspection_data

def introspect_object(named_service, object_path):
    obj = SessionBus().get_object(named_service, object_path)
    iface = Interface(obj, 'org.freedesktop.DBus.Introspectable')
    return process_introspection_data(iface.Introspect())

Example usage:

>>> introspect_object('org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Shell')
{'org.freedesktop.DBus.Introspectable.Introspect': '',
 'org.freedesktop.DBus.Properties.Get': 'ss',
 'org.freedesktop.DBus.Properties.Set': 'ssv',
 'org.gnome.Rhythmbox.Shell.addToQueue': 's',
 'org.gnome.Rhythmbox.Shell.clearQueue': '',
 'org.gnome.Rhythmbox.Shell.getPlayer': '',
 'org.gnome.Rhythmbox.Shell.getPlaylistManager': '',
 'org.gnome.Rhythmbox.Shell.getSongProperties': 's',
 'org.gnome.Rhythmbox.Shell.loadURI': 'sb',
 'org.gnome.Rhythmbox.Shell.present': 'u',
 'org.gnome.Rhythmbox.Shell.quit': '',
 'org.gnome.Rhythmbox.Shell.removeFromQueue': 's',
 'org.gnome.Rhythmbox.Shell.setSongProperty': 'ssv'}

Unfortunately this does not show the names of the arguments, just the types thereof. If you remove the process_introspection_data call you get back a string with the XML data containing all the introspection information. You can then parse it on your own, the format is straightforward.

cogitations driven by wordpress