def record_events(): """ Multi-threaded trait change event tracer. Usage ----- :: >>> from trace_recorder import record_events >>> with record_events() as change_event_container: ... my_model.some_trait = True >>> change_event_container.save_to_directory('C:\\dev\\trace') This will install a tracer that will record all events that occur from setting of some_trait on the my_model instance. The results will be stored in one file per running thread in the directory 'C:\\dev\\trace'. The files are named after the thread being traced. """ container = MultiThreadRecordContainer() recorder = MultiThreadChangeEventRecorder(container=container) trait_notifiers.set_change_event_tracers( pre_tracer=recorder.pre_tracer, post_tracer=recorder.post_tracer) try: yield container finally: trait_notifiers.clear_change_event_tracers() recorder.close()
def test_multi_thread_change_event_recorder(self): test_object = TestObject() container = MultiThreadRecordContainer() recorder = MultiThreadChangeEventRecorder(container=container) trait_notifiers.set_change_event_tracers( pre_tracer=recorder.pre_tracer, post_tracer=recorder.post_tracer) try: test_object.number = 5.0 thread = threading.Thread(target=test_object.add_to_number, args=(5, )) thread.start() thread.join() finally: trait_notifiers.clear_change_event_tracers() self.assertEqual(len(container._record_containers), 2) # save records container.save_to_directory(self.directory) for name in container._record_containers: filename = os.path.join(self.directory, '{0}.trace'.format(name)) with open(filename, 'r') as handle: lines = handle.readlines() self.assertEqual(len(lines), 4) # very basic checking if 'MainThread.trace' in filename: self.assertTrue( "-> 'number' changed from 2.0 to 5.0 in 'TestObject'\n" in lines[0]) else: self.assertTrue( "-> 'number' changed from 5.0 to 10.0 in 'TestObject'\n" in lines[0]) self.assertTrue('CALLING' in lines[1]) self.assertTrue('EXIT' in lines[2])
def record_events(): """ Multi-threaded trait change event tracer. Example ------- This will install a tracer that will record all events that occur from setting of some_trait on the my_model instance:: >>> from trace_recorder import record_events >>> with record_events() as change_event_container: ... my_model.some_trait = True >>> change_event_container.save_to_directory('C:\\dev\\trace') The results will be stored in one file per running thread in the directory 'C:\\dev\\trace'. The files are named after the thread being traced. """ container = MultiThreadRecordContainer() recorder = MultiThreadChangeEventRecorder(container=container) trait_notifiers.set_change_event_tracers(pre_tracer=recorder.pre_tracer, post_tracer=recorder.post_tracer) try: yield container finally: trait_notifiers.clear_change_event_tracers() recorder.close()
def test_multi_thread_change_event_recorder(self): test_object = TestObject() container = MultiThreadRecordContainer() recorder = MultiThreadChangeEventRecorder(container=container) trait_notifiers.set_change_event_tracers( pre_tracer=recorder.pre_tracer, post_tracer=recorder.post_tracer) try: test_object.number = 5.0 thread = threading.Thread( target=test_object.add_to_number, args=(5,)) thread.start() thread.join() finally: trait_notifiers.clear_change_event_tracers() self.assertEqual(len(container._record_containers), 2) # save records container.save_to_directory(self.directory) for name in container._record_containers: filename = os.path.join(self.directory, '{0}.trace'.format(name)) with open(filename, 'Ur') as handle: lines = handle.readlines() self.assertEqual(len(lines), 4) # very basic checking if 'MainThread.trace' in filename: self.assertTrue( "-> 'number' changed from 2.0 to 5.0 in 'TestObject'\n" in lines[0]) else: self.assertTrue( "-> 'number' changed from 5.0 to 10.0 in 'TestObject'\n" in lines[0]) self.assertTrue('CALLING' in lines[1]) self.assertTrue('EXIT' in lines[2])
def test_change_event_hooks(self): # Create the test object and a function listener. foo = Foo() def _on_foo_baz_changed(obj, name, old, new): pass foo.on_trait_change(_on_foo_baz_changed, 'baz') # Set the event tracer and trigger a cascade of change events. trait_notifiers.set_change_event_tracers( pre_tracer=self._collect_pre_notification_events, post_tracer=self._collect_post_notification_events) foo.baz = 3 self.assertEqual(len(self.pre_change_events), 4) self.assertEqual(len(self.post_change_events), 4) expected_pre_events = [ (foo, 'baz', 0.0, 3.0, foo._on_baz_change_notification), (foo, 'bar', 0.0, 1.0, foo._bar_changed.__func__), (foo, 'bar', 0.0, 1.0, foo._on_bar_change_notification), (foo, 'baz', 0.0, 3.0, _on_foo_baz_changed), ] self.assertEqual(self.pre_change_events, expected_pre_events) expected_post_events = [ (foo, 'bar', 0.0, 1.0, foo._bar_changed.__func__), (foo, 'bar', 0.0, 1.0, foo._on_bar_change_notification), (foo, 'baz', 0.0, 3.0, foo._on_baz_change_notification), (foo, 'baz', 0.0, 3.0, _on_foo_baz_changed), ] self.assertEqual(self.post_change_events, expected_post_events) self.assertEqual(self.exceptions, [None] * 4) # Deactivate the tracer; it should not be called anymore. trait_notifiers.clear_change_event_tracers() foo.baz = 23 self.assertEqual(len(self.pre_change_events), 4) self.assertEqual(len(self.post_change_events), 4)
def test_change_event_hooks(self): # Create the test object and a function listener. foo = Foo() def _on_foo_baz_changed(obj, name, old, new): pass foo.on_trait_change(_on_foo_baz_changed, 'baz') # Set the event tracer and trigger a cascade of change events. trait_notifiers.set_change_event_tracers( pre_tracer=self._collect_pre_notification_events, post_tracer=self._collect_post_notification_events) foo.baz = 3 self.assertEqual(len(self.pre_change_events), 4) self.assertEqual(len(self.post_change_events), 4) expected_pre_events = [ (foo, 'baz', 0.0, 3.0, foo._on_baz_change_notification), (foo, 'bar', 0.0, 1.0, foo._bar_changed.im_func), (foo, 'bar', 0.0, 1.0, foo._on_bar_change_notification), (foo, 'baz', 0.0, 3.0, _on_foo_baz_changed), ] self.assertEqual(self.pre_change_events, expected_pre_events) expected_post_events = [ (foo, 'bar', 0.0, 1.0, foo._bar_changed.im_func), (foo, 'bar', 0.0, 1.0, foo._on_bar_change_notification), (foo, 'baz', 0.0, 3.0, foo._on_baz_change_notification), (foo, 'baz', 0.0, 3.0, _on_foo_baz_changed), ] self.assertEqual(self.post_change_events, expected_post_events) self.assertEqual(self.exceptions, [None] * 4) # Deactivate the tracer; it should not be called anymore. trait_notifiers.clear_change_event_tracers() foo.baz = 23 self.assertEqual(len(self.pre_change_events), 4) self.assertEqual(len(self.post_change_events), 4)
def test_change_event_hooks_after_exception(self): # Create the test object and a function listener. foo = Foo() def _on_foo_fuz_changed(obj, name, old, new): raise FuzException('function') foo.on_trait_change(_on_foo_fuz_changed, 'fuz') # Set the event tracer and trigger a cascade of change events. trait_notifiers.set_change_event_tracers( pre_tracer=self._collect_pre_notification_events, post_tracer=self._collect_post_notification_events) foo.fuz = 3 self.assertEqual(len(self.pre_change_events), 4) self.assertEqual(len(self.post_change_events), 4) expected_pre_events = [ (foo, 'fuz', 0.0, 3.0, foo._on_fuz_change_notification), (foo, 'bar', 0.0, 1.0, foo._bar_changed.__func__), (foo, 'bar', 0.0, 1.0, foo._on_bar_change_notification), (foo, 'fuz', 0.0, 3.0, _on_foo_fuz_changed), ] self.assertEqual(self.pre_change_events, expected_pre_events) expected_post_events = [ (foo, 'bar', 0.0, 1.0, foo._bar_changed.__func__), (foo, 'bar', 0.0, 1.0, foo._on_bar_change_notification), (foo, 'fuz', 0.0, 3.0, foo._on_fuz_change_notification), (foo, 'fuz', 0.0, 3.0, _on_foo_fuz_changed), ] self.assertEqual(self.post_change_events, expected_post_events) self.assertEqual(self.exceptions[:2], [None, None]) self.assertIsInstance(self.exceptions[2], FuzException) self.assertEqual(self.exceptions[2].args, ('method', )) self.assertIsInstance(self.exceptions[3], FuzException) self.assertEqual(self.exceptions[3].args, ('function', ))
def test_change_event_hooks_after_exception(self): # Create the test object and a function listener. foo = Foo() def _on_foo_fuz_changed(obj, name, old, new): raise FuzException('function') foo.on_trait_change(_on_foo_fuz_changed, 'fuz') # Set the event tracer and trigger a cascade of change events. trait_notifiers.set_change_event_tracers( pre_tracer=self._collect_pre_notification_events, post_tracer=self._collect_post_notification_events) foo.fuz = 3 self.assertEqual(len(self.pre_change_events), 4) self.assertEqual(len(self.post_change_events), 4) expected_pre_events = [ (foo, 'fuz', 0.0, 3.0, foo._on_fuz_change_notification), (foo, 'bar', 0.0, 1.0, foo._bar_changed.im_func), (foo, 'bar', 0.0, 1.0, foo._on_bar_change_notification), (foo, 'fuz', 0.0, 3.0, _on_foo_fuz_changed), ] self.assertEqual(self.pre_change_events, expected_pre_events) expected_post_events = [ (foo, 'bar', 0.0, 1.0, foo._bar_changed.im_func), (foo, 'bar', 0.0, 1.0, foo._on_bar_change_notification), (foo, 'fuz', 0.0, 3.0, foo._on_fuz_change_notification), (foo, 'fuz', 0.0, 3.0, _on_foo_fuz_changed), ] self.assertEqual(self.post_change_events, expected_post_events) self.assertEqual(self.exceptions[:2], [None, None]) self.assertIsInstance(self.exceptions[2], FuzException) self.assertEqual(self.exceptions[2].args, ('method',)) self.assertIsInstance(self.exceptions[3], FuzException) self.assertEqual(self.exceptions[3].args, ('function',))
def test_change_event_recorder(self): test_object = TestObject() container = RecordContainer() recorder = ChangeEventRecorder(container=container) trait_notifiers.set_change_event_tracers( pre_tracer=recorder.pre_tracer, post_tracer=recorder.post_tracer) try: test_object.number = 5.0 finally: trait_notifiers.clear_change_event_tracers() filename = os.path.join(self.directory, 'MainThread.trace') container.save_to_file(filename) with open(filename, 'r') as handle: lines = handle.readlines() self.assertEqual(len(lines), 4) # very basic checking self.assertTrue( "-> 'number' changed from 2.0 to 5.0 in 'TestObject'\n" in lines[0]) self.assertTrue('CALLING' in lines[1]) self.assertTrue('EXIT' in lines[2])
def test_change_event_recorder(self): test_object = TestObject() container = RecordContainer() recorder = ChangeEventRecorder(container=container) trait_notifiers.set_change_event_tracers( pre_tracer=recorder.pre_tracer, post_tracer=recorder.post_tracer) try: test_object.number = 5.0 finally: trait_notifiers.clear_change_event_tracers() filename = os.path.join(self.directory, 'MainThread.trace') container.save_to_file(filename) with open(filename, 'Ur') as handle: lines = handle.readlines() self.assertEqual(len(lines), 4) # very basic checking self.assertTrue( "-> 'number' changed from 2.0 to 5.0 in 'TestObject'\n" in lines[0]) self.assertTrue('CALLING' in lines[1]) self.assertTrue('EXIT' in lines[2])