Archive for the 'Snippet' Category

Mocker 0.10 and trivial patch-mocking of existing objects

Mocker 0.10 is out, with a number of improvements!

While we’re talking about Mocker, here is another interesting use case, exploring a pretty unique feature it offers.

Suppose we want to test that a method hello() on an object will call self.show(“Hello world!”) at some point. Let’s say that the code we want to test is this:

 class Greeting(object):

     def show(self, sentence):
         print sentence

     def hello(self):
         self.show("Hello world!")

This is the entire test method:

def test_hello(self):
    # Define expectation.
    mock = self.mocker.patch(Greeting)
    mock.show("Hello world!")
    self.mocker.replay()

    # Rock on!
    Greeting().hello()

This has helped me in practice a few times already, when testing some involved situations.

Note that you can also passthrough the call. In other words, the call may actually be made on the real method, and mocker will just assert that the call was really made, whatever the effect is.

One more important point: mocker ensures that the real method exists in the real object, and has a specification compatible with the call made. If it doesn’t, and assertion error is raised in the test with a nice error message.

UPDATE: The method for doing this is actually mocker.patch() rather than mocker.mock(), as documented. Apologies.

Partial stubbing of os.path.isfile() with Mocker

One neat feature which Mocker offers is the ability to very easily implement custom behavior on specific functions or methods.

Take for instance the case where you want to pretend to some code that a given file exists, but you don’t want to get on the way of everything else which needs the same function:

>>> from mocker import *
>>> mocker = Mocker()
>>> isfile = mocker.replace("os.path.isfile", count=False)
>>> _ = expect(isfile("/non/existent")).result(True)
>>> _ = expect(isfile(ANY)).passthrough()

>>> mocker.replay()

>>> import os
>>> os.path.isfile("/non/existent")
True
>>> os.path.isfile("/etc/passwd")
True
>>> os.path.isfile("/other")
False

>>> mocker.restore()

>>> os.path.isfile("/non/existent")
False

Notice that the count=False parameter is available in version 0.9.2. Without it Mocker will act in a more mocking-strict way and enforce that the given expressions should be executed precisely the given number of times (which defaults to one, and may be modified with the count() method).

Python’s os.environ

As Chris Armstrong pointed out yesterday, os.environ.pop() is broken in Python versions at least up to 2.5. The method will simply remove the entry from the in-memory dictionary which holds a copy of the environment:

>>> import os
>>> os.system("echo $ASD")

0
>>> os.environ["ASD"] = "asd"
>>> os.system("echo $ASD")
asd
0
>>> os.environ.pop("ASD")
'asd'
>>> os.system("echo $ASD")
asd
0

I can understand that the interface of dictionaries has evolved since os.environ was originally planned, and the os.environ.pop method was overlooked for a while. What surprises me a bit, though, is why it was originally designed the way it is. First, the interface will completely ignore new methods added to the dictionary interface, and they will apparently work. Then, why use a copy of the environment in the first place? This will mean that any changes to the real environment are not seen.

This sounds like something somewhat simple to do right. Here is a working hack using ctypes to show an example of the behavior I’d expect out of os.environ (Python 2.5 on Ubuntu Linux):

from ctypes import cdll, c_char_p, POINTER
from UserDict import DictMixin
import os

c_char_pp = POINTER(c_char_p)

class Environ(DictMixin):

    def __init__(self):
        self._process = cdll.LoadLibrary(None)
        self._getenv = self._process.getenv
        self._getenv.restype = c_char_p
        self._getenv.argtypes = [c_char_p]

    def keys(self):
        result = []
        environ = c_char_pp.in_dll(self._process, "environ")
        i = 0
        while environ[i]:
            result.append(environ[i].split("=", 1)[0])
            i += 1
        return result

    def __getitem__(self, key):
        value = self._getenv(key)
        if value is None:
            raise KeyError(key)
        return value

    def __setitem__(self, key, value):
        os.putenv(key, value)

    def __delitem__(self, key):
        os.unsetenv(key)

I may be missing some implementation detail which would explain the original design. If not, I suggest we just change the implementation to something equivalent (without ctypes).

Mandelbrot Set

I’ve finally posted the Mandelbrot Set code snippet that was sitting on my disk for a while.

It computes and draws the Mandelbrot Set fractal using pygame, and also Python for Series 60.

Three different screenshots are provided. They show the snippet running under pygame, under pymaemo in a Nokia 770, and under Python for Series 60 in a Nokia N70 phone.

I was quite amazed to see the Nokia 770 running the pygame version without any changes in the code. Kudos to Osvaldo, Rodrigo and Ruda at INdT for the pymaemo port, and to Nokia for the great device.

Labyrinth Solver

What about a labyrinth solver function in 16 lines of Python? :-)

Textual watermarks with Python Imaging Library

I’ve added a new snippet about doing watermarks with PIL.

Decorator for automatic inclusion of function definition in __doc__

Python 2.4 included support for function decorators. Decorators are callable objects that may modify a given function or class method arbitrarily when they’re prepended with specific syntax to the function/method definition.

The following code implements a decorator that will automatically include the arguments accepted by a given function in its own documentation:

import inspect
def argspec(object):
    spec = inspect.formatargspec(*inspect.getargspec(object))
    if object.__doc__:
        object.__doc__ = "%s%s\n\n%s" % (object.__name__, spec, object.__doc__)
    else:
        object.__doc__ = "%s%s" % (object.__name__, spec)
    return object

It may be used as follows:

>>> @argspec
... def test(a,b=1,*c,**d):
...     """My test function"""
...
>>> print test.__doc__
test(a, b=1, *c, **d)

My test function

Notice that this is interesting mostly for hacking value. Most softwares that generate documentation for Python code, like the standard pydoc module, already take care of building and showing that information.

All combinations of N elements

Here’s a snippet to compute all combinations of N elements over K positions.

Permutations of all subsets

Another snippet to compute the permutations of all subsets.

Permutations and derangements

Two snippets to compute permuatations and derangements in Python.