How to mock the "+" operator in python (specifically datetime.date + datetime.timedelta)

mocking, python, python-mock

Solution

Add a `__add__` method to your `FakeDate()` class:

class FakeDate(datetime.date):
     @classmethod
     def today(cls):
         return cls(1999, 12, 31)
     def __add__(self, other):
         res = super(FakeDate, self).__add__(other)
         return type(self)(res.year, res.month, res.day)

Demo:

>>> class FakeDate(datetime.date):
...      @classmethod
...      def today(cls):
...          return cls(1999, 12, 31)
...      def __add__(self, other):
...          res = super(FakeDate, self).__add__(other)
...          return type(self)(res.year, res.month, res.day)
... 
>>> FakeDate.today() + datetime.timedelta(days=1)
FakeDate(2000, 1, 1)

Note that you can simply delegate the actual adding to the `datetime.date` class here; all we need to do is convert the result back to a `FakeDate()` instance.

Problem

I have working through some date mocking issues in Django, and have the final hurdle (I hope) is the following situation. I have a FakeDate class, which derives from `datetime.date`, which it mocks out. The FakeDate class works as expected, however I get a problem when adding a `datetime.timedelta` to the FakeDate, in that it returns a genuine `datetime.date`, rather than the mock. This is important as elsewhere in a third party library there is an `isinstance(value, datetime.date)` check, which will always fail when using timedelta. ``` >>> import mock >>> import datetime >>> >>> class FakeDate(datetime.date): ... @classmethod ... def today(cls): ... return cls(1999, 12, 31) ... >>> FakeDate.today() FakeDate(1999, 12, 31) >>> FakeDate(2000, 1, 1) FakeDate(2000, 1, 1) >>> FakeDate(1999, 12, 31) + datetime.timedelta(days=1) datetime.date(2000, 1, 1) ``` I want the FakeDate + timedelta addition to return a FakeDate object rather than a datetime.date object - which I imagine involves patching the timedelta somehow - but how / where can I do this?

Original source