Revision: 3658
Author: pekka.klarck
Date: Sat May 29 07:03:02 2010
Log: Now that parallel is no more (win!) only timeouts use threads and our
custom threading module could be simplified.
http://code.google.com/p/robotframework/source/detail?r=3658
Modified:
/trunk/src/robot/running/timeouts.py
/trunk/src/robot/utils/robotthread.py
/trunk/src/robot/utils/stoppablethread.py
/trunk/utest/utils/test_robotthread.py
=======================================
--- /trunk/src/robot/running/timeouts.py Thu May 20 23:49:18 2010
+++ /trunk/src/robot/running/timeouts.py Sat May 29 07:03:02 2010
@@ -15,7 +15,7 @@
import time
from robot import utils
-from robot.utils.robotthread import Thread, Runner, Event
+from robot.utils.robotthread import ThreadedRunner
from robot.errors import TimeoutError, DataError, FrameworkError
from signalhandler import STOP_SIGNAL_MONITOR
@@ -72,7 +72,7 @@
return cmp(self.time_left(), other.time_left())
def run(self, runnable, args=None, kwargs=None, logger=None):
- if self.error is not None:
+ if self.error:
raise DataError(self.error)
if not self.active():
raise FrameworkError('Timeout is not active')
@@ -84,21 +84,10 @@
STOP_SIGNAL_MONITOR.start_running_keyword()
if timeout <= 0:
raise TimeoutError(self.get_message())
- notifier = Event()
- runner = Runner(runnable, args, kwargs, notifier)
- # Thread's name is important - it's used in utils.outputcapture
- thread = Thread(runner, stoppable=True, daemon=True,
name='TIMED_RUN')
- thread.start()
- time.sleep(0.001)
- notifier.wait(timeout)
- if runner.is_done():
+ runner = ThreadedRunner(runnable, args, kwargs)
+ if runner.run_in_thread(timeout):
return runner.get_result()
- try:
- thread.stop()
- except utils.RERAISED_EXCEPTIONS:
- raise
- except:
- pass
+ runner.stop_thread()
raise TimeoutError(self.get_message())
def get_message(self):
=======================================
--- /trunk/src/robot/utils/robotthread.py Tue Mar 23 04:15:41 2010
+++ /trunk/src/robot/utils/robotthread.py Sat May 29 07:03:02 2010
@@ -13,62 +13,36 @@
# limitations under the License.
-import os
import sys
-import threading
-
-from robot.errors import FrameworkError
-
-if os.name == 'java':
- from java.lang import Runnable, Throwable
- from java.lang import Thread as JavaThread
- java_exceptions = (Throwable,)
-else:
- from stoppablethread import StoppablePythonThread
- class Runnable:
- pass
- java_exceptions = ()
-
-
-class _FakeSemaphore:
- def acquire(self):
+from threading import Event
+
+from robot.utils import RERAISED_EXCEPTIONS
+
+
+if sys.platform.startswith('java'):
+ from java.lang import Thread, Runnable, Throwable
+ JAVA_EXCEPTIONS = (Throwable,)
+
+else:
+ from stoppablethread import Thread
+ class Runnable(object):
pass
- def release(self):
- pass
-
-def Semaphore():
- # Cygwin Python threads are buggy so use a fake semaphore when possible
- if sys.platform.count('cygwin') > 0 \
- and threading.currentThread().getName() == 'MainThread':
- return _FakeSemaphore()
- return threading.Semaphore()
-
-
-Event = threading.Event
-
-
-def current_thread():
- if os.name == 'java':
- return JavaThread.currentThread()
- return threading.currentThread()
-
-
-class Runner(Runnable):
+ JAVA_EXCEPTIONS = ()
+
+
+class ThreadedRunner(Runnable):
def __init__(self, runnable, args=None, kwargs=None, notifier=None):
- self._runnable = runnable
- self._args = args is not None and args or ()
- self._kwargs = kwargs is not None and kwargs or {}
- self._notifier = notifier is not None and notifier or
threading.Event()
+ self._runnable = lambda: runnable(*(args or ()), **(kwargs or {}))
+ self._notifier = Event()
self._result = None
self._error = None
+ self._thread = None
def run(self):
- if self.is_done():
- raise FrameworkError('Runner can be run only once')
try:
- self._result = self._runnable(*self._args, **self._kwargs)
- except java_exceptions, error:
+ self._result = self._runnable()
+ except JAVA_EXCEPTIONS, error:
self._error = error
except:
self._error = sys.exc_info()[1]
@@ -76,25 +50,22 @@
__call__ = run
- def is_done(self):
+ def run_in_thread(self, timeout):
+ self._thread = Thread(self)
+ self._thread.setDaemon(True)
+ self._thread.start()
+ self._notifier.wait(timeout)
return self._notifier.isSet()
def get_result(self):
- if not self.is_done():
- self._notifier.wait()
- if self._error is not None:
+ if self._error:
raise self._error
return self._result
-
-def Thread(runner, stoppable=False, daemon=False, name=None):
- if os.name == 'java':
- thread = JavaThread(runner) # This is always stoppable
- elif not stoppable:
- thread = threading.Thread(target=runner)
- else:
- thread = StoppablePythonThread(target=runner)
- thread.setDaemon(daemon)
- if name is not None:
- thread.setName(name)
- return thread
+ def stop_thread(self):
+ try:
+ self._thread.stop()
+ except RERAISED_EXCEPTIONS:
+ raise
+ except:
+ pass
=======================================
--- /trunk/src/robot/utils/stoppablethread.py Fri May 28 04:17:47 2010
+++ /trunk/src/robot/utils/stoppablethread.py Sat May 29 07:03:02 2010
@@ -16,8 +16,7 @@
import threading
-class StoppablePythonThread(threading.Thread):
-
+class Thread(threading.Thread):
"""A subclass of threading.Thread, with a stop() method.
Original version posted by Connelly Barnes to python-list and
available at
@@ -29,14 +28,13 @@
in Python because in Jython we can use java.lang.Thread.
"""
- def __init__(self, *args, **kwargs):
- threading.Thread.__init__(self, *args, **kwargs)
+ def __init__(self, runner):
+ threading.Thread.__init__(self, target=runner)
self._stopped = False
def start(self):
- """Start the thread."""
self.__run_backup = self.run
- self.run = self.__run # Force the Thread to install our trace.
+ self.run = self.__run
threading.Thread.start(self)
def stop(self):
=======================================
--- /trunk/utest/utils/test_robotthread.py Thu Mar 4 20:58:41 2010
+++ /trunk/utest/utils/test_robotthread.py Sat May 29 07:03:02 2010
@@ -1,83 +1,39 @@
-import unittest, time, os, sys
-from threading import Event
-if os.name == 'java':
- import java.lang
+import unittest
+import sys
from robot.utils.asserts import *
-from robot.errors import *
-
-from robot.utils.robotthread import Runner, Thread
+
+from robot.utils.robotthread import ThreadedRunner
from thread_resources import *
class TestRunner(unittest.TestCase):
def test_passing(self):
- runner = Runner(passing)
- assert_false(runner.is_done())
+ runner = ThreadedRunner(passing)
runner.run()
- assert_true(runner.is_done())
assert_none(runner.get_result())
-
- def test_notifier(self):
- notifier = Event()
- runner = Runner(passing, notifier=notifier)
- assert_false(runner.is_done())
- assert_false(notifier.isSet())
- runner.run()
- assert_true(runner.is_done())
- assert_true(notifier.isSet())
def test_returning(self):
for arg in [ 10, 'hello', ['l','i','s','t'], unittest]:
- runner = Runner(returning, args=(arg,))
- assert_false(runner.is_done())
+ runner = ThreadedRunner(returning, args=(arg,))
runner.run()
- assert_true(runner.is_done())
assert_equals(runner.get_result(), arg)
def test_failing(self):
- runner = Runner(failing, args=('hello world',))
- assert_false(runner.is_done())
+ runner = ThreadedRunner(failing, args=('hello world',))
runner.run()
- assert_true(runner.is_done())
- try:
- runner.get_result()
- fail('get_result did not raise an exception as expected')
- except Exception, err:
- assert_equals(str(err), 'hello world')
-
- if os.name == 'java':
+ assert_raises_with_msg(Exception, 'hello world', runner.get_result)
+
+ if sys.platform.startswith('java'):
+ from java.lang import Error
+
def test_java_failing(self):
- runner = Runner(java_failing, args=('hi tellus',))
- assert_false(runner.is_done())
+ runner = ThreadedRunner(java_failing, args=('hi tellus',))
runner.run()
- assert_true(runner.is_done())
- try:
- runner.get_result()
- fail('get_result did not raise an exception as expected')
- except java.lang.Error, err:
- assert_equals(err.getMessage(), 'hi tellus')
+ assert_raises_with_msg(Error, 'java.lang.Error: hi tellus',
+ runner.get_result)
-class TestThread(unittest.TestCase):
-
- def test_stoppable(self):
- thread = Thread(Runner(None), stoppable=True)
- assert_true(hasattr(thread, 'stop'))
-
- def test_daemon(self):
- assert_true(Thread(Runner(None), daemon=True).isDaemon())
- assert_false(Thread(Runner(None), daemon=False).isDaemon())
-
- def test_name(self):
- thread = Thread(Runner(None), name='My Name')
- assert_equals(thread.getName(), 'My Name')
-
- def test_noname(self):
- name = Thread(Runner(None)).getName()
- assert_true(isinstance(name, basestring))
- assert_true(len(name) > 0)
-
if __name__ == '__main__':
unittest.main()