decorator issue with modules dbus & gobject

Makiavelik eudes.elie at gmail.com
Thu Aug 18 14:02:44 CEST 2011


Hi,
Here is a sample code that reproduces the issue :
[code]
import logging
import unittest
import signal
import gobject
import dbus
from functools import wraps
from dbus.mainloop.glib import DBusGMainLoop

class TimeoutException(Exception):
   pass

def timeout(timeout_time=1800):
   """
   decorator function catching the argument
   """
   def timeout_function(func):
       """
       decorator function
       """
       @wraps(func)
       def _timeout_function(self):
           """
           create a signal handler
           set the timeout with the argument given while calling the
decorator @timeout
           call the function
           catch a timeout exception if necessary
           """
           def timeout_handler(signum, frame):
               print 'Timeout (%s sec) reached' % str(timeout_time)
               raise TimeoutException()

           old_handler = signal.signal(signal.SIGALRM,
timeout_handler)
           signal.alarm(timeout_time) # triger alarm in timeout_time
seconds
           try:
               retval = func(self)
           finally:
               signal.signal(signal.SIGALRM, old_handler)
           signal.alarm(0)
           return retval
       return _timeout_function
   return timeout_function

class Test_loopRun_And_Timeout(unittest.TestCase):
   def __init__(self,*args,**kwargs):
       super(Test_loopRun_And_Timeout, self).__init__(*args,**kwargs)
       dbus_loop = DBusGMainLoop(set_as_default=True)
       self.bus = dbus.SessionBus(private=True,mainloop=dbus_loop)
       self.loop = gobject.MainLoop()

       logging.basicConfig()
       self.__logger = logging.getLogger("Tests.%s" %
self.__class__.__name__)
       self.__logger.setLevel(logging.DEBUG)

   def setUp(self):
       '''
       in this part, mediarouter can not be created
       Setup are all launch in //
       So if 50 tests are run in this class, 50 mediarouters are
created
       '''
       pass


   def tearDown(self):
       '''
       '''

   @timeout(5)
   def test_001(self):
       '''
       '''
       self.__logger.info('[CHECKPOINT] test_001')
       try:
           self.__logger.info('entering a waiting loop')
           self.loop.run()
           self.__logger.info('dummy log, should not appear')
           self.fail()

       except KeyboardInterrupt:
           self.__logger.exception('Catching a Ctrl+c event (user or
timeout)')
       except :
           self.__logger.exception('Unexpected error')
           self.fail()


   @timeout(5)
   def test_002(self):
       '''
       '''
       def loop_quit(loop):
           loop.quit()
           return False


       self.__logger.info('[CHECKPOINT] test_002')
       try:
           self.__logger.info('entering a waiting loop')
           gobject.timeout_add(1000, loop_quit, self.loop)
           self.loop.run()
           self.__logger.info('exiting the loop')

       except KeyboardInterrupt:
           self.__logger.exception('Catching a Ctrl+c event (user or
timeout)')
           self.fail()
       except :
           self.__logger.exception('Unexpected error')
           self.fail()
[/code]

If I start a unittest campaign like this :
[code]
if __name__ == "__main__":
   #Add the test you want to run
   suite = unittest.TestSuite()

   #To choose a list of tests, comment those you don't want to run
   suite.addTest(Test_loopRun_And_Timeout('test_002'))
   suite.addTest(Test_loopRun_And_Timeout('test_001'))
   unittest.TextTestRunner(verbosity=0).run(suite)
   print 'done'
[/code]
the result give me 2 tests OK

Now If I launch this
[code]
if __name__ == "__main__":
   #Add the test you want to run
   suite = unittest.TestSuite()

   #To choose a list of tests, comment those you don't want to run
   suite.addTest(Test_loopRun_And_Timeout('test_001'))
   suite.addTest(Test_loopRun_And_Timeout('test_002'))
   unittest.TextTestRunner(verbosity=0).run(suite)
   print 'done'
[/code]
1 OK (test_001)
1 Fail (test_002 goes on timeout)

And if I am using more than 3 Testcases, the code is going to run in
infinite loop (Ctrl+C or timeout decorator does not work, only a kill
works)


Is there an issue using the 'timeout' decorator with the loop.run() ?



More information about the Python-list mailing list