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.

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%snn%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.