Running PyPy in a virtualenv

This is a quick guide to running your [python/django] project on PyPy, the fast JIT-based Python interpreter (and optionally benchmark re: cPython)

Install PyPy

Follow the clearly detailed instructions in: http://pypy.readthedocs.org

For example, for 32-bit linux I used:

$ wget https://bitbucket.org/pypy/pypy/downloads/pypy-1.8-linux.tar.bz2
$ tar xvf pypy-1.8-linux.tar.bz2

This will create a folder named pypy-1.8, which matches Python 2.7.2:

$ ./pypy-1.8/bin/pypy --version
Python 2.7.2 (0e28b379d8b3, Feb 09 2012, 19:41:19)
[PyPy 1.8.0 with GCC 4.4.3]

Create your virtual environment

Install distribute and pip for pypy:

$ wget http://python-distribute.org/distribute_setup.py
$ wget https://raw.github.com/pypa/pip/master/contrib/get-pip.py
$ ./pypy-1.8/bin/pypy distribute_setup.py
$ ./pypy-1.8/bin/pypy get-pip.py

Make sure you have at least virtualenv 1.6, else it won’t work with PyPy:

$ virtualenv --version
1.6.4

Install virtualenvwrapper, and create a new virtual environment for your projectx:

$ ./pypy-1.8/bin/pip install virtualenvwrapper
$ mkvirtualenv --no-site-packages --distribute --python=/path/to/pypy-1.8/bin/pypy projectx-pypy
$ python --version
Python 2.7.2 (0e28b379d8b3, Feb 09 2012, 19:41:19)
[PyPy 1.8.0 with GCC 4.4.3]

Now we have a virtual environment named projectx based on pypy that we can use as just any other virtualenv.

Setup your project

Install your project’s requirements as usual:

$ workon projectx-pypy
$ pip install -r requirements.txt -r test-requirements.txt

Benchmark if desired

Now I can easily compare timings between cPython and PyPy. I created another identical virtualenv based on cPython (2.7.2) and run the same tests (one testcase replicated 100000 times using nose test generators, just to have something time consuming and CPU-intensive).

PyPy:

$ workon projectx-pypy
$ nosetests
...
----------------------------------------------------------------------
Ran 100000 tests in 8.624s

cPython:

$ workon projectx
$ nosetests
...
----------------------------------------------------------------------
Ran 100000 tests in 38.180s

Of course this is not a representative sample, but just a simple test. In this one case, PyPy takes approximately 20% the execution time of cPython. Not bad, huh?

The PyPy people have more comprehensive benchmarks in their speed center.

So give PyPy a try, and share your results.

, , ,

1 Comment

Multiplying Python Unit Test Cases with Different Sets of Data

…or Data-Driven Tests

Often I find myself in the situation of wanting to run some unit test for a part of my system with different data values. I want to verify that the system works correctly with some combinations of data – and not just have a single good case test with a specific combination of parameters (which is often what people are contented with).

I do not want to create a test that loops over the test data, exercises the code, and verifies the correct execution with some assertions… that would make for a single test case that would fail at the first data combination that doesn’t work. I want it to be run as one test case per test data value.

The typical naive approach to this is to write a method that runs the actual test and performs assertions on the results (say verify_xxx_works), and create some test_xxx_* methods that call that one with different data values. Boy is that lame.

Fortunately, nose includes the concept of test functions as generators. If you write your test as a generator that spits out tuples of (callable, argument...), nose will call it and run one test case per yielded value, thus effectively multiplying your number of test cases. You will see OKs for values that pass, and one failure per each set of arguments that fails. Great!

Oops, wait, not so great. If you read the docs carefully (I didn’t on my first try) you will find the small print: Please note that method generators are not supported in unittest.TestCase subclasses

Meaning that if your tests are written using unittest.TestCase you’re on your own again.

