Commits

Georges Racinet  committed 68f1c1e

Solving the pbm that internal datetime computations don't pass isinstance()

  • Participants
  • Parent commits 0dac599

Comments (0)

Files changed (2)

    datetime(2013, 1, 1, 3, 57)
    >>> datetime.date(2013, 1, 1)
    datetime.date(2013, 1, 1)
+
+Our replacement class is the one loaded from the ``datetime`` module,
+but instances of the original ``datetime`` class behave exactly as
+instances of our ``datetime.datetime``. This is needed because most
+computational methods, actually return an object of the original
+``datetime`` class. This works with python >= 2.6 only.
+
+First let's check that our class is a subclass of the orininal
+one. If this fails, this test does not mean anything anymore::
+
+  >>> datetime.datetime is datetime.original_datetime
+  False
+  >>> issubclass(datetime.datetime, datetime.original_datetime)
+  True
+
+Then let's demonstrate the behaviour::
+
+  >>> odt = datetime.original_datetime(2012, 1, 1)
+  >>> isinstance(odt, datetime.datetime)
+  True
+  >>> issubclass(datetime.original_datetime, datetime.datetime)
+  True

File anybox/testing/datetime/mock_dt.py

-import sys
 from datetime import *
 from datetime import datetime as original_datetime
-from time import time as original_time
+
+class ReplacementSubclassMeta(type):
+    """A metaclass for classes that subclass a given one to replace it.
+
+    Usually, internal methods of the original class (or of the same module)
+    will return instances of the original class directly. This meta-class
+    makes it so that ``isinstance`` (resp. ``isssubclass``) does not fail for
+    instances of the original class (resp. the original class).
+
+    The replacement subclass is expected to have an ``__original_class__``
+    attribute or to inherite the original class in latest position.
+    """
+
+    @classmethod  # dont' want to pollute the classes themselves
+    def get_original_class(mks, cls):
+        orig = getattr(cls, '___original_class__', None)
+        if orig is not None:
+            return orig
+        bases = cls.__bases__
+        if not bases:
+            return
+        return bases[-1]
+
+    def __instancecheck__(cls, instance):
+        return isinstance(instance, cls.get_original_class(cls))
+
+    def __subclasscheck__(cls, subcls):
+        return issubclass(subcls, cls.get_original_class(cls))
+
 
 class datetime(original_datetime):
 
+    __metaclass__ = ReplacementSubclassMeta
+
     _current_now = None
 
     @classmethod
         of 'now'.
         """
         cls.set_now(None)
+