Wednesday, September 21, 2011

I'm my own grandpa.

A fellow Pythonaut had a simple problem...
How to test code with dependencies on the date?  Specifically, a Django project with models that have DateTimeFields with auto_now=True.

The chosen approach was to monkey-patch datetime.date.today() in order to return a constant value.
The first snag: datetime.date is a C class.  This means it is not monkey-patchable.

This can be solved by monkey-patching the entire datetime.date class.  The most straightforward thing to replace datetime.date with is a new subclass of datetime.date, whose only change is to override the today() function.

The second problem: there are now two kinds of datetime.date's floating around the system.  Those by datetime.date.today(), and those created by every other function, which being C code will still return the same class.

Specifically, DateTimeField validates isinstance(data, datetime.date) before saving to the database.

A class which is simultaneously a super and subclass of datetime.date is required.
Override __subclasshook__ so that isinstance(super(datetime.date)(), datetime.date) is True.

>>> class DateProxy(datetime.date):
...    __metaclass__ = abc.ABCMeta
...    @classmethod
...    def __subclasshook__(cls, C): return True
...    @classmethod
...    def today(cls): return datetime.date(2011,9,20)
...
>>> datetime.date = DateProxy


In other words, the superclass is also a subclass.  The parent of the parent being the grandparent, this class is it's own grandpa.

4 comments:

  1. I get why it has to be a _subclass_ of date, but why would it have to be a superclass??

    ReplyDelete
  2. Check Our Website For Play Online Casino Thanks For Sharing...!!!
    baccarat online
    royal gclub
    ผลบอลสด

    ReplyDelete
  3. Hello!! I'am glad to read the whole content of this blog and am very excited.Thank you.
    gclub
    gclub casino online
    gclub casino

    ReplyDelete
  4. Nice article great post comment ,thank for your sharing.

    goldenslot
    Gclub จีคลับ

    ReplyDelete