Unhappy with the situation of not being able to run one TestCase method with different sets of data in a non-clumsy way, I’ve been playing around and the result is a small library that I’ve called “DDT” (which could either stand for Data-Driven or Data-Decorated Tests). It allows developers to create multiple test cases from a single test method, feeding it different data using a decorator.
Read the rest of this entry »

, , ,

3 Comments

Remote-Control Jenkins from Python

Motivation

I just recently changed jobs: my new development team is larger, it’s a very dynamic environment with multiple branches being created in git repositories all the time, and people are creating Jenkins build jobs in order to run automated builds and tests for these branches on a daily basis.

At some point the manual copy-pasting of Jenkins jobs that was the general practice was beginning to annoy me and I decided to give a try to Jenkins’ HTTP API. The goal was to be able to script the creation of jobs, from consistent updateable descriptions. The result has been the creation of the autojenkins package written in Python, that will allow us to query the status of Jenkins jobs, trigger manual builds, create new ones, and cleanup by removing old jobs.

Using Autojenkins

Autojenkins is published on PyPI, you install it simply with:
pip install autojenkins

Once installed, it provides an easy to use Python client for the Jenkins HTTP API. Here’s a taste of the API with some sample usage:

from autojenkins import Jenkins

j = Jenkins('http://jenkins.pe.local')

# trigger a manual build and check results
j.build('my-job')
j.last_result('my-job')

# get only the result string (one of 'SUCCESS', 'UNSTABLE', 'FAILURE'):
j.last_result('my-job')['result']

# get the configuration file for a job:
j.get_config_xml('template')

# Create a new job from a job named 'template', replacing variables
j.create_copy('my-new-job', 'template',
              repo='my-repo',
              branch='my-branch')

# build
j.build('my-new-job')

# check result and delete if successful:
result = j.last_result('my-new-job')['result']
if result == 'SUCCESS':
    j.delete('my-new-job')

Read the rest of this entry »

,

2 Comments

Only 960px? No More. Please

According to web browsing statistics only about 20% of the web users use displays 1024 pixels wide or less, and this count is fast declining. It looks like 1366px will quickly become the most used width. And still so many web pages are designed around fixed-width layouts of 960px, leaving most of us with half-empty displays with vertically laid-out information. Haven’t we realized displays are very horizontal nowadays?

I believe designers should seriously start considering adapting to the real sizes of their users’ screens. Be creative. Think of web pages as something horizontal rather than vertical – don’t make us scroll down all the time while leaving lots of empty space at the sides. Think adaptive layouts. Think. Do not copy what is already old and doesn’t suit most of us.

Hopefully at some point we developers will all use media queries and designers insisting on fixed width (which I understand gives them much more control) will provide for at least a couple of alternative layouts, one of them looking good on 1024px, and another one on 1366px or wider. Maybe things like this will help.

(For a time, this might be a little like when people supported IE6 and other browsers via loading alternative style sheets, but this time by using standard methods.)

Is anyone seriously raising to the challenge? Please let me know. I’d love to hear of high traffic sites already using some approach to multi-resolution support.

, ,

3 Comments

Publishing Django Test Coverage Reports in Jenkins

This post is built on some assumptions.

First, I assume that you already know that writing unit tests is good for you. Well, to be honest, if you are not systematically writing tests for your code, you shouldn’t be calling yourself a software engineer anyway. No excuses.

In consequence I also assume that your latest Django project includes its dose of unit testing. But do you have a clear idea of which parts of your Django site are not being tested? Are you taking action to improve on that area? In other words, are you already obtaining and analysing coverage data for your project?

If so, lucky you. I didn’t, decided it was about time, and set out to the task.

I will try to demistify the process, since it takes very little effort and you can reap substantial benefits from it – provided, of course, that you take a look at the coverage reports on a regular basis, and add tests for the uncovered methods… but you promise you will do that, won’t you? Great!

We will start by generating the reports manually, and will then move on to automating them into Jenkins, our friendly build butler.
Read the rest of this entry »

, , , , ,

2 Comments