Implementation Details¶
Internally, time-travel
has 2 main objects: a clock
, and
an event pool
.
The Clock¶
The clock is an object that holds the current time (as a float), and has
listeners
that are registered to it.
Whenever the time changes, the listeners’s callback is called with the new
time so they can react to it.
The Event Pool¶
The event pool keeps a set of events for different file descriptors, in different timestamps. The pool’s job is to keep those events and to retrieve them for different patchers.
Writing a Patcher¶
Lets create a new patcher that patches the time
module.
Your patcher should inherit from BasePatcher
and implement 2 methods:
- get_patched_module should return the actual module being patched by the patcher.
- get_patch_actions should return a list containing 3-tuples with the following information: (object_name, the_real_object, fake_object)
import time
from time_travel.patchers.basic_patcher import BasicPatcher
class MyNewPatcher(BasicPatcher):
def get_patched_module(self):
return time
def get_patch_actions(self):
return ('time.time', time.time, self._mock_time)
def _mock_time(self):
return 4 # Decided by a fair dice roll.
Adding the patcher to time-travel¶
time-travel
uses entry points to add external patchers to it.
For example let’s imagine that our MyNewPatcher
class is located in a file
named my_new_patcher.py
. In order to add the new patcher to time-travel
just add the new class to the time_travel.patchers entry point in
setup.py
:
from setuptools import setup
setup(
...,
entry_points={
'time_travel.patchers' : [
'my_new_patcher = my_new_patcher:MyNewPatcher',
],
}
)
Event Types Hooks¶
If you need to hook event types to TimeTravel.event_types
(like
select.select()
does) your patcher should override 2 methods:
- get_events_namespace should return a string that identifies the “namespace”
of the event types. For example, if this returns “foo”, your events will be
registered under
TimeTravel.event_types.foo
. - get_event_types should return an
Enum
object that contains the events.
For example:
from time_travel.patchers.basic_patcher import BasicPatcher
class MyNewPatcher(BasicPatcher):
@staticmethod
def get_events_namespace():
return "foo"
@staticmethod
def get_event_types():
return Enum("events", ['READ', 'WRITE'])