class ClockUnitTester(unittest.TestCase): """ Tester for the auxi.core.time.Clock class. """ def setUp(self): self.object = Clock("NameA", description="DescriptionA", start_datetime=datetime(2016, 2, 1), timestep_period_duration=TimePeriod.year, timestep_period_count=3) def test_constructor(self): self.assertEqual(self.object.name, "NameA") self.assertEqual(self.object.description, "DescriptionA") self.assertEqual(self.object.start_datetime, datetime(2016, 2, 1)) self.assertEqual(self.object.timestep_period_duration, TimePeriod.year) self.assertEqual(self.object.timestep_period_count, 3) def test_tick(self): self.assertEqual(self.object.timestep_ix, 0) self.object.tick() self.assertEqual(self.object.timestep_ix, 1) def test_reset(self): self.object.tick() self.object.reset() self.assertEqual(self.object.timestep_ix, 0) def test_get_datetime_at_period_ix(self): self.assertEqual(self.object.get_datetime_at_period_ix(3), datetime(2019, 2, 1)) def test_get_datetime(self): self.object.tick() self.assertEqual(self.object.get_datetime(), datetime(2017, 2, 1))
class TimeBasedModel(NamedObject): """ Represents an time based model class. An instance of this class is by default configured to run only once, thus functioning as a steady state model. The instance's time based parameters must be configured for it to function as a time based model. :param name: The name. :param description: The description. :param start_datetime: The start datetime of the model. :param period_duration: The duration of the model's time period. e.g. month, day etc. :param period_count: The number of periods to execute the model for. """ def __init__(self, name, description=None, start_datetime=datetime.now(), period_duration=TimePeriod.year, period_count=1): self.clock = Clock( "Clock", start_datetime=get_date(start_datetime), timestep_period_duration=period_duration) self.period_count = period_count self.entities = [] super(TimeBasedModel, self).__init__(name, description=description) def _update_childrens_parent_path(self): for e in self.entities: e.set_parent_path(self.name) @property def name(self): return self._name @name.setter def name(self, value): self._name = value self._update_childrens_parent_path() def create_entity(self, name, gl_structure, description=None): """ Create an entity and add it to the model. :param name: The entity name. :param gl_structure: The entity's general ledger structure. :param description: The entity description. :returns: The created entity. """ new_entity = Entity(name, gl_structure, description=description) self.entities.append(new_entity) return new_entity def remove_entity(self, name): """ Remove an entity from the model. :param name: The name of the entity to remove. """ entity_to_remove = None for e in self.entities: if e.name == name: entity_to_remove = e if entity_to_remove is not None: self.entities.remove(entity_to_remove) def prepare_to_run(self): """ Prepare the model for execution. """ self.clock.reset() for e in self.entities: e.prepare_to_run(self.clock, self.period_count) def run(self): """ Execute the model. """ self.prepare_to_run() for i in range(0, self.period_count): for e in self.entities: e.run(self.clock) self.clock.tick() def __getitem__(self, key): return [e for e in self.entities if e.name == key][0